1

After windows installs a msi file, it will rename that file, move it to C:\Windows\Installers and write the info on how the file can be found to the registry.

I want to query the registry for that key in order to get the exact location of the installed file. The values I am looking for can be found at: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\

Unfortunately I won't know the exact ID of the installed file, so I'll have to open all the items listed at this location and check the product names.

However when I try to query this part of the registry programmatically, I am unable to see any of the items that should be listed at this place.

This is the code I am using right now (no exception handling etc included):

Registry.LocalMachine.OpenSubKey("SOFTWARE").OpenSubKey("Microsoft").OpenSubKey("Windows").OpenSubKey("CurrentVersion").OpenSubKey("Installer").OpenSubKey("UserData").OpenSubKey("S-1-5-18").OpenSubKey("Products")

How can I query this part of the registry? Any other ideas on how to get the location (and name) of the msi file I am looking for?

buddybubble
  • 1,269
  • 14
  • 33

2 Answers2

2

First of all, you can just write:

Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products")

There's no need to open each key individually.

Second, I believe you problem might be that you're running the code from a 32-bit assembly on a 64-bit machine, and are trying to access the data found in the 64-bit part of the SOFTWARE key. Instead, you are being rerouted to the Wow6432Node, where the key UserData does not necessarily exist inside Installer.

See this answer for how to read from the 64-bit part in a 32-bit assembly.

Community
  • 1
  • 1
Rotem
  • 21,452
  • 6
  • 62
  • 109
  • As I said, the code postet is just something I used for testing :) Thank you for the suggestion with the architecture! I'll check that and update this response – buddybubble Dec 23 '13 at 08:39
  • This seems to work perfectly. Combined it with .net4's cool Environment.Is64BitOperatingSystem – buddybubble Dec 23 '13 at 14:09
  • Somehow, installed 32 bit MSIs seem to get listed in the 64 bit registry... which is completely retarded. The 32 bit equivalent node, meanwhile, stays empty, meaning programs will find the node on a 32 bit machine but not on a 64 bit one. – Nyerguds Jan 22 '14 at 14:30
1

Spelunking the registry is not the way to go. Windows Installer provides a Win32 API to access this information. For C#/.NET there is a very nice interop library to encapsulate all of this for you. It's called Microsoft.Deployment.WindowsInstaller and ships with Windows Installer XML (WiX) which can be found on CodePlex.

In this library is a class called ProductInstallation with a static method named GetProducts that wraps the underlying MsiEnumProducts function.

public static IEnumerable<ProductInstallation> GetProducts(
    string productCode,
    string userSid,
    UserContexts context
)

productCode (String) ProductCode (GUID) of the product instances to be enumerated. Only instances of products within the scope of the context specified by the userSid and context parameters will be enumerated. This parameter may be set to null to enumerate all products in the specified context.

userSid (String) Specifies a security identifier

(SID) that restricts the context of enumeration. A SID value other than s-1-1-0 is considered a user SID and restricts enumeration to the current user or any user in the system. The special SID string s-1-1-0 (Everyone) specifies enumeration across all users in the system. This parameter can be set to null to restrict the enumeration scope to the current user. When context is set to the machine context only, userSid must be null. context

(UserContexts)

Specifies the user context.

Christopher Painter
  • 54,556
  • 6
  • 63
  • 100
  • Does MsiEnumProducts use the WMI class Win32_Product? I came accross that one already. See this (http://sdmsoftware.com/group-policy-blog/wmi/why-win32_product-is-bad-news/) article. Also I decided to query the registry manually because this is part of a rather big software and I'm not sure whether it is ok to ship 3rd party assemblies so easily. So if possible, I'd just query the registry myself – buddybubble Dec 23 '13 at 08:55
  • I just checked the license of WiX. Don't want to start a discussion here, but I think if I use it, we'd have to distribute the source code of any file that uses WiX. I think thats not possible in my case – buddybubble Dec 23 '13 at 09:09
  • It's the other way around. Win32_Product uses MsiEnumProducts. As does DTF. If you don't want a discussion, don't make your incorrect assumption about WiX licensing. If you are still worried about it, then look through the DTF source to pick out how to P/Invoke MsiEnumProducts and don't use the entire library. – Christopher Painter Dec 23 '13 at 14:23
  • How is my assumption incorrect? WiX is MS-RL and it clearly says "For any file you distribute that contains code from the software (in source code or binary format), you must provide recipients the source code to that file". If this was not the case, I'd go with WiX anytime, so please elaborate – buddybubble Dec 27 '13 at 11:55
  • 1
    Read here: http://robmensching.com/blog/posts/2012/8/20/the-wix-toolset-license If you have any questions, ask Rob. – Christopher Painter Dec 28 '13 at 14:31
  • I tried this approach, but this does not seem to enumerate all products. For example, some products listed in Programs and Features are not included `ProductInstallation.AllProducts`. Is there a reason for that? `MsiEnumProducts` doc does not seem to mention anything about this. So I ended up sticking w/ the registry-way (iterating `Microsoft\\Windows\\CurrentVersion\\Uninstall` keys). – sjlewis Sep 18 '19 at 13:08
  • Not all installers use Windows Installer. – Christopher Painter Sep 18 '19 at 17:52