开发者

Calling MSIGetProductInfo from a Windows service returns garbage values

开发者 https://www.devze.com 2023-04-11 21:31 出处:网络
I have two apps I am working on, both of which rely on the MSIGetProductInfo call to retrieve the serial number that a user entered during setup (a standard visual studio setup and deployment project)

I have two apps I am working on, both of which rely on the MSIGetProductInfo call to retrieve the serial number that a user entered during setup (a standard visual studio setup and deployment project).

Here is the code I am using t开发者_Python百科o retrieve the serial number:

Int32 len = 512;
var builder = new StringBuilder(len);
MsiGetProductInfo("{98A0A10F-5E78-4FA6-83F6-6B356D75ADD4}", "ProductId", builder, ref len);
return builder.ToString();

The first app, a visual c# forms app, returns as I expect (when I enter 1111-1111-1111-1111, it indicates as such). However, when I put the same call in the OnStart method of a c# windows service, I get random garbage such as Unicode characters, occasionally a word, and the returned value is different on every runtime. Occasionally I get a result that contains part of the path of the dll which contains the MsiGetProductInfo call, such as "㷨H꿈Eindows\system32\msi.dll."

It looks to me (uneducated guess) like the call to the dll function is failing and it is just returning data from an unused memory location.

I have tried reading other properties, such as InstallSource and InstalledProductName, but those are garbage in the service as well (while also being fine in the forms app). I also thought it might be a permissions issue, so I have tried running the service under the NetworkService, LocalService, and LocalSystem accounts with no success.

Both the Forms app and the service are installed simultaneously by the same setup project, so they should share the same ProductCode, correct? If not, I could see why the service is failing to retrieve the product information.

Has anyone encountered this or have any idea what is causing this?


I needed to answer this same problem. I added a UserRegistrationDlg.wxs to a wix msi project to collect the PIDKEY. However, I then needed to grab the serial entered at install time at program first run to complete an activation/registration step.

This is the code I used to interrogate the license key entered at install time at runtime (VB.NET, sorry):

Declare Auto Function MsiGetProductInfo Lib "msi.dll" (ByVal product As String, ByVal [property] As String, <MarshalAs(UnmanagedType.VBByRefStr)> ByRef valueBuf As String, ByRef len As Long) As Int32

Private Shared Function GetMSIKey() As String

Dim lsResult As String = Nothing
Try
    Dim loUninstallHive As RegistryKey = Registry.LocalMachine.OpenSubKey("Software\Microsoft\Windows\CurrentVersion\Uninstall")
    For Each loProgramHiveID As String In loUninstallHive.GetSubKeyNames()
        Dim loProgramHive As RegistryKey = loUninstallHive.OpenSubKey(loProgramHiveID)
        Dim lsProgramName As String = NullReaders.StringValue(loProgramHive.GetValue("DisplayName"))

        If lsProgramName.StartsWith("<your app name>", StringComparison.OrdinalIgnoreCase) Then

            Dim loInstallLocation = loProgramHive.GetValue("InstallLocation")

            Dim lsHiveName As String = loProgramHive.Name
            Dim lsGUID As String = lsHiveName.Substring(lsHiveName.LastIndexOf("\") + 1)

            Dim lsIKC As String = New String(" ", 255)
            Dim liLen As Integer = 255
            MsiGetProductInfo(lsGUID, "ProductID", lsIKC, liLen)

            lsResult = lsIKC.Substring(6, 24).Replace(" ", "-")

            Exit For
        End If
    Next
Catch ex As Exception
    TraceLog.DoErr(ex)
End Try
Return lsResult
End Function

Note that it seemed to be important to have ProductID with the capital D.

The substring/replace will depend on your PIDTemplate property in your Setup.wxs e.g.:

 <Property Id="PIDTemplate"><![CDATA[12345<#### #### #### #### ####>@@@@@]]></Property>

Lastly, here is the line from UserRegistrationDlg.wxs that puts the license key boxes into the installer UI:

<Control Id="CDKeyEdit" Type="MaskedEdit" X="45" Y="159" Width="250" Height="16" Property="PIDKEY" Text="[PIDTemplate]" />


This isn't really the answer to my question, but I didn't want to leave the question unresolved in case someone else ends up in the same situation.

I have gotten around this issue by storing the user's entered serial number in the registry during the setup process. By creating a registry key (string value) with the value "[PIDKEY]" the user's serial number can be stored, and then later retrieved during the application's execution with the .NET RegistryKey class.

If I had more time to spend on this issue I would, but thanks to Harry for helping me get on the right track.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号