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

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;
}

Related

C# Folder browse Dialog not showing Network shared folders win10

I have created an application(windows) compiled with .NET 4.6.1 and used the FolderBrowserDialog object. When a button is pressed I execute this code:
FolderBrowserDialog folderbrowserdialog = new FolderBrowserDialog();
folderbrowserdialog.Description = "Custom Description";
if (folderbrowserdialog.ShowDialog() == DialogResult.OK)
{
filePath = folderbrowserdialog.SelectedPath ;
}
what i get from the folderbrowserdialog(like foto)
however ,the folder browserdialog is not showing the networks shared folder(that the purpose of my app) otherewise just the pc folders.
but what i want to get it is the network shared folders which could i also access from windows 10 like foto here:
notes to be marked:
i could not use the open file dialog cause i need the folder location.
i desgined the Appto be opened just like admin by adding manisfest so the app is always starting like admin.
the app should be comptiable with windows 10,7
note i know that i could try setting this registry option (could be broken in Win10):
HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows/CurrentVersion/Policies/System
EnableLinkedConnections=1
but it does not make a sense to add this registry by every customer PC
so is there any tipps to show the network shared folders in FolderBrowserDialog ?
Finally after reading many topics i found that the only solution is to add a Registry key programmatically so here how to add specfic C# Registry Subkey with dword value:
i wrote a method wich could all use it
just to let you know after using it you have to restart the device after it ,it will work ;)
public void ConfigureWindowsRegistry()
{
RegistryKey localMachine = RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, RegistryView.Registry64); //here you specify where exactly you want your entry
var reg = localMachine.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System", true);
if (reg == null)
{
reg = localMachine.CreateSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System", true);
}
if (reg.GetValue("EnableLinkedConnections") == null)
{
reg.SetValue("EnableLinkedConnections", "1", RegistryValueKind.DWord);
MessageBox.Show(
"Your configuration is now created,you have to restart your device to let app work perfektly");
}
}
I had the same issue. The reason of the problem: I was using as an Administrator. The mapped drives are related to the user, so I tried to use as an normal user and I could see the mapped drives.

How to check which file type has PrintTo command available in Windows?

In Windows Explorer, when you right click, there is a 'Print' function for some of the file type. I know it's using the vert PrintTo to print the file.
I want to know how can I identify does a specific file type has this PrintTo verb association? Any available library in C#?
The context menu from the windows explorer is build with the information from the registry => HKEY_CLASSES_ROOT. Here you will find all registered extensions. For example .txt, under .txt you will find his (Default) => txtfile.
My Windows is german so whats called (Default) is here (Standard).
And when you look for the txtfile entry in the registry there will be txtfile=>shell=>print/printto. And if you don't find the shell=>print/printto entry, there also will be no print option in the context menu. There even is the print command which windwos will use to print your file. You can to this for every file type.
And to read from the registry there will be many example on the web like this: https://www.codeproject.com/Articles/3389/Read-write-and-delete-from-registry-with-C
This is how I implement it in C# based on Momo's answer.
public static bool HasPrintToVerb(string filename)
{
try
{
var ext = Path.GetExtension(filename);
var value = Registry.GetValue("HKEY_CLASSES_ROOT\\" + ext, string.Empty, null);
var printToValue = Registry.GetValue(string.Format(#"HKEY_CLASSES_ROOT\{0}\shell\Printto\command", value), string.Empty, null);
return printToValue != null;
}
catch(Exception ex)
{
return false;
}
}

How to make a registry entry using C# cake?

I need to create a registry entry based on finding of 32/64-bit system from cake script. I can see the File operations reference, Directory operations reference in C# cake site. But i could not find the registry related reference in C# cake. Could anyone please let me know is there any option to make a registry entry using C# cake? If so, please specify the reference link. This will help me a lot to continue in cake script.
An alternative to using C# you could also be using the Reg.exe shipped with all major versions of Windows.
You could use this tool with Cake using StartProcess alias.
An example of doing this below:
DirectoryPath system32Path = Context.Environment
.GetSpecialPath(SpecialPath.Windows)
.Combine("System32");
FilePath regPath = system32Path.CombineWithFilePath("reg.exe");
string keyName = "HKEY_CURRENT_USER\\Software\\Cake";
string valueName = "Rocks";
string valueData = "1";
ProcessSettings regSettings = new ProcessSettings()
.WithArguments(
arguments => arguments
.Append("add")
.AppendQuoted(keyName)
.Append("/f")
.AppendSwitchQuoted("/v", valueName)
.AppendSwitchQuoted("/t", "REG_DWORD")
.AppendSwitchQuoted("/d", valueData)
);
int result = StartProcess(regPath, regSettings);
if (result == 0)
{
Information("Registry value successfully set");
}
else
{
Information("Failed to set registry value");
}
Currently, there are no Cake aliases for working with the registry. Having said that, there is nothing to stop you manipulating the Registry directly using that standard C# types.
An example of one such approach is here:
Writing to registry in a C# application
Cake provides a number of aliases for things that are more complicated to do, however, remember that almost everything that is provided in an alias could be done directly with C# in your main script. The aliases are simply there as a convenience.

Check if there is any kind of PDF Reader installed

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;
}
}

Force remove the user.config during uninstall?

how do i code the custom action during the uninstall?
Would it require a batch file?
thanks!
The user.config data gets stored in the %APPDATA%\ProjectName folder.
If you want to remove the user.config data when you uninstall then you can just use the System.IO.Directory.Delete("%APPDATA%\ProjectName");
Note: You can get the installed path using the following Context.Parameters["assemblypath"] this is the path that the user selects to install the project.
This worked for me, based on the answer above. For my app I only allow per user installs, not "all users" so I don't have to worry about uninstalling for multiple users, or for users other than the current user running uninstall. If you allow "all user" installs, you'll have some issues to work out.
public override void Uninstall(System.Collections.IDictionary savedState)
{
String p = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "CompanyName");
string[] ss = Directory.GetDirectories(p, "ProjectName.*");
foreach (string s in ss)
{
if(MessageBox.Show("Delete " + s + "?","Delete Settings?",MessageBoxButtons.YesNo) == DialogResult.Yes)
Directory.Delete(s, true);
}
base.Uninstall(savedState);
}
I'm not actually going to leave the prompt in there, that is just for testing to make sure I'm not deleting the wrong folders on my PC.. until this code has been fully tested. CompanyName and ProjectName need to be changed to match your project.
I might add a page to uninstall UI or just a prompt to ask if they want to delete all settings (so they can choose not to if they are going to reinstall).
var filePath = Environment.ExpandEnvironmentVariables(#"%userprofile%\APPDATA/ProjectName");
System.IO.Directory.Delete(filePath );
You can write a custom action to trigger an executable while install or uninstall or both.
for eg: create an .exe which will delete the user.config folder. Add this exe in binary table. Add an entry in CustomAction table with Source being the foreign key to name in Binary table and TArget being the actual exe file name and type = 2. Now add this action in InstallExecuteSequence with whatever sequence order you wish to trigger the .exe in installation process.
1) Create a custom action (article includes pictures)
2) Handle the Uninstall event of the custom action
[System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)]
public override void Uninstall(IDictionary savedState)
{
try
{
string path = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
path = Path.Combine(path, "{Your application folder name}");
Directory.Delete(path, true);
}
catch(Exception)
{
}
base.Uninstall(savedState);
}

Categories