You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

通过OLE在Delphi/Inno Setup读取MSI信息遇类型不匹配问题

解决Inno Setup/Delphi读取MSI属性时的“Type Mismatch”异常

错误原因

你遇到的“Type Mismatch”异常,是因为Windows Installer COM对象的Record成员(IsNull、DataSize、StringData)都是需要传入列索引的带参数属性/方法,而非无参属性。你的代码中直接访问这些成员时未指定列索引(MSI的列索引从1开始),导致类型不匹配。

修正后的Delphi测试代码

procedure Test(const MsiFileName: String);
var
  Installer: Variant;
  Database: Variant;
  SQL: String;
  View: Variant;
  Rec: Variant;
  ProductVersion: String;
begin
  CoInitialize(nil);
  try
    Installer := CreateOleObject('WindowsInstaller.Installer');
    Database := Installer.OpenDatabase(MsiFileName, 0);
    SQL := 'SELECT Value FROM Property WHERE Property = ''ProductVersion''';
    View := Database.OpenView(SQL);
    View.Execute(Null); // 需传入Null作为无参数的Execute调用

    Rec := View.Fetch;
    if not VarIsNull(Rec) then
    begin
      // 读取第1列的数据(查询结果只有1列,索引为1)
      if not Rec.IsNull(1) then
      begin
        ProductVersion := Rec.StringData(1);
        ShowMessage('Product Version: ' + ProductVersion);
      end;
      Rec.Close; // 释放Record对象
    end;

    View.Close; // 释放View对象
    Database := Unassigned;
    Installer := Unassigned;
  except
    on E: Exception do
      ShowMessage('Error: ' + E.Message);
  end;
  CoUninitialize;
end;

Inno Setup 实现代码

适配Inno Setup的Pascal Script语法,实现读取MSI版本的函数:

function GetMSIProductVersion(const MSIPath: String): String;
var
  Installer: Variant;
  Database: Variant;
  View: Variant;
  Rec: Variant;
begin
  Result := '';
  try
    Installer := CreateOleObject('WindowsInstaller.Installer');
    Database := Installer.OpenDatabase(MSIPath, 0);
    View := Database.OpenView('SELECT Value FROM Property WHERE Property = ''ProductVersion''');
    View.Execute(Null);
    
    Rec := View.Fetch;
    if not VarIsNull(Rec) then
    begin
      if not Rec.IsNull(1) then
        Result := Rec.StringData(1);
      Rec.Close;
    end;
    
    View.Close;
  except
    // 捕获异常,返回空字符串表示失败
  end;
end;

关键注意事项

  • Record的成员(IsNull、DataSize、StringData)必须传入1-based的列索引,因为MSI查询结果的列从1开始计数。
  • 调用View.Execute时需传入Null(或Unassigned),因为该方法需要参数(即使无查询参数)。
  • 必须在使用完Record、View对象后调用Close方法释放资源,避免内存泄漏。
  • 需处理Fetch返回Null的情况(即MSI文件中不存在指定属性)。

内容的提问来源于stack exchange,提问作者Illishar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 04:22:44