如何在Delphi中打开MSI表?

我需要从MSI数据库打开一些表,阅读这个和使用delphi(在我的例子是delphi7,但允许其他版本,如果需要的话)放在这一些行。

例如,它看起来像ORCA。 Msi必须是开放的,写入到可以编辑并写入msi文件的表格中。

默认情况下,Delphi不能像我那样打开MSI表,但是我发现了JEDI Windows API ,其中存在像JwaMsi和JwaMsiQuery这样的库。 但是我找不到使用函数的文档或例子

function MsiOpenProduct(szProduct: LPCTSTR; var hProduct: MSIHANDLE): UINT; stdcall; {$EXTERNALSYM MsiOpenProduct} 

顺便说一下,当我search有关这个信息,我发现这个代码:

 const msilib = 'msi.dll'; type MSIHANDLE = DWORD; TMsiHandle = MSIHANDLE; function MsiCloseHandle(hAny: MSIHANDLE):UINT;stdcall;external msilib name 'MsiCloseHandle'; function MsiOpenProduct(szProduct:LPCSTR;var hProduct:MSIHANDLE):UINT;stdcall;external msilib name 'MsiOpenProductA'; function MsiGetProductProperty(hProduct:MSIHANDLE;szProperty:LPCSTR;lpValueBuf:LPSTR;pcchValueBuf:LPDWORD):UINT;stdcall; external msilib name 'MsiGetProductPropertyA'; function MsiSetInternalUI(dwUILevel:INSTALLUILEVEL;phWnd:LPHWND):INSTALLUILEVEL;stdcall; external msilib name 'MsiSetInternalUI'; function GetMSIProperty(aProductCode:string):string; var msi:TMSIHandle; t:string; function _getmsiproperty(_name:string):string; var txt:PChar; sz:DWORD; begin sz:=MAX_PATH; txt:=AllocMem(sz+1); if MsiGetProductProperty(msi,PChar(_name),txt,@sz)=ERROR_MORE_DATA then begin ReAllocMem(txt,sz+1); MsiGetProductProperty(msi,PChar(_name),txt,@sz); end; SetString(Result,txt,sz); FreeMem(txt,sz+1); end; begin MsiSetInternalUI(2,nil); // скрываем GUI/hide GUI if MsiOpenProduct(PChar(aProductCode),msi)=ERROR_SUCCESS then begin t:=_getmsiproperty('ARPPRODUCTICON'); // главная иконка приложения/main program icon if t='' then t:=_getmsiproperty('ProductIcon'); if t='' then t:=_getmsiproperty('CompleteSetupIcon'); if t='' then t:=_getmsiproperty('CustomSetupIcon'); if t='' then t:=_getmsiproperty('InfoIcon'); if t='' then t:=_getmsiproperty('InstallerIcon'); if t='' then t:=_getmsiproperty('RemoveIcon'); if t='' then t:=_getmsiproperty('RepairIcon'); Result:=t; MsiCloseHandle(msi); end; end; 

什么是更好的使用和我可以看到文档和/或例子?

PS对不起,我的英语

我会使用基于COM的API到MSI。

看到这个线程和MSI API文档

所以,解决方案存在,我做到了! 这不是那么优雅,但它的工作…

起初,从MSDN阅读文章(在我的情况是关于MSI数据库工作的文章)。 第二,你必须明白你需要做什么。 在我的情况是这样的:

  1. 打开msi数据库
  2. 阅读表名
  3. 阅读需要的表格并显示
  4. 如果需要 – 进行更改并保存

在这里我展示了我如何做到三个第一步。

准备


下载JEDI Windows AP (用于msi的更快捷的工作)并添加到项目JwaMsi.pas,JwaMsiDefs.pas和JwaMsiQuery.pas(不要忘记使用列表)。 依赖关系将被自动添加。 接下来,放置所有需要的组件。

让我们编码!

1打开msi数据库和2读取表名


为处理程序和缓冲区定义变量

 var msi_handler_DB, msi_handler_view, msi_handler_record:TMSIHandle; txt:PChar; sz:DWORD; 

现在我们需要获取一个表格列表( 更多信息在这里 ),并将其放在ListBox中

 begin sz:=MAX_PATH; //initialise txt:=AllocMem(sz+1); //variables OpenDialog1.Execute; //select file If MsiOpenDatabase(PChar(OpenDialog1.FileName), MSIDBOPEN_DIRECT, msi_handler_DB)=ERROR_SUCCESS //check if DB is open then begin //start reading Listbox1.Clear; //prepare listbox for filling MsiDatabaseOpenView(msi_handler_DB, 'SELECT * FROM _Tables',msi_handler_view); //prepare query to _Table MsiViewExecute(msi_handler_view, msi_handler_record); //execute... While not MsiViewFetch(msi_handler_view, msi_handler_record)=ERROR_NO_MORE_ITEMS //and fetch it in cycle until end of table do begin MsiRecordGetString(msi_handler_record,1,txt,sz); //read string ListBox1.Items.Add(txt); //and write to listbox end; //end of fetch cycle MsiCloseAllHandles; //close handles (we don't need they more) end; //stop reading end; 

3阅读需要的表格并显示


这很容易!

  begin edit1.text:=Listbox1.Items.ValueFromIndex[ListBox1.ItemIndex]; If MsiOpenDatabase(PChar(OpenDialog1.FileName), MSIDBOPEN_DIRECT, msi_handler_DB)=ERROR_SUCCESS //open database again then begin MsiDatabaseExport(msi_handler_DB, pchar(ListBox1.Items.Strings[ListBox1.ItemIndex]), 'C:\Windows\Temp', Pchar(ListBox1.Items.Strings[ListBox1.ItemIndex]+'.idt')); //export table to .idt MsiCloseAllHandles; //and close handler again //... //here must be placed code for //parsing .idt as tabulation separated file //with wordwrap and show it. //for example - in StringGrid //... DeleteFile('C:\Windows\Temp\'+ ListBox1.Items.Strings[ListBox1.ItemIndex]+'.idt'); //do not forget delete temporary .idt file. save our planet! :) end; end; 

4如果需要 – 进行更改并保存


只需重复第三步从头到尾:将StringGrid导出到文件(关于.idt和它可以在这里读取的结构: 一 , 二 , 三 ),导入到带有属性MsiDatabaseImport的MSI中(不要忘记打开数据库,然后附加它之后,还要记住关闭处理程序)并删除临时.idt文件。

祝你好运!

PS对不起,我的英文,第二部分:)