Вчера я искал высоко и низко, ища, как быстро получить ProductVersion базы данных msi. В основном, что я нашел, используя оболочку WindowsInstaller COM, в то время как это выполнялось, я хочу добиться тех же результатов, используя pinvoke, используя msi.dll.
Проверка ProductVersion MSI программно
Ответ 1
Вот что я придумал.
С# Библиотека установщика 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);
С# 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. Надеюсь, это поможет кому-то.
Ответ 2
Любой, кто должен выполнить .NET-взаимодействие с MSI, должен использовать Microsoft.Deployment.WindowsInstaller, найденный в WiX DTF SDK. Это очень чистая библиотека и способ лучше, чем попытка написать свой собственный.