Search code examples
c#.netwindowsregistrywindows-installer

How to reliably find app InstallLocation without WMI


I'm trying to find if an app is installed, and what the installed path is. I have tried using WMI Win32_SoftwareElement and also enumerating the following registry keys

  • HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
  • HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall
  • HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall
  • HKCU\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall

What I've found out is that although it's the fastest method (as opposed to WMI) it's not as reliable. Not all apps are listed, and out of those listed, not all have their InstallLocation properly set. Searching Win32_SoftwareElement yielded the best result, but it is sluggish, wondering if there is any better alternative, perhaps a reg location I failed to include in my search, or if there are other alternatives to WMI, like P/Invoke.


Solution

  • The install location isn't always set because it's not automatic. Some installs might not be MSI-based installs and I don't know if the other tools that are used will all set the location. If it's an MSI-based install the location is there only if the package developer sets the ARPINSTALLOCATION property during the install to the actual location.

    http://msdn.microsoft.com/en-us/library/aa367589(v=vs.85).aspx

    The plain old Win32 Windows Installer API to enumerate installed products is MsiEnumProducts () to return the ProductCode values one at a time, then to call MsiGetProductInfo() passing that product code guid and asking for INSTALLPROPERTY_INSTALLLOCATION, but again that's only there if the MSI developer did the right thing.

    There's no reliable way to get installed products all at once because some are MSI-based, some are not, and they may or may not set the install location, and that install location is typically only the application directory and doesn't include files installed in any number of other places so it's value is minimal. Trawling through the registry and making decisions on what you find seems to be the only way to get the list.

    Having said all that, short answer is that if you know a ProductCode then call MsiGetProductInfo() as above and get the location!