Проверка версии продукта MSI программно
Вчера я искал максимум и минимум, пытаясь быстро получить ProductVersion для базы данных MSI. Главным образом то, что я обнаружил, было связано с использованием оболочки WindowsInstaller COM, в то время как это сделало свою работу, я хочу достичь тех же результатов с помощью pinvoke, используя msi.dll.
3 ответа
Вот что я придумала.
Библиотека C# для установщика Windows:
// 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();
}
Это может быть легко экстраполировано на получение любого свойства или поля из базы данных msi путем изменения оператора SQL. Я надеюсь, что это поможет кому-то.
Любой, кому необходимо взаимодействие с.NET с MSI, должен использовать Microsoft.Deployment.WindowsInstaller, который находится в DTX SDK WiX. Это очень чистая библиотека и гораздо лучше, чем пытаться написать свою.
Мне не удалось получить ответ @user529570, работающий на меня, однако это сработало на С #
using System;
using System.Runtime.InteropServices;
using System.Text;
public static class Msi
{
public static string GetProductVersion(string fileName)
{
IntPtr hInstall = IntPtr.Zero;
try
{
uint num = MsiOpenPackage(fileName, ref hInstall);
if ((ulong)num != 0)
{
throw new Exception("Cannot open database: " + num);
}
StringBuilder szValueBuf = new StringBuilder();
int pcchValueBuf = 255;
num = MsiGetProperty(hInstall, "ProductVersion", szValueBuf, ref pcchValueBuf);
if ((ulong)num != 0)
{
throw new Exception("Failed to Get Property ProductVersion: " + num);
}
return szValueBuf.ToString();
}
finally
{
if(hInstall != IntPtr.Zero)
{
MsiCloseHandle(hInstall);
}
}
}
[DllImport("msi.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
private static extern int MsiCloseHandle(IntPtr hAny);
[DllImport("msi.dll", CharSet = CharSet.Unicode, EntryPoint = "MsiOpenPackageW", ExactSpelling = true, SetLastError = true)]
private static extern uint MsiOpenPackage(string szDatabasePath, ref IntPtr hProduct);
[DllImport("msi.dll", CharSet = CharSet.Unicode, EntryPoint = "MsiGetPropertyW", ExactSpelling = true, SetLastError = true)]
private static extern uint MsiGetProperty(IntPtr hInstall, string szName, [Out] StringBuilder szValueBuf, ref int pchValueBuf);
}