#$Microsoft Installer Help Contents
NOTE: If you see this topic initially instead of the outline content view, make sure that msiauto.cnt is in the same directory as msiauto.hlp the first time you run help.
Objects
Properties
Database Tables
Actions
Installer Components
Released Components
Command Line Options
REGMSI.EXE Tool
MSIALTER.EXE Tool
MSIVAL.EXE Tool
MSIDB.EXE Tool
MSIINFO.EXE Tool
MSITRAN.EXE Tool
MSIMERG.EXE Tool
Automating C++ method
Help File Syntax

Obsolete tools

MSIDBVAL.EXE Tool
MSITABLE.EXE Tool
#Under Construction
	Automation Overview	Msi Objects	Database Tables
No help is available for this topic yet.
#Obsolete Method or Property
	Automation Overview	Msi Objects	Database Tables
This method or property has been replaced. It is retained temporarily until code and tests are updated.
#$KWhat Is The Microsoft Installer?
The  Microsoft Installer is an all new installation technology designed from the ground up using COM and relational database principles; targeting the Windows 95, Windows NT, and PowerMac platforms (32-bit only).  Utilizing relational database principles frees the Microsoft Installer from the myriad parsers previously required to interpret an Acme STF, making the code smaller and faster.  In addition, databases are easily merged.  Components can be added to an existing installation and be supported as if they were authored here at Microsoft.
Reduced Overhead
The Microsoft Installer's components are shared system components.  In the near term Microsoft Installer components will still need to be shipped, but they may not be installed.  Even if installed, there is only ever one copy as opposed to the per product copies of Acme which tend to litter a user's computer over time.  Eventually, Darwin components should make their way into the operating system, freeing product groups from having to ship them at all.
Regarding speed, the Microsoft Installer uses pre-defined queries.  Two substantial advantages result from this design: processing is file based rather than in memory and no parsing is required.  Acme uses an in memory model, meaning an entire STF is read into memory for processing.  Therefore, the memory footprint is proportional to the complexity of a product's installation.  The Microsoft Installer, on the other hand, loads into memory only those database tables required for the task at hand. So the memory footprint is greatly reduced.  Rather than the multitude of parsers Acme supports for all its different actions, the Microsoft Installer uses pre-defined queries and fetching.  Very little overhead and faster processing are the result.
Perceived performance is also improved by performing background searching and costing. While a user navigates through the interface, the Microsoft Installer is searching for previously installed products, compliant products (i.e., CCP), etc.  Also in the background the Microsoft Installer is adjusting initial costing estimates, accounting for files being replaced to improve disk space calculations.  Performing these tasks in the background alleviates the need to make users explicitly wait.
Easier Authoring
A multitude of schemes exist throughout Microsoft to facilitate Acme authoring.  These were born out of the inherent complexities of the Acme STF as well as the pronounced lack of formal support.  The Microsoft Installer addresses these by providing an integrated authoring environment, code named Scopes.  Scopes is a separate yet parallel effort with a similar time frame as the installer.  Two of the major goals for Scopes are to provide a clear migration path from Acme and to support buttom up authoring.  A semi-interactive conversion utility between Acme's *.STF and the Microsoft Installer's *.MSI is provided.  Because of the radically different paradigms used by these two products, the process does not achieve 100 percent conversion.  But all of the content of an *.STF (i.e., files, registry entries, shortcuts, etc.) gets converted as well as some of the logic.  In bottom up authoring, a component such as Graph can be authored and tested independently.  Once completed, the Graph component can be imported into a larger authoring effort such as Excel.  Additional authoring is required to wire up the dependencies between Graph and other components, but the logic for installing Graph does not change.
Upgrading
In order to reduce the pain associated with upgrading, the Microsoft Installer provides support for moving files and folders as well as reading and propagating registry settings.  REcognizing that locations of product components change over time, the Microsoft Installer facilitates keeping up.  User settings files (e.g., *.ACL, *.FAV) and template folder hierarchies are two examples.  Similarly, registry organization changes over time.  Registry based settings made in the past should be preserved when upgrading. For these reasons, the Microsoft Installer provides support for detecting and propagating registry settings to preserve behavior.
Administration
Like the Office business unit, many business units within Microsoft are facing previous versions of their own products as their largest competitor.  Though an envious position to be in, it has its problems.  Maintaining a steady revenue stream in such a situation requires establishing some form of annuity model where customers pay a periodic fee to Microsoft for products and services.  This is particularly true for corporate sales; whether small, medium, or large corporations. The Microsoft Installer addresses this new market landscape by providing a host of administration features like an integrated Network Installation Wizard for creating network installations, an Installation Script Wizard for creating one or more department specific scripts to be run from a network installation, the ability to add corporate specific templates to an existing network installation and have them managed like intrinsic components, silent installations, tight integration with SMS, and more.
Wizard User Interface
Though authorable, the default user interface is a wizard.  Users may go back and forth through a consistent set of dialogs any number of times, making changes along the way or viewing what the Microsoft Installer has chosen.  Not until the "Install Now" button is clicked are a user's choices cast in stone.  Special emphasis has been placed on providing both novice and advanced paths through the user interface.  For novice users, the novice path is easier than Acme while advanced users have more flexibility when taking the advanced path.
Pre-Installation
OEM pre-installation of Microsoft products is an over growing business and one which Acme does not address very well.  Coincidentally, many corporations have a centralized purchasing and deployment center which employs similar techniques as OEMs to get new machiens pre-configured and tested before rolling out to end users.  Both of these scenarios are addressed by the Microsoft Installer's build int pre-installation support.  This support creates an image directly, without having to take before and after snapshots of a reference machine to derive file and registry differences.
Intra(er)net
The Internet offers a pervasive low cost infrastructure for distributing product updates as well as content.  The Microsoft Installer, because of its database underpinnings, allows for the modification of existing components or the addition of new components without distruption.  Once modified or introduced, these components behave as if they were authored and shipped with theoriginal product.  This capability dramatically simplifies and reduces the cost of letter releases.  Plus, a new vehicle is created for disseminating product content not mainstream enough to make the CD content bar.
Distribution via the Internet can be accomplished with the Microsoft Installer using a general concept known as launchers.  Launchers are executables responsible for bootstrapping Microsoft Installer compnents.  One way to package up an Internet installation is to stuff into the resource section of a launcher a table file containing authored installation logic, a cabinet file, and properties to set conditions.  The Microsoft Installer then runs directly out of the launcher's resource section.  IN this way, a single file can be downloaded from the Internet then an installation can be invoked.
OLE Automation
For the ultimate in flexibility, the Microsoft Installer provides an OLE automation wrapper for all of its COM interfaces.  While quite useful inside Microsoft for testing purposes, the automation layer also offers corporations with advanced IS departments a framework around which they cna build even more sophisticated deployment schemes than the Microsoft Installer will ever consider.
#$KSupported Platforms
The Microsoft Installer is a core code application.  This is accomplished by centralizing all platform specific code in the Services component where low level file and operating system functionality resides.  Above that layer in the Services component, the rest of the Microsoft Installer's code is platform independent.  Using this approach, the platforms support by the Microsoft Installer include the following 32-bit only platforms:

Windows 95
Windows 98
Windows NT 4.0	(x86, Alpha)
Windows NT 5.0	(x86, Alpha)
#$KLocalization
None of the Microsoft Installer's components contain any resources requiring localization. The user interface is authored as part of a Microsoft Installer installation database, so visible text resides in the database.  Error strings also reside in the installation database.  In addition to abstracting out all strings form within the Installer's components, the Microsoft Installer is also DBCS enabled. As the Microsoft Installer loads it checks the operating system to see if DBCS is turned on.  If it is then it loads code to handle double byte characters as part of its string object.  However, if a user's system is not DBCS enabled then the Microsoft Installer does not incur the performance penalty of loading double byte character handling code.
#$KMicrosoft Installer Components
Microsoft Installer has been developed as a set of shared components:  Automation, Engine, Handler, Services. These components are DLLs that expose COM objects.  These objects are accessible from a simple bootstrapper executable known as a Launcher, from C++ programs, or from VBA applications using the OLE automation facility. All of the functionality within the Microsoft Installer is exposed as a rich set of objects exposing only abstract COM interfaces. These interfaces are operating system independent; operating system dependencies are encapsulated within the implementation.
#$KActive Installation Manager Installer
For cases where the Installer is not delivered with the operating system, it is supplied as a separate self-installing executable that unregisters old components and installs and registers new Installer components. The location of this installer package is specified by the INSTALLER property in the launcher, and may be a URL. If the installer package is a relative path, it will be copied during an admin install.
#$KLauncher (INSTALL.EXE)
Because the Installer components all live in shared DLLs, an executable module is required to load the rest of the components. The basic launcher is very small, containing only enough code to handle any startup errors occurring before the components are initialized. In addition, its resources can be configured to set any number of initial property values, most importantly the names of the  component libraries and the installation database to use. Also configurable is the icon to use and the name of the launcher so that multiple specific use launchers can be created.  For instance, the distribution media might contain a launcher with an installation type icon and a name like "Install".  However, on a user's machine after installation, a launcher may be created with a modification type icon and a name like "Change Installation". Or in a corporate world an administrator might create a launcher named "Install Finance Templates" containing properties to install only a set of internally developed financial templates.
The launcher is responsible for loading the various Installer COM components. It loads each DLL, calls the public entry point to obtain a class factory for the desired object, the calls the entry point to create an instance. The also reads property values from its resources parses the command line for additional property settings. Command line data can consist of either option flags followed by a data value if appropriate or property names with associated values, separated by an equals sign. This module is not used when an installation is controlled by OLE Automation (VBA). The automation wrapper DLL is used to load components instead.
#$KAutomation (MSIAUTO.DLL)
Each of the objects exposed by the various Microsoft Installer components is exposed to OLE automation by using a shadow object which contains the COM  object pointer and dispatches calls through that pointer. The automation translation code is contained in a separate DLL to permit the use of highly shared code, and because this capability is not required for most shipping products. The main uses for the automation include testing and custom install controllers employed by many corporate customers. The automation code for each function has been kept as small as possible, mostly specifying the arguments to pass and testing for error returns.
#$KEngine (MSIENG.DLL)
The Engine object controls the installation process, relying on the Services object to perform all of the operating system functions. It opens the installation database containing the installation logic and data as well as passes error handling on to the Handler object. The Engine object is associated with a standard set of Actions, each of which performs a particular operation on data from one or more action specific table. Additional Custom Actions may be added for particular product installations requiring functionality not provided natively. The basic Engine functionality is that of a sequencer which is driven by  data authored into a designated "sequence" table (such as  InstallSequence) in the installation database. In addition, the Engine manages the source and destination directory layout, the product selection tree, and cost calculations.
#$KHandler (MSIHND.DLL)
The Handler module is a replaceable component which processes all interactions with users or a controlling applications. The interface provides two functions, one of which handles messages of several kinds: warnings, errors,  and progress notifications. The other function is a request to perform a particular action. The action is normally used to invoke a particular dialog or wizard sequence, but can also be implemented as code functionality. The standard implementation utilizes its own database tables to store the structure and sequencing of all the dialogs. However, an alternate implementation of the Handler module could operate completely silently or even remotely.
#$KServices (MSISRV.DLL)
The Services component provides wrappers for several operating system functions as well as higher level functionality appropriate to the installation process. Some services are implemented as objects, as they have a lifetime beyond a single method call, while others are simple function calls. Examples of some of the services include:

1. String handling - Common string handling objects to avoid the use of buffers and to minimize string copying.
2. Record management - Generalized mechanism for passing sets of values, used for database access and error handling.
3. Property management - Centralized global install property table management.
4. Volumes - Management of the characteristics of the various drive types, including floppy, hard, CD-ROM, and network servers.
5. File paths - Performs all file and folder operations used by install, provides path parsing, concatenation, and validation.
6. File copy - Copies compressed and uncompressed files, handles resource copying on Mac.
7. Registry - Handles all registry and INI file operations, including key cleanup on uninstall.
8. Program groups and shortcuts - Creating linkes on the Start menu or anywhere else in a user's file system.
9. Hardware and OS detection - Setting the appropriate property values that can be tested elsewhere.
#$K+Shipped Components
The following components are shipped with each product installed using the Microsoft Installer. Microsoft Installer components are included in this list because in a majority of the scenarios, they need to be shipped even if they are not installed or used.  Major releases of a product must contain Microsoft Installer components because you cannot assume a user has them already.  However, for letter upgrades, patches, Web content releases, etc. you can assume user's have these components.  Consequently, they need not be shipped.

INSTALL.EXE  Launcher that loads the Installer's components.
MSIENG.DLL    Installer engine responsible for sequencing actions in the Action table.
MSIHND.DLL    UI handler which constructs dialogs and processes errors.
MSISRV.DLL    Operating system and database services available to the rest of the Installer.
<app>.MSI      A product specific installation database containing install logic and data.
<app>.CAB      One or more cabinet files containing compressed files to be installed.
#$K+Released Components
The following components are delivered with each retail build of the Microsoft Installer. Because the Microsoft Installer is a cross platform application, separate sets of components are produced for each platform.

ERROR.IDT        Table of parameterized Microsoft Installer error messages.
INSTALL.EXE    Launcher that loads the Installer's components.
MSIALTER.EXE  Tool to load or display properties and resources into(in) a launcher.
MSI.ODL            Type library used for VBA object browsing .
MSIAUTO.CNT    WinHelp contents file used to organize information about the Microsoft Installer.
MSIAUTO.DLL    OLE automation layer and loader for use with VBA.
MSIAUTO.HLP    WinHelp file containing on-line help information for the Microsoft Installer.
MSIENG.DLL      Installer engine responsible for sequencing actions in the Action table.
MSIHND.DLL      UI handler which constructs dialogs and processes errors.
MSISRV.DLL      Operating system and database services available to the rest of the Installer.
MSIDB.EXE  Tool to import from and export to a text based archive format for tables.
REGMSI.EXE    Tool to self-register and unregister installer components as OLE objects.
MSIVAL.EXE  Tool to validate an authored database.
TESTDB.MDB      Test database containing the basic tables and examples of data.

In addition, debug builds of the Microsoft Installer deliver the following additional components:

 INSTALLD.EXE   Launcher stub with properties set to use debug components
 MSIAUTOD.DLL,MSIAUTOD.PDB,MSIAUTOD.BSC,MSIAUTOD.MAP Automation, debug components
 MSIENGD.DLL, MSIENGD.PDB, MSIENGD.BSC, MSIENGD.MAP  Engine, debug components
 MSIHNDD.DLL, MSIHNDD.PDB, MSIHNDD.BSC, MSIHNDD.MAP  Handler, debug components
 MSISRVD.DLL, MSISRVD.PDB, MSISRVD.BSC, MSISRVD.MAP  Services, debug components
 REGMSID.EXE   debug build for registration tools, works identically to REGMSI.EXE
#$KCommand Line Options
Command line options may be specified when invoking a Windows launcher executable. The command line is parsed by the launcher with corresponding property values being passed on to the Services module, along with any properties stored in the resource section of the launcher itself.  The general format is to specify property =value pairs using an equals sign between the case insensitive property name and value. Property pairs are separated by white space on the command line.  If a value contains embedded white space it must be enclosed in double quotes.  Only properties whose names consist of all upper case characters can be entered on the command line.
Help for command line parameters is available by using a question mark as the command line artument, (e.g., install ?). A selected list of property names and descriptions are displayed. If two successive question marks are provided as a property, the default values for properties predefined in the launcher are displayed. Both property values and their descriptions are programmed either by the build process or by using the MSIALTER.EXE tool.
For backward compatibility with Acme, forward slash or minus sign followed by a letter continues to be supported by the Microsoft Installer (e.g., install /?).  The letters are case-insensitive and must be immediately preceeded by either a forward slash or minus sign. Some of the options set a particular value for a property while others require the value to follow the option letter. Backwards compatibile options are shown below, along with their resultant property assignments.

  /A            ACTION = Admin
  /G logfile    LOGFILE = logfile
  /I rootdrive  ROOTDRIVE = rootdrive
  /K cdkey      !!?? CDKEY = cdkey
  /M logmode    LOGMODE = logmode
  /N username   USERNAME = username
  /O orgname    COMPANYNAME = orgname
  /P pidstring  PRODUCTID = pidstring
  /R            ACTION = Reinstall
  /S sourcedir  SOURCEDIR = sourcedir
  /T database   DATABASE = database 
  /U            ACTION = Uninstall

Remarks
Command line options are not available on the Mac. In their place will be an alternate mechanism for the user to specify property settings such as a preference file.
#$KMicrosoft Installer Automation Interface
Access to C++ Libraries
An MsiAuto object must be initially created in order to load the automation support that is required in order to access the Microsoft Installer components through OLE automation. This object provides wrappers to create the top level objects and access their methods. These wrapper simply provide argument translations to expose the C++ methods in manner consitent with BASIC without changing the behavior of the methods. When possible, a pair of Get and Set C++ methods will be exposed to BASIC as a single property. Multiple C++ methods that simply handle different data types will be exposed as a single method. Where appropriate, C++ methods taking an index argument will be exposed as an indexed property. Many C++ methods return the result through an argument, as the return value is used for the error return; however in BASIC errors are handled by a separate mechanism, and the result is always passed in the return value.
#$K+MSIDB.EXE Tool To Modify A Database
The MSIDB.EXE tool uses the MSI database external API to import and export database tables as well as merge databases and apply transforms to databases.  It is essentially a UI and/or command line processing layer on MsiDatabase.Import and .Export.  If all required parameters (mode, folder, database and and table list) are specified on the command line, the tool will not bring up any UI and will operate as silent command line-driven utility, suitable for a build script. The -m and -t and create modes can only be used in silent command line mode.  Up to 10 transforms or merge databases can be specified. If the folder containing the text archive files is not specified it will be prompted for; likewise the database will  be prompted for if not specified. Create new database (both .msi and .mdb), Import archives to database and Export tables to archives.  Tables can be exported from a read only database (only in interactive mode).
Command Line Syntax
MsiDb {option}...{option}... {table}...{table}
The following case-insensitive command line options are supported (slash delimiter may also be used).
 -i    Import text archive files from folder into specified database
 -e    Export selected tables into text archive files in specified folder
 -c    Creates a new database file (overwrites existing) and imports tables
 -f    Specifies the folder containing the text archive files for tables and streams
 -d    Fully-qualified path to the database
 -m    Fully-qualified path to the database to merge in
 -t    Fully-qualified path to the transform to apply
 -?    Displays command line help dialog
Table names for import are file names. Standard wild card specifications may be used.
Table names for export are table names. Only the wildcard specification, "*", may be used.
Archive Table Naming
The table name is truncated to 8 characters and the extension ".idt" added.
Tables names supplied by command for import are likewise converted.
The name used for database table creation is maintained in the .idt file.
Binary data streams are stored as separate files with extension ".ibd".
Binary filename used is primary key data for the row containing the stream.
Database Naming Syntax
Microsoft Installer database:  {databasepath(*.msi)}
Access database:    {databasepath(*.mdb)}[@{owner}][#{password}]
SQLServer database: \\{server}\{database}[@{owner}][#{password}]
ODBC data source:   {ODBCdatasource name}[@{owner}][#{password}]
       {owner} defaults to the current network username
       {password} defaults to none

Note:  When using long filenames with spaces, use quotes around them.  For example, for a database that is in the 'My Documents' folder, specify it as "c:documents".
#$K+MSITABLE.EXE Tool To Modify A Database

!!! OBSOLETE !!! 

The MSITABLE.EXE tool uses the MSI database engine to import and export database tables as well as merge databases.  It is essentially a UI and/or command line processing layer on MsiDatabase.Import and .Export.  This tool uses OLE to create an instance of the MsiServices component. If all required parameters (mode, folder, database and and table list) are specified on the command line, the tool will not bring up any UI and will operate as silent command line-driven utility, suitable for a build script. It will also operate as a silent command line-driven utility if the -m mode and database are specified for merging.  No UI is available for merging.  If the folder containing the text archive files is not specified it will be prompted for; likewise the database will  be prompted for if not specified. There are three modes in which to tool can operate: Create new database, Import archives to database and Export tables to archives.  The Create and Merge  options are not available when in interactive mode.  One can use multiple merge options (up to 10).
Command Line Syntax
MsiTable {option}...{option}... {table}...{table}
The following case-insensitive command line options are supported (slash delimiter may also be used).
 -i    Import text archive files from folder into specified database
 -e    Export selected tables into text archive files in specified folder
 -c    Creates a new database file (overwrites existing) and imports tables
 -f    Specifies the folder containing the text archive files for tables and streams
 -d    Fully-qualified path to the database
 -m    Fully-qualified path to the database to merge in
 -?    Displays command line help dialog
Table names for import are file names. Standard wild card specifications may be used.
Table names for export are table names. Only the wildcard specification, "*", may be used.
Archive Table Naming
The table name is truncated to 8 characters and the extension ".idt" added.
Tables names supplied by command for import are likewise converted.
The name used for database table creation is maintained in the .idt file.
Binary data streams are stored as separate files with extension ".ibd".
Binary filename used is primary key data for the row containing the stream.
Database Naming Syntax
Microsoft Installer database:  {databasepath(*.msi)}
Access database:    {databasepath(*.mdb)}[@{owner}][#{password}]
SQLServer database: \\{server}\{database}[@{owner}][#{password}]
ODBC data source:   {ODBCdatasource name}[@{owner}][#{password}]
       {owner} defaults to the current network username
       {password} defaults to none

#$K+REGMSI.EXE Tool to Self-register Installer Components
The REGMSI.EXE tool simply calls the DllRegisterServer and DllUnregisterServer entry points of the Installer components to cause them to register or unregister themselves as OLE objects. Registration allows them to be called using the OLE call CoCreateInstance, or by using CreateObject from VBA. The tool interprets individual characters on the command line to set execution options. Options are case insensitive and may appear in any order. The default behavior is to register all the components designated below:
 A    Automation module, MsiAuto(D).DLL, ProgId = Msi.Automation(Msi.AutoDebug)
 S    Services module,     MsiSrv(D).DLL,   ProgId = Msi.Services(Msi.ServicesDebug)
 E    Engine module,       MsiEng(D).DLL,  ProgId = Msi.Engine(Msi.EngineDebug)
 H    Handler module,      MsiHnd(D).DLL,  ProgId = Msi.Handler(Msi.HandlerDebug)
 D    Access the debug builds of the components (D suffix), rather than ship.
 B    Access the Lego (BBT) builds of the components (L suffix), not available on Mac.
 U    Unregister modules, otherwise register
 Q    Quiet, no Errors show, returns non-zero status to batch file if failure.
 G    Generate tool module, MsiGen(D).DLL,  ProgId = Msi.Generate
 L    Localaize tool module, MsiLoc(D).DLL,  ProgId = Msi.Localize
 T    Utilities tool module, MsiUtil(D).DLL,  ProgId = Msi.Utilities
 P    Patch tool module,      MsiPat(D).DLL,  ProgId = Msi.Patch    
 C    Acme convert tool module, MsiAcme(D).DLL,  ProgId = Msi.AcmeConvert
 ?    Displays option letters
The REGMSID.EXE tool is simply a debug build of the tool and is no differentin funtionality.
MAC NOTE: This tool cannot use command line arguments on the Mac, and thus only can register the components. A solution to this is being considered for unregistration. On the Mac, only the Automation module self-registers, as the others have no access to the registry, yet.
#$K+MSIALTER.EXE (formerly LOADPROP.EXE) Tool 
The MSIALTER.EXE tool sets, updates, or displays launcher resources.  Also inserts cabinets or transforms into a Database.
Stuffing cabinets or transforms into the database: 
The tool can be used to stuff a cabinet or transform into the database storage.  For cabinets, use the syntax msialter {database} {cabinet file} where {cabinet file} is the full path to the cabinet and {database} is the full path to the database.  The cabinet will be stored as the base name in the database.  For example, if you specify the cabinet file as c:\temp\msproj1.cab, the c:\temp\msproj1.cab file will be opened and its data put into the database storage file as a stream whose name is msproj1.cab.  For transforms, use the syntax msialter -t {database} {transform file} where {transform file} is the full path to the transform file and {database} is the full path to the database.  Note, you don't have to use full paths if the transform or cabinet or database is in the same directory as msialter.exe.  Like the cabinet file, the transform file will be stored under its base name.  The transform is stored as a child storage of the database.  Note, OLE limits the size of streams and child storages allowed in the database.  This could be the cause of the 'Unable to open child storage' error.  Currently, spaces are not allowed in the names of the cabinet stream or transform storage.
Setting or Updating resources: 
The tool can be used to set specific properties like DATABASE, ACTION, MESSSAGEBASE, and COMPANYNAME.  It can also update the ICON resource and insert a DATABASE, TRANSFORMS, and/or CABINET file resource(s) into the launcher.  The input is a text file of property and value pairs with one pair per text line.  Note that the end of line/carriage return is required for a property-value pair to be added. The delimiter between the property and value pair is the equals sign '='.  Only property  names that use no lower case characters can be set; however, the property names in the text file are case-insensitive. The value string in the text file is case sensitive.  File resources are designated by an at sign '@' preceding the name of the file in the value string.  The resource is loaded as a file resource in the launcher and its resource name is the base name [no path or file extension].  For the DATABASE property, an at sign loads the resource as a file resource and sets the DATABASE property to point to that resource using the @{RESOURCE NAME} syntax.  To specifiy languages for a property, use the following format: {Property}(langId)={Value} where langId is the language in decimal form.  All file resources, CABINET, DATABASE, ICON, and TRANSFORMS are always netural and the DATABASE property is always neutral.  All other properties can have multiple languages associated with them.  If no language is specified, it is assumed to be language neutral or zero (0).  To remove an install property from the launcher, simply supply nothing after the delimiter as in the following format: {Property}(langId)=    .  Only one DATABASE property/file resource and one ICON resource is allowed per launcher.  One can only specifiy a DATABASE property once in the property text file. 
Displaying resources: 
The tool can also be used to display the resources in the launcher.  It will display the install property resources as well as the transform, cabinet, database, and icon file resources.  Use of the -f option will dump the file resources into the current directory. The Icon file resource is displayed as ICON=@exe name where exe name is the executable whose resources the tool is displaying.
Command Line Syntax: 
msialter {database} {cabinet file}  -- Stuffs the Cabinet file into the database 
msialter -t {database} {transform file}  -- Stuffs the Transform file into the database. 
msialter -l {launcher} {property file}  -- Loads resources in the property file into the launcher 
msialter {launcher}  -- Displays the resources in the launcher. 
msialter -f {launcher}  -- Displays the resources in the launcher and outputs the file resources to the current directory 

Sample property file: 
COMPANYNAME(1032)=Microsoft 
DATABASE=@testdb.msi 
ICON=@cd.ico 
MESSAGEBASE=32 

Comments on property file: 
COMPANYNAME(1032)=Microsoft sets the COMPANYNAME property to have the value of Microsoft in the Greek language. DATABASE=@testdb.msi loads the testdb.msi database as a file resource in the launcher.  It will be called TESTDB and the DATABASE property will contain the value @TESTDB.  ICON=@cd.ico changes the current icon resource in the launcher to display the cd.ico icon.  MESSAGEBASE=32 sets the MESSAGEBASE property to 32 in language neutral.
NOTE: 
This tool does not run on the current Windows95 release, as the API function UpdateResource is not implemented. It requires WindowsNT.
#$K+MSIINFO.EXE Tool To Modify A Database
The MSIINFO.EXE tool uses the MSI database external API to edit or display the summary information of a database. It is a command line tool.
Command Line Syntax
MsiInfo {database}
Displays the Summary information of the database to the console

MsiInfo {database} {option} {data}.....
Sets the corresponding summary information property

The following case-insensitive command line options are supported (slash delimiter may also be used).
 -I     PID_DICTIONARY
 -C     PID_CODEPAGE
 -T     PID_TITLE
 -J     PID_SUBJECT
 -A     PID_AUTHOR
 -K     PID_KEYWORDS
 -O     PID_COMMENTS
 -P     PID_TEMPLATE
 -L     PID_LASTAUTHOR
 -V     PID_REVNUMBER
 -E     PID_EDITTIME
 -S     PID_LASTPRINTED
 -R     PID_CREATE_DTM
 -Q     PID_LASTSAVE_DTM
 -G     PID_PAGECOUNT
 -W     PID_WORDCOUNT
 -H     PID_CHARCOUNT
        PID_THUMBNAIL     !! NOT SUPPORTED !!
 -N     PID_APPNAME
 -U     PID_SECURITY

The data following the option is optional. If there is no data following the option, then the property is removed. The database must not be a readOnly database.  The same properties can be specified again on the command line, but only 20 switches can be used.  If the data for a particular option contains a space, encapsulate it in quotes, such as /T "MY TITLE".  The quotation marks notify the command line parser to ignore the space.  For the file time  properties, those being PID_EDITTIME, PID_LASTPRINTED, PID_CREATE_DTM, and PID_LASTSAVE_DTM, use the following format "year/month/day hour:minute:second" which is required to be "yyyy/mm/dd hh:mm:ss" (i.e. "1997/06/20 03:25:59).
#$K+MSIDBVAL.EXE Tool to Validate an Msi Database

!!! OBSOLETE !!!The MSIDBVAL.EXE tool validates a *.msi database.  It utilizes the Validation tool module MsiVal(D).DLL for validation.  For any database to be validated, the tool requires that the _Validation table  ( _Validation table ) exist in that database.  This table contains the values allowed in the columns of all of the tables.  This is a console app and output is output to stdout or a pipe or handle if specified.  If any errors are found in validation, they are output to the screen. A valid database returns a valid database message.
COMMAND LINE SYNTAX: 
msidbval {database} 
#$K+MSIVAL.EXE Tool to Validate an Msi Database
The MsiVal.EXE tool validates a *.msi database.  It utilizes the external API for validation.  For any database to be validated, the tool requires that the _Validation table  ( _Validation table ) exist in that database.  This table contains the values allowed in the columns of all of the tables.  The msival.exe tool also performs the Missing Columns validation in which any column defined in the _Validation table, but not in the Columns catalog of the database is considered an error.  If one wishes to add a new table/column, then one has to add the corresponding entry(ies) to the _Validation table.  If one removes an optional column (no way of regulating this except through the authoring environment), then one has to remove the corresponding entry from the _Validation table.  The _Validation table is not shipped, and is merely used for validation during authoring.  The Missing column validation code is external to the Darwin code.  This is a console app and output is output to stdout or a pipe or handle if specified.  If any errors are found in validation, they are output to the screen. A valid database returns a valid database message.

Required Tables:

Depending on the validation, the following tables are required for the msival.exe tool to work
_Validation: Required when using the external APIs for validation.
_Required: Required for the 'Required' validation.  Not needed if use -OFF option
_InstallSequence: Required for the 'Organizational' InstallSequence validation.  Not needed if use -OFF option
_Sequence: Required for the 'Sequential' InstallSequence validation.  Not needed if use -OFF option

Command Line Syntax: 

msival {database}  --> All validation (missing column, data/foreign key, required, organizational install, sequential install)
msival {database} -OFF  --> Missing column and data/foreign key validation 

How Validated:

Missing Columns:
Use the _Validation table and ensure that every column listed in the _Validation table is also listed in the _Columns catalog of the database. (Normal validation using the API's catches the other way from _Columns to _Validation)
Required:
Use the _Required table and ensure that the values are found in the particular table.  This only makes sure that the primary keys are there, not that the values are valid.  See below for table definition information.
Install Organization:
Use the _InstallValidate table and ensure that the organization of the actions fall in the sections defined in the table.  If an action is not listed in this table, it is assumed to be either a Dialog or a Custom Action and checked to be sure that it is found in either the Dialog or CustomAction tables.
Install Sequence:
Use the _Sequence table and ensure that the actions occur in the correct order.  Some actions have pre and post conditional actions. 

Table Definitions (except _Validation)

_Required
Table (string, primary key, required) -- name of table with said required value
Value (string, primary key, required) -- required value, if multiple primary keys, then it is a delimited list (separator is semi-colon)
KeyCount (short, required) -- number of primary keys in table
Description (string, optional) -- description of required value

_InstallValidate
Action (string, primary key, required) -- name of action (do not list Dialog or CustomActions here!!)
SectionFlag (integer, required) -- flag value of sections, 1 or more of the following:
Search --> Searching actions, from LaunchConditions to RMCCPSearch
Costing --> Costing actions
Selection --> UI actions, CustomActions, etc.
Advertise --> RegisterProduct, PublishProduct, PublishFeatures, PublishComponents actions
Execution --> Script operations, InstallFiles, etc
Other notes:
1.) Divisor between search and costing is CostInitialize
2.) Divisor between costing and selection is CostFinalize
3.) Divisor between selection and advertise is RegisterProduct
4.) Divisor between advertise and execution is InstallValidate
5.) If any advertise or execute action called, then ExecuteFinalize must be called
6.) A call to ExecuteFinalize resets section to search so more actions can occur afterwards

_Sequence
Action (string, primary key, required) -- name of action (do not list Dialog or CustomActions here!!)
Dependent (string, primary key, required) -- action required to come before or after said action
After (boolean, required) -- 0 if action comes before dependent, 1 if action comes after dependent
Optional (boolean, required) -- (ignored for 'Before') 0 if action is not optional, 1 if optional
Other notes:
1.) Temporary column is created for marking 'dependent' action of actions

2.) As action is encountered in InstallSequence table, its sequence number if filled in for every row of the _Sequence table where the 'Dependent' action value equals the current action (thus marking the temp column)

3.) Two special queries are done for the _Sequence table (one for 'Before' and one for 'After' actions)

4.) The result sets of the fetches are important, as the idea is to not have a result set for valid (explained below)

a.) Action Is To Go After A Required Dependent Action And Marking Column Is  Zero --> ERROR
Explanation: A preceding action is required before this one, but it hasn't been found, so this is an error

b.) Action Is To Go After A Required Dependent Action And Marking Column Is Not Zero --> CORRECT
Explanation: A preceding action is required before this one, and it has been found, so this is valid

c.) Action Is To Go After An Optional Dependent Action And Marking Column Is Zero --> CORRECT
Explanation: This action doesn't have to be listed, but if it were to be found (some point after us, it would be caught as if the _Sequence table is authored correctly, the Dependent Action would have us listed as coming Before them so we would be caught in that pass)

d.) Action Is To Go After An Optional Dependent Action And Marking Column Is Not Zero --> CORRECT
Explanation: This action must come after an optional dependent action which happens to be listed before us, so this is valid

Optional/Required Attrib is ignored for Before conditions

e.) Action Is To Go Before Optional/Required Dependent Action And Marking Column Is Zero --> CORRECT
Explanation: Action is supposed to come before the dependent action and the dependent action hasn't been seen yet, so this is valid

f.) Action Is To Go Before Optional/Required Dependent Action And Marking Column Is Not Zero --> ERROR
Explanation: Action is supposed to come before the dependent action, but the dependent action has already been found, so this is invalid

Extensibility of Validation
Validation is very extensible, as it is dependent upon tables, so changing the _Validation, _Required, _InstallValidate, and _Sequence tables will change validation.

#$K+MSITRAN.EXE Tool to Generate, Apply, or View a Transform file
The MSITRAN(d).EXE tool can generate or apply a transform file  and can be used to view the transform file.  It utilizes the external API.  
COMMAND LINE SYNTAX: 
msitran(d) -g {base db} {ref db} {transform file name} [{error conditions}] --> Generate a Transform file 
msitran(d) -v {transform} {base db} --> View a Transform file
msitran(d) -a {transform} {database} [{error conditions}] --> Apply a Transform

Error Conditions:
The following errors may be suppressed when applying a transform. To suppress an error, include the appropriate character in the {error conditions} argument. Conditions specified with -g are placed in the summary information of the transform, but are not used when applying a transform with -a.

'a': Add existing row.
'b': Delete non-existing row.
'c': Add existing table.
'd': Delete non-existing table.
'e': Modify existing row.

#$K+MSIMERG.EXE Tool to Merge a database into another
The MSIMERG(d).EXE tool can a database into another.  If MergeConflicts are reported, information is placed in the _MergeErrors table.  Note, the _MergeErrors table may not always be created depending on the error that occured (an error not related to the actual merge of the data).  It utilizes the external API.  
COMMAND LINE SYNTAX: 
msimerg(d) {base db} {ref db}

*#$K+Steps to Exposing a C++ Method to Automation
The following describes the series of operations that must be performed in order to expose a C++ method to OLE Automation and Object browers, including help topics, for use with VBA applications.
For each C++ class that is exposed to OLE automation, a shadow class is defined which is derived from the common base class CAutoBase, and which simply holds a pointer to the C++ object. A member function is defined for each property or method exposed. All such functions take argument stack object, which abstracts the complicated Variant arguments and return values. All functions have a void return, as they throw exceptions on any error.
C++ functions that get and set values are usually exposed as properties, with the "Get" and "Set" part of the names removed. If both a Get and a Set are present, they will likely be exposed as a single property. Since all data is passed as Variant unions, multiple functions that vary only in data types can sometimes be combined into a single function. Also note that properties can accept arguments, such that access to data from a particular field can be exposed as an indexed property. These index arguments may be of any data type.
Automation Wrapper
Add function to wrapper class definition:
  void MyFunc(CAutoArgs& args);
Add implementation function that processes the arguments and return values:
 void CAutoFoo::MyFunc(CAutoArgs& args)
  {
     args = m_riFoo.MyFunc(args[1], args[2]);
  }
Dispatch Table Entry
Add an entry to the dispatch table, supplying function and argument names, separated only by a comma. The convention is that both are mixed case, but the method or property names start with upper case, and the argument names start with lower case. Each entry in the dispatch table must be assigned a unique dispatch Id, normally starting with the number 1. The value 0 denotes the default property, which is called if the object itself is used in the context of a value, i.e. assignment or function argument. Properties use aafPropRW or aafPropRO instead of aafMethod.
 10, aafMethod, CAutoFoo::MyFunc, "MyFunc,arg1,arg2", 

ODL Specification
To expose the method in the type library, the prototype of the exposed method or property must be defined in ODL syntax, along with the help info:
  [id(10),helpcontext(MsiFoo_MyFunc),helpstring("What MyFunc does.")]
     Boolean MyFunc([in] long arg1, [in] BSTR arg2);
Help Context ID
In the file "msiauto.hh", the help context Id must be defined. This file is used to compile the ODL file to the type library and to generate the help file. To insure uniqueness of the Ids, the low two digits are the same as the dispatch Id, and the upper digits are the decimal equivalent of the low byte of the GUID defined for the class.
  #define MsiFoo_MyFunc  1510
Help Topic
Generate a new topic, including the necessary header information. It is best to copy an existing topic or the sample topic, and modify it as required.*
  *{\footnote VBA}            <-Build tab, must be first
  #{\footnote MsiFoo_MyFunc}  <-Topic Id
  ${\footnote MsiFoo.MyFunc}  <-Topic Title, diplayed in Find
  +{\footnote MsiFoo:MyFunc}  <-Browse Sequence Id
  K{\footnote MyFunc;Internet}<-List of keywords, separated by ';'
  \pard\f0\cf1\sb90           <-Restore paragraph and text styles
  {\li-150\fi150\brdrb\fs24\b <-Set special format for heading
  MyFunc Method               <-Heading text, larger font size, bold
  \line\tx360\tab\fs18\b0{\uldb MsiFoo Object}{\v MsiFoo_Object} 
  \tx3000\tab{\uldb Msi Objects}{\v Msi_Objects} <-Hot links
  \tx5000\tab{\uldb Database Tables}{\v Database_Tables} 
  \par}\li180                 <-End of heading, set normal indent
  Tell what MyFunc does here. 
  \par\li0{\b Syntax}\par\li500\fi-320 <-Hanging indend
  {\i object}{\b .MyFunc({\i arg1, arg2})} 
  \par{\i object}\line 
  Required. The MsiFoo object. 
  \par{\i\b arg1}\line 
  Required. Description of a required argument. 
  \par{\i\b arg2}\line 
  Optional. Description of an optional argument. 
  \par\fi0\li0{\b Remarks}\par\li180 <-No indent, bold title, normal indent
  Additional notes as required.... 
  \page                       <-End of topic
Help References
Incorporate links to the new topic inside other relevent topics. In particular, include the new topic under the appropriate Methods or Properties section within the topic for the class itself.
 {\uldb DoAction}{\v MsiEngine_DoAction\line
Help Contents Entry
In the help contents file, "msiauto.cnt" for the VBA help file, the new topic must be inserted in the proper place in the topic hierarchy. The single digit at the start of each line is the tree level. Spaces are inserted only for clarity when editing this file. The first symbol is what is shown in the contents view.  Following the equal sign is the help topic Id.
  3 MyFunc=MsiFoo_MyFunc 
*#$K+Help Source File Syntax
This topic describes the syntax and tokens used to develop help topics for Microsoft Installer. For a complete reference, use the VC++ help file HCW.HLP.
General RTF notes
The RTF format used in help files is a subset of that used by word processors. Some of the tokens have been usurped to have different meanings. Tokens always begin with a backslash and must be followed with a space (ignored), another backslash, or a brace character. Enclosing tokens within braces restricts their effect to the text enclosed within the braces. The entire RTF souce file must also be enclosed in a set of braces (take care not to delete the ending brace.)
Line breaks are ignored in RTF files, but spaces are displayed except for the space immediately following an RTF token. Avoid accidently use of tab characters. When wrapping text, the space between words must be included. The convention here to avoid errors is to indent each wrapped line by a single space.
Text format tokens
These tokens change the following text style, independent of paragraph formatting. The change ends when the value is restored, either by explicitly restoring the previous value or preferably by enclosing the token with the affected text in braces. Avoid using "\plain" as this will reset the font size set in the file header.
  \b      Starts bold text, ends at \b0 or closing }.
  \i      Starts italic text, ends at \i0 or closing }.
  \f1     Starts font number 1 (fixed-pitch here), ends at \f0 or closing }.
  \fs16   Starts font size 8 (half the value), ends at next \fs or closing }.
Paragraph format tokens
These tokens affect line indentation and spacing, and will be reset either by the \pard token, or by the ending brace if the token is enclosed in braces.
  \tab     Inserts a tab character, moves to the next tab stop
  \line    Forced line feed within a paragraph
  \par     Start a new paragraph
  \li300   Specified the line indent from left margin in twips (1440 inch)
  \fi-100  Specified the first line indent relative to the line indent
  \sb90    Specifies the extra space before paragraph in twips
  \tx500   Specifies the location of a single tab stop in twips
Topic header tokens
These tokens must placed at the start of each topic. Each topic must be terminated with a \page token. If build tags are specified, the topic will only be included based on the  BUILD expression in the help project file (.HPJ). Topics may be group into a browse sequence, enabling the next and previous buttons, by specifiying browse identifiers with identical text before the colon. The build tag and keyword tokens may be repeated as necessary.
  *{\footnote VBA}             Optional build tag, must be first tokens
  #{\footnote MsiFoo_MyFunc}   Required Topic Id, used by links and contents
  ${\footnote MsiFoo.MyFunc}   Topic Title, diplayed in Find and History
  +{\footnote MsiFoo:MyFunc}   Optional Browse Sequence Id, group and sequence
  K{\footnote MyFunc;Internet} Optional list of keywords, separated by ';'
Hot links
These paired tokens create hot spots, displayed as green underlined text.
  {\uldb Hot Spot Text}{\v Help_Topic}   Jumps to another topic
  {\ul Hot Spot Text}{\v Help_Topic}     Creates a popup window
File header tokens
These tokens are required to appear at the start of each RTF file. In addition, the default font size for the file is set to 10 points with the token: \fs20.
  \rtf1            Identifies the file as RTF, must be first.
  \ansi            Identifies the character set
  {\fonttbl{\f0\fswiss Arial;}{\f1\fmodern Courier New;}} Font table
  {\colortbl;}     Color table, only color 0, black, is used here.
*#$K+Tracking Down Memory Leaks
Memory errors come in two flavors.  Rarely seen, but possible is a list of memory blocks not freed when the services DLL goes away. More common is an assert the CMsiMalloc was not released and then a list of memory blocks not freed. The first case happens when everyone releases CMsiMalloc correctly. The second happens when someone holds on to CMsiMalloc without releasing it and we assert when the destructor for the object is called when the DLL is being removed by the system. Both give a stack backtrace of when the memory was allocated, hopefully with function names. They should also print out the type of object and which allocation it was made on. In order to get the stack backtrace to give function names, you need some DLLs in your system or system32 directory to allow Darwin to interpret the PDB files.
On Win95 and NT you need imagehlp.dll and mspdb50.dll in your system32 directory.
If you think you have this set-up and it's not working, see DavidMck.
The memory management code also allows you to increase the size of the stack back trace if you need more data kept to make it easier to debug. There is a #define at the beginning of imemory.cpp for cFuncTrace. It is currently set to 4 by default. You can adjust it as needed.
The output of the asserts should go to the log file if the log is open and set on the command line. Otherwise the output of all asserts goes to the file c:.log.
Generally memory leaks are either a simple case of not freeing something that was allocated, or a more complex issue of a reference counting problem. We have integrated code to help track down reference counting issues. See Reference Tracking for more information on those features.
*#$K+Hooking up the Debug memory manager
The debug memory manager is hooked up for the main darwin DLLs. There are two cases where you will need to hook it up your self to either make debugging easier or get your new object to work.
The debug memory manager overloads the new and delete operators. In order to work, a global piMalloc needs to be set (since we have globally defined the new and delete overloaded functions). These functions are in imsimem.h. In order to set piMalloc you need to call SetAllocator with a pointer to a services object. The allocator will be retrieved from the services object. We also keep a count for the DLL of how many objects have called SetAllocator. This is needed since some DLLs contain multiple objects that do not hold references to each other. When your object that called SetAllocator is being deleted, you will want to call ReleaseAllocator. The object that calls SetAllocator, however, cannot be allocated with the overloaded new and delete operators since piMalloc will probably not be set correctly. In order to handle this we have functions AllocSpc and FreeSpc which should be included as public member functions of your class as follows.
	static void *operator new(size_t cb) { return AllocSpc(cb); }
	static void operator delete(void * pv) { FreeSpc(pv); }
If you include imsimem.h in all the source files of your DLL, and appropriately hook up SetAllocator, ReleaseAllocator, AllocSpc and FreeSpc, you should have the Darwin memory management installed. I would urge that we have this done in all our DLLs in order to track down memory issues.
*#$K+Tracking Down Reference Counting Problems
The services DLL (and in the future other Darwin DLLs) has a reference counting harness built in to it to aid in tracking down problems with AddRefs and Releases. Currently it is only useful in tracking down problems where objects are not released correctly. I plan to add code to handle the case where an object is released too many times.
The code hooks in to the AddRef and Release calls and uses the CMsiRef ref object which encompases the m_iRefCnt as well as pointers to keep a link list of objects and a list of reference counting actions and the stack track of each action.
Due to the overhead imposed by keeping the tracking data this functionality is turned on for individual classes. The environment variable TRACK_OBJECTS should be set to a comma separated list of darwin iids which you wish to have tracked (you just need to use the low byte of the iid so to track services set TRACK_OBJECTS=B).
A static object that is an object of the CMsiRefHead class checks for objects not deleted in its destructor. At that point it will assert with a list of actions and the stack track for those actions. This info is also placed in the debug log (since usually the normal log has been closed by this point in the process). Using this information it is usually quite simple to look at the log and pair up AddRef and Release calls until you end up with one or more AddRefs that shouldn't have happened. Looking through the code you can then uncover the problem.
As with the memory manager you can increase the size of the stack backtrace that is recorded if you need more information. In imsidbg.h the defined value cFuncStack defaults to 3 currently and can be adjusted as necessary.
*#$K+Coding Conventions and Code Review Guidelines
General Coding Conventions
Tabs
* Every 3 columns, i.e. 1,4,7..., but only before the first non-white space character on the line.
* Use tabs rather than spaces to indent lines, no tabs between any text on a line.
* Avoid trailing white space on a line (expecially important for help .RTF files).
* Avoid lines greater than 80 characters when possible (hard to diff and print).
* When wrapping lines with multiple arguments, indent (with tabs) to line up the args if possible.
* A utility exists, FIXTAB.EXE (from OTOOLS), to indicate or correct tab problems.

Braces
* Opening and closing braces line up with each other and with the enclosing scope.
* Code within braces indented one tab stop.
* Braces may optionally be omitted for single line clauses following if, else, for, etc.
* Lines with switch case values are lined up with the switch braces, code lines are indented.

Variable naming
Global Variables
Use the "g_" prefix followed by the Hungarian name. Ex: int g_cInstances

Member Data Variables
Use the "m_" prefix followed by the Hungarian name. Ex: int m_iRefCnt

COM Object Methods
Use mixed-case non-Hungarian (OLE Standard); args use Hungarian prefixes.
Ex: int GetPropertyLen(const ICHAR* szProperty)

Methods that return enumerators should be named GetItemEnumerator. 
Ex: IEnumMsiString* GetSubFolderEnumerator()

COM Pointers And References
Use the "pi" (pointer to interface) and "ri" (reference to interface) prefixes followed by the variable name, followed by the object type.  Do not include the type of instance pointer in the hungarian prefix.For the standard Darwin objects, preferred naming convention examples are:

IMsiString*:   piComponentString (not pistrComponent)
IMsiRecord&:   riErrRecord (riErrRec is also common in Darwin code, and is ok)
IMsiCursor*:   piFeatureCursor
IMsiTable*:    piFeatureTable
IMsiDatabase&: riDatabase
IMsiEngine&:   riEngine
IMsiPath&:     riSourcePath

MsiString
Use the "str" prefix followed by the variable name. After the prefix follow the sameconvention as for COM pointers. Ex: MsiString strUserName.

Wrapper COM Pointers (PMsi...)
Use the "p" prefix, followed by the same convention as for "COM Pointers and References". Ex: PMsiRecord pErrorRecord(0); 

Usage of char[], ICHAR[], IMsiString, and MsiString types
IMsiString is Darwin's string interface. It provides reference-counted string handling. An MsiString is a wrapper object around an IMsiString interface. The MsiString class simplifies string handling by automating the reference-counting.
Avoid the use of the char data type except where 8-bit bytes are used. Use ICHAR to refer to text characters; this define is current char but eventually will be changed to wchar_t (16-bit) when we convert Darwin to Unicode. Avoid the direct use of strlen, strcpy, strcat (run-time library functions). Use the string functions defined in ISTRING.H: IStrLen, IStrCopy, etc. These are wrappers for system APIs that are DBCS enabled. These will change to Unicode someday. For non-trivial string handling, use the IMsiString and MsiString objects.

Type
Avoid the use of Windows-defined macros, such as WORD, whenever possible; use the inherent C type instead. The exception is local variables used directly as in/out parameters to Windows API. For boolean values, use the Darwin Bool enum, to allow type checking and automation conversion. Avoid #defines whenever possible; use "const int" or other const values instead. This allows full type checking without generating additional code. Use the int type when size doesn't matter, since that is processed most efficiently.

Header Files
 Only put defines in header files that are required by more than one source file. Otherwise, dependencies may inadvertently be created by exposing internal structures. Define derived implementation classes at the start of the .CPP file when possible. Headers local to a module are put in the same directory as the .CPP files Put detailed method comments in the help file, put the help file source name in the header Put comments in the header file describing classes defined and include and define requirements.

Function calls
All calls to functions other than a member function of the current object, or a static member of another class,  should be qualified with one of the dummy specifiers below to indicate the API that is being used. Unspecified global functions can use just a "::" prefix, such as ::operator new.

Currently the following API dummy specifiers are defined (all defined to nothing):
WIN::  - Win32 API call, fails on Mac
MAC::  - Mac API call, fails on Win32
OLE::  - OLE API call, fails on modules not using OLE
AUT::  - Local automation DLL functions
SRV::  - Local services DLL function
LOC::  - Functions local to a file

Procedure headers
All procedures should be well documented, with all input and return parameters described.  If the procedure is an interface function of any object exposed through an IMsi* COM interface, the documentation for that function should reside in the MSIAUTO help file (not in the source code).  In this case, the function header should be formatted like this example:
 
IMsiRecord* CMsiEngine::GetFeatureCost(IMsiString& ristrFeature, int& iCost)
//----------------------------------------------
{
...
}

If the procedure is a local function (whether global, or a protected or private member of a class), then the documentation should appear in the function header, as in this example:

ifiEnum CMsiPath::GetFileVersion(const ICHAR* szFullPath, int& riMS, int& riLS )
/*----------------------------------------------------------------------------
Gets the file version values from the given file and sets the given riMS & 
riLS variables.

Arguments:
	szFullPath: a zero terminated character string containing the fully
		qualified path (including disk drive) to the file.
	riMS: Most significant 32 bits of source file version stamp.
	riLS: Least significant 32 bits of source file version stamp.
Returns:
	ifiNoError-       Version retrieved successfully 
	ifiNoFile-        Specified file does not exist
	ifiNoFileInfo-    Specified file has no version
	ifiFileInfoError- An error occurred while trying to retrieve the version
------------------------------------------------------------------------------*/
{
...
}

General Code Review Checklist
Here are a few of the important issues, and potential problems, to look for when reviewing code:

* Are all input values and return values well-defined?

* Are all return states well-defined and correct?

* Are potential errors returned by function calls always being handled properly?

* Are there any "magic numbers" that should be made into well-defined constants?

* Are there any useful assertions (or other debugging code) missing?

* Are comments correct and concise?

* Any code that is commented or #IFDEF'ed out should either be taken out, or well commented as to why the code isn't being used.

* Are any header files included that are unnecessary?

* Is there code here that duplicates code found elsewhere in the project?

* Are there any local variables which are used only once, where a constant value might be better?

* Are there any unnecessary globals?

* Are there any other performance problems?

Specific problems to watch for
* Is the value returned by the GetLastError() system call being interpreted properly?  Remember that the error code returned by GetLastError() gets reset on every system call (successful or not), so a better name for it would be GetLastStatus().

#$K+Using the Debug memory manager
The debug memory manager has several flags you can set to change how it works.
Setting the environment variable DEBUGMEM or calling the SetDebugFlags method on an allocator from VB allows you to set several flags.
1	Does not actually free memory.  Places it in a linked list for comparing with future free requests. Useful for tracking down doubly freeing memory.
2	Logs all allocations to the debug log file.
4	Checks the status of all memory blocks when a block is allocated
8	Checks the status of all memory blocks when a block is freed.
16	Only initializes the symbol information when it's needed. This is useful when tracking down a memory leak when the EXE terminates and frees memory. There are currently problems with the symbol information being freed when this happens.
#$K+Building the databases
The makefile currently builds five databases during the debug build process: testdb.msi, template.msi, schema.msi, testcab.msi, and repack.msi and then validates all five (validation won't catch everything though).
Source directories for the databases
 testdb.msi     %DARWIN%\data\testdb 
 template.msi   %DARWIN%\data\template 
 schema.msi     %DARWIN%\data\schema 
 testcab.msi    %DARWIN%\data\testdb.cab 
 repack.msi     %DARWIN%\src\tools\repack\support 

Build order
first   schema.msi 
second  template.msi 
third   testdb.msi 
fourth  testcab.msi 
fifth   repack.msi 

What's in the databases
schema.msi    contains defined _Validation table, all other table schemas (no row data)
template.msi  basic UI, install sequences and actions 
testdb.msi    UITEST, sample install 
testcab.msi   sample install 
repack.msi    repackager template database, some extra tables (i.e. SourceDirectory)

How built
schema.msi    create new, import from schema source
template.msi  create new, import from template source, merge in schema.msi 
testdb.msi    create new, import from testdb source, merge in template.msi 
testcab.msi   create new, import from testcab source, merge in template.msi, add msproj1.cab
repack.msi    create new, import from repack source, merge in template.msi 

Making changes

Table schema changes
	When adding, removing, or modifying columns or tables, always change the .idt file in the schema source.  If the table also exists in one of the other four source directories, be sure to change it there as well (or merge problems or worse could arrise). Always remember to make the change to the Validation table as well.  You will also have to modify the _Validation table in %DARWIN%\data\testdb.cab\validate as it is another copy of the _Validation table which was required since the cabinets were generated before the decision to enforce the primary key as token rule.

Bumping the Database version
	When the database version is bumped up, edit the _Summary.idt tables in all five source directories.  Merging does not deal with the Summary Information stream.

 Changing the _Validation table
 	When changing the entries in the _Validation table, be sure to change it in schema source and in  the _Validation table in %DARWIN%\data\testdb.cab\validate.  If you add a new table particular to  only one database (and not any others), update or add the _Validation table and the entries required  for the new table or column.  During merging, the database will import those new entries and  receive the rest from the merging of the other database (which will bring schema.msi's _Validation  table).

Other
	Make sure all of the databases pass validation and that the '_MergeErrors' table is not created as it means that merge conflicts occured and those conflicts should be investigated.
#$K+MSISPY: A Tool to Display Component-Level View of System

MSISPY provides a component level view of the products and features installed on a system, using either a Darwin database, or the registry information. Msispy also displays the status of each, and allows you to partially or completely re-install missing or damaged items. You  can also re-configure any product or feature, selecting the install level, and specifying whether to install it locally or run it from a network server. 

Menu Options

 Under the File Menu,
	Open Any Database allows you to open an MSI package.
	Open Local Database uses the registry information to display information about all the
	  products installed on the computer.
	Load Saved Profile allows you to load a profile of the system previously saved by Msispy.
	Restore Profile (enabled only when a profile is loaded) attempts to restore the system
	  to the saved profile. If more components have been added since the profile was saved, they
	  are left untouched. If some products or components have been damaged since the profile was
	  saved, msispy attempts to restore them by attempting to re-install them from the original
	  source. If the source is not available, you are given the option to abort, retry or ignore.
	Save Current Profile allows you to save a complete profile of the system onto a file. The
	  information is stored in an easy to read text format. This information should not be modified
	  directly.

 Under the View Menu,
	Refresh refreshes the display by getting the displayed information again and redrawing it.

 Under the Options Menu, 
	Diagnostic Mode allows you to run msispy in either of the two modes- normal and diagnostic.
	  In the Normal mode, a component's status is determined by the status of its key-file.
	  In the Diagnostic mode, each file of the component is checked and the component status
	  displayed is determined using this information. This gives a more accurate picture of the
	  system, but make the program much slower.

Context Menus

When a product, feature or component is selected, clicking on the right mouse-button brings up the  context menus that allow you to perform operations on the selected item.

All context menus have a Properties option, that brings up a property sheet containing information about the selected item. In addition to the General tab that contains the information, the property sheets also contain a File List tab, that contains information about all the files needed by the selected item. The list of files contains information about the file including the component that uses it, the file name and size when it was installed, the location of the file. In this tab, the Verify Files button allows you to check the current status of the files. This button brings up a window with the current file information, including current size, creation, last access and modification dates. If the file is not found, or if the file size is different, the file is marked broken with an icon to the its left.

Important: If a profile is in use, the verify files brings up information about the files when the profile was saved, not the current file information.

Additional context-menu choices cary depending on the item selected. When the selected item is a

Component: The menu comprises 
	Re-install Component (enabled only if the component is broken), which allows you to re-install
	  the component from it's original install source.

Installed Feature or Product: The menu comprises 
	Re-install, which allows you to use one of the available re-install modes, including
	  options to re-install just the damaged or missing files. Other options allow you to force all 
	  the files to be re-installed, the registry entries to be verified, and so on.
	Configure, which allows you to install the feature on your local machine, or run it
	  from a remote source. Some features may have components that need to be installed on the local
	  machine. Attempting to install such features to run from a remote location will lead to a mix
	  of some components being on the local system and the rest at the remote location.
	Un-install, which allows you to un-install the product or feature. If a feature with
	  sub-features is un-installed, all of its sub-features will be un-installed as well.

Uninstalled Product or Feature: If an MSI package for a product not installed on the local system 
	  is in use, the context menu has the following options:
	Install Product, which will install the product on the local system using the default options
	Advertise Product, which will advertise the product on to the local system. This will 
	  set all the registry entries needed for the product, but will not actually install any files 
	  on the local system. The files will be transferred in when the component they belong to is used.

Product or Feature in a Profile: The menu always comprises:
	Restore Profile, which has the same functionality as Restore Saved Profile described above.

Command Line Syntax: 
msispy