NAME
Win32::MSI::DB - 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
MSI::DB::new($filename, $mode)
returns a new database object, open in one of the following modes:
- $Win32::MSI::MSIDBOPEN_READONLY
-
This doesn't really open the file read-only, but changes will not be written to disk.
- $Win32::MSI::MSIDBOPEN_TRANSACT
-
Open in transactional mode so that changes are written only on commit. 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.
A database object allows creation of table
s or view
s. 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 successively 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 doesn't open the file 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.
Fetch records from a table or view
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. Records are fetched as needed. Using undef
as parameter fetches all records and returns the first (index 0).
Another possibility is to use the records
method, which returns an array of all records in this table or view.
A record has fields
A record's 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);
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? In particular, 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).
A big thank you goes to DBH for various changes throughout the code.
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