windows - 从 Windows 服务调用 MSIGetProductInfo 返回垃圾值

标签 windows windows-services installation

我有两个正在开发的应用程序,这两个应用程序都依赖于 MSIGetProductInfo 调用来检索用户在安装过程中输入的序列号(标准的 visual studio 设置和部署项目)。

这是我用来检索序列号的代码:

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

第一个应用程序是一个可视化 C# 窗体应用程序,它按我的预期返回(当我输入 1111-1111-1111-1111 时,它会这样指示)。但是,当我在 c# windows 服务的 OnStart 方法中进行相同的调用时,我得到了随机垃圾,例如 Unicode 字符,偶尔是一个单词,并且每次运行时返回的值都不同。有时我得到的结果包含包含 MsiGetProductInfo 调用的 dll 路径的一部分,例如“㷨H꿈Eindows\system32\msi.dll”。

在我看来(无根据的猜测)对 dll 函数的调用失败了,它只是从未使用的内存位置返回数据。

我已经尝试读取其他属性,例如 InstallSource 和 InstalledProductName,但这些在服务中也是垃圾(但在表单应用程序中也很好)。我还认为这可能是权限问题,所以我尝试在 NetworkService、LocalService 和 LocalSystem 帐户下运行该服务,但没有成功。

Forms 应用程序和服务是通过同一个安装项目同时安装的,所以它们应该共享同一个 ProductCode,对吗?如果不是,我可以了解服务无法检索产品信息的原因。

有没有人遇到过这种情况或知道是什么原因造成的?

最佳答案

我需要回答同样的问题。我将 UserRegistrationDlg.wxs 添加到 wix msi 项目以收集 PIDKEY。但是,然后我需要在程序首次运行时获取安装时输入的序列号以完成激活/注册步骤。

这是我用来查询在运行时安装时输入的许可证 key 的代码(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 似乎很重要。

子字符串/替换将取决于 Setup.wxs 中的 PIDTemplate 属性,例如:

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

最后,这是 UserRegistrationDlg.wxs 中将许可证 key 框放入安装程序 UI 的行:

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

关于windows - 从 Windows 服务调用 MSIGetProductInfo 返回垃圾值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7719739/

相关文章:

windows - 作为服务运行的 PowerShell 脚本行为异常

c# - 构建 Windows 资源管理器扩展

c - 标准输入上的 ReadFile 在 Windows 7 上崩溃

django - eb 创建 : ERROR: PermissionError - [Errno 13] Permission denied: './catroot2\\edb.log'

php - fatal error - 找不到 'Mongo' 类

configuration - 在 600 台客户端计算机上安装 PowerShell - 推荐设置

c# - WIX 和 C# 中的 "SystemFolder"

windows - 如何在安装过程中为应用程序添加防火墙权限?

windows - SVN 在 Windows 上以不同用户身份 checkin

c# - Windows 服务停止时子进程被终止