【问题标题】:How to get the product version from an msi file, without installing the msi?如何在不安装 msi 的情况下从 msi 文件中获取产品版本?
【发布时间】:2015-02-22 10:11:24
【问题描述】:

我正在寻找一个获取 msi 路径并返回产品版本(主要和次要)而不安装 API 的 C API。

谢谢, 艾坦

【问题讨论】:

标签: c winapi windows-installer


【解决方案1】:

我不会使用开放包的东西 - 这是一个静态数据库,所以MsiOpenDatabase 和 SQL 是要走的路。缺少一些包含,但这工作正常:

#include "stdafx.h"
UINT GetProperty (MSIHANDLE dbHand, LPCTSTR  propname, LPTSTR strVal)
{
    PMSIHANDLE viewH = NULL;
    WCHAR qry [100] = {0};
    StringCchCat (qry, 100, L"Select `Value` from `Property` where `Property`='" );
    StringCchCat (qry, 100, propname);
    StringCchCat (qry, 100, L"'");
    UINT res = MsiDatabaseOpenView (dbHand, qry, &viewH);
    if (ERROR_SUCCESS!=res)
        return res;
    res = MsiViewExecute (viewH, 0); 
    if (ERROR_SUCCESS!=res)
    {
        MsiCloseHandle (viewH);
        return res;
    }
    PMSIHANDLE recH=NULL; 
    res = MsiViewFetch (viewH, &recH); 
    if (ERROR_SUCCESS!=res)
    {
        MsiCloseHandle (viewH);
        return res;
    }
    WCHAR buff [50] = {0}; 
    DWORD dwlen = 50;
    res = MsiRecordGetString (recH, 1, buff, &dwlen);
    if (ERROR_SUCCESS!=res)
    {
        MsiCloseHandle (viewH);
        MsiCloseHandle (recH); 
        return res;
    }
    StringCchCopy (strVal, dwlen+1, buff);
    MsiViewClose (viewH);
    MsiCloseHandle (recH); 
    return (ERROR_SUCCESS);

}

int _tmain(int argc, _TCHAR* argv[])
{
    PMSIHANDLE dbH=NULL;
    UINT res = MsiOpenDatabase (L"C:\\Phil\\MyDD\\Samples Setup\\GetMsiProperty\\Set2.msi", MSIDBOPEN_READONLY, &dbH);
     WCHAR pversion [512] = {0}; 
     res = GetProperty (dbH, L"ProductVersion", pversion); 
    WCHAR ubuff [50] = {0}; 
    res = GetProperty(dbH, L"UpgradeCode", ubuff); 
    WCHAR pbuff [50] = {0}; 
     res = GetProperty(dbH, L"ProductCode", pbuff); 
     WCHAR prodName [512] = {0}; 
     res = GetProperty (dbH, L"ProductName", prodName); 
     WCHAR prodLang [512] = {0}; 
     res = GetProperty (dbH, L"ProductLanguage", prodLang); 
    return 0;
}

【讨论】:

  • 非常感谢您的详细解答!
  • 我试过了,但 MsiViewFetch() 失败并显示 ERROR_NO_MORE_ITEMS。我怀疑 MsiOpenDatabase() 中已经存在问题,因为它给了我 1 作为数据库句柄(就像我之前尝试使用 MsiOpenPackage() 时发生的那样)。 1 是数据库句柄的合法值吗?
  • 数据库句柄只是数字,1没有错。错误没有更多项目意味着MSI文件中没有ProductVersion。使用 Orca 打开它并查看属性表。该代码每次都对我有用!
  • 谢谢,现在它可以工作了——问题是我使用了 INSTALLPROPERTY_VERSIONMAJOR 而不是“ProductVersion”。它现在也适用于 MsiOpenPackage()。
【解决方案2】:

MsiGetFileVersion() 从普通文件(exe、dll 等)中读取版本信息,而不是从 MSI 数据库中读取产品版本。

要从 MSI 中获取产品版本,您可以使用 MsiOpenPackage 获取 MSI 的句柄,然后使用该句柄调用 MsiGetProductProperty,请求 ProductVersion 属性。

CoInitialize(NULL);

MSIHANDLE hPackage = NULL;
UINT retVal = MsiOpenPackage(_T("TortoiseSVN-1.8.10.26129-x64-svn-1.8.11.msi"), &hPackage);
if (retVal != ERROR_SUCCESS)
{
    return retVal;
}

TCHAR versionBuf[64] = { 0 };
DWORD versionBufSize = sizeof(versionBuf) / sizeof(versionBuf[0]);

MsiGetProductProperty(hPackage, _T("ProductVersion"), versionBuf, &versionBufSize);

MsiCloseHandle(hPackage);

【讨论】:

  • 谢谢,我试试看。
  • 我调用了MsiOpenPackage(),得到的MSI句柄是1;我相信这没关系,因为每次我调用 MsiOpenPackage() 时,可能都会递增地给出句柄。我对吗?但是,当我使用 INSTALLPROPERTY_VERSIONMAJOR 作为属性参数调用 MsiGetProductProperty() 时,我得到一个空字符串。这是为什么呢?
  • 您是否尝试过参考列表中的任何属性? msdn.microsoft.com/en-us/library/…
  • 没有。我使用了 INSTALLPROPERTY_VERSIONMAJOR 字符串,如 MsiGetProductInfo() 中记录的(并为我工作)。我无法从您提供的属性文档中理解如何使用这些属性 - MsiGetProductProperty 获取一个字符串 (LPCTSTR) 作为属性参数 - 如果我想使用您提到的属性,我应该传递哪个字符串?
  • 此外,我不确定我从 MsiOpenPackage() 获得的句柄是否正确,因为我尝试在 2 个不同的 msi 文件上运行它两次(在同一次运行中),并且得到了相同的处理这两个文件。我能否以某种方式验证返回的 msi 句柄是否正确?
猜你喜欢
  • 2015-11-02
  • 2014-08-18
  • 1970-01-01
  • 1970-01-01
  • 2013-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多