Check if there is any kind of PDF Reader installed - c#

I have a Help function in my Application, that consists of one webbrowser control. That webbrowser control gets filled with a .pdf file, the source for that .pdf file is our own website.
The problem is, that not everyone will have a PDF Reader installed on their machine, so I want to check whether one is installed: Yes or No. I searched the internet and I mostly saw that users on Stackoverflow where wanting to check if Adobe Reader was installed, that is not what I want. I need to know IF there is a PDF Reader somewhere installed on the machine.
I did find the following code, that can possibly help me:
public void CheckPdfReaderAvailable()
{
RegistryKey key = Registry.ClassesRoot.OpenSubKey(".pdf");
Assert.IsNotNull(key);
}
As I look at the above code, my thoughts are that the code checks if the registry does know the .pdf format, but I'am not sure.
Can somebody tell me how to use the code above or provide me an example, about how I should take down this problem?
Thanks in advance!
EDIT:
The following answer helped my out: https://stackoverflow.com/a/774482/1661209
Another way to solve this problem, is to add a pdf reader lite to the prerequisites and make the users install that first, you don't have to check for a pdf Reader, because you know one is installed then, if it isn't you could say it is the mistake of the user that they can't use the help function, because you offered them a way to install the pdf reader easily using the published project.

Apart from whether it is useful to know or not, you could probable check the following registry key:
HKEY_CLASSES_ROOT\MIME\Database\Content Type\application/pdf
This will have an entry CLSID, which points to the class ID of the default application.
If the registry key or CLSID value is not present, then the MIME type is unknown, or there is no default application to handle the MIME type application/pdf files.

You can query the registry directly but the recommended solution is to use the IQueryAssociations interface to see if there is a program registered to open pdf's. An example can be found on pinvoke.net.

C# implementation of the approach suggested by John Willemse (won't recognize Edge as default viewer on non-N version of Windows 10) :
private bool CanOpenPDFFiles
{
get
{
bool CLSIDpresent = false;
try
{
using (Microsoft.Win32.RegistryKey applicationPDF = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(#"MIME\Database\Content Type\application/pdf"))
{
if (applicationPDF != null)
{
var CLSID = applicationPDF.GetValue("CLSID");
if (CLSID != null)
{
CLSIDpresent = true;
}
}
}
}
catch (Exception)
{
}
return CLSIDpresent;
}
}

Related

How to set the WebBrowser object in the .NET Framework to use whatever highest version of IE is installed on the users system

So the title says it all, I would like C# code (so please, PLEASE make sure it isn't Visual Basic code). And that is all I want to ask. I have tried the web browser built in to the .NET framework, but it looks like some old version of IE (if I am right or not). And if you answered, well thanks I guess! I need this for a small project where a bot would just log on to a website (its a base for future projects).
By default it's IE7. You can bang a registry entry in to make it later:
public static void EnsureBrowserEmulationEnabled(string exename = "YourAppName.exe", bool uninstall = false)
{
try
{
using (
var rk = Registry.CurrentUser.OpenSubKey(
#"SOFTWARE\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION", true)
)
{
if (!uninstall)
{
dynamic value = rk.GetValue(exename);
if (value == null)
rk.SetValue(exename, (uint)11001, RegistryValueKind.DWord);
}
else
rk.DeleteValue(exename);
}
}
catch
{
}
}
Code courtesy of this blog
The values you can use in place of 11001 can be found in MSDN
Alternatively; can you do what you want by using WebClient/HttpWebRequest rather than poking at a web browser control to navigate around? Or can you find some web service/api version of the site that will respond with JSON rather than trying to manipulate html?
I was mildly curious why you'd care what a page looks like if it's a bot that is using it, but perhaps you're hitting a "your IE is too old" from the server..

Choose a File from OpenFileDialog with C#

I have a little problem - I don't know how to Select a File and Open it in the Mozilla OpenFileDialog.
First, I open the Dialog by pressing "Browse" with Selenium and then I want to put in a File-Name (I know the exact location via Environment variable)
In my case: Environment.GetEnvironmentVariable("Testplatz_Config_Location") + "\TestConfig.fpc"
So my Question, does anyone know how to handle an already open OpenFileDialog using C# - Or is it perhaps possible to handle this with Selenium?
Selenium does not provide any native way to handle windows based pop ups. But we have some third party tools like AutoIT and RobotClass to handle those windows based pop ups. Refer those and give it a a try.
AutoIT with Selenium and Java
Selenium/SeleniumWebDriver does not provide any native way to handle windows based popups. Still, the best way is to miss this popup using
IWebElement element = driver.FindElement(By.Id("file_input"));
element.SendKeys(filePath);
but this is not allways is possible. And if it is not, you can use my lib:
https://github.com/ukushu/DialogCapabilities
by the following way:
OpenFileDialog:
// for English Windows
DialogsEn.OpenFileDialog(#"d:\test.txt");
//For windows with russian GUI
Dialogs.OpenFileDialog("Открыть", #"d:\test.txt");
MultiFile selection in OpenFileDialog:
var filePaths = new string[] {#"d:\test1.txt", #"d:\test2.txt", #"d:\test3.txt"};
//Or for Eng windows:
DialogsEn.OpenFileDialog(filePaths);
//for russian language OS
Dialogs.OpenFileDialog("Открыть", filePaths);
You can use sendKeys() on the file upload element to upload a file using selenium by path. I would suggest using this instead of AutoIT or Robot.
So instead of clicking on the browse button, you send the path directly to the file input element using sendKeys().
Example:
IWebElement element = driver.FindElement(By.Id("file_input"));
element.SendKeys(
Environment.GetEnvironmentVariable("Testplatz_Config_Location") + "\TestConfig.fpc");
i used selenium with Robot class from Java awt. This is my solution
public static void setClipboardData(String string) {
//StringSelection is a class that can be used for copy and paste operations.
StringSelection stringSelection = new StringSelection(string);
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(stringSelection, null);
}
public static void uploadFile(String fileLocation) {
try {
//Setting clipboard with file location
setClipboardData(fileLocation);
//native key strokes for CTRL, V and ENTER keys
Robot robot = new Robot();
robot.keyPress(KeyEvent.VK_CONTROL);
robot.keyPress(KeyEvent.VK_V);
robot.keyRelease(KeyEvent.VK_V);
robot.keyRelease(KeyEvent.VK_CONTROL);
robot.keyPress(KeyEvent.VK_ENTER);
robot.keyRelease(KeyEvent.VK_ENTER);
} catch (Exception exp) {
exp.printStackTrace();
}
}

How can I get another application's installation path programmatically?

I'd like to know where the installation path for an application is. I know it usually is in ...\Program Files... but I guess some people install it in different locations. I do know the name of the application.
Thank you.
The ideal way to find a program's installation path (on Windows) is to read it from the registry. Most installers will create a registry key for that program that contains the installation path. Exactly where this key is and what it will be named varies depending on the program in question.
To find if the program has a key in the registry, open 'regedit' and use the Edit > Find option to try and locate a key with the program name. If such a key exists, you can read it using the RegistryKey class in the .NET Framework library.
If the program does not have a registry key then another option is just to ask the user to locate the .exe file with the OpenFileDialog, although this is obviously not ideal.
Many (most?) programs create an App Paths registry key. Have a look at
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths
If you know the application in question (as compared to any application) registry key is the probably the best option (if one exists).
The install might put in its own custom "install path key" somewhere (so do a find as Fara mentioned) or it might be in the uninstall section for installed programs, so you could check:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
But be aware that any new version of an install could change the key it writes out, both for a custom key or for the uninstall entry. So checking the registry should probably be only for a known install\version.
tep
Best way is to use Installer APIs to find the program location.
You can write a Managed wrapper over the APIs
Search for MsiGetProductInfo
Reference: http://msdn.microsoft.com/en-us/library/aa369558(VS.85).aspx
You can use MSI (I wrote a C# wrapper for it here https://github.com/alialavia/MSINet). Here is a simple example:
var location = "";
foreach (var p in InstalledProduct.Enumerate())
{
try
{
if (p.InstalledProductName.Contains("AppName"))
{
location = p.InstallLocation;
break;
}
}
catch { }
}
Take a look in the registry.
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\
or
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\
Each of the above contain a list of sub-keys, one for each installed application (as it appears, for example, in the "Programs and Features" applet)
You can search for your application there, or if you know the product code, access it directly.
public string GetInstallPath(string applicationName)
{
var installPath = FindApplicationPath(#"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall", applicationName);
if (installPath == null)
{
installPath = FindApplicationPath(#"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall", applicationName);
}
return installPath;
}
private string FindApplicationPath(string keyPath, string applicationName)
{
var hklm = Registry.LocalMachine;
var uninstall = hklm.OpenSubKey(keyPath);
foreach (var productSubKey in uninstall.GetSubKeyNames())
{
var product = uninstall.OpenSubKey(productSubKey);
var displayName = product.GetValue("DisplayName");
if (displayName != null && displayName.ToString() == applicationName)
{
return product.GetValue("InstallLocation").ToString();
}
}
return null;
}

Is there a way to follow a windows fileystem shortcuts programatically in C# without using COM?

Back in .NET 1.0 days I wrote a method to return the target of a shortcut on MS Windows. It did this through using an interop to the Windows Script Hosting Object Model and brute forced through the COM interface:
private FileInfo GetFileFromShortcut(FileInfo shortcut)
{
FileInfo targetFile = null;
try
{
IWshRuntimeLibrary.WshShell wShell = new IWshRuntimeLibrary.WshShellClass();
IWshRuntimeLibrary.WshShortcut wShortcut = (IWshRuntimeLibrary.WshShortcut)wShell.CreateShortcut(shortcut.FullName);
// if the file wasn't a shortcut then the TargetPath comes back empty
string targetName = wShortcut.TargetPath;
if (targetName.Length > 0)
{
targetFile = new FileInfo(targetName);
}
}
catch (Exception)
{ // will return a null targetFile if anything goes wrong
}
return targetFile;
}
This still bugs me, and I was looking to replace this with something more elegant, but only if the replacement actually works at least as well. I still can't find a native C# way of finding the target of a shortcut. Is there one, or is this still the best way of doing this type of thing?
It looks like someone has written a class to manipulate shortcut files in C# called ShellLink, but it too uses COM.
Can't you just open the .lnk or .url file and parse it?
This talks about the same thing and shows what the files look like:
http://www.programmingtalk.com/showthread.php?t=7335
I got interested in this as well a while ago.
Here is the accepted response with a link to a (informal) description of the format of LNK files. Apparently, all available methods yet go through some API.

Is it possible to open a PDF inside a c# application with Acrobat.dll?

I know that I can display a PDF file in my c# executable (not web app) with:
private AxAcroPDFLib.AxAcroPDF axAcroPDF1;
axAcroPDF1.LoadFile(#"somefile.pdf");
axAcroPDF1.Show();
But that is the regular pdf viewer like in the browser. I don't want that. I want full Adobe Standard or Professional functionality in my C# application using the Adobe controls. For example, if I use the code above, it loads in the C# app and I can see the adobe toolbar (print, save, etc.) But it is useless to me because I need things like save which cannot be done with the activex viewer above. Specifically, you cannot save, just as you cannot within the broswer.
So, I referenced the acrobat.dll and am trying to use:
Acrobat.AcroAVDocClass _acroDoc = new Acrobat.AcroAVDocClass();
Acrobat.AcroApp _myAdobe = new Acrobat.AcroApp();
Acrobat.AcroPDDoc _pdDoc = null;
_acroDoc.Open(myPath, "test");
pdDoc = (Acrobat.AcroPDDoc)(_acroDoc.GetPDDoc());
_acroDoc.SetViewMode(2);
_myAdobe.Show();
It opens adobe acrobat but it opens it outside of my c# application. I need it to open in my c# application like the activex library does. Can it be done with these libraries?
If I cannot open it in my c# application I would like to be able to "hold" my c# app tied to it so the c# app knows when I close the adobe app. At least that way I'd have some measure of control. This means I would hit open, the adobe app opens. I close the adobe app, my C# app is aware of this and loads the newly changed doc with the activex library (because I don't need change ability anymore, just displaying.)
I have the full versions of adobe acrobat installed on my computer. It is not the reader.
Thank you for any help.
edit:
There is an example in vb in the adobe acrobat sdk. I believe it is called activeview.
you can check out ABCpdf. I dont know if it has this capability but we have used it for several of our apps
Using a webbrowser control would be an option to display the content.
IText# may help you out.
You can create PDF's and I believe you can use it to read and modify them.
As for displaying in the app..... I am not sure how to display them with iText or if it is possible (have not tried this yet), sorry. iText does let you convert to RTF which may be one approach.
Best option is to write a listener which tells your calling code when Adobe.exe is no longer running. Something like the following (with tweaks for your uses) should work:
public void Open(string myPath)
{
Acrobat.AcroAVDocClass _acroDoc = new Acrobat.AcroAVDocClass();
Acrobat.AcroApp _myAdobe = new Acrobat.AcroApp();
Acrobat.AcroPDDoc _pdDoc = null;
_acroDoc.Open(myPath, "test");
_pdDoc = (Acrobat.AcroPDDoc) (_acroDoc.GetPDDoc());
_acroDoc.SetViewMode(2);
_myAdobe.Show();
NotifyAdobeClosed += new EventHandler(Monitor_NotifyAdobeClosed);
MonitorAdobe();
}
private void Monitor_NotifyAdobeClosed(object sender, EventArgs e)
{
NotifyAdobeClosed -= Monitor_NotifyAdobeClosed;
//Do whatever it is you want to do when adobe is closed.
}
private void MonitorAdobe()
{
while(true)
{
var adcount = (from p in Process.GetProcesses()
where p.ProcessName.ToLower() == "acrobat"
select p).Count();
if (adcount == 0)
{
OnNotifyAdobeClosed();
break;
}
}
}
public event EventHandler NotifyAdobeClosed;
public void OnNotifyAdobeClosed()
{
if (NotifyAdobeClosed != null)
NotifyAdobeClosed(this, null);
}

Categories