以编程方式检查MSI的ProductVersion

昨天我一直在搜索高低,寻找如何快速获得msi数据库的ProductVersion。 大多数情况下,我发现使用WindowsInstaller COM包装器,虽然这完成了工作,我想通过pinvoke使用msi.dll实现相同的结果。

这就是我想出来的。

C#Windows Installer COM库:

// Get the type of the Windows Installer object Type installerType = Type.GetTypeFromProgID("WindowsInstaller.Installer"); // Create the Windows Installer object Installer installer = (Installer)Activator.CreateInstance(installerType); // Open the MSI database in the input file Database database = installer.OpenDatabase(od.FileName, MsiOpenDatabaseMode.msiOpenDatabaseModeReadOnly); // Open a view on the Property table for the version property WindowsInstaller.View view = database.OpenView("SELECT * FROM Property WHERE Property = 'ProductVersion'"); // Execute the view query view.Execute(null); // Get the record from the view Record record = view.Fetch(); // Get the version from the data string version = record.get_StringData(2); 

C#Pinvoke:

  [DllImport("msi.dll", SetLastError = true)] static extern uint MsiOpenDatabase(string szDatabasePath, IntPtr phPersist, out IntPtr phDatabase); [DllImport("msi.dll", CharSet = CharSet.Unicode)] static extern int MsiDatabaseOpenViewW(IntPtr hDatabase, [MarshalAs(UnmanagedType.LPWStr)] string szQuery, out IntPtr phView); [DllImport("msi.dll", CharSet = CharSet.Unicode)] static extern int MsiViewExecute(IntPtr hView, IntPtr hRecord); [DllImport("msi.dll", CharSet = CharSet.Unicode)] static extern uint MsiViewFetch(IntPtr hView, out IntPtr hRecord); [DllImport("msi.dll", CharSet = CharSet.Unicode)] static extern int MsiRecordGetString(IntPtr hRecord, int iField, [Out] StringBuilder szValueBuf, ref int pcchValueBuf); [DllImport("msi.dll", ExactSpelling = true)] static extern IntPtr MsiCreateRecord(uint cParams); [DllImport("msi.dll", ExactSpelling = true)] static extern uint MsiCloseHandle(IntPtr hAny); public string GetVersionInfo(string fileName) { string sqlStatement = "SELECT * FROM Property WHERE Property = 'ProductVersion'"; IntPtr phDatabase = IntPtr.Zero; IntPtr phView = IntPtr.Zero; IntPtr hRecord = IntPtr.Zero; StringBuilder szValueBuf = new StringBuilder(); int pcchValueBuf = 255; // Open the MSI database in the input file uint val = MsiOpenDatabase(fileName, IntPtr.Zero, out phDatabase); hRecord = MsiCreateRecord(1); // Open a view on the Property table for the version property int viewVal = MsiDatabaseOpenViewW(phDatabase, sqlStatement, out phView); // Execute the view query int exeVal = MsiViewExecute(phView, hRecord); // Get the record from the view uint fetchVal = MsiViewFetch(phView, out hRecord); // Get the version from the data int retVal = MsiRecordGetString(hRecord, 2, szValueBuf, ref pcchValueBuf); uRetCode = MsiCloseHandle(phDatabase); uRetCode = MsiCloseHandle(phView); uRetCode = MsiCloseHandle(hRecord); return szValueBuf.ToString(); } 

这可以很容易地推断为通过更改SQL语句从msi数据库获取任何属性或字段。 我希望这可以帮助别人。

任何需要与MSI进行.NET互操作的人都应该使用WiX的DTF SDK中的Microsoft.Deployment.WindowsInstaller。 它是一个非常干净的库,比试图编写自己的库更好。