我正在处理两个应用程序,这两个应用程序都依赖于MSIGetProductInfo调用来检索用户在安装过程中输入的序列号(标准的可视演播室设置和部署项目)。
以下是我用来检索序列号的代码:
Int32 len = 512;
var builder = new StringBuilder(len);
MsiGetProductInfo("{98A0A10F-5E78-4FA6-83F6-6B356D75ADD4}", "ProductId", builder, ref len);
return builder.ToString();
第一个app,一个visual c#forms app,按照我的预期返回(当我输入1111-1111-1111-1111时,它表示如此)。但是,当我在c#windows服务的OnStart方法中放入相同的调用时,我会得到随机垃圾,例如Unicode字符,偶尔会出现一个字,并且每个运行时返回的值都不同。偶尔我会得到一个结果,其中包含包含MsiGetProductInfo调用的dll路径的一部分,例如“㷨H꿈Eindows \ system32 \ msi.dll”。
在我看来(没有受过教育的猜测),就像对dll函数的调用失败一样,它只是从未使用的内存位置返回数据。
我已经尝试过阅读其他属性,例如InstallSource和InstalledProductName,但这些也是服务中的垃圾(同时在表单应用程序中也很好)。我还认为它可能是权限问题,因此我尝试在NetworkService,LocalService和LocalSystem帐户下运行该服务但没有成功。
Forms应用程序和服务都是由同一个安装项目同时安装的,因此它们应该共享相同的ProductCode,对吗?如果没有,我可以看到服务无法检索产品信息的原因。
有没有人遇到这个或者知道是什么导致了这个?
答案 0 :(得分:1)
我需要回答同样的问题。我在wix msi项目中添加了UserRegistrationDlg.wxs
来收集PIDKEY。但是,我需要在程序首次运行时获取在安装时输入的序列,以完成激活/注册步骤。
这是我用来查询在运行时安装时输入的许可证密钥的代码(VB.NET,抱歉):
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
请注意,ProductID
与大写字母D一起显得很重要。
子字符串/替换将取决于PIDTemplate
中的Setup.wxs
属性,例如:
<Property Id="PIDTemplate"><![CDATA[12345<#### #### #### #### ####>@@@@@]]></Property>
最后,这是来自UserRegistrationDlg.wxs
的行,它将许可证密钥框放入安装程序UI:
<Control Id="CDKeyEdit" Type="MaskedEdit" X="45" Y="159" Width="250" Height="16" Property="PIDKEY" Text="[PIDTemplate]" />
答案 1 :(得分:0)
这不是我的问题的答案,但我不想让问题得不到解决,以防其他人在同样的情况下结束。
通过在设置过程中将用户输入的序列号存储在注册表中,我解决了这个问题。通过创建值为“[PIDKEY]”的注册表项(字符串值),可以存储用户的序列号,然后在使用.NET RegistryKey类执行应用程序期间检索该序列号。
如果我有更多时间花在这个问题上,我会这样做,但感谢Harry帮助我走上正轨。