通过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
相关产品推荐
相关产品推荐

