鉴于MSI产品代码,我希望从已安装的产品中获取升级代码(以及其他属性)。我通过调用MsiOpenProduct方法,然后调用MsiGetProductProperty()来尝试这个。 (缩写)示例如下所示:
MSIHANDLE handle = NULL;
MsiOpenProduct(strProductCode,&handle);
CString strUpgradeCode;
MsiGetProductProperty(handle,_T("UpgradeCode"), strUpgradeCode.GetBuffer(GUID_LENGTH), &dwSize);
strUpgradeCode.ReleaseBuffer();
MsiCloseHandle(handle);
这让我得到了理想的值,从MSDN文档来看,这似乎是一种有效的方法:
MsiOpenProduct函数打开一个 与功能一起使用的产品 访问产品数据库。该 必须调用MsiCloseHandle函数 当手柄没有时用手柄 需要更长时间。
但是,调用MsiOpenProduct()会弹出“Windows安装程序正在准备安装...”对话框。对MsiCloseHandle()的调用使它再次消失。
这让我想知道:
答案 0 :(得分:3)
MsiOpenProduct应该没问题只要你不运行任何序列或动作,它就不会做任何事情。如果要使对话框静音,可以小心使用MsiSetInternalUI()或MsiSetExternalUI()。
您可以采取的另一种方法,只要ProductCode
和UpgradeCode
安全静态(即只要它们不被变换更改),就是使用MsiGetProductInfo()定位数据库并在其上调用MsiOpenDatabase()。区别在于MsiOpenProduct()(或类似的MsiOpenPackage)应用在安装时使用的转换并准备会话,而MsiOpenDatabase()则不应用。
答案 1 :(得分:1)
对于您想要的信息,听起来您可以调用:: MsiGetProductInfo()。 :: MsiOpenDatabase()是一个非常慢的操作,而:: MsiGetProductInfo()是(IIRC)更符合注册表查找。
答案 2 :(得分:1)
有一个全面的答案,其中提供了有关如何使用 Powershell 或 VBScript 和 WMI 获取UpgradeCode的信息:How can I find the Upgrade Code for an installed MSI file?
下面是一个使用VBScript / COM自动化( MSI API ,而不是WMI)的快速基本示例以及OP讨论的方法(使用OpenProduct方法 - 相当于Win32安装程序功能的COM)
正如我在上面的评论中所讨论的,我将添加这个小VBScript,就像OP在C ++中一样。请注意,可以通过Windows Installer(Win32_Product对象),WMI和COM automation访问Win32 C++ installer functions。
由于某些原因,程序包的UpgradeCode
似乎无法直接从COM API或Win32 API中获得。确实非常奇怪,特别是因为它是Installer.RelatedProducts等函数的输入参数 - 文档中不清楚实际调用应该是RelatedProducts(UpgradeCode)
,而是查看msi.IDL
你看到的:StringList* RelatedProducts([in] BSTR UpgradeCode);
WMI选项有效,但下面显示的这个OpenProduct
调用也是如此(显然更快,看起来很安全 - 据我所知,WMI完全是只读的 - 但天知道他们在做什么“ “它们是否会启动会话对象?或者它们是否正在从WMI数据库中读取?WMI确实”感觉“更安全”。
以下方法的优点在于它将应用在安装时应用于相关产品的所有变换。如果你想写入磁盘而不是显示消息框而且无法查找文档,这里有一个类似的VBScript,它将包信息写入桌面文本文件:How can I find the product GUID of an installed MSI setup? - 相当多的页面,只需复制几行,你就可以免费留言了。)
注意!如果在系统上启用automatic logging,则下面的脚本将为每个打开的MSI创建一个日志文件。目前,脚本只会在它存在之前打开一个MSI(
Exit For
构造)。
On Error Resume Next ' This "tersified" script has no error handling
Const msiUILevelNone = 2
Set installer = CreateObject("WindowsInstaller.Installer")
Set products = installer.ProductsEx("", "", 7)
installer.UILevel = msiUILevelNone ' Suppress GUI (MSI progress dialog)
'Iterate over all MSI packages on the box
For Each product In products
' productcode = product.ProductCode
' name = product.InstallProperty("ProductName")
' version = product.InstallProperty("VersionString")
' pkgcode = product.InstallProperty("PackageCode")
Set session = installer.OpenProduct(product.ProductCode)
upgradecode = session.ProductProperty("UpgradeCode")
MsgBox upgradecode
Set session = Nothing ' Important, close the session (doesn't work in Javascript btw)
Exit For ' End after one iteration (so you don't get a million message boxes)
' Alternatively something like: If i > 4 Then Exit For
Next
Set installer = Nothing
MsgBox "Finished"
我试图查看C ++ Win32安装程序函数以获取任何其他方法来检索UpgradeCode,但我看不到任何明显的东西。会话方法也应该在C ++中工作,但我对句柄和资源的释放有点担心。我没有用C ++进行过适当的训练,但知道的不仅仅是危险的。 在洞中射击。等...
我想知道OP是否检索了盒子上的所有包,或者只是一个包。我想知道用Javascript看到的时序问题和并发会话对象问题是否会在C ++中出现?我想 - 有一天我会试一试。