Reputation: 633
I'm writing a tool in c++ to get the version of a given MSI file. I'm using MsiOpenDatabase() to get the handle
MsiOpenDatabase(msifile.c_str(), MSIDBOPEN_READONLY, &db);
This function returns ERROR_SUCCESS and the MSIHANDLE db is not null Then I call MsiGetProperty()
MsiGetProperty(db, L"ProductVersion", buffer, &buffsize);
And this function returns ERROR_INVALID_HANDLE. What am I doing wrong?
http://msdn.microsoft.com/en-us/library/aa370338%28v=vs.85%29.aspx
http://msdn.microsoft.com/en-us/library/aa370134%28v=vs.85%29.aspx
Upvotes: 0
Views: 1510
Reputation: 633
Thanks for pointing the difference between the Database handle and the Installer handle. It turns out that I found some VBS examples (http://msdn.microsoft.com/en-us/library/aa372865%28v=vs.85%29.aspx) that guided me on how to use the Windows Installer API. I used WiRunSQL.vbs as a guide.
At the end, the workflow is roughly this one:
MsiOpenDatabase(file.c_str(), MSIDBOPEN_READONLY, &db);
MsiDatabaseOpenView(db, query.c_str(), &view);
MsiViewExecute(view, 0);
MsiViewFetch(view, &record);
MsiRecordGetString(record, i, buffer, &buffsize); //(repeat as many times as necessary, incrementing i)
Of course, as Christopher said, there is A LOT of error checking, memory allocation and handle closing in the process. But the general idea is that one.
The number of times you will have to call MsiRecordGetString() will depend on your query. I used this one
SELECT Value From Property WHERE Property='ProductVersion'
With this query, I had to call MsiRecordGetString() once, with i = 1
Upvotes: 0
Reputation: 55601
MsiOpenDatabase returns a database handle not an installer handle. MsiGetProperty requires an installer handle because you are getting a property of the running installer.
You need to execute a SQL query on the Property table using the API's to open a view, execute it, fetch the records and get the column data. Be sure to check all return codes, allocate memory correctly and close your handles when you are done.
FWIW all of this is much easier in .NET via Microsoft.Deployment.WindowsInstaller if this is an option for you.
Upvotes: 2
Reputation: 37192
If you look at the docs for MsiGetProperty
it says:
hInstall [in]
Handle to the installation provided to a DLL custom action or obtained through MsiOpenPackage, MsiOpenPackageEx, or MsiOpenProduct.
Your handle doesn't come from one of those three functions - it comes from MsiOpenDatabase
. So even though your handle is valid, it's not valid for the MsiGetProperty
call.
Upvotes: 3