views:

35

answers:

2

Given an MSI product code I want to get the upgrade code (among other properties) from an already installed product. I have tried this by calling the MsiOpenProduct method, followed by MsiGetProductProperty(). An (abbreviated) example looks like this:

MSIHANDLE handle = NULL;
MsiOpenProduct(strProductCode,&handle);
CString strUpgradeCode;
MsiGetProductProperty(handle,_T("UpgradeCode"), strUpgradeCode.GetBuffer(GUID_LENGTH), &dwSize);
strUpgradeCode.ReleaseBuffer();
MsiCloseHandle(handle);

This gets me the desired value, and judging from the MSDN documentation this seems like a valid way to do this:

The MsiOpenProduct function opens a product for use with the functions that access the product database. The MsiCloseHandle function must be called with the handle when the handle is no longer needed.

However the call to MsiOpenProduct() pops up the "Windows installer is preparing the installation..." dialog. The call to MsiCloseHandle() makes it disappear again.

This left me wondering:

  • What does the call to MsiOpenProduct() do under the hood? I do not want to trigger any actions, I just want to read properties.
  • I don't mind the dialog popping up, as this is only for unit test code as long as this has no side effects. And as there are many unit tests that do this, it must still work when opening and closing handles in rapid succession.
  • Although I stumbled over the MsiGetProductInfo method, there seems to be no way to get the upgrade code. Am I right?
  • Is MsiOpenProduct the correct way to read properties like the upgrade code?
A: 

MsiOpenProduct should be fine So long as you don't run any sequences or actions, it won't do anything. If you want to silence the dialog, you can with careful use of either MsiSetInternalUI() or MsiSetExternalUI().

Another approach you can take, as long as the ProductCode and UpgradeCode are safely static (i.e. as long as they aren't changed by transforms), is to locate the database using MsiGetProductInfo() and call MsiOpenDatabase() on that. The difference is that MsiOpenProduct() (or similarly MsiOpenPackage) applies the transforms that were used at installation time and prepares a session, whereas MsiOpenDatabase() does neither.

Michael Urman
A: 

For the information you want, it sounds like you can just call ::MsiGetProductInfo(). ::MsiOpenDatabase() is a very slow operation while ::MsiGetProductInfo() is (IIRC) more on par with registry look ups.

Rob Mensching
That may be true, but like I wrote above, I found no way to get the upgrade code via MsiGetProductInfo. It seems that you can only query a limited set of properties. See http://msdn.microsoft.com/en-us/library/aa370130%28VS.85%29.aspx for a list of properties.
Hatch
Oh, you're right. I mis-remembered UpgradeCode in the list.
Rob Mensching