Environment: VC++ 6.0, Windows XP
Introduction
I needed to read data from an .msi file, and after reading a nice article in the form of a PDF file, I created a simple console application. It takes two command-line arguments. The first is a full path to the .msi file, and the second one is the table name. I prefered doing a console application because it will be useful to all, even those who have MFC or Windows knowledge.
Background
Last week, I installed InstallShield for Windows Installer 1.5 on my system and somehow I learned to create an .msi setup file. I needed it because we planned to port the tool on which I am working to a higher version of InstallShield. I searched for help, but finally helped myself learn how to create .msi files with InstallShield. I won’t say I mastered InstallShield, but I can say I know a little bit about it.
Fine, but the tool on which I have actually been working needs the details of an .msi file to create MOF files, so I was trying to read the .msi database. (.msi is a setup file implemented as a database by Microsoft; it is run by Windows Installer as a service that runs in Windows 2000 and Windows XP.)
Using the Code
The first location I referred to is the MSDN. It explains the functions we have to manipulate an .msi database. But, my attempt, with the MSDN’s help, to read an .msi databse didn’t work. So, I searched on the Net and I got a nice PDF file regarding the subject: http://www.wise.com/filelib/MSIwhitepaper.pdf.
Please read the article for a full description of “how to” use it.
I used the code help from this article only. The flow goes like this. First, we have to start with MsiOpenDatabase(..), which gives a MSIHANDLE after successfully opening the .msi database. Then, I called MsiDatabaseOpenView(hDatabase,szSelect,&hView), where “hDatabase” is the handle gotten from MsiOpenDatabase(). “szSelect” is a normal SQL query, and “hView” is the MSIHANDLE returned by this function on success. This function, when called, creates a view with the given query. To get the actual records, we have to call MsiViewExecute(), which gives the perfection to the view. (Practically, this means this function executes the query and stores the result in the view.)
The remaining part of the code is parsing the data and printing to the screen. I once again repeat that the PDF I read is the source for my application. I thank “Gary Chirhart” for writing such a nice article on Installer. My application takes two command-line arguments (other than the application name):
- .msi file path: Remember to give the path with “\” separation, such as D:\Share\VMTNet.msi”.
- A table name existing in the .msi database. There are so many tables, but I prefer to give “File” as the second parameter. This table contains all the details about the embedded files in the .msi database.
For better understanding of the database structure, one can use the “ORCA” tool.
Points of Interest
The interesting thing I learned is that we don’t actually need any third-party tools such as InstallShield or Wise Installer to create .msi setup files. We can do everything. The only thing the third-party vendors are doing is making things simple. That way, we can concentrate on developing our software so that we need not worry as much about creating installers for our software.