check Acrobat reader installed in pc and display installer - c#

my Manager asked about autoplay cd which has PDF files and check on user pc if adobe acrobat installed on user pc or not if it dosent installed message apear to install this program from cd I had windows application to check if adob reader or acrobat installed in pc or not I did that well but I want if this program wasnot installed acrobat reader installer apear from cd and user install this program.
public Form1()
{
RegistryKey adobe = Registry.LocalMachine.OpenSubKey("Software").OpenSubKey("Adobe");
if (adobe != null)
{
RegistryKey acroRead = adobe.OpenSubKey("Acrobat Reader");
if (acroRead != null)
{
string[] acroReadVersions = acroRead.GetSubKeyNames();
MessageBox.Show("The following version(s) of Acrobat Reader are installed: ");
foreach (string versionNumber in acroReadVersions)
{
MessageBox.Show(versionNumber);
}
}
}
else
{
MessageBox.Show("The following version(s) of Acrobat Reader arenot installed: ");
}

you need to invoke installer process. something like this.
Process myProcess = new Process();
myProcess.StartInfo.FileName = "path to acrobat installer";
myProcess.Start();
Better approach would be to add a custom action in your application setup for this.

There are several ways to check for this.
1/Check installed applications (win installer)
Each Windows installer project (MSI) has an updgrade code and a product code.
Simply put, the product code defines the version of the installed application and it's dependencies. The updgrade code stays the same over diffirent versions.
You can search the product code for acrobat reader and use windows installer dll to check if it is installed.
There is some code on codeproject (search for MsiInterop) which will has all the needed dllimports.
2/ Keep it simple.
Why not just check if there is an application associated with files that have a PDF extension??
If there is an associated application (may be something other than Acrobat Reader, e.g. foxit) assume everything is all right.
Otherwise, launch a browser pointing to http://get.adobe.com/reader/
This way, your application does not assume responsability over the user's choice of PDF reader.

Accessing the windows installer in C#:
public enum InstallState
{
NotUsed = -7,
BadConfig = -6,
Incomplete = -5,
SourceAbsent = -4,
MoreData = -3,
InvalidArg = -2,
Unknown = -1,
Broken = 0,
Advertised = 1,
Removed = 1,
Absent = 2,
Local = 3,
Source = 4,
Default = 5
}
[System.Runtime.InteropServices.DllImport("msi.dll", CharSet = CharSet.Unicode)]
internal static extern InstallState MsiQueryProductState(string szProduct);
If you know the product codes for Adobe Acrobat you can query its installation status:
bool acrobatInstalled = allAcrobatReaderProductCodes.Any(guid =>
{
var productCode = "{" + guid.ToString().ToUpper() + "}";
var msiState = MsiQueryProductState(productCode);
return msiState == InstallState.Local || msiState == InstallState.Default);
});
Where allAcrobatReaderCodes is an IEnumerable of all the acrobat reader product codes.

Related

Check if Adobe Acrobat Reader installed - pdf in WebBrowser control

I have an application that displays a pdf in a webBrowser control, using the following code
webBrowser1.Navigate(filename + "#toolbar=0");
It works perfectly if Adobe Reader is installed
I would like to check if Adobe Acrobat Reader is installed before displaying the window, or at least when trying to display the pdf.
I have adapted the following code from here Check Adobe Reader is installed (C#)?
As mentioned in the comments, unfortunately, it flags uninstalled versions as well.
I have also tried the 64 bit code in the same article but find errors I can't easily resolve and suspect would give the same result anyway as it simmply looks at the registry in a similar way.
using System;
using Microsoft.Win32;
namespace MyApp
{
class Program
{
static void Main(string[] args)
{
RegistryKey adobe = Registry.LocalMachine.OpenSubKey("Software").OpenSubKey("Adobe");
if(null == adobe)
{
var policies = Registry.LocalMachine.OpenSubKey("Software").OpenSubKey("Policies");
if (null == policies)
return;
adobe = policies.OpenSubKey("Adobe");
}
if (adobe != null)
{
RegistryKey acroRead = adobe.OpenSubKey("Acrobat Reader");
if (acroRead != null)
{
string[] acroReadVersions = acroRead.GetSubKeyNames();
Console.WriteLine("The following version(s) of Acrobat Reader are installed: ");
foreach (string versionNumber in acroReadVersions)
{
Console.WriteLine(versionNumber);
}
}
}
}
}
}
If Adobe pdf Reader is not loaded, a prompt appears to open(in any other installed reader), save the file or cancel.
I would like to be able to intercept this so as to Indicate that Adobe's reader is not available.
I have tried
private void webBrowser1_Navigating(object sender, WebBrowserNavigatingEventArgs e)
{
string url = e.Url.ToString();
if (url.StartsWith("res://ieframe.dll/navcancl.htm") && url.EndsWith("pdf"))
{
e.Cancel = true;
MessageBox.Show("Cannot open PDF!");
}
}
at the following https://social.msdn.microsoft.com/Forums/en-US/46aaeecd-5317-462a-ac36-9ebb30ba90e7/load-pdf-file-using-webbrowser-control-in-windows-form-c?forum=csharpgeneral
but found the open, save cancel event precedes the webBrowser1_Navigating.
I would appreciate any help in a reliable solution that will not flag uninstalled versions, or a seperate solution that will stop the open, save, cancel prompt, and allow me to create a message to install the reader
Thanks
The Simple Way is to use try / catch
in the try give the code.
The web browser will give error if there is an error so in the catch then say the user to install adobe reader.
Here is the sample
try
{
//your code goes her
}
catch(Exception ex)
{
if(ex.Message != null)
{
Console.WriteLine("Adobe Reader not Installed");
//this is where you say adobe reader is not installed
}
}

CefSharp Winform deployment via ClickOnce and requirements vc redist in Visual Studio 2019 - Error

When launch clickonce setup of CefSharp Winform Application return an error installing vc++ 2019 redist (vc++ is in deployment requirements). It's generate an empty directory during install.
"C:\Users\xxxxxx\AppData\Local\Temp\VSD66FC.tmp\vcredist_x86\vcredist_x86.exe has changed since it was initially published."
Both on Windows 7 and 10, same error. I need to install manually package.
I've removed Visual C++ "14" from requirements, but I don't know how include c++ library in the Application code.
I found a workaround. I'm using a service, but it should work in a winform:
private void InstallVCredist()
{
string exe = #"path to exe\VC_redist.x86.exe"; //set path
string stp = #"\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"; //set subkey
using (RegistryKey reg = Registry.LocalMachine.OpenSubKey(stp)) //recall registry
{
if (reg != null)
{
foreach (string dname in reg.GetSubKeyNames()) //loop search
{
using (RegistryKey sreg = reg.OpenSubKey(dname))
{
if (sreg.GetValue("DisplayName").ToString() == "Microsoft Visual C++ 2015-2019 Redistributable (x86) - 14.23.27820") //set dispayname of version
{
vcredist = "1"; //it's mine control variable
break;
}
}
}
}
}
if (vcredist == "0") //now testing if it was found
{
Process vc = new Process();
vc.StartInfo.FileName = exe;
//silent install
vc.StartInfo.Arguments = "/install /passive /norestart";
vc.StartInfo.UseShellExecute = false;
vc.StartInfo.CreateNoWindow = true;
//silent install
vc.Start();
vc.WaitForExit(); //as he says ;)
}
}

Uninstalling program

I'm trying to uninstall a program with this code.. But it doesn't seem to work. I've tried the other answers but didn't seem to work either.. Can someone help me with this? I'm trying to uninstall the program by a given name(displayName)
For example I give the displayName = Appname then this code should uninstall the Appname program from my computer.
public static void UninstallApplictionInstalled(string p_name)
{
string displayName;
string uninstlString;
RegistryKey key;
ProcessStartInfo info = new ProcessStartInfo();
Process uninstallProcess = new Process();
string temp;
// search in: CurrentUser
key = Registry.CurrentUser.OpenSubKey(#"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall");
foreach (String keyName in key.GetSubKeyNames())
{
RegistryKey subkey = key.OpenSubKey(keyName);
displayName = Convert.ToString(subkey.GetValue("DisplayName"));
uninstlString = Convert.ToString(subkey.GetValue("UninstallString"));
if (p_name.Equals(displayName, StringComparison.OrdinalIgnoreCase) == true)
{
uninstallProcess.StartInfo.FileName = "MsiExec.exe";
uninstallProcess.StartInfo.Arguments = " /x " + uninstlString + " /quiet /norestart";
uninstallProcess.Start();
uninstallProcess.WaitForExit();
break;
//Console.WriteLine(subkey.GetValue("UninstallString"));
}
}
// search in: LocalMachine_32
key = Registry.LocalMachine.OpenSubKey(#"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall");
foreach (String keyName in key.GetSubKeyNames())
{
RegistryKey subkey = key.OpenSubKey(keyName);
displayName = Convert.ToString(subkey.GetValue("DisplayName"));
uninstlString = Convert.ToString(subkey.GetValue("UninstallString"));
if (p_name.Equals(displayName, StringComparison.OrdinalIgnoreCase) == true)
{
uninstallProcess.StartInfo.FileName = "MsiExec.exe";
uninstallProcess.StartInfo.Arguments = " /x " + uninstlString + " /quiet /norestart";
uninstallProcess.Start();
uninstallProcess.WaitForExit();
break;
//Console.WriteLine(subkey.GetValue("UninstallString"));
}
}
// search in: LocalMachine_64
key = Registry.LocalMachine.OpenSubKey(#"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall");
foreach (String keyName in key.GetSubKeyNames())
{
RegistryKey subkey = key.OpenSubKey(keyName);
displayName = Convert.ToString(subkey.GetValue("DisplayName"));
uninstlString = Convert.ToString(subkey.GetValue("UninstallString"));
if (p_name.Equals(displayName, StringComparison.OrdinalIgnoreCase) == true)
{
//string prdctId = uninstlString.Substring((uninstlString.IndexOf("{")));
uninstallProcess.StartInfo.FileName = "MsiExec.exe";
uninstallProcess.StartInfo.Arguments = " /x " + uninstlString + " /quiet /norestart";
uninstallProcess.Start();
uninstallProcess.WaitForExit();
break;
//Console.WriteLine(subkey.GetValue("UninstallString"));
}
}
}
Only this pops up..
Duplicates: Welcome to Stackoverflow. Just to mention to you that I see this question asked in at least 3 different flavors. We will have to close some of your questions since the duplication scatters replies and can waste a lot of time if people answer the (seemingly) unanswered duplicates.
In short: please don't post the same question several times. Here are the other questions:
MsiExec.exe product id uninstall
MSI installer option- uninstalling an application
C#: Using C# for this can be clunky - no matter how you do it. I would not push a command line to msiexec.exe, but go directly via the MSI API. This API can be accessed via Win32 functions or COM automation.
Uninstall Appraches for MSI: For your reference, there is a myriad of ways to kick of an MSI
uninstall:
Uninstalling an MSI file from the command line without using msiexec.
Section 14 from the link above shows how to uninstall using C++ - if that is an option. However:, there are changes in the Visual Studio 2017 templates again, so it might need a tune-up to work "out-of-the-box".
However, I would use the MSI API - as already stated - and I would recommend you go via the native Win32 functions and that you use DTF (Deployment Tools Foundation) which is part of the WiX toolkit. It is a .NET wrapper for the MSI API - which will save you a lot of boilerplate code, at the expense of having to deploy the DTF DLL: Microsoft.Deployment.WindowsInstaller.dll along with your product. I do not know if this is acceptable. I have code that does not depend on DTF if need be, but it is much longer.
Mock-up C# Sample. Project reference to Microsoft.Deployment.WindowsInstaller.dll needed. Then try the below code in a fresh C# .NET project. You can get that DLL by installing the WiX toolkit - the open source toolkit to create MSI files. After installation check in %ProgramFiles(x86)%\WiX Toolset v3.11\bin (adjust for WiX version - current as of September 2018).
Installer GUI: Important note first: the setup's UI level is set via the Installer.SetInternalUI function. If you run in silent mode, then you need to run the executable elevated for the uninstall to work properly, or an access exception occurs. When you run in Full GUI mode, you need to elevate the install yourself - provided you have the rights to do so.
Run Elevated: How to check for admin rights: Check if the current user is administrator.
using System;
using Microsoft.Deployment.WindowsInstaller;
namespace UninstallMsiViaDTF
{
class Program
{
static void Main(string[] args)
{
// Update this name to search for your product. This sample searches for "Orca"
var productcode = FindProductCode("orca");
try
{
if (String.IsNullOrEmpty(productcode)) { throw new ArgumentNullException("productcode"); }
// Note: Setting InstallUIOptions to silent will fail uninstall if uninstall requires elevation since UAC prompt then does not show up
Installer.SetInternalUI(InstallUIOptions.Full); // Set MSI GUI level (run this function elevated for silent mode)
Installer.ConfigureProduct(productcode, 0, InstallState.Absent, "REBOOT=\"ReallySuppress\"");
// Check: Installer.RebootInitiated and Installer.RebootRequired;
}
catch (Exception e)
{
Console.WriteLine("Exception: " + e.Message);
}
Console.ReadLine(); // Keep console open
}
// Find product code for product name. First match found wins
static string FindProductCode(string productname)
{
var productcode = String.Empty;
var productname = productname.ToLower();
foreach (ProductInstallation product in ProductInstallation.AllProducts)
{
if (product.ProductName.ToLower().Contains(productname))
{
productcode = product.ProductCode;
break;
}
}
return productcode;
}
}
}

Bootstrap Uno API LibreOffice exception

With the following code:
static void Main()
{
try
{
var context = uno.util.Bootstrap.bootstrap();
}
catch (Exception ex)
{
Console.WriteLine(ex.toString());
}
}
I can start Writer of LibreOffice. This works fine with Version 4.4.4 but after installing version 5.0.0 and with new SDK Bootstrap.bootstrap() throws the exception:
"External component has thrown an exception"
Has anyone faced the same problem or some solution?
(.NET 4.0, Windows 7 64-bit, LibreOffice 5.0 Lite)
I have managed to solve the problem by setting the UNO_PATH environment variable before starting the soffice.exe server:
using static System.Environment;
var unoPath = #"C:\Program Files\LibreOffice 5\program"
// when running 32-bit LibreOffice on a 64-bit system, the path will be in Program Files (x86)
// var unoPath = #"C:\Program Files (x86)\LibreOffice 5\program"
SetEnvironmentVariable("UNO_PATH", unoPath, EnvironmentVariableTarget.Process);
SetEnvironmentVariable("PATH", GetEnvironmentVariable("PATH") + #";" + unoPath, EnvironmentVariableTarget.Process);
This was required because LibreOffice 5's program directory does not have "URE" subdirectory anymore (previous versions did) which is required for UNO layer.
To get the path to the LibreOffice installation you can ask e.g. the Windows registry. In C# this is smoething like that:
String unoPath = "";
// access 32bit registry entry for latest LibreOffice for Current User
Microsoft.Win32.RegistryKey hkcuView32 = Microsoft.Win32.RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.CurrentUser, Microsoft.Win32.RegistryView.Registry32);
Microsoft.Win32.RegistryKey hkcuUnoInstallPathKey = hkcuView32.OpenSubKey(#"SOFTWARE\LibreOffice\UNO\InstallPath", false);
if (hkcuUnoInstallPathKey != null && hkcuUnoInstallPathKey.ValueCount > 0)
{
unoPath = (string)hkcuUnoInstallPathKey.GetValue(hkcuUnoInstallPathKey.GetValueNames()[hkcuUnoInstallPathKey.ValueCount - 1]);
}
else
{
// access 32bit registry entry for latest LibreOffice for Local Machine (All Users)
Microsoft.Win32.RegistryKey hklmView32 = Microsoft.Win32.RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, Microsoft.Win32.RegistryView.Registry32);
Microsoft.Win32.RegistryKey hklmUnoInstallPathKey = hklmView32.OpenSubKey(#"SOFTWARE\LibreOffice\UNO\InstallPath", false);
if (hklmUnoInstallPathKey != null && hklmUnoInstallPathKey.ValueCount > 0)
{
unoPath = (string)hklmUnoInstallPathKey.GetValue(hklmUnoInstallPathKey.GetValueNames()[hklmUnoInstallPathKey.ValueCount - 1]);
}
}
Then you can use the answer of Funbit [ https://stackoverflow.com/a/31937114/2936206 ]
The most easiest way I found is just copy the URE folder from previous LibreOffice version to LibreOffice 5.

Adobe acrobat reader registry key location keeps changing

My requirement is to read a particular registry key related to Adobe acrobat reader and take a decision based on the value of that key.
Though this seems straightforward like I need to query the key using Registry class (for .NET)
and then take a decision based on the value.
However, the issue i face now is that, the registry key location keeps changing in almost every new version of Adobe Acrobat Reader.
All I can think of now is to have a switch case to handle for all the different Adobe versions in my code.
RegistryKey adobe = Registry.LocalMachine.OpenSubKey("Software").OpenSubKey("Adobe");
if (adobe != null)
{
RegistryKey acroRead = adobe.OpenSubKey("Acrobat Reader");
if (acroRead != null)
{
string[] acroReadVersions = acroRead.GetSubKeyNames();
Console.WriteLine("The following version(s) of Acrobat Reader are installed: ");
foreach (string versionNumber in acroReadVersions)
{
switch(versionNumber)
{
case 1.x = //do something;
//break;
case 2.x = //do something;
//break;
case 6.x = //do something;
//break;
case 9.x = //do something;
//break;
}
}
}
}
But some im not satisfied with this approach. Every time Adobe releases a new version i have to make sure i have to handle it differently. Any suggestions for a better approach.
Thanks
you best hope is to open the registry key containing the version numbers, then enumerate each sub key, possibly validating it looks like a version number, then look in each of those subkeys for the thing that you want. You might want to only use the highest number version that you find.
Obviously this will only work if what you want is always contained in the same registry entry relative to the version key, or always in the same named entry (and you would then have to enumerate every element under the sub key looking for the thing you want).
if the thing you want changes name and location in every release then you will have a problem, unless you can somehow recognize it from the data, in which case enumerate every element and look at the4 data and try to decide if it is what you want, but this approach is likely to be fraught with danger or false positives.
Well, I have the exact same problem and since I know Adobe is not so brilliant in their decisions and makings, I think I will try this approach:
public static string AcrobatReaderPath
{
get
{
var paths = new List<string>()
{
Registry.GetValue(#"HKEY_CLASSES_ROOT\Software\Adobe\Acrobat\Exe", "", #"C:\Program Files (x86)\Adobe\Reader 10.0\Reader\AcroRd32.exe") as string
};
var files = Directory.GetFileSystemEntries(#"C:\Program Files (x86)\Adobe\", #"*Acr*R*d*32.exe", SearchOption.AllDirectories);
paths.AddRange(files);
foreach(var path in paths) if (File.Exists(path)) return path;
return "";
}
}
My registry has nothing related to Acrobat at :
HKEY_LOCAL_MACHINE\SOFTWARE\Adobe\
..so it seems Adobe is moving their registry keys all over the registry with time passing...
I just hope they will avoid moving Acrobat itself outside the Program Files folder in the future... (you never know with these people...)
I think you can apply following logic:
adobe file associations are kept in registry - you can read them under
HKEY_CLASSES_ROOT \ .pdf \ OpenWithList
Those subkeys are app names (if any):
Acrobat.exe
AcroRD32.exe
etc.
Use them to combine and read keys (either Open or Read should be present)
HKEY_CLASSES_ROOT\Applications\XXXX\shell\Open\command
HKEY_CLASSES_ROOT\Applications\XXXX\shell\Read\command
If present, they would be similar to
"C:\Program Files (x86)\Adobe\Acrobat 7.0\Acrobat\Acrobat.exe" "%1"
from where you can strip %1 and get adobe app path.
Here is C# code:
private void AddShellCommandDefault(List<string> lst, RegistryKey shell, string reg KeyOpenRead)
{
var shellOpen = shell.OpenSubKey(regKeyOpenRead);
if (shellOpen == null) return;
var shellOpenCommand = shellOpen.OpenSubKey("command");
if (shellOpenCommand == null) return;
var defaultVal = shellOpenCommand.GetValue(null);
if (defaultVal == null) return;
int kex = defaultVal.ToString().LastIndexOf(".exe", StringComparison.OrdinalIgnoreCase);
if (kex < 0) return;
lst.Add(defaultVal.ToString().Substring(0, kex).Replace("\"", "") + ".exe");
}
public List<string> GetAdobeApps()
{
var addobeList = new List<string>();
// HKEY_CLASSES_ROOT\.pdf\OpenWithList\Acrobat.exe
// HKEY_CLASSES_ROOT\Applications\Acrobat.exe\shell\Open\command
// default "C:\Program Files (x86)\Adobe\Acrobat 7.0\Acrobat\Acrobat.exe" "%1"
var adobe = Registry.ClassesRoot.OpenSubKey(".pdf");
if (adobe == null) return addobeList;
var openWith = adobe.OpenSubKey("OpenWithList");
if (openWith == null) return addobeList;
var apps = Registry.ClassesRoot.OpenSubKey("Applications");
if (apps == null) return addobeList;
foreach (string sLong in openWith.GetSubKeyNames())
{
string s = sLong.Split(#"\/".ToCharArray()).Last();
var adobeApp = apps.OpenSubKey(s);
if (adobeApp == null) continue;
var shell = adobeApp.OpenSubKey("shell");
if (shell == null) continue;
AddShellCommandDefault(addobeList, shell, "Read");
AddShellCommandDefault(addobeList, shell, "Open");
}
return addobeList;
}
When run GetAdobeApps, it returns collection similar to
Count = 2
[0]: "C:\\Program Files (x86)\\Adobe\\Acrobat 7.0\\Acrobat\\Acrobat.exe"
[1]: "C:\\Program Files (x86)\\Adobe\\Reader 9.0\\Reader\\AcroRd32.exe"

Categories