MAKEMSI quickly and reliably creates MSI files in a non-programmatic way
Have your say! Join the MAKEMSI discussion list or view archive! Suggest improvements. No question too simple or too complex.
[Bottom][Contents][Prev]: UISAMPLE.MSI[Next]: Invoking MSI Update Via Batch File
Have your say! Join the MAKEMSI discussion list or view archive! Suggest improvements. No question too simple or too complex.
\->MAKEMSI Installs...->Available Frameworks->OPENMSI.MMH - Making changes to existing databases

OPENMSI.MMH - Making changes to existing databases

This section deals mainly with making changes to existing Windows Installer databases. The same process could be used to build a complete Windows Installer database from scratch but this is basically covered under the section "Preferred MSI Interface for Building a Complete MSI" as you would wish to create some sort of "wrapper" to take care of common requirements such as what do you begin with (a "template" MSI etc) and common requirements such as setting package GUIDs.

As an alternative to this "OPENMSI.MMH" approach you could use a batch file running multiple "WiRunSql.VBS" commands. The main advantage of this is that it will be much quicker, the downsides include that errors are difficult to test for, its harder to create the correct commands and its not as easy to understand. The "MsiDiff.VBS" tool can generate the correct MAKEMSI code for you.

To use the "OpenMsi.MMH" header simply include it rather than "MAKEMSI.MMH".

These are the main "basic" macros you would likely wish to use (as they basically supply most of what "ORCA" does):

  1. MSI and /MSI
  2. Row and /Row
  3. RowsDelete
  4. RowsDeleteAll
  5. Table and /Table
  6. TableCreate
  7. TableDefinition and /TableDefinition
  8. TableExportToIdt
  9. TableImportFromIdt
  10. Property

EXAMPLE - Basic ("OPENMSI.MMH")

;--- Include MAKEMSI Support ------------------------------------------------
#include "OpenMsi.MMH"

;--- Do the work ------------------------------------------------------------
<$Msi "out\TestMsi.mm\Msi\After.msi" template="out\TestMsi.mm\Msi\Before.msi">
   ;--- A simple change to an existing MSI ----------------------------------
   <$Property "ABCDEFG" VALUE="C:\">
<$/Msi>

Of course there is no reason most of the many higher level commands can't be used if you wish although some of these may need a bit more care (mostly checking prerequisites and defaults), for example this code can be used to add files:

;--- Include MAKEMSI Support ------------------------------------------------
#include "OpenMsi.MMH"

;--- Do the work ------------------------------------------------------------
<$Msi "out\TestMsi.mm\Msi\After.msi" template="out\TestMsi.mm\Msi\Before.msi">
   <$Cabinet "Added Files">
       ;<$Feature "ALL.3.080.0101.TESTMSI"                CREATE="N">
           <$Component "c1.ALL.3.080.0101..INSTALLDIR_x"  CREATE="N">
                <$Files "TryMe.*">
           <$/Component>
       ;<$/Feature>
   <$/Cabinet>
<$/Msi>

The above is just one possibility (as to how you may need to do that depending on the source msi and your requirements), here are some notes:

  1. Some other examples showing "OPENMSI.MMH" in use:

  2. If you are unsure how as to how to code "row" commands (whether or not you are providing an SQL where clause) you can use the "MsiDiff.VBS" command to create them for you. Simply create a backup of your database and make the changes with "ORCA". It is then a simple matter of using the "Compare -> MAKEMSI Format" shortcut to compare the "before" and "after" databases and generate the appropriate commands for you to paste in.

  3. I used the "Cabinet" command as it was probably the simplest way to be 100% sure I wouldn't be creating ".cab" files with the same name as any existing ones! You need to be careful that whatever you do doesn't clobber something in the original msi!

  4. I didn't need the "Feature" command as I wasn't creating a new component.

  5. I used the "Component" command to reuse the existing component and define the files installation directory.

  6. Note that no MSI Filtering is performed, so if the original msi or your changes create messages that require filtering you should use the "MsiValFilter" command.

  7. You may have noticed that the feature and component names in this example contain the version number (making it more problematic than demonstrated). If you have control over this I'd stop that from occuring in the source msi otherwise use an alternative approach (creating your own feature and components is probably the simplest choice).

EXAMPLE - WRAP IT - Perhaps a Smarter Way...

The previous example directly included the "OPENMSI.MMH" header file, while this is OK you probably also wish to do other "standard" things when you change and MSI (or you may wish to in the future). An example of this is any "standard" (for you) "MsiValFilter" commands mentioned above.

Its a good idea if you create your own header file (even if it doesn't do much more than include "OpenMSI.MMH"), that way you can add to your wrapper header at any time and the changes will be included in any future updates you do without the need to retrofit anything.

The most obvious thing you may wish to do when updating an MSI is to to update the author information. You can make any application of "standards" optional to handle any instances where you may not be able to apply the updates. You may also wish to require the user (probably you!) to specifically refer to macros you create in this header, whatever you do have a think about how you like to work and how you can maximise your flexibility.

The following is one example of such a header file (called "MyMsiUpdate.MMH").

;--- Include the standard MAKEMSI "update" header ---------------------------
#include "OpenMsi.MMH"

;--- Start the Update process -----------------------------------------------
<$Msi "<$UPDATE_TO>" template="<$UPDATE_FROM>">

;--- Schedule the update termination after all your changes -----------------
#OnExit #100 <$ExecutedAfterAllUserUpdates>
#(
    #define ExecutedAfterAllUserUpdates

    ;--- Record Details about who is making the change ----------------------
    <$Summary "LastAuthor" VALUE="<$MAKEMSI_USERNAME>">
    <$Summary "EDITTIME"   VALUE="now()">

    ;--- Now finish off the "MSI" nesting -----------------------------------
    <$/Msi>
#)

As you hopefully noticed, the header requires the "includer" to define some standard definitions which contains the "before" and "after" database information and also removes the need for the "MSI" and "/MSI" commands in the including code.

The following shows the changes to the original sample to include the header:

;--- Include My MAKEMSI Update Support --------------------------------------
#define  UPDATE_FROM         out\TestMsi.mm\Msi\Before.msi
#define  UPDATE_TO           out\TestMsi.mm\Msi\After.msi
#include "MyMsiUpdate.MMH"   ;;Include header and do "standard" things

;--- A simple change to an existing MSI ----------------------------------
<$Property "ABCDEFG" VALUE="C:\">

Note that the "before" and "after" macros could be passed on the invoking command line (with the PPWIZARD "/Define" switch) or via environment variables (see the "Invoking MSI Update Via Batch File" section for an example of this).


Microsoft awarded me an MVP (Most Valuable Professional award) in 2004, 2005, 2006, 2007, 2008 & 2009 for the Windows SDK (Windows Installer) area.Please email me any feedback, additional information or corrections.
See this page online (look for updates)

[Top][Contents][Prev]: UISAMPLE.MSI[Next]: Invoking MSI Update Via Batch File


MAKEMSI© is (C)opyright Dennis Bareis 2003-2008 (All rights reserved).
Saturday May 28 2022 at 3:11pm
Visit MAKEMSI's Home Page
Microsoft awarded me an MVP (Most Valuable Professional award) in 2004, 2005, 2006, 2007, 2008 & 2009 for the Windows SDK (Windows Installer) area.