[英]How to open MSI table in Delphi?
I need to open some tables from MSI database, read this and place some rows in this with using Delphi (in my example is Delphi 7 but allowed other versions if it needed). 我需要从MSI数据库中打开一些表,阅读本文并使用Delphi放置一些行(在我的例子中是Delphi 7,但如果需要则允许其他版本)。
For example it would look like ORCA. 例如,它看起来像ORCA。 Msi must be open, written to the table where it's can be edited and written to the msi file. Msi必须是开放的,写入表格,可以编辑并写入msi文件。
By default, Delphi can't open MSI tables as I thing but I found a JEDI Windows API where exists libraris like JwaMsi and JwaMsiQuery. 默认情况下,Delphi无法打开MSI表,但我找到了一个JEDI Windows API ,其中存在像JwaMsi和JwaMsiQuery这样的库。 But I can't find documentations or examples of using functions like 但是我找不到文档或使用函数的例子
function MsiOpenProduct(szProduct: LPCTSTR; var hProduct: MSIHANDLE): UINT; stdcall;
{$EXTERNALSYM MsiOpenProduct}
By the way, while I search information about this I found this code: 顺便说一句,当我搜索有关此信息时,我发现此代码:
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;
What is better to use and where I can see documentation and/or examples? 什么是更好的使用,我可以看到文档和/或示例?
PS Sorry for my English PS抱歉我的英文
I would use the COM-based API to MSI. 我会使用基于COM的API到MSI。
See this thread and the MSI API documentation 请参阅此主题和MSI API文档
So, solution exist and I do it! 所以,解决方案存在,我做到了! It's not so gracefully but it's working... 这不是那么优雅,但它的工作......
At first, read articles from MSDN (in my case is articles about work with MSI database). 首先,阅读MSDN上的文章(在我的例子中是关于使用MSI数据库的文章)。 At second, you must understand what you need to do. 第二,你必须明白你需要做什么。 In my case it is: 在我的情况下它是:
Here I show how I do the three first steps. 在这里,我将展示如何完成前三个步骤。
Preparing 准备
Download JEDI Windows AP (for easer work with msi) and add to project JwaMsi.pas, JwaMsiDefs.pas and JwaMsiQuery.pas (do not forget about USES list). 下载JEDI Windows AP (轻松使用msi)并添加到项目JwaMsi.pas,JwaMsiDefs.pas和JwaMsiQuery.pas(不要忘记USES列表)。 Dependencies will be added automatically. 将自动添加依赖项。 Next, place on form all needed components. 接下来,在表单上放置所有需要的组件。
Let's code! 我们的代码!
1 Open msi database and 2 Read table names 1打开msi数据库和2个读取表名
Define variables for handlers and for buffers 为处理程序和缓冲区定义变量
var msi_handler_DB, msi_handler_view, msi_handler_record:TMSIHandle;
txt:PChar;
sz:DWORD;
Now we need take a list of tables ( more info here ) and place it in ListBox, for example 现在我们需要获取一个表列表( 这里有更多信息 )并将其放在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 Read needed table and show it 3阅读所需的表并显示它
It's easy! 这很容易!
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 If it needed - make changes and save it 4如果需要 - 进行更改并保存
Just repeat third step from the end to beginning: export StringGrid to file (about .idt and it's structure you can read here: one , two , three ), import in to MSI with property MsiDatabaseImport (do not forget open database before and append it after, also remember about close handlers) and delete temporary .idt file. 只需重复从头到尾的第三步:将StringGrid导出到文件(关于.idt及其结构,你可以在这里阅读: 一 , 二 , 三 ),导入到具有属性MsiDatabaseImport的MSI(不要忘记之前打开数据库并附加它之后,还记得关闭处理程序)并删除临时.idt文件。
Good luck! 祝好运!
PS Sorry for my English, part two :) PS抱歉我的英文,第二部分:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.