Friday, April 17, 2009

Test String for alphanumeric characters

Hello Friends, i had used a very useful installscript function for testing a string for alphanumeric characters. The function will accept the string to be tested as a parameter.
You can use the below code and can edit according to your need.

prototype IsAlphanumeric (string);

function IsAlphanumeric (szStuff)
     /* Check if a string is alphanumeric
         In: szStuff -- string to test
         Out: Returns TRUE or FALSE
     */
      #define ALPHANUMERIC_CHARS "abcdefghijklmnopqrstuvwxyz_0123456789"
     // For my purposes, underscore is considered alphanumeric.
     number nPos;
     string szChar;
begin
     for nPos = 0 to StrLength (szStuff)
          StrSub (szChar, szStuff, nPos - 1, 1);
          if !(ALPHANUMERIC_CHARS % szChar) then
              return FALSE;
         endif;
    endfor;
    return TRUE;
end;

Wednesday, April 15, 2009

Creating custom file browse dialog


Hi, here I have to share you an interesting post for including a file browse dialog into our Installscript project. 
Here we use a Windows API GetOpenFileNameA for the purpose. 
We will use two files named brwsdlg.h and Brwsdlg.rul. Follow these simple steps as explained below:
  1. Open the Installation Designer view.
  2. Under Behavior and Logic, select InstallScript.
  3. Right-click on your setup.rul file and select New Script File.
  4. Name it as brwsdlg.h. Similarly create brwsdlg.rul file.
  5. Paste the below code in brwsdlg.h script .
    // Avoid multiple include collisions.
    #ifndef _BRWSDLG_H_
    #define _BRWSDLG_H_

    // Options for Flags member of OPENFILENAME.
    #define OFN_READONLY 0x00000001
    #define OFN_OVERWRITEPROMPT 0x00000002
    #define OFN_HIDEREADONLY 0x00000004
    #define OFN_NOCHANGEDIR 0x00000008
    #define OFN_SHOWHELP 0x00000010
    #define OFN_ENABLEHOOK 0x00000020
    #define OFN_ENABLETEMPLATE 0x00000040
    #define OFN_ENABLETEMPLATEHANDLE 0x00000080
    #define OFN_NOVALIDATE 0x00000100
    #define OFN_ALLOWMULTISELECT 0x00000200
    #define OFN_EXTENSIONDIFFERENT 0x00000400
    #define OFN_PATHMUSTEXIST 0x00000800
    #define OFN_FILEMUSTEXIST 0x00001000
    #define OFN_CREATEPROMPT 0x00002000
    #define OFN_SHAREAWARE 0x00004000
    #define OFN_NOREADONLYRETURN 0x00008000
    #define OFN_NOTESTFILECREATE 0x00010000
    #define OFN_NONETWORKBUTTON 0x00020000
    #define OFN_NOLONGNAMES 0x00040000
    #define OFN_EXPLORER 0x00080000
    #define OFN_NODEREFERENCELINKS 0x00100000
    #define OFN_LONGNAMES 0x00200000

    // CommDlgExtendedError-related defines.
    #define CDERR_DIALOGFAILURE 0xFFFF
    #define CDERR_DIALOGFAILURE_MSG "The file browse dialog box could not be created."
    // The dialog box could not be created. The common dialog box function
    // call to the DialogBox function failed. For example, this error occurs
    // if the common dialog box call specifies an invalid window handle."
    #define CDERR_FINDRESFAILURE 0x0006
    #define CDERR_FINDRESFAILURE_MSG "The file browse dialog box function failed to find a specified resource."
    // The common dialog box function failed to find a specified resource.
    #define CDERR_INITIALIZATION 0x0002
    #define CDERR_INITIALIZATION_MSG "The file browse dialog box function failed during initialization."
    // The common dialog box function failed during initialization. This error
    // often occurs when sufficient memory is not available.
    #define CDERR_LOADRESFAILURE 0x0007
    #define CDERR_LOADRESFAILURE_MSG "The file browse dialog box function failed to load a specified resource."
    // The common dialog box function failed to load a specified resource.
    #define CDERR_LOADSTRFAILURE 0x0005
    #define CDERR_LOADSTRFAILURE_MSG "The file browse dialog box function failed to load a specified string."
    // The common dialog box function failed to load a specified string.
    #define CDERR_LOCKRESFAILURE 0x0008
    #define CDERR_LOCKRESFAILURE_MSG "The file browse dialog box function failed to lock a specified resource."
    // The common dialog box function failed to lock a specified resource.
    #define CDERR_MEMALLOCFAILURE 0x0009
    #define CDERR_MEMALLOCFAILURE_MSG "The common dialog box function was unable to allocate memory for internal structures."
    // The common dialog box function was unable to allocate memory
    // for internal structures.
    #define CDERR_MEMLOCKFAILURE 0x000A
    #define CDERR_MEMLOCKFAILURE_MSG "The common dialog box function was unable to lock the memory associated with a handle."
    // The common dialog box function was unable to lock the memory associated
    // with a handle.
    #define CDERR_NOHINSTANCE 0x0004
    #define CDERR_NOHINSTANCE_MSG "The ENABLETEMPLATE flag was set, but you failed to provide a corresponding instance handle."
    // The ENABLETEMPLATE flag was set in the Flags member of the initialization
    // structure for the corresponding common dialog box, but you failed to provide
    // a corresponding instance handle.
    #define CDERR_NOHOOK 0x000B
    #define CDERR_NOHOOK_MSG "The ENABLEHOOK flag was set, but you failed to provide a pointer to a corresponding hook procedure."
    // The ENABLEHOOK flag was set in the Flags member of the initialization
    // structure for the corresponding common dialog box, but you failed to provide
    // a pointer to a corresponding hook procedure.
    #define CDERR_NOTEMPLATE 0x0003
    #define CDERR_NOTEMPLATE_MSG "The ENABLETEMPLATE flag was set, but you failed to provide a corresponding template."
    // The ENABLETEMPLATE flag was set in the Flags member of the initialization
    // structure for the corresponding common dialog box, but you failed to provide
    // a corresponding template.
    #define CDERR_REGISTERMSGFAIL 0x000C
    #define CDERR_REGISTERMSGFAIL_MSG "The RegisterWindowMessage function returned an error code when it was called by the file browse dialog box function. "
    // The RegisterWindowMessage function returned an error code when it was called
    // by the common dialog box function.
    #define CDERR_STRUCTSIZE 0x0001
    #define CDERR_STRUCTSIZE_MSG "The lStructSize member of the initialization structure for the corresponding file browse dialog box is invalid. "
    // The lStructSize member of the initialization structure for the corresponding
    // common dialog box is invalid.
    #define FNERR_BUFFERTOOSMALL 0x3003
    #define FNERR_BUFFERTOOSMALL_MSG "The buffer pointed to by the lpstrFile member of the OPENFILENAME structure is too small for the filename specified by the user."
    // The buffer pointed to by the lpstrFile member of the OPENFILENAME structure
    // is too small for the filename specified by the user. The first two bytes
    // of the lpstrFile buffer contain an integer value specifying the size, in bytes
    // (ANSI version) or 16-bit characters (Unicode version), required to receive the full name.
    #define FNERR_INVALIDFILENAME 0x3002
    #define FNERR_INVALIDFILENAME_MSG "A filename is invalid."
    // A filename is invalid.
    #define FNERR_SUBCLASSFAILURE 0x3001
    #define FNERR_SUBCLASSFAILURE_MSG "An attempt to subclass a list box failed because sufficient memory was not available."
    // An attempt to subclass a list box failed because sufficient memory was not available.


    // OPENFILENAME structure. Notice that all string members below are declared
    // as LONG. For example, lpstrFilter. Do not use STRING.
    typedef OPENFILENAME
    begin
    LONG lStructSize;
    HWND hwndOwner;
    HWND hInstance;
    POINTER lpstrFilter;
    POINTER lpstrCustomFilter;
    LONG nMaxCustFilter;
    LONG nFilterIndex;
    POINTER lpstrFile;
    LONG nMaxFile;
    POINTER lpstrFileTitle;
    LONG nMaxFileTitle;
    POINTER lpstrInitialDir;
    POINTER lpstrTitle;
    LONG Flags;
    SHORT nFileOffset;
    SHORT nFileExtension;
    POINTER lpstrDefExt;
    POINTER lCustData;
    POINTER lpfnHook;
    POINTER lpTemplateName;
    end;

    // Windows API declares.
    prototype comdlg32.GetOpenFileNameA( LONG );
    prototype comdlg32.CommDlgExtendedError();
    prototype user32.wsprintf(STRING, STRING, POINTER);
    // Our file browse API, defined in matching .rul file.
    prototype FileBrowseDlg( BYREF STRING, NUMBER, STRING, STRING, STRING, BOOL, LIST , BOOL );

    #endif

  6. Paste below code in Brwsdlg.rul file.
    #ifndef _BRWSDLG_RUL_
    #define _BRWSDLG_RUL_

    prototype Kernel32.RtlMoveMemory(BYREF STRING, POINTER, NUMBER);

    typedef STR260
    begin
    STRING sz[260];
    end;

    ///////////////////////////////////////////////////////////////////////////////
    // FileBrowseDlg() uses the Windows GetFileNameA function to allow single file
    // selection. Callers specify filter, dialog title, and initial browse directory.
    //
    // Input:
    //
    // szFile: String variable into which FileBrowseDlg() will place the selected
    // file's fully qualified pathname. The variable passed in as szFile must
    // be explicitly sized (declared as szMyFile[260] for example) and the
    // size must be passed in as the second parameter (nszFileSize).
    // szFile is passed by reference.
    //
    // nszFileSize: The size that szFile was explicitly declared as.
    //
    // szFilter: Filter spec for dialog. In the form "\0\0\0". For example:
    //
    // "Text files (*.txt)\0*.txt\0\0"
    //
    // The description ("Text files (*.txt)" above) must be separated from the
    // extension ("*.txt" above) by a "\0" character. The entire string must
    // end in a double null ("\0\0").
    //
    // szDialogTitle: A string containig the title to display on the file browse dialog.
    //
    // szInitialDir: A string specifying the directory the browse dialog opens to.
    //
    // bMultiSel: Set to TRUE if you wish to enable multiple selection.
    //
    // listFiles: List that will be loaded with directory and filenames if multiple
    // selection is enabled. List is passed by reference (by default,
    // since list variables are pointers).
    //
    // bDerefLinks: Set to TRUE to dereference link files to the file browse. 
    //
    // Return:
    //
    // Returns 0 when a file is successfully selected. Returns less than zero when
    // when the user cancels/closes the browse dialog or an error occurs. If an
    // error occurs, a message box displays the error identifier.
    //
    ///////////////////////////////////////////////////////////////////////////////

    function FileBrowseDlg( szFile, nszFileSize, szFilter, szDialogTitle, szInitialDir, bMultiSel, listFiles, bDerefLinks )
    OPENFILENAME ofn;
    STRING szMsg, szFileTitle[260];
    STRING szCustomFilter[260], szTemp[260];
    LONG nResult, n, nFlags, nErr; 
    STR260 str;
    begin

    UseDLL(WINSYSDIR ^ "comdlg32.dll");

    nFlags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY |
    OFN_NOCHANGEDIR | OFN_EXPLORER;
    if bMultiSel then
    nFlags = nFlags | OFN_ALLOWMULTISELECT;
    endif;
    if bDerefLinks = FALSE then
    nFlags = nFlags | OFN_NODEREFERENCELINKS;
    endif;

    nResult = GetWindowHandle(HWND_INSTALL);

    ofn.lStructSize = SizeOf(ofn);
    ofn.hwndOwner = nResult;
    // Notice how the address of an explicitly sized string
    // is used when assigning to a member who was declared
    // as a LONG string pointer (lpstr). For example, &szFilter.
    ofn.lpstrFilter = &szFilter;
    ofn.nFilterIndex = 1;

    //The string pointed to by lpstrFile is modified by
    //GetOpenFileName. The only way to have a string in
    //script to reflect the change is to point lpstrFile
    //to a structure that just a string member.
    str.sz = szFile;
    ofn.lpstrFile = &str;
    ofn.nMaxFile = SizeOf(str);

    ofn.lpstrFileTitle = &szFileTitle;
    ofn.nMaxFileTitle = 260;
    ofn.lpstrTitle = &szDialogTitle;
    ofn.Flags = nFlags;
    ofn.lpstrDefExt = &szTemp;
    ofn.lpstrInitialDir = &szInitialDir;
    ofn.hInstance = 0;
    ofn.lpstrCustomFilter = &szCustomFilter;
    ofn.nMaxCustFilter = 260;
    ofn.lpfnHook = 0;

    nResult = GetOpenFileNameA(&ofn);
    if nResult = 1 then 
    if bMultiSel then
    //A direct assignment in the form of szFile = str.sz
    //will result in all data beyond the first null to be
    //lost. This only happend when the string is assigned
    //with a structure member. This is the reason why a
    //very indirect method is being used the transfer the
    //contents of str.sz to szFile
    Resize(szFile, SizeOf(str));
    RtlMoveMemory(szFile, &str, SizeOf(str));
    StrGetTokens(listFiles, szFile, "");
    else
    szFile = str.sz;
    endif;
    else
    nErr = CommDlgExtendedError();
    switch (nErr)
    case CDERR_DIALOGFAILURE: szMsg = CDERR_DIALOGFAILURE_MSG;
    case CDERR_FINDRESFAILURE: szMsg = CDERR_FINDRESFAILURE_MSG;
    case CDERR_INITIALIZATION: szMsg = CDERR_INITIALIZATION_MSG;
    case CDERR_LOADRESFAILURE: szMsg = CDERR_LOADRESFAILURE_MSG;
    case CDERR_LOADSTRFAILURE: szMsg = CDERR_LOADSTRFAILURE_MSG;
    case CDERR_LOCKRESFAILURE: szMsg = CDERR_LOCKRESFAILURE_MSG;
    case CDERR_MEMALLOCFAILURE: szMsg = CDERR_MEMALLOCFAILURE_MSG;
    case CDERR_MEMLOCKFAILURE: szMsg = CDERR_MEMLOCKFAILURE_MSG;
    case CDERR_NOHINSTANCE: szMsg = CDERR_NOHINSTANCE_MSG;
    case CDERR_NOHOOK: szMsg = CDERR_NOHOOK_MSG;
    case CDERR_NOTEMPLATE: szMsg = CDERR_NOTEMPLATE_MSG;
    case CDERR_REGISTERMSGFAIL: szMsg = CDERR_REGISTERMSGFAIL_MSG;
    case CDERR_STRUCTSIZE: szMsg = CDERR_STRUCTSIZE_MSG;
    case FNERR_BUFFERTOOSMALL: szMsg = FNERR_BUFFERTOOSMALL_MSG;
    case FNERR_INVALIDFILENAME: szMsg = FNERR_INVALIDFILENAME_MSG;
    case FNERR_SUBCLASSFAILURE: szMsg = FNERR_SUBCLASSFAILURE_MSG;
    endswitch;
    if nErr != 0 then
    // User did not close or cancel dialog box.
    MessageBox("FileBrowseDlg() error:\n\n" + szMsg, SEVERE);
    endif;
    return -1;
    endif;

    UnUseDLL(WINSYSDIR ^ "comdlg32.dll");
    return 0; 
    end;
    #endif


  7. Use below code in your setup.rul file. 
    Click on your setup.rul file to bring up your script in the right hand window and insert the following code to your script, after the #include "ifx.h" statement.

    #include "brwsdlg.h"
    #include "brwsdlg.rul"

    Add the following sample script to call the API to display the file browse dialog.
    function OnBegin()
    // FileBrowseDlg requires the szFile parameter be explicitly sized
    // and that the size be passed as the second parameter.
    STRING szFile[512], svDir, svFileList, svTemp;
    NUMBER nResult, nReturn;
    BOOL bMultiSel, bDerefLinks;
    LIST listFiles;

    begin
    // If I want to support multiple selection, set bMultiSel to TRUE
    // and pass in a valid string list.
    bMultiSel = TRUE;
    bDerefLinks = FALSE;
    listFiles = ListCreate(STRINGLIST);
    // Open the file browse dialog.
    nResult = FileBrowseDlg( szFile, 512, "All files (*.*)\0*.txt\0\0", "Select File", "c:\\", bMultiSel, listFiles, bDerefLinks );
    if nResult = 0 then
    if bMultiSel then
    // If I chose multiple selection, I must parse the info, which is stored
    // in list. First item will be dir, all others are individual filenames.
    nReturn = ListGetFirstString(listFiles, svTemp);
    while nReturn != END_OF_LIST
    svFileList = svFileList + svTemp + "\n";
    nReturn = ListGetNextString(listFiles, svTemp);
    endwhile;
    MessageBox("Directory (first item) and selected files:\n\n" + svFileList, 0);
    else
    // No multiple selection, so a single file/path was set.
    MessageBox("Selected file:\n\n" + szFile, 0);
    endif;
    endif;
    ListDestroy(listFiles);
    end;

    Note: You have to customize this code according to your needs.


Friday, April 3, 2009

Cache location of Windows installer

"C:\windows\Installer"

When we click "Remove" button from ADD/REMOVE panel, then the installer look for the source in this directory.

How can I use a custom action to dynamically populate rows in the table?

Immediate custom actions have full access to the Windows Installer database. All you need to do is use the database API to open a view and execute the view. The rest is the SQL query you create that performs an insert of a temporary row in the database. All of this, the APIs + SQL queries, are documented on MSDN in the Windows Installer documentation. If the table needs to be around in memory so that your changes aren't lost when dropped from view, then add a hold count to it (and release the hold count at the end after the requisite action runs).

* MsiGetActiveDatabase
* MsiDatabaseOpenView
* MsiViewExecute

MsiGetActiveDatabase

The MsiGetActiveDatabase function returns the active database for the installation. This function returns a read-only handle that should be closed using MsiCloseHandle.


MSIHANDLE MsiGetActiveDatabase(
MSIHANDLE hInstall
);

Parameters
hInstall
[in] Handle to the installation provided to a DLL custom action or obtained through MsiOpenPackage, MsiOpenPackageEx, or MsiOpenProduct.
Return Values
If the function succeeds, it returns a read-only handle to the database currently in use by the installer. If the function fails, the function returns zero, 0.

Remarks
The MsiGetActiveDatabase function accesses the database in use by the running the installation.

Note that it is recommended to use variables of type PMSIHANDLE because the installer closes PMSIHANDLE objects as they go out of scope, whereas you must close MSIHANDLE objects by calling MsiCloseHandle.

For example, if you use code like this:


MSIHANDLE hRec = MsiCreateRecord(3);

Change it to:


PMSIHANDLE hRec = MsiCreateRecord(3);

MsiDatabaseOpenView
The MsiDatabaseOpenView function prepares a database query and creates a view object. This function returns a handle that should be closed using MsiCloseHandle.


UINT MsiDatabaseOpenView(
MSIHANDLE hDatabase,
LPCTSTR szQuery,
MSIHANDLE* phView
);

Parameters
hDatabase
[in] Handle to the database to which you want to open a view object. You can get the handle as described in Obtaining a Database Handle.
szQuery
[in] Specifies a SQL query string for querying the database. For correct syntax, see SQL Syntax.
phView
[out] Pointer to a handle for the returned view.
Return Values
The MsiDatabaseOpenView function returns one of the following values:
ERROR_BAD_QUERY_SYNTAX
An invalid SQL query string was passed to the function.
ERROR_INVALID_HANDLE
An invalid or inactive handle was supplied.
ERROR_SUCCESS
The function succeeded, and the handle is to a view object.
Remarks
The MsiDatabaseOpenView function opens a view object for a database. You must open a view object for a database before performing any execution or fetching.

If an error occurs, you can call MsiGetLastErrorRecord for more information.

Note that it is recommended to use variables of type PMSIHANDLE because the installer closes PMSIHANDLE objects as they go out of scope, whereas you must close MSIHANDLE objects by calling MsiCloseHandle.

For example, if you use code like this:


MSIHANDLE hRec = MsiCreateRecord(3);

Change it to:


PMSIHANDLE hRec = MsiCreateRecord(3);

If the function fails, you can obtain extended error information by using MsiGetLastErrorRecord.

MsiViewExecute
The MsiViewExecute function executes a SQL view query and supplies any required parameters. The query uses the question mark token to represent parameters as described in SQL Syntax. The values of these parameters are passed in as the corresponding fields of a parameter record.


UINT MsiViewExecute(
MSIHANDLE hView,
MSIHANDLE hRecord
);

Parameters
hView
[in] Handle to the view upon which to execute the query.
hRecord
[in] Handle to a record that supplies the parameters. This parameter contains values to replace the parameter tokens in the SQL query. It is optional, so hRecord can be zero. For a reference on syntax, see SQL Syntax.
Return Values
ERROR_FUNCTION_FAILED
A view could not be executed.
ERROR_INVALID_HANDLE
An invalid or inactive handle was supplied.
ERROR_SUCCESS
The function succeeded.

Note that in low memory situations, this function can raise a STATUS_NO_MEMORY exception.


Remarks
The MsiViewExecute function must be called before any calls to MsiViewFetch.

If the SQL query specifies values with parameter markers (?), a record must be supplied that contains all of the replacement values in the exact order and of compatible data types. When used with INSERT and UPDATE queries all the parameterized values must precede all nonparameterized values.

For example, these queries are valid.

UPDATE {table-list} SET {column}= ? , {column}= {constant}

INSERT INTO {table} ({column-list}) VALUES (?, {constant-list})

However these queries are invalid.

UPDATE {table-list} SET {column}= {constant}, {column}=?

INSERT INTO {table} ({column-list}) VALUES ({constant-list}, ? )

If the function fails, you can obtain extended error information by using MsiGetLastErrorRecord.

Thursday, April 2, 2009

How do services work?

Start ->Run -> services.msc. will list the services and it will be present in registry under this path
Hklm\system\ControlSet\Services\

How do u hide program name to appear in the control panel (Add/Remove Programs)

By Setting the public property ARPSYSTEMCOMPONENT = 1

What is a Custom Action?

To understand custom actions, you have to also understand sequences. An installation starts with a User Interface sequence where data is collected from the user, but nothing is changed on the target system. It then moves to the Execute sequence where there are no UI elements, but changes are made to the target system through various types of actions. So, what is an action?

Since Windows Installer installations are not controlled by a script (like InstallScript installations), there needed to be a way for developers to control the logic of an installation. This is facilitated by providing a set of standard and custom actions. An action in a Windows Installer installation is like a function in a program.

Now, actions are arranged in sequences, and sequences tell the Windows Installer the order to which actions are to be executed. The Custom Actions and Sequences view shows the sequences in an installation project. Next, we have to understand the types of Windows Installer installations.

There are three types of Windows Installer installations. There is Installation, Advertisement, and Administrative. In an Installation installation, the sequence is executed during a normal installation. In an Advertisement installation, the availability of an application is advertised, but not installed until requested. In an Administrative installation, an uncompressed source image of an application is created on a network. It's similar to the source image on a CD-ROM. Users can then install the product from this source.

The Installation and Administration installations both have User Interface and Execute sequences, but the Advertisement installation only has an execute sequence. But, let's get back to actions.

There are several types of actions. There is the Immediate action, Deferred action, Rollback action, and Commit action. Here are the differences.

An Immediate action is executed immediately and does not odify the target system, because there would be no rollback operations that can undo the changes.

A Deferred action will not be executed immediately when encountered but deferred to the installation script. Typical Deferred actions install files, modify the registry, etc.

A Rollback action is a special type of Deferred action. When the Windows Installer generates is script, it simultaneously generates a rollback script. The rollback script contains operations to be performed when the installation is rolled back. With custom actions, it is the developer's responsibility to provide a method to rollback system changes, since the Windows Installer would know nothing about the custom action.

A Commit action is a type of deferred action which is a complement to a rollback action. Commit actions are only executed at the end of a successful installation. There are placed in the installation script, but not executed until the end.

There is a lot more to all of this, but you have enough information to understand about custom actions. Custom Actions are simply a way to integrate custom code and data into a Windows Installer installation. Because after all, the Windows Installer is not all things to all people. It will probably not provide everything you need to do your installation. So, custom actions are a way to customize the installation for your own needs.

What's nice is that there are many types of custom actions. For example, you can create a custom action that just sets a property. Other types of custom actions are similar to functions, and can be written in VBScript or InstallScript. Also, new to InstallShield 2009 is the ability to write Managed Code Custom Actions. You can now write custom actions in your favorite language, C#, VB.NET, or something else. Very convenient.

Uninstall Information in the Registry

When you are developing and testing installations, you will at times make mistakes, an installation will fail, and the files will be partially installed onto your development machine. As a result, you won’t be able to uninstall your application, because everything is not working properly.

At these times, you can go to the Registry and manually delete the entries. When you do this, it will appear to Windows as if the application is not installed. Then, you will be able to go on with your business. So, where do you delete these entries?

You first need to go to the General Information view, Product Properties, and find the Product GUID property. If you wish, you can copy this GUID to the clipboard (minus the curly braces), then run Regedit, and search for it. But searching takes a while. So, in the registry, you can go to the following place and look for the GUID that matches your installation project.

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall

When you find this node, you can start your search for the Product GUID there. It will take no time at all, and when you find the node, you can just delete it. Then the next time you run your installation, to Windows and to InstallShield, it will appear as a first-time installation of your product.

Of course, after you delete the entry from the registry, you wll still have to manually delete the product files from your hard drive. You have to clean up after yourself.

Uninstalling run-time-created files

In a Basic MSI project, there are three ways to uninstall run-time-created files:

  1. You can create a dummy file that has the same name as the file created at run-time. There doesn't have to be any information in the file. Generally, I just put the words "Dummy File" or "Placeholder" in the file and save it out. Add this file to a component in your installation, rebuild and test. The installer will install the file. When you run the application, it will overwrite the file. Then when you uninstall, the file will be deleted, because InstallShield installed it originally. Personally, I use this method almost exclusively. It works when you have a small number of files to work with.
  2. You can create an InstallScript Custom Action which deletes the file or folder of files. Place a condition on the Custom Action such that it is only run during uninstallation. Then, add it to the User Interface sequence after ExecuteAction. This works. Some may not consider this very elegant, but it does work.
  3. Add the file(s) to the RemoveFile table. This is a little more complicated, so you'll have to consult the InstallShield Help. If you are a Basic MSI or Windows Installer purist, you will probably like this solution the best.

That's it. Three ways to get rid of files created at run-time.

How to install SQL Server 2008 from a Basic MSI Project

SQL Server 2008 Express requires that the .NET Framework 3.5 SP1 and Windows Installer 4.5 be installed prior to it being installed. Windows Installer 4.5 had to be installed first. Windows Installer 4.5 has to be installed before .NET 3.5 SP1, or .NET 3.5 SP1 won't be installed. You won't get any errors if you install .NET 3.5 SP1 first when Windows Installer 4.5 is not already installed on the system. The problem will arise when you try to install SQL Server 2008 Express. It will just fail.

Here is the order of things.

Windows Installer 4.5 for Windows XP SP2 and later (x86)
Windows Installer 4.5 for Windows Server 2003 SP1 and later (x86)
Windows Installer 4.5 for Windows Vista and Server 2008 (x86)
Microsoft .NET Framework 3.5 SP1
Force a reboot of the machine

Microsoft SQL Server 2008 Express RTM (x86)
Main Product Install

You will have to add the prerequisites and then edit their order to get things right. Remember to force a reboot after the install of .NET 3.5 SP1. After Windows reboots, the install of SQL Server 2008 Express will take place, followed by your main product installation.

Wednesday, April 1, 2009

InstallScript vs. Basic MSI

InstallScript projects use the InstallScript language to control the installation. You may want to choose InstallScript and exploit the following features:

  • The InstallScript language is easy to learn.
  • In this project type, you can display full-screen billboards (background images).
  • This project type makes use of the InstallScript language, which allows you to write a procedural installation rather than author a set of tables.
  • The InstallScript installation type is easier to learn than the Basic MSI installation type. Actually, the learning curve for InstallScript is much less than that of Basic MSI.
  • InstallScript allows you to perform actions before or after the main installation has run, meaning that InstallScript makes use of an event-driven model, which is useful if you're used to programming for Windws.
  • You will have to work with InstallScript if you are given an existing InstallScript installation to maintain.
  • InstallScript projects don't use the Windows Installer, which means your product can not be submitted to the Certified for Windows Vista Logo program.

Basic MSI projects use the Windows Installer service to run the installation. You will want to choose this project type for the following reasons:
  • You want to submit your product to the Certified For Windows Vista Logo program. One of the main requirements is that you must use the Windows Installer for your installation.
  • You don't want to use a scripting language for your installation.
  • You have to work with Basic MSI if you are given an existing Basic MSI installation to maintain.
  • You want to maximize compatibility with administrative tools such as Microsoft SMS.
  • Your software will be customized by system administrators prior to release.
  • You want to create transforms for the installation. A transform is used to modify an existing installation project.
  • There is more of a learning curve associated with learning Basic MSI installation development.

If I were just learning how to use InstallShield, the first question I would ask is whether my company wants the Vista logo on it's product. If they want to meet the Certified For Windows Vista program requirements, then you have no choice but to use the Basic MSI project. End of story. In the end, Basic MSI installation development has more of a learning curve, while InstallScript installation development is pretty easy.

Troubleshooting Unnecessary Repairs

Sometimes you may encounter the problem of unnecessary repairs of MSI while launching the shortcut in the same logged in user. Here is the way to troubleshoot this problem.
You can go to eventviewr (by typing eventvwr in Run command) then to applications and check the latest error message after repair. It will tell you which component is missing and because of which MSI went for self heal.
You can now check out this component in your package and see what the problem is. Maybe your keypath is a moving target for that component.

There are other methods too which can be used in case the above does not work. These are Logs/Gap capture.

Using VBScript to Set Properties in MSI

We can easily use Set Property Custom Action to set Windows Installer Property, but sometimes we wish to set the property directly in VbScript, specially if we are taking an input from a user through VBScript. Hope this tip helps.

To set property through VBScript we can use "Session" object like:

Session.Property("ALLUSERS")="1"

or we can directly use Property keyword like:

Property("REBOOT")="ReallySuppress"

The only catch here is that we cannot set INSTALLDIR property through the above method as the package uses Directory table to store the value of INSTALLDIR. We need to write the below VBScript to set INSTALLDIR:

dim instpath

instpath = "C:\newpath\newfolder"

Session.TargetPath("INSTALLDIR")=instpath

Remember to place this Custom Action after CostFinalize if you are changing the value of INSTALLDIR property in UI Sequence.

Difference between self-heal and repair

Most people often think that self-heal and repair are the same thing, but they are two different things.

Self Heal is triggered by advertised shortcuts, or other advertising information in the package which eventually Repairs the application.

When the application is launched by advertised shortcut, it checks for all the key paths of the Current Feature, if any of the key paths is missing it will launch Repair.

Note that if there are multiple features then it will not check the missing key paths of the other features, but only the feature of which the advertised shortcut is launched.

Repair of an MSI can be triggered by

1) Repair button in Add/Remove programs

2) Giving the command line msiexec /f{other option} {MSI name}

Once the repair of the package is triggered, then the whole of the MSI is reinstalled. Then it does not see that only the feature which triggered the self heal should be repaired, but the whole MSI, by which I mean, all its features are reinstalled.

About Windows Installer properties

The following link provides you the best information you want to know about the Windows installer properties

http://helpnet.acresso.com/robo/projects/helplibdevstudio9/IHelpPropReference.htm

Tuesday, March 31, 2009

Frequently Asked Questions About Windows Installer (MSI) Packaging

These are the most Frequently asked queries about Windows Installer.
Q. What is Windows Installer?
A. Windows Installer is a system service for installing and managing applications. It provides a standard method for developing, customizing, installing, and updating applications.

Q. What basic functionality is provided by Windows Installer?
A. Windows Installer provides the following basic functions:
Transactional operations: All installation operations are transactional. For each operation that Windows Installer performs, it generates an equivalent undo operation that would undo the change made to the system. If a failure occurs during the middle of an installation, Windows Installer can roll back the machine to its original state.
Self-healing: Windows Installer supports "self-healing" abilities for applications. Applications can detect common installation problems at launch, like missing files or registry keys, and automatically repair themselves.
Installation on demand: Windows Installer supports on-demand installations of application features. For example, the spelling checker in Microsoft Office Word may not be installed by default, but a user can trigger an on-demand installation of this feature.
Installation in locked-down environments: In fully locked-down environments, users don't generally have permission or the ability to install applications. In most cases, they don't have write-access to the Program Files folder of their computers or to the HKEY_LOCAL_MACHINE registry location. If an administrator approves an installation package by means of Group Policy, for instance, Windows Installer can perform an installation on the user's behalf.
State management: Windows Installer provides a set of standard Win32® application programming interfaces (APIs) and automation interfaces for applications and administrators to use for querying the installation state on the machine. The APIs allow querying of the current state, verification of the existing state, repair of a corrupted state, and transition from one state to another.

Q. What versions of Windows include Windows Installer?
A. Microsoft Windows 2000, Windows Millennium Edition (Windows Me), and Windows XP include Windows Installer. Windows 2000 includes version 1.1 of Windows Installer, Windows Me includes version 1.2, and Windows XP includes version 2.0. Windows 2000 SP3 also contains version 2.0 of Windows Installer.

Q. Why are multiple MSIExec.exe processes running on my machine during an installation?
A. A number of MSIExec processes can be running during an installation. The reason for this is that Windows Installer uses a client-server model for performing installations. Additionally for security reasons, Windows Installer hosts DLL and script custom actions in a "sandbox" process. Depending on how the install was initiated, one of the MSIExec processes can be the client process. Another MSIExec process is Windows Installer service. Any remaining MSIExec processes are usually sandbox processes for hosting custom actions. The determination as to which MSIExec process will serve as the sandbox process for a script or DLL custom action depends in part on whether the custom action will run elevated or impersonated and whether the custom action is 32-bit or 64-bit.

Q. What is an MST, and why it is used?
A. Whenever there is a vendor supplied MSI, then it is not recommended to do capture the MSI, hence all the changes need to be done in the MSI are done is a Microsoft Transform. Then this MST file is applied on the MSI with the following command line.
MSIEXEC /I {path}\file.msi TRANSFORMS={path}\file.mst /q

Where {path} is the location of the folder where MSI and MST are kept.

Q. What are the differences between small, minor, and major updates?
A. A small update is a product update that changes a few files or possibly adds some new content. A minor update is a product update that makes enough changes to warrant changing the product version for the product, whereas a major update is a product update with a large number of changes that warrants a change in the product code.
It's sometimes easier to think of a small update as a "hotfix" or Quick Fix Engineering (QFE) update, a minor update as a service pack, and a major update as a product upgrade.
Small and minor updates can be considered almost equal in that the only real difference is that a minor update has a change to the ProductVersion whereas a small update does not. The rules that they follow and application of the patch are the same. Application of small and minor update patches requires explicit reinstallations. Major updates are not subject to that limitation and a reinstallation is not required for patch application. Additionally small and minor update patches are limited in the changes that can be made to the feature-component structure for the package. Significant changes can be made to the feature-component structure in the scope of a major update.

Q. What is the Logical structure of package?
A. A package describes the installation of a full product (Windows Installer does not handle dependencies between products) and is universally identified by a GUID. A product is made up of components, grouped into features.

1. Components
A component is the minimal part of a product-each component is treated by Windows Installer as a unit: the install developer cannot, for example, use a condition to specify to install just part of a component. Components can contain files, groups of files, directories, COM components, registry keys, shortcuts, and other data. The end user does not directly interact with components.
Components are identified globally by GUIDs, thus the same component can be shared among several features of the same package or multiple packages, ideally through the use of merge modules (although, for this to work correctly, different components should not share any sub-components).

2. Key paths
A key path is a specific file, registry key, or ODBC data source that the package author specifies as critical for a given component. Because a file is the most common type of key path, the term key file is commonly used. A component can contain at most one key path; if a component has no explicit key path, the component's destination directory is taken to be the key path. When an MSI-based application is launched, Windows Installer checks the existence of these critical files or registry keys (that is, the key paths). If there is a mismatch between the current system state and the value specified in the MSI package (e.g., a key file is missing), then the related feature is re-installed. This process is also known as self-healing or self-repair. No two components should use the same key path.

3. Features
A feature is a hierarchical group of components-a feature can contain any number of components and other features (a feature contained in another feature is called a "subfeature"). Most installation programs display a "custom setup" dialog box at run time, from which the end user can select which features to install or remove.
The package author defines the product features. A word-processing program, for example, might provide features for the main program executable, the program's help files, and optional spelling checker and stationery modules.

Q. What is Advertisement?
A. Windows Installer can advertise a product rather than actually installing it. The product will appear installed to the user, but it will not actually be installed until it is run for the first time (by means of a Start menu shortcut, by opening a document that the product is configured to handle, or by invoking an advertised COM class).

Q. What is Installation on demand?
A. Similar to advertisement, it consists in the installation of features as soon as the user tries to use them.

Q. How to do Diagnostic Logging?
A. Windows Installer supports detailed logging as a powerful diagnostic tool. Logging can be enabled in the following four ways:
Command-line: If installing an MSI package from the command-line, the /L switch can be used to enable logging. For example, the following command installs Package.msi and outputs verbose logging to c:\Package.log:
msiexec /i Package.msi /l*v c:\package.log

Windows Registry: The following registry value can be used to enable verbose logging:

Key: HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\Installer

Value Name: Logging

Type: REG_SZ

Data: voicewarmup

The resulting log is named MSI###.log (where "###" is a unique random identifier) and is placed in the system's Temp directory.

Group Policy: The following Group Policy setting can be used to manage logging on multiple systems:

Computer Configuration -> Administrative Templates -> Windows Components -> Windows Installer -> Logging.

Windows Installer API: If installing an MSI package programmatically, the MsiEnableLog function call can be used to create a log file and determine the logging level for the life of the calling process.

Although verbose logs are very useful for diagnosing Windows Installer problems, they can be very long and difficult to read without practice. A quick way to find the location of a problem in the log is to open it in a text editor (such as Notepad) and search for the phrase "Return Value 3". This entry commonly appears in logs close to the point where a critical error has occurred. The Windows Installer SDK provides a tool called WiLogUtl, which parses and annotates Windows Installer log files.

Q. Why does the package go for Self Healing first time the user launches the Application?
A. If the package is containing some HKCU entries then the package will always go for self healing for the first time. This happens because the HKCU keys are only installed for the current user present while installing the package and not all the users as it is the property of the HKCU. So, if other user logs in then there is a mismatch between the current system state and the value specified in the MSI package (e.g., a key file is missing), then the related feature is re-installed. This is called the Self Healing.

Basics of MSI

MSI files are basically relational database files that contain all the information that the Windows Installer requires to install or uninstall an application and to run the setup user interface. Installation packages are organized like the diagram above. Each package has one or more independent features. Each feature can have one or more components. The installer always installs or removes a component from a user's computer as a coherent piece. A component can be a single file, or a group of files, a registry setting, COM objects, resources, etc.

1. Installation Mechanism
There are two phases to a successful installation process: acquisition and execution. If the installation is unsuccessful, a rollback phase may occur.

2. Acquisition
At the beginning of the acquisition phase, an application or a user instructs the installer to install a feature or an application. The installer then progresses through the actions specified in the sequence tables of the installation database. These actions query the installation database and generate a script that gives a step-by-step procedure for performing the installation.

3. Execution
During the execution phase, the installer passes the information to a process with elevated privileges and runs the script.

4. Rollback
If an installation is unsuccessful, the installer restores the original state of the computer. When the installer processes the installation script it simultaneously generates a rollback script. In addition to the rollback script, the installer saves a copy of every file it deletes during the installation. These files are kept in a hidden, system directory. Once the installation is complete, the rollback script and the saved files are deleted. For more information, see Rollback Installation.

Advantages of Using MSI based Installations

MSI provides a host of advantages over other installation programs which include but are not limited to:

1. Repair Damaged Installations
At times a clean installation can turn bad owing to a missing file or accidental deletion of some files from the applications folder. This could be due to an error on the user’s part, corrupt files, disk crashes, etc. When run in maintenance mode, MSI based installations provide a “Repair” Mode which allows user to repair their existing applications without bothering to uninstall / re-install the whole application. MSI installer replaces any missing or corrupt files from the files installed on the user’s machine and the system is ready for use. The Windows Installers service identifies the missing or corrupt files from the users system and replaces them from the source media or Network Image.

2. Easy Management of upgrades / patches
MSI supports creation of updates or patches and has an in-built functionality to implement the rules for applying patches on the user’s machine. With the help of its inbuilt version field, the developers need not worry about writing rules for the patch installations.

3. Ability to provide Roll Back in case of a failed installation
This is in all probability the biggest advantage of MSI over other setup types. One of the trickiest things to handle during installations is a state when the half way through the installation needs to be aborted for one or more of the reasons listed below
• The user cancels the installation
• There is an irrecoverable error
• Changes to the state of the system by another application

This often leads to a dirty installation. From the users’ perspective, they would prefer to have their state back as it was prior to commencement of installations. Implementing a complete Roll Back was never a good option with traditional installer software’s owing to time consuming procedures and managing various states of files.

With MSI the Roll Back functionality is in-built and is ready to use out of the box. If the user cancels or aborts the installation in between, the Windows Installer restores the user’s machine to the state it was before the installation started. It restores any deleted files, removes any registry entries done, deletes any folders the installer might have created, etc.

4. If enabled, extensive logging enables easy debugging
With Installations becoming more complex and increased demand for support for installations over the network, it becomes difficult to handle a broken installation package. MSI by default provides logging features which help in providing meaningful information to the users in case of failed installations. The developers need not write additional code to log messages; the logging engine is intrinsic to the MSI Installer and logs each action from the sequence.

5. Ability to customize installations with Transforms
Transforms are additional files that can be associated with the MSI installers to customize the installations. As an example if the installation is to be repeated over several workstations in a Lab, a transform can help in installing the product with a pre-determined set of settings on one machine and replicate the same across all other machines in the Lab.

6. Ability to do a silent installation without any user intervention
In addition to the transforms, MSI can be used to author silent installations with ‘Zero’ user interaction. The installers can read the parameters from a configuration file and complete the installation.

7. Permissions and rights management
In case of traditional installers the installation is run in the context of the user who has logged into the system. This brings up a challenge of handling user permissions and security settings. In case of MSI Installers, the Windows Installer runs as a system service and hence there are fewer issues with respect to security.

8. Network Deployment using Group Policy
When used with Active Directory, an MSI can be associated with a group policy to let end users install the application on their systems even if they don't have rights to modify the file system or registry. The request is passed on to WIS (Windows Installer Service) for the actual install.

What are MSI based Installations?

Windows Installer is an engine you can use to manage the state of an application. The state of an application includes installation, modification, upgrade, or removal.
Windows Installer is not a tool to create and deploy installations, rather it is a service built into the OS. Software-distribution technologies use Windows Installer to install and manage software applications.
The Windows Installer technology is made up of three elements that work together: the Windows Installer client, the Windows Installer service, and the Windows Installer package (an .msi file).

1. Windows Installer Client
The Windows Installer client is any application that calls upon Windows Installer service to perform a task.
The Windows Installer client is responsible for user interactions such as displaying the Setup user interface during an installation. For example, the Windows Installer client uses the Windows Installer service to change the computer state by copying files and writing registry changes.
Some common clients include the following:
a) The Windows-based shell.
b) Add or Remove Programs in Control Panel of Windows XP Professional and Windows 2000 Professional.
c) Windows Installer-enabled applications, such as Office 2000.

2. Windows Installer Service
The Windows Installer service uses information in a Windows Installer package file to manage all phases of installing a program– add, change, upgrade, and remove. The Windows Installer service performs all installation-related tasks as needed by copying files onto the hard disk, making registry modifications, creating shortcuts on the desktop, and displaying dialog boxes to capture user preferences.

3. Windows Installer Packages
Each Windows Installer package (.msi) file contains a database that stores all the instructions for the Windows Installer service and data required to manage the state of a program, such as adding, changing, or removing it from a computer.
Creating and editing all the tables in the database could by itself be a huge task to accomplish.
To simplify creating and customizing .msi files, Software-distribution authoring tool vendors have developed various authoring tools for Windows Installer such as Wise Installer or Installshield Professional.
As is evident from above, since the Installer service is part of the OS, we need not include an engine to carry out the installation, rather we need to supply all the information that is needed by this service to execute the installation. It does not matter what tool has been used to create the MSI package.