NAME
Win32::MSI::DB - a Perl package to modify MSI databases
SYNOPSIS
use Win32::MSI::DB;
$database=Win32::MSI::DB::new('filename', $flags);
$database->transform('filename', $flags);
$table=$database->table("table");
$view=$database->view("SELECT * FROM File
WHERE FileSize < ?",100000);
@rec=$table->records();
$rec4=$table->record(4);
$rec->set("field","value"); # string
$rec->set("field",4); # int
$rec->set("field","file"); # streams
$rec->get("field");
$rec->getintofile("field","file");
$field=$rec->field("field");
$field->set(2);
$data=$field->get();
$field->fromfile("autoexec.bat");
$field->intofile("tmp.aa");
$db->error();
$view->error();
$rec->error();
DESCRIPTION
Obtaining a database object
This is currently done by using MSI::DB::new
. It takes filename as first parameter and one of the following constants as optional second.
- $Win32::MSI::MSIDBOPEN_READONLY
-
This opens the file not read-only, but changes will not be written to disk.
- $Win32::MSI::MSIDBOPEN_TRANSACT
-
This allows transactional functionality, ie. changes are written on commit only. This is the default.
- $Win32::MSI::MSIDBOPEN_DIRECT
-
Opens read/write without transactional behaviour.
- $Win32::MSI::MSIDBOPEN_CREATE
-
This creates a new database in transactional mode.
This database object allows creation of table
or view
s, depending on your needs. If you simply need access to a table you can use the table
method; for a subset of records or even a SQL-query you can use the view
method.
Using transforms
When you have got a handle to a database, you can successivly apply transforms to it. You do this by using transform
, which needs the filename of the transform file (normally with extension .mst) and optionally a flag specification.
Most of the possible flag values specify which merge errors are to be suppressed.
- $Win32::MSI::MSITR_IGNORE_ADDEXISTINGROW
-
Ignores adding a row that already exists.
- $Win32::MSI::MSITR_IGNORE_ADDEXISTINGTABLE
-
Ignores adding a table that already exists.
- $Win32::MSI::MSITR_IGNORE_DELMISSINGROW
-
Ignores deleting a row that doesn't exist.
- $Win32::MSI::MSITR_IGNORE_DELMISSINGTABLE
-
Ignores deleting a table that doesn't exist.
- $Win32::MSI::MSITR_IGNORE_UPDATEMISSINGROW
-
Ignores updating a row that doesn't exist.
- $Win32::MSI::MSITR_IGNORE_CHANGECODEPAGE
-
Ignores that the code pages in the MSI database and the transform file do not match and neither has a neutral code page.
- $Win32::MSI::MSITR_IGNORE_ALL
-
This flag combines all of the above mentioned flags. This is the default.
- $Win32::MSI::MSITR_VIEWTRANSFORM
-
This flag should not be used together with the other flags. It specifies that instead of merging the data a table named
_TransformView
is created in memory, which has the columnsTable
,Column
,Row
,Data
andCurrent
.This way the data in a transform file can be directly queried.
For more information please see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/_transformview_table.asp.
This opens the file not read-only, but changes will not be written to disk.
A transform is a specification of changed values. So you get a MSI database from your favorite vendor, make a transform to <overlay> your own settings (the target installation directory, the features to be installed, etc.) and upon installation you can use these settings via a commandline similar to
msiexec /i TRANSFORMS=F<your transform file> F<the msi database> /qb
The changes in a transform are stored by a (table, row, cell, old value, new value) tuple.
From a table or view to records
When you have obtained a table
or view
object, you can use the record
method to access individual records. It takes a number as parameter. Here the records are fetched as needed; using undef
as parameter fetches all records and returns the first (index 0).
Another possibility is to use the method records
, which returns an array of all records in this table or view.
A record has fields
And this fields can be queried or changed using the record
object, as in
$rec->set("field","value"); # string
$rec->set("field",4); # int
$rec->set("field","file"); # streams
$rec->get("field");
$rec->getintofile("field","file");
or you can have separate field
objects:
$field=$rec->field("field");
$data=$field->get();
$field->set(2);
Remark: the access to files (streams) is currently not finished.
Errors
Each object may access an error
method, which gives a string or an array (depending on context) containing the error information.
Help wanted: Is there a way to get a error string from the number which does not depend on the current MSI database?
Especially the developer-errors (2000 and above) are not listed.
REMARKS
This module depends on Win32::API
, which is used to import the functions out of the msi.dll.
Currently the Exporter
is not used - patches are welcome.
AUTHOR
Please contact pmarek@cpan.org
for questions, suggestions, and patches (diff -wu2
please).
Further plans
A Win32::MSI::Tools
package is planned - which will allow to compare databases and give a diff, and similar tools.
I have started to write a simple Tk visualization.
SEE ALSO
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/installer_database_reference.asp