I need to know the application's ProductCode in the Installer.OnCommitted callback. There doesn't seem to be an obvious way of determining this.
4 Answers
You can avoid hardcoding your product code, using /productCode=[ProductCode] in your CustomActionData property.
I ended up passing the product code as a command line argument to my Installer class using the CustomActionData property in Visual Studio (e.g. /productcode={31E1145F-B833-47c6-8C80-A55F306B8A6C}. I can then access this from any callback within the Installer class using the Context.Parameters StringDictionary
string productCode = (string)Context.Parameters["productcode"];
-
No need to cast to a string, as it's alreay a string – Cocowalla Apr 17 '10 at 19:01
The MSI function MsiGetProperty can be used to get the name of the ProductCode property. I don't know if that would work in this case, since I've never created a .NET installer.

- 1,612
- 2
- 23
- 38
The suggestion from @Chris Tybur seems to work
Here's my C# Code:
public static string GetProductCode(string fileName)
{
IntPtr hInstall = IntPtr.Zero;
try
{
uint num = MsiOpenPackage(fileName, ref hInstall);
if ((ulong)num != 0)
{
throw new Exception("Cannot open database: " + num);
}
int pcchValueBuf = 255;
StringBuilder szValueBuf = new StringBuilder(pcchValueBuf);
num = MsiGetProperty(hInstall, "ProductCode", szValueBuf, ref pcchValueBuf);
if ((ulong)num != 0)
{
throw new Exception("Failed to Get Property ProductCode: " + num);
}
return szValueBuf.ToString();
}
finally
{
if (hInstall != IntPtr.Zero)
{
MsiCloseHandle(hInstall);
}
}
}
[DllImport("msi.dll", CharSet = CharSet.Unicode, EntryPoint = "MsiGetPropertyW", ExactSpelling = true, SetLastError = true)]
private static extern uint MsiGetProperty(IntPtr hInstall, string szName, [Out] StringBuilder szValueBuf, ref int pchValueBuf);
[DllImport("msi.dll", CharSet = CharSet.Unicode, EntryPoint = "MsiOpenPackageW", ExactSpelling = true, SetLastError = true)]
private static extern uint MsiOpenPackage(string szDatabasePath, ref IntPtr hProduct);
[DllImport("msi.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
private static extern int MsiCloseHandle(IntPtr hAny);
FWIW: There is a small blurb on this MSDN Site that might be cause for concern: https://learn.microsoft.com/en-us/windows/win32/msi/obtaining-context-information-for-deferred-execution-custom-actions
Function Description
MsiGetProperty Supports a limited set of properties when used with deferred execution custom actions:
the CustomActionData property, ProductCode property, and UserSID property.Commit custom
actions cannot use the MsiGetProperty function to obtain the ProductCode property.
Commit custom actions can use the CustomActionData property to obtain the product code.
Note the call out cannot use the MsiGetProperty function to obtain the ProductCode property
. So YMMV.
Reviewing How can I find the product GUID of an installed MSI setup? you can use the COM API to gather this (the current version shows a VBScript) which might be worth inspecting as well.

- 1,300
- 12
- 36