View Full Version : MsiGetUserInfo returns empty information - Express 4 issue?

Painin the S.
01-16-2003, 05:48 PM
According to the Windows Installer API, the function MsiGetUserInfo should supply information about the installed product for all MSI-based installations. I wrote a simple test application in Delphi, which checks the installation info for an installation performed via an Express4-based setup program.

Here's the result. MsiGetUserInfo returns USERINFOSTATE_ABSENT, which indicates that the queried product is actually installed, but user name, company name and serial number have not been set by the setup program (as built by Express 4). I'm sure that my function call is correct, otherwise MsiGetUserInfo would have returned USERINFOSTATE_UNKNOWN (product unknown or not installed) or USERINFOSTATE_INVALIDARG (function call incorrect). I double checked it for products that weren't installed via an InstallShield product and those products actually did return useful installation information. Conclusion: the problem is in the setup program, not in my code.

I suspect that a setup program built by Express 4 does not set the user name, company name and serial number properties in the installation database. Can anyone confirm this? If so, is there a workaround?

01-17-2003, 12:00 PM
Could you try the following?

1. Open your project in Express
2. Go to Registry View
3. Create the following key


4. Create the following string entries in this key:

Entry name: ProductID

Entry name: RegOwner

Entry name: RegCompany

5. Build and Install
6. Run your code that calls MsiGetUserInfo

Does this return the correct information?

Painin the S.
01-19-2003, 11:11 AM
Unfortunately, that's not the solution. The information is still not displayed. I've included a small test app, which shows the information that MsiGetUserInfo returns for all installed applications. You may notice that some applications (especially some Microsoft applications) do return the information, even though the registry values you referred to are absent.

For those who are interested, I've included the Delphi source code as well.

01-20-2003, 05:52 PM
Thanks for the attachment. I see what you mean. I actually found out where in the registry it get's this information from but don't know a reliable way to put information there. It's (on my Win2K)


According to the msi help the RegisterUser Action registers these three properties. This action is in our sequence and get's called at runtime but doesn't seem to be doing anything. I'm confused because it works with the setup of Express 4.0 itself (we create the Express 4 setup using Express 4). I'll have to do more research on this to see what's happening.

01-21-2003, 05:05 PM
A few developers having been looking in to this issue for a while and can't figure out why it happens. We are leaning towards some descrepency in the Windows Installer service. In the meantime though, I was told that you can use the API MsiGetProductInfo instead. By passing in properties of RegOwner, RegCompany and ProductID you can retrieve the information you want.

Painin the S.
01-26-2003, 04:17 PM
Thanks a lot for all the effort you put into this problem. Now that I'm back at my desk, I can finally respond. HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\[some GUID]\InstallProperties is indeed the registry key where MsiGetUserInfo and MsiGetProductInfo retrieve their information. Both RegOwner and ProductID need to be set for MsiGetUserInfo to succeed. By the way, I don't have a clue where [some GUID] comes from.
Using MsiGetProductInfo instead of MsiGetUserInfo does not resolve the problem.
The problem seems to be related to the PIDKEY and/or ProductID properties. After a lot of frustrating testing I found out that there is a way to have MSI store RegOwner, RegCompany and ProductID. Using Orca, the following property has to be added to the Property table: ProgID. The value you enter for ProgID is the value that the installer adds to the registry.
The PIDTemplate property in the Property table is set to some default value: 12345<### -%%%%%%%>@@@@@. Is this meant to be?
I attached a revised version of the test tool so that the results of MsiGetProductInfo can be checked. Again, source code included.

Edit: typo in text formatting

02-15-2004, 12:25 AM
The RegisterUser action fails if the ValidateProductID action fails. Express does not write the ProductID property in the "Property" table. The PIDTemplate specifies the template in which the ProductID must be. By default InstallShield Express adds the following PIDTemplate to the Property table.

12345<### -%%%%%%%>@@@@@

Thus, Windows installer expects the ProductID to be in this format.

nnn-nnnnnnn (where n is any numeric from 0-9).

The Windows Installer help library article on "PIDTemplate Property" contains a good deal of information on the format followed. Once this property is added to the Property table the RegisterUser action works. :cool:

04-07-2005, 09:40 AM
I have FINALLY solved this problem, no thanks to the technical support from InstallShield. :mad:

It is possible to enter a serial number on the Customer Information dialog and have it stored in the registry as ProductID, along with RegOwner and RegCompany, so they can then be read using the MsiGetUserInfo function.

I have been experimenting with this using trial and error and using the Orca program to modify the tables directly. Orca can be found at http://support.microsoft.com/kb/255905/EN-US or http://www.winisp.net/astebner/bin/orca.msi.

Below is a description of the results of my labours...

I have determined that RegOwner, RegCompany and ProductID are written to the registry ONLY if ProductID is defined. Without it, the other two values are not written.

As ProductID is a private variable, it cannot be directly manipulated. However, PIDKEY is a public variable and, once defined, is used internally to create ProductID. ProductID is constructed according to PIDTemplate and the value of PIDKEY is inserted into the ProductID if it matches the defined template.

Thus, if PIDTemplate="12345<###-%%%%%%%>@@@@@" and PIDKEY="333-7654321", the resulting ProductID will be "12345-333-7654321-63732", where the last 5 digits are random numbers. # and % allow numeric values only.

The PIDTemplate can be changed to your own required format and you can omit the data outside the <>. In my case I've changed it to "<????-????>" (any character). The value of Serial Number Template in InstallShield Customer Information dialog need to match this too, thus mine is "????-????".

I can now enter a key like "TEST-1234" on the Customer Information dialog.

So the process required to set this up is:

1) Create your InstallShield package in the normal manner.
2) In the Customer Information dialog, specify your required Serial Number Template using # for numeric and ? for any character.
3) It is NOT essential to define a Serial Number Validation DLL or Validate Function.
4) Save your file.
5) Run Orca and open the InstallShield project file (you'll need to select files of type *.* to see it).
6) Find the CustomAction table and create a new row: Action=SetPIDKEY, type=51, Source=PIDKEY, Target=[ISX_SERIALNUM]
7) Find the InstallExecuteSequence table and create a new row: Action=SetPIDKEY, Sequence=n, where n is a number somewhere before the number used by ValidateProductID. In my case ValidateProductID seq=700, so I set n=650.
8) Save the file and test your installation.

If you simply wish to store the RegOwner and RegCompany in the registry, and don't need the ProductID, follow instructions 1-5 above, then find the Property table and create a new row called ProductID. Set a value of "None". Save and test.

I hope this works as required for everyone. I'm sure it will deal with most cases. However, you may need to add a Condition to deal with PIDKEY being set from the command line, etc.

Cheers, Mark