InstallShield Tips and Techniques

June 15, 2009

Altering setup.exe to embed customized icon

Filed under: Reference Materials — shieldmaster @ 11:27 pm

I have had quite a few requests to have a customer’s icon embedded in their setup program – and not use the default InstallShield one.  In the past I have poked around trying to see if there was an “Undocumented” method to do it and just simply gave up after spending a fruitless hour or so.

This time, I was going to try again – it should not be so ridiciously hard! 

Damn I’m good!  

After searching the forums, one post gave me a glimmer of hope – but not the method I wanted to employ.  The poster suggested that you take the final setup.exe and open in a Resource Editor and look at the Icon resource and there make your changes.  Well this means you need to alter the setup each time you generated an output file – that wastes my time, plus the setup.exe might be digitally signed – not a good solution.  But the germ of an idea was to alter the bootstrap setup.exe.

After searching, performing various test builds, I finally found a solution that works! 

  1.  Navigate to the directory “c:\Program Files\InstallShield\2009\Redist\Language Independent\i386″
  2. Locate the two bootstrap files “setupPreReq.exe” and “setupPreReqW.exe”.  Make a copy of them to preserve in case you have problems.
  3. Open each in a Resource Editor and look at the Icon resource.  In my method, I used Visual Studio 2005 and opend a file, selected the icons section, and  added a new Icon resource that a customer supplied (a 32 bit .ico file), which became Icon 101 – I had to then delete #100 (the InstallShield default one) and renamed my new Icon from 101 to be 100.  I then saved the modified SetupPreReq.Exe and made the same change to the other one.  Forgive the improper use of technical terms – I don’t program at all, I am relatively new to the VS IDE!
  4. Rebuild the application media.  Now the new setup will display the customize icon.  This works for each and every build!

Now I modified these two files for a project that has quite a few setup prerequisites – hence the ones that worked were named appropriately “setupPreReq.exe” and “setupPreReqW.exe”.  There were two other bootstrap setup’s, a “Setup.exe” and “SetupW.exe” but they did not work for my needs – but may be used if you don’t have setup prerequisites.  You may need to modify them as well.

For my needs, I will archive the original ones and use to create new customized ones for each customer.

Hope this helps!

Charles

April 26, 2009

Tutorial: Adding Setup Prerequisites to InstallShield package

Filed under: Reference Materials — shieldmaster @ 1:11 pm

Recently I was working on a project and it required the Sage Data Objects to be installed for the application to work correctly.  Already packaged setups, I had to come up with a strategy to install them with my application package – built as a Basic MSI project.  After finding out the Sage packages were built as a InstallScript MSI package I knew they would collide unless I nested them (deprecated) or ran them as Immediate Custom Actions – which I detest because the client may cancel the install during the dialogs, but the Sage was forced on their workstations. 

 

 

Finally I decided to “repackage” them as Setup Prerequisites, so after completing this I decided to create a simple tutorial to guide others in this task.  Hope it helps!

 

Note:  All dialog screens are from InstallShield v2009.

 

 

 

 

First, look at the Redistributables selection – the middle panel shows you the final results of our created prerequisite.  In this case I had to create three (3) separate one, for each applicable version that was to be distributed.  Note the names are somewhat wordy – I initially used “SDObj15” but when it was installing, it was so cryptically it was unusable.  So write it out so the customer knows what is being installed.

 

 

The setup prerequisites will end up being stored in the sub-directory “SetupPrerequisites” under the location where InstallShield was installed.  In my case it’s “C:\Program Files\InstallShield\2009\SetupPrerequisites”.  They will be stored as PRQ files (my example would be “Sage Data Object Engine v15.prq”) – so be sure to stage them into your Source Repository afterwards before you misplace them!

 

To get started, we need to open the Prerequisites Editor – accessible from the “Tool\Prerequisites Editor” dropdown menu choice.  You will be presented with this blank panel:

 

 

 

 prereq1

 

Go ahead and save this using your new name (example:  Sage Data Object Engine v15)

 

Now select the first tab “Properties” and let’s review:

 

Prereq Properties

 

 prereq2

 

Note the pre-generated “unique identifier” that is associated with this Prereq – it’s used to stage the separate file in the Windows Temp directory during extraction and execution.  Preserve its value.   Add a description for clarity. 

 

If the file is of considerable size, you may want to consider hosting the file on a website.  This will work if you are certain that every customer will be installing on a network connected workstation.  Remember there are some installations that are secure networks and are not allowed internet capability – this should be your guide as to where to host it or incorporate it within the setup.  An example of the web site would be http://www.InstallSolutionsInc.com/prereq

 

Prereq Conditions

 

The next tab is “Conditions” which we can modify to see what conditions this EXE will run under:

 

        prereq4  

 

 

There is a condition that we want to occur before the prereq for Sage Data Object v13 needs to meet before we consider installing it.  Select the button Add to create the first condition.

                  

 prereq5

 

For this Prereq, I am looking for the existence of the file “sg50SdoEngine150.dll” that would have been installed into the Windows System32 file.  In addition I am checking that the version number is at least the one delivered with the EXE itself.  Obviously I would have to have installed the Sage setup to gather this information.  I just could have easily looked in the registry for the GUID under “HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall” and set to condition to install the Prereq if that registry did not exist.

 

Remember you can chain the conditions together.  For example if I was installing the Microsoft Office 2007 Primary Interop Assembly to support a MS Word plug-in, I would want to check for both:

  • Office 2007 was installed
  • Office 2007 Word was installed
  • Office 2007 Primary Interop Assembly was not installed

 

 

 

 

Prereq “Files to Include”

 

 

The next tab is the “Files to Include”, which allows us to lock down the files that are to be installed.

 

prereq6           

 

Here, I include both the EXE and its associated Setup.ISS file – which is critical to run silently. 

Note that the files are hard-coded!  You must change it depending on where you stashed the EXE/ISS files. 

 

To be honest I did not evaluate whether It was possible to use a InstallShield path reference, such as <ISProductFolder> – but under the time constraints I did not evaluate that.  I remember that IS 12 finally allows a path reference for storing the setup after a build – quite a few releases after incorporating that technique.

 

Now the nice thing about the unique GUID Identifier we saw in the first panel, is that it segregates the files for this Prereq from other Prereq’s that are with the project.  In this situation, the ISS file is a silent parameter file used to provide dialog sequence for the InstallScript MSI Sage project.  Each Prereq that we will create (v13, v14 and v15) will have a similar named “Setup.ISS” – so we don’t have to worry about clashing the files.

 

 

Prereq “Application to Run”

 

The next tab “Application to run” allows me to point to the EXE with the simple “/s” parm to run it silently.

 

 

 prereq7

 

A simple drop down menu allows you to set the correct file amongst the files you included.

 

Prereq “Behavior”

 

The next tab “Behavior” offers some basic criteria on what to do if it requires reboot.

 

   prereq8        

 

 

The available selections are geared towards supporting the “Chained MSI’s” capable with Windows Installer 4.5.  Since I know the Sage DO does not require a reboot, I was not worried about which I put here.

 

Prereq “Dependencies”

 

The final tab “Dependencies” allows you to have one run before the other. 

 

prereq9           

 

 

 

In our case, we want this Prereq to run AFTER the “Sage Data Object v14.prq” – which itself will run after “Sage Data Object v13”! – Ok, we haven’t built those yet – so save this one, go build the other two and return to this panel to set the execution order!

 

 

 

 

Final Edits

Now that the setup prerequisites have been created, we need to go back and make some final edits to them. 

 

Within the InstallShield project, you should be able to see your new prerequites listed in the Redistributables/Setup Prerequisites panel:

 

 prereq10

 

1)  Select the checkbox on each one to inject it into the project. 

 

2) Right-click each one and select properties.  Ensure each is set to “Extract from the Setup.exe”

                    

 

3)  Right-click and verify “set prerequisite order” – as shown here. 

   prereq12             

 

Now, to my initial confusion, this panel seems to duplicate the Prereq “dependencies” we used earlier, that panel dealt only with sequencing the prerequisites – this one deals with the other non-related prerequisites.

 

Make the Sage objects come after the .NET setup’s, and before the SQL Server (Not really important re: SQL Server since that one runs after the dialogs are selcted.)  Ensure that v14 follows v13 and v15 is the final one!

 

Final item – go to the Releases panel and ensure that the element for your release media (7.00.0001/Release in the example) has “InstallShield Prerequisites Location” value set to either “Extract from Setup.exe” or “Follow individual selections”.

 

       prereq13    

 

Otherwise, you will lose your religion trying to determine why the Sage EXE file are written to sub-dir under the Setup.exe file! :->}

 

 

March 26, 2009

Windows Installer – are we seeing a new strategic direction?

Filed under: Reference Materials, Techniques — shieldmaster @ 11:06 pm

I have done my share of packages, ranging from the complex to the simple.  One thing is certain, sophisticated software packages using leading-edge technology is requiring a tremendous amount of application prerequisites to be installed. 

 

For example, for an 1 MB Excel “Plug-in” that I created the install package, the following software packages were required to be installed before the application package (ignore the obvious Microsoft Office with Excel):

  • Microsoft .NET 2.0
  • Microsoft Visual Studio 2005 Tools for Office
  • Microsoft Office 2003 Primary Interop Assemblies – for when Office 2003 is installed
  • Microsoft Office 2007 Primary Interop Assemblies – for when Office 2007 is installed

 

All of these prerequisites packages must be installed before the application can be installed – in fact if they are not installed you will encounter errors during the configuration. 

 

Just getting them deployed within the application install package has been frustrating because:

 

-         Technique – correctly getting the technique in installing them  is very tricky to do when you have to have MS Office 2003 PIA look for its registry key (don’t attempt to run it if its already been install) and then look for the presence of Office 2003 registry key (it will error off if its prerequisite has not been installed)

-         Package size – start with a 1 MB Excel ‘plug-in’, and then add up the disk space consumed in incorporating these application prerequisites within your deliverable.  Over 50MB in this install package – for a 1MB Plug-in!  Web staging of these prerequisite packages becomes a mandatory requirement.

 

In the past I would silently install some software packages (.NET 1.1 and Adobe) in the short period before the dialogs appeared (traditionally the Windows Installer engine is locked into your MSI and won’t let any other MSI packages execute).  Yes it violates the golden rule about not altering your client’s desktop until they gave permission by pressing INSTALL on the “Ready for Install” dialog – but many times you don’t have much choice.

 

This growing requirement for application prerequisites force us to utilize the InstallShield “Setup Prerequisites” capability – which is steadily increased in usability until it now looks like its works in IS 2009!  Granted you can’t run silently/unattended since it will always pop up the Setup Prerequisites panel!

 

Lately I have been installing some high-end application packages and am finding a new trend – that of having a sophisticated “bootstrap” application to manage the installation, that is a C# type application that runs with panels to guide you through the installation process.  Consider the SQL Server 2005-8 or Visual Studio 2008 application dialog panel that steps you thru the various installation and configuration steps.  Look at Verint Systems with their Master Installer package – which handles prerequisites by neatly isolating them from the application installation package.  The MSI’s are launched separately which allows for the MSI Packages to be focused on just delivering the application files – not being concerned with prerequisites!

 

These are vastly different approaches than that embodied within the “Chained MSI’s” approach that Windows Installer v4.5 is touting as the newest strategy – which is demonstrated within the .NET Framework 3.5 SP1.  This package actually is comprised of various MSI’s under the covers for the different .NET Framework versions (2.0, 2.0 SP1, 3.0, 3.5, 3.5 SP1) that are daisy chained together similar to early patches were cobbled together.

 

Personally I think very highly of Microsoft’s “Chained MSI’s” technique – but let’s be realistic – how many technology firms can dedicate resources to accomplish this and test it!

 

The longer I stay in this business, the simpler I want to make my application packages.  Because when I develop them, I may not be maintaining them – the customer may have a individual with limited skill set trying to accomplish a simple maintenance task.  My stint with  EDS (back when 3 piece suits and lace-up florsheim’s were the norm!) taught me that for each dollar in development, an organization spends $100 in maintenance costs – so keep it simple!

 

From my viewpoint – the technology to create the installation package is surpassing the expertise found in most development shops.  I think the approach that allows a InstallShield developer to create the most dependable “Bullet-proof” installation needs to be seriously considered!

 

The heretic has emerged! 

 

ShieldMaster

February 2, 2009

Testing your install to get consistent results

Filed under: Reference Materials, Techniques — shieldmaster @ 2:10 am

As a professional that is proud of my work, I ensure that each of my installs is thoroughly “Unit Tested” by me before they go to QA – after all, the install is not ready until it can do the basics:

  • Install cleanly on each approved Operating System – using Dialogs and running unattended/silently!
  • Uninstall cleanly on each approved Operating System
  • All registry entries properly configured based on dialog selection and input values
  • All files are installed – in the correct directories, based on Feature selection
  • All configurable files (XML, INI) are properly configured based on dialog selection and input values
  • All shortcuts are created and functionally work
  • All NT Services are created and started correctly.
  • Any Web Services are created and configured correctly

 

Plus, realistically if it doesn’t perform the basics – what does the quality of my install package relay to the development team that is facing pressure to get their application in front of the testers – they don’t need doubts as to whether iteration #1 will be hung up with an installation that simply doesn’t install!

 

But what about situations where the new install will be “upgrading” previous releases that are out in the field?  You have introduced a different set of testing criteria, such as:

  • All ‘approved’ previously released application versions are recognized – some versions may not be approved for upgrade, so they have to be recognized and dealt with appropriately
  • All ‘approved’ previously released application versions are upgraded to the new release.  This includes removing any trace of previous versions, removing obsolete files, preserving user configured files.

When I perform Unit Testing on my installation package, I seem to have a handle on the iterations that must be accomplished (test with this dialog selection on, test with it off), but I also found myself needing to be able to accomplish a test and be able to compare the results with a previous results set. 

 

What I needed was a consistent method to preserve the installed components for in-depth analysis.  I started out by having a check-list, such as:

·        Verify all registry entries –  HKLM created

·        Verify all registry entries – HKCU created

·        Verify the AppPath entries are correctly created and configured

·        Verify the registry entries are correctly created and configured

·        Verify the services are created, started and configured as Automatic or Manual as required

·        Verify all of the files are installed based on the dialog choices/Feature selection – then copy the installed file to network for analysis – be sure to preserve the Time/Date stamp!

 

With this checklist, I could perform multiple installs on my list of Test cases, but whenever I missed gathering something, I had to go back and recreate the test scenario just to capture the data. 

 

Plus, I was finding that some of the test Iterations could be given to QA and reviewed for their smoke testing – because I was not gathering the data for their analysis.

 

 

Batch Archive Method

I found that I needed a method to easily gather the installed components for preservation.  I ended up creating a simple BATCH Archive job that would handle the data gathering consistently and would ensure that I did not miss anything!

 

Typically my testing is performed under VMware’s Workstation Server and I have an open connection to the domain network.  I created a BATCH job that would collect the data and copy it to a network location.  If you use ROBOCOPY (available as part of the Windows Resource Kit, and introduced as a standard feature of Windows Vista and Windows Server 2008. ) you can easily copy the collected files and critically those installed directories – preserve the file attributes (Time/Date stamp).

 

Here is a sample batch files I created, “Forensics_Archive.BAT” – you needed to pass it one parameter, the directory subset on the network shared that I created to hold the test results.  For example on \\DevShare\DevTesting\Charles\R7_Results I would create various sub-directories (NewInstall; Upgrade; etc) using the Batch Archive.  For example, I could run the following:

 

Forensics_Archive.bat “NewInstall\Iteration1_Dialogs”

Forensics_Archive.bat “Upgrade\Iteration1_Dialogs”

Forensics_Archive.bat “NewInstall\Iteration1_Silent”

 

Here is an extract of the batch file “Forensics_Archive.BAT”

 

@ECHO ON

IF [%1]==[/?] GOTO Syntax

IF [%1]==[] GOTO Syntax

SET ArchiveDest=%~1

SET ArchiveDestPath=%TEMP%\%ArchiveDest%

 

rmdir /S /Q %ArchiveDestPath%\

md %ArchiveDestPath%\

 

ECHO.

ECHO Archiving SOFTWARE Registry Entries from installation

REGEDIT /E “%ArchiveDestPath%\ Forensics.REG” “HKEY_LOCAL_MACHINE\SOFTWARE\Forensics”

REGEDIT /E “%ArchiveDestPath%\ISI Systems.REG” “HKEY_LOCAL_MACHINE\SOFTWARE\ISI Systems”

REGEDIT /E “%ArchiveDestPath%\Uninstall Entries.REG” “HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall”

REGEDIT /E “%ArchiveDestPath%\HKCurrentUser_Forensics.REG” “HKEY_CURRENT_USER\SOFTWARE\Forensics”

 

 

ECHO.

ECHO Archiving SERVICES Registry Entries from installation

REGEDIT /E “%ArchiveDestPath%\DirectoryService.REG”

 

REGEDIT /E “%ArchiveDestPath%\Forensics Content Server.REG” “HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Recorder Content Server”

 

REGEDIT /E “%ArchiveDestPath%\RecorderTomcat.REG” “HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\RecorderTomcat”

 

 

ECHO.

ECHO Archiving PROGRAMFILES Files from installation

XCOPY “c:\Program Files\ComPlus Applications” “%ArchiveDestPath%\Program

Files\ComPlus Applications” /C /E /I /R /Y

XCOPY “c:\Program Files\ISI Systems” “%ArchiveDestPath%\Program Files\ISI Systems” /C /E /I /R /Y

 

ECHO.

ECHO Archiving Files archived during Upgrade

XCOPY “C:\Documents and Settings\All Users\Application Data\ISI Systems\Archive” “%ArchiveDestPath%\Archived Files” /C /E /I /R /Y

 

ECHO.

ECHO Archiving Information on IIS Virtual Directory from installation

cd c:\inetpub\AdminScripts

cscript.exe adsutil.vbs ENUM w3svc/1/root/Forensics > IISVertDir_Forensics.txt

md “%ArchiveDestPath%\IIS_VirtDir”

XCOPY “c:\inetpub\AdminScripts\IISVertDir*.txt” “%ArchiveDestPath%\IIS_VirtDir” /C /E /I /R /Y

del “c:\inetpub\AdminScripts\IISVertDir*.txt”

 

 

ECHO.

ECHO Archiving %TEMP% Files from installation

XCOPY %TEMP%\*.log “%ArchiveDestPath%\TEMPDir” /C /I /R /Y

 

ECHO.

ECHO Archiving Migration Saved configuration files from installation

XCOPY “C:\Documents and Settings\All Users\Application Data\ISI Systems\Archive” “%ArchiveDestPath%\Migration Archived Files” /C /E /I /R /Y

 

ECHO.

ECHO Transferring Archived Files to localhost machine

 

NET USE \\DevShare\DevTesting\Charles\R7_Results /USER:DOMAIN\USERNAME PASSWORD  ß Plug in your domain, user and password!

  

\\DevShare\DevTesting\Charles\robocopy.exe %ArchiveDestPath% “\\DevShare\DevTesting\Charles\R7_Results\%ArchiveDest%” /MIR

 

NET USE \\DevShare\DevTesting\Charles\R7_Results /DEL

 

rmdir /S /Q %ArchiveDestPath%

 

:: Ready

GOTO End

 

:Syntax

ECHO.

ECHO Forensics_Archive.bat – batch utility to copy installation results off of VM Image to Host machine share 

ECHO.

ECHO Usage:  Forensics_Archive “NewInstall\Iteration1_Dialogs”

ECHO.Note:   Cannot have spaces in the directory name!!!!!

ECHO.

ECHO. Final results stored on

ECHO. \\DevShare\DevTesting\Charles\R7_Results\[Your Directory Name]

 

ECHO Written by Charles B. Hodge

:: Clean up variables and quit

:End

 

 

 

Data Collection Comparison Method

As noted in a early posting – I have an affinity for the file/directory comparison tool “Beyond Compare”.   I have found that once I have gathered the data – I can simply compare one directory against another.  Very useful for comparing the known result set for an install with dialogs that I approved for TestCase #1 against the results set of a silent/unattended install that used the same selection criteria.

 

Hope this helps!

Charles

January 31, 2009

Reading a Silent Install Parameter File

Filed under: Reference Materials — shieldmaster @ 1:29 am

 

I have been focusing quite a bit on silent installs lately.  In fact I have recently rewritten two installs that were giving problems to the customer base simply because they could not be installed silently – or unattended.

 

In my experience, quite a few corporations require that software be able to be installed in an unattended/silent method.  For example, when a large corporation with 20,000 customer support personnel wants to distribute new software to their desktops, they use a high-end software distribution program (SMS, Trivoli) that will push the application install to the desktops during the night, launch the install package and reboot the machine.  No user intervention is required, and typically the user may not have administrative privileges so the application install package needs to be able to run both unattended and with elevated administrative privileges.
 
Smaller organizations may simply stage the application install program on a network share and provide every customer support personnel a link to a batch file (.BAT) that will run the application, supplying all of the options and data input without requiring user intervention.  All the user would do would be to click on the link before departing the office. 

 

I know the vast majority of installs are very simple and when you create a batch file, about the only item you will need is to pass the INSTALLDIR parameter.  But what happens when you have 6 to 8 dialogs, each with multiple data fields.  Here is an example of the MSI Properties I needed to pass to an application install to run silently with the correct configuration:

 

INSTALLDIR=\”C:\Program Files\ISI Systems\”

ISI_PLATFORM_GROUP=1

ISI_CS_COMPONENT_AS=1

ISI_CS_COMPONENT_CM=1

ISI_CS_COMPONENT_SM=1

ISI_CS_COMPONENT_AD=1

ISI_CS_TOPOLOGY_GROUP=1

ISI_AUDITDB_SERVER=DEVSERVER

ISI_AUDITDB_NAME=MSSQLSERVER

ISI_HTTP_SERVERNAME=ISI_SERVER

ISI_HTTP_SERVERPORT=80

ISI_HTTP_SERVERPATH=haven/services/content.asp

 

 

It looks nice lined up and very easy to read, but unfortunately the MSI Command line parameters must be on one contiguous input line – you cannot break these input parameters across two or more lines.  Now image how difficult it will be to explain the information clearly to a customer who is attempting to create a silent install BATCH file.

 

I remember years back how very much in vogue the INI type files were for reading in program data.  Now everything is XML format, which is not quite as easy for the customer to manipulate.  Started me thinking…

 

I ended up playing around with a silent parameter file – using a INI file format.  I wanted to keep the MSI Command line as simple as possible.  The goal is to create a BATCH file, such as “SilentInstall.bat”, but just specify a MSI Property, such as: “SILENT_PARAMETER_FILE” which provides the path and file name of the special INI file that would contain all of the application configuration items.   


Examples of the contents of a  BATCH file “SilentInstall.BAT”, would be:

 

“c:\Install\Setup.exe” /s /v”/qb ß Line break for clarity only

SILENT_PARAMETER_FILE=C:\Install\SilentParms.INI REBOOT=ReallySuppress

 

Msiexec /I c:\Install\AppSetup.msi /qb ß Line break for clarity only

SILENT_PARAMETER_FILE=C:\Install\SilentParms.INI REBOOT=ReallySuppress

 

 

Now the contents of the SilentParms.INI file would contain the application information that would normally be filled in the dialog data element fields.  Use comments to ensure clarity, especially if you are informing the customer of the relationships between selection values.

 

Here is a sample SilentParms.INI file:

 

REM ****************************************************************

REM **   Silent Parm File for running application Packrat

REM ****************************************************************

 

[GLOBAL]

InstallDirectory=”c:\Program Files\ISI Systems”

 

[PLATFORM_GROUP]

REM ****************************************************************

REM ** Activate only one Platform – choices are:

REM **   Platform=Rotunda

REM **   Platform=Balance

REM **   Platform=Beam

REM ****************************************************************

Platform=Rotunda  

 

[ROTUNDA]

REM ****************************************************************

REM ** Choose as many Components for the Rotunda selection

REM ** required

REM ** Note: values are not used if Platform selected was not

REM **       ROTUNDA

REM ****************************************************************

AudioServer=Yes

CacheMonitor=Yes

SearchMonitor=No

Auditing=NO

 

REM ****************************************************************

REM ** Choose Web or Viewer Services for the Rotunda selection.

REM ** Choices are:

REM **    CS_Services=Web

REM **    CS_Services=Viewer

REM ** Note: values are not used if Platform selected was not

REM **       ROTUNDA

REM ****************************************************************

CS_Services=Viewer

 

REM ****************************************************************

REM ** Provide data for the Rotunda HTTP Services selection.

REM **

REM ** Choices for Viewer Services:

REM **    HTTP_SERVERNAME=CHARLES1

REM **    HTTP_SERVERPORT=80

REM **    HTTP_SERVERPATH=witness/services/content.asp

REM **

REM ** Choices for WEB Services:

REM **    HTTP_SERVERNAME=CHARLES1

REM **    HTTP_SERVERPORT=8080

REM **    HTTP_SERVERPATH=adapter/locator

REM ** Note: values are not used if Platform selected was not

REM **       ROTUNDA

REM ****************************************************************

HTTP_SERVERNAME=CHARLES1

HTTP_SERVERPORT=80

HTTP_SERVERPATH=witness/services/content.asp

 

REM ****************************************************************

REM ** Provide data for the Rotunda Auditing selection.

REM ** Choices are:

REM **    AUDITDB_SERVER=CHARLES1

REM **    AUDITDB_NAME=CHARLES2

REM ** Note: values are not used if Platform selected was not

REM **       ROTUNDA

REM ****************************************************************

AUDITDB_SERVER=CHARLES1

AUDITDB_NAME=CHARLES2

 

[BALANCE_SERVICES]

REM ****************************************************************

REM ** Choose Web or COM Services for the Balance selection.

REM ** Choices are:

REM **    Balance_Services=WEB

REM **    Balance_Services=COM

REM ** Note: value is not used if Platform selected was not BALANCE

REM ****************************************************************

Bal_Services=WEB

 

Personally the INI style format is just cleaner to look at, and should be much easier to document – especially when you can put comments throughout the document.

 

InstallScript Custom Action

Now here is a sample InstallScript that will read the INI file and create the selected values to MSI Properties.  Couple of things to note:

  1. Since you typically will run silently, the Custom Action must be run both in the UI Sequence as well as the Execute Sequence.  Obviously the majority of time the appliation will be running silently and only in the Execute Sequence.  But also think of the INI file used as a method to prefill data elements if QA decides to run with dialogs for evaluation requirements.  That is why you need to enable it to run in both sequences – but only allow it to run once!
  2. The conversion of the INI values into MSI Properties should precisely deliver the same installation configuration.  This is a good method to test – run the install silently with the MSI Properties, and then run with the INI file.  The results should match up correctly.
  3. If a file and path are entered via the MSI Property “SILENT_PARAMETER_FILE”, and the file cannot be found, then trigger an abort.
  4. When the Script contains a INSTALLDIR parm, you need to create a Type 35 Custom Action and use the property value “ISI_INSTALLPATH” (Set in the script) to set the INSTALLDIR directory property.
  5. Be sure to allow for the path entered to be in UNC form – could be a remote location! 
  6. To shorten the Script – I have excised the redundant script code.

 

/////////////////////////////////////////////////////////////////////////

// Function:  ISI_ReadSilentParms

//                                                                          

//  Purpose:  This function will be called by the script engine when

//            Windows(TM) Installer executes your custom action

//            and will read and validate the Silent run parms

//

///////////////////////////////////////////////////////////////////////function ISI_ReadSilentParms(hMSI)          

      STRING   szProgramFolder, szCommandLine, szItemName, szMigration; 

      STRING   szPath, szRegKey, szRegSubKey, szSupportDir;

STRING   szProgramFiles, szBuffer, szLogMessage, szParmFile;

STRING   szINI_SectionName, szINI_ValueName; 

      STRING   szPlatform, szAudioServer, szCacheMonitor;

STRING   szSearchMonitor;

      STRING   szAuditing, szCS_Services, szBalance_Services;

STRING   szAuditDB, szAuditDB_Server;

      STRING   szAuditDB_Name, szCS_ServerName, szCS_ServerPort;

STRING   szCS_ServerPath;

      NUMBER   nBuffer, nResult, nvType, nvSize;

 

begin  

 

//WriteToLogFiles

ISI_WriteLogFile (”ISI–> Entering ISI_ReadSilentParms Function”);   

 

 

//***********************************************

//** Retrieve MSI Property that tells where

//** the silent parm file is located

//*********************************************** 

nBuffer = 256;

MsiGetProperty (ISMSI_HANDLE, “SILENT_PARAMETER_FILE”, szParmFile, nBuffer);

if (nBuffer = 0) then

            szBuffer = “ISI–> INFO: Retrieved no value from the MSI Property ‘SILENT_PARAMETER_FILE’!”;

            Sprintf (szLogMessage, szBuffer, szParmFile);

            ISI_WriteLogFile (szLogMessage);

            goto BypassSilentParmFileRead;

endif;

 

szBuffer = “ISI–> INFO: Retrieved ‘%s’ value from the MSI Property ‘SILENT_PARAMETER_FILE’ “;

Sprintf (szLogMessage, szBuffer, szParmFile);

ISI_WriteLogFile (szLogMessage);

 

LongPathToShortPath (szParmFile);                                

LongPathToQuote ( szParmFile, TRUE );

 

if ( Is (FILE_EXISTS, szParmFile) = FALSE) then  

      szBuffer = “ISI–> ERROR: File ‘%s’ was not found –

cancelling install! “;

      Sprintf (szLogMessage, szBuffer, szParmFile);

      ISI_WriteLogFile (szLogMessage);  

      return ERROR_INSTALL_FAILURE;   //Breaks out of install and aborts

endif;

     

      szINI_SectionName =    “GLOBAL”;

      szINI_ValueName   =    “InstallDirectory”;

      nResult = GetProfString ( szParmFile, szINI_SectionName, szINI_ValueName, g_szInstallDir );

      if (nResult = 0) then

            szBuffer = “ISI–> INFO: Value retrieved from Section ‘%s’ with name ‘%s’! was ‘%s’ “;

            Sprintf (szLogMessage, szBuffer, szINI_SectionName, szINI_ValueName, g_szInstallDir);

            ISI_WriteLogFile (szLogMessage);  

      else

            szBuffer = “ISI–> ERROR: Value could not be retrieved from Section ‘%s’ with name ‘%s’! “;

            Sprintf (szLogMessage, szBuffer, szINI_SectionName, szINI_ValueName);

            ISI_WriteLogFile (szLogMessage);  

      endif;

 

      // Set MSI Property which will reset INSTALLDIR Property for new files being installed

      MsiSetProperty (ISMSI_HANDLE, “ISI_INSTALLPATH”, g_szInstallDir);

            szBuffer = “ISI–> INFO: Set ISI_INSTALLPATH Directory to be: ‘%s’ “;

            Sprintf (szLogMessage, szBuffer, g_szInstallDir);   

            ISI_WriteLogFile (szLogMessage);

 

     

// ********************************************************

// ** Retrieve the Platform value

// ********************************************************

szINI_SectionName =    “PLATFORM_GROUP”;

szINI_ValueName   =    “Platform”;

nResult = GetProfString ( szParmFile, szINI_SectionName, szINI_ValueName, szPlatform );

if (nResult = 0) then

      szBuffer = “ISI–> INFO: Value retrieved from Section ‘%s’ with name ‘%s’! was ‘%s’ “;

      Sprintf (szLogMessage, szBuffer, szINI_SectionName, szINI_ValueName, szPlatform);

      ISI_WriteLogFile (szLogMessage);  

      nResult = StrCompare ( “Rotunda”, szPlatform );  //Case insensitive comparison

      if (nResult = 0) then

            MsiSetProperty (ISMSI_HANDLE, “ISI_PLATFORM_GROUP”, “1″); 

            szBuffer = “ISI–> INFO: Set MSI Property ‘%s’ with value of 1 – set as Rotunda”;

            Sprintf (szLogMessage, szBuffer, “ISI_PLATFORM_GROUP”);

            ISI_WriteLogFile (szLogMessage);    

            goto BypassPlatformRead;

      endif;

      nResult = StrCompare ( “Balance”, szPlatform ); 

      if (nResult = 0) then

            MsiSetProperty (ISMSI_HANDLE, “ISI_PLATFORM_GROUP”, “2″); 

            szBuffer = “ISI–> INFO: Set MSI Property ‘%s’ with value of 2 – set as Balance”;

            Sprintf (szLogMessage, szBuffer, “ISI_PLATFORM_GROUP”);

            ISI_WriteLogFile (szLogMessage);    

            goto BypassPlatformRead;

      endif;

      nResult = StrCompare ( “Ultra”, szPlatform ); 

      if (nResult = 0) then

            MsiSetProperty (ISMSI_HANDLE, “ISI_PLATFORM_GROUP”, “3″); 

            szBuffer = “ISI–> INFO: Set MSI Property ‘%s’ with value of 3 – set as Ultra”;

            Sprintf (szLogMessage, szBuffer, “ISI_PLATFORM_GROUP”);

            ISI_WriteLogFile (szLogMessage);    

            goto BypassPlatformRead;

      endif;

            //PROBLEM DID NOT FIND MATCHING VALUE!!!

            szBuffer = “ISI–> ERROR: Value could not be retrieved from Section ‘%s’ with name ‘%s’! “;

            Sprintf (szLogMessage, szBuffer, szINI_SectionName, szINI_ValueName);

            ISI_WriteLogFile (szLogMessage);        

            MsiSetProperty (ISMSI_HANDLE, “ISI_PLATFORM_GROUP”, “1″);  //Setting Default!

 

else

      szBuffer = “ISI–> ERROR: Value could not be retrieved from Section ‘%s’ with name ‘%s’! “;

      Sprintf (szLogMessage, szBuffer, szINI_SectionName, szINI_ValueName);

      ISI_WriteLogFile (szLogMessage);  

      MsiSetProperty (ISMSI_HANDLE, “ISI_PLATFORM_GROUP”, “1″);  //Setting Default!

endif;

 

BypassPlatformRead:

// ********************************************************

// ** Retrieve the ROTUNDA Components value

// ********************************************************    

szINI_SectionName =    “ROTUNDA”;

      szINI_ValueName   =    “AudioServer”;

      nResult = GetProfString ( szParmFile, szINI_SectionName, szINI_ValueName, szAudioServer );

      if (nResult = 0) then

            szBuffer = “ISI–> INFO: Value retrieved from Section ‘%s’ with name ‘%s’! was ‘%s’ “;

            Sprintf (szLogMessage, szBuffer, szINI_SectionName, szINI_ValueName, szAudioServer);

            ISI_WriteLogFile (szLogMessage);  

      else

            szBuffer = “ISI–> ERROR: Value could not be retrieved from Section ‘%s’ with name ‘%s’! “;

            Sprintf (szLogMessage, szBuffer, szINI_SectionName, szINI_ValueName);

            ISI_WriteLogFile (szLogMessage);  

      endif;

            nResult = StrCompare ( “Yes”, szAudioServer );  //Case insensitive comparison

            if (nResult = 0) then

                  MsiSetProperty (ISMSI_HANDLE, “ISI_CS_COMPONENT_AS”, “1″); 

                  szBuffer = “ISI–> INFO: Set MSI Property ‘ISI_CS_COMPONENT_AS’ with value of 1″;

                  Sprintf (szLogMessage, szBuffer, “ISI_CS_COMPONENT_AS”);

                  ISI_WriteLogFile (szLogMessage);    

            else

                  MsiSetProperty (ISMSI_HANDLE, “ISI_CS_COMPONENT_AS”, “”); 

                  szBuffer = “ISI–> INFO: Set MSI Property ‘ISI_CS_COMPONENT_AS’ with value of 0″;

                  Sprintf (szLogMessage, szBuffer, “ISI_CS_COMPONENT_AS”);

                  ISI_WriteLogFile (szLogMessage);    

            endif;

 

 

// ********************************************************

// ** Retrieve the ROTUNDA Services values

// ********************************************************

szINI_ValueName   =    “CS_Services”;

nResult = GetProfString ( szParmFile, szINI_SectionName, szINI_ValueName, szCS_Services );

if (nResult = 0) then

      szBuffer = “ISI–> INFO: Value retrieved from Section ‘%s’ with name ‘%s’! was ‘%s’ “;

      Sprintf (szLogMessage, szBuffer, szINI_SectionName, szINI_ValueName, szCS_Services);

      ISI_WriteLogFile (szLogMessage);

            nResult = StrCompare ( “Viewer”, szCS_Services );  //Case insensitive comparison

            if (nResult = 0) then

                  MsiSetProperty (ISMSI_HANDLE, “ISI_CS_TOPOLOGY_GROUP”, “1″); 

                  szBuffer = “ISI–> INFO: Set MSI Property ‘ISI_CS_TOPOLOGY_GROUP’ with value of 1 – Viewer”;

                  Sprintf (szLogMessage, szBuffer, “ISI_CS_TOPOLOGY_GROUP”);

                  ISI_WriteLogFile (szLogMessage);    

            else

                  MsiSetProperty (ISMSI_HANDLE, “ISI_CS_TOPOLOGY_GROUP”, “2″); 

                  szBuffer = “ISI–> INFO: Set MSI Property ‘ISI_CS_TOPOLOGY_GROUP’ with value of 2 – WEB”;

                  Sprintf (szLogMessage, szBuffer, “ISI_CS_TOPOLOGY_GROUP”);

                  ISI_WriteLogFile (szLogMessage);    

            endif;

else

      szBuffer = “ISI–> ERROR: Value could not be retrieved from Section ‘%s’ with name ‘%s’! “;

      Sprintf (szLogMessage, szBuffer, szINI_SectionName, szINI_ValueName);

      ISI_WriteLogFile (szLogMessage);  

endif;

 

 

//WriteToLogFiles  

 BypassSilentParmFileRead:

ISI_WriteLogFile (”ISI–> Exiting ISI_ReadSilentParms Function”);   

 

 

end;

 

Hope this helps!  Happy Coding…

Charles

January 16, 2009

Conditionally install features via scripting

Filed under: InstallShield Scripting — shieldmaster @ 7:08 pm

 

 

 

I was recently dealing with an application install and wanted to selectively activate some features via scripting.  Turns out the application had three platforms and one of the platforms had four separate options. The typical method was to use the Custom Setup, but I wanted more flexibility.

 

Here was the situation, I created two screens that the user would be able to choose selections; the first was a Platform screen,

 

vision1

 

 

And then if Balance was chosen then they could pick components (one, none or all) from the four that were available.

vision2

 

 

What I wanted to achieve was to have InstallShield features created for the following:

  • CommonFiles – this contains all common files needed by application, regardless of the platform chosen
  • Stability – these files would be delivered if customer selected Stability as a platform
  • Balance – this was some core files for Vision that would be required when the platform Balance was selected.
  • Optionally, when the these specific components for Balance are selected:
    • Balance_Client – these files within this feature would be selected if the user checked the box “Client for Balance”
    • Balance_CacheMonitor – these files within this feature would be selected if the user checked the box “Cache Monitor”
    • Balance_SearchMonitor – these files within this feature would be selected if the user checked the box “Search Monitor”
    • Balance_AuditMonitor – these files within this feature would be selected if the user checked the box “Auditing”
  • Viewer – these files would be delivered if customer selected Viewer as a platform

 

 

With those dialogs and the features created, and components and files populated, how could I selectively activate the features based on user selection?

 

Here is how I accomplished it:

  1. On each feature that I wanted conditionally set, I first set the InstallLevel value to be 300 – which prevents the feature from being installed (assuming default INSTALLLEVEL property value of 100). 

       

 

  1. You will need to create a script that runs after the dialogs have been displayed and the user makes the selection.  Here is a snippet that I created:

 

// ******************************************************

// ** Obtain the value of the MSI Property associated

// ** with the Audit Checkbox

// ******************************************************

nBuffer = 256;   

MsiGetProperty (ISMSI_HANDLE, “VER_BAL_COMPONENT_AU”,

               szCS_Component_AU, nBuffer);

szBuffer = “ver–> Retrieved ‘%s’ value from the MSI Property “ +

“VER_BAL_COMPONENT_AU ‘ “;

Sprintf (szLogMessage, szBuffer, szCS_Component_AU);

ver_WriteLogFile (szLogMessage);

 

// ******************************************************

// ** If checkbox was checked, then set the corresponding

// ** MSI Property to be an ACTIVE switch

// ******************************************************

 

if (szCS_Component_AU  = “1″) then

   MsiSetProperty (ISMSI_HANDLE, “AUDIT_SWITCH”, “ACTIVE”);

   szBuffer = “ver–> Set ‘%s’ as value for the MSI Property “ +

               “’AUDIT_SWITCH’ “;

   Sprintf (szLogMessage, szBuffer, “ACTIVE”);

   ver_WriteLogFile (szLogMessage);

endif;  

  

I pulled the value of the MSI Property associated with the Balance Component “Auditing”.  If the value was “1” – then the user had checked the “Audit” box. All I had to do was then set the MSI Property “AUDIT_SWITCH” to have a value of “ACTIVE”.

 

Now this script is run by a Custom Action that is set to run after the dialogs have completed in the UI Sequence.  But because the UI Sequence does not run when executing silently – you need to have the Custom Action set to “Run Only Once” and have the CA also run in the Execute Sequence. 

 

  1. Finally, I created some Custom Actions that will set the MSI Property “ADDLOCAL” which is the property that lets the Windows Installer know what features are being installed.  These will be Type 51 – “New Set Property” and will only run in the Execute Sequence.  I will initialize the MSI Property “ADDLOCAL” with the features that are always required and then build the string, adding more features as necessary.  Here are some sample Custom Actions:
    1. Custom Action Name:  ISI_SetBaseFeatures

                                                               i.      Property Name: ADDLOCAL

                                                             ii.      Property Value:  CommonFiles

                                                            iii.      Execution Scheduling: Always Execute

                                                           iv.      Install Exec Sequence:  Schedule after AppSearch

                                                             v.      Install Exec Condition:  NOT Installed

  1.  
    1. Custom Action Name:  ISI_SetBalance

                                                               i.      Property Name: ADDLOCAL

                                                             ii.      Property Value:  [ADDLOCAL],Balance

                                                            iii.      Execution Scheduling: Always Execute

                                                           iv.      Install Exec Sequence:  Schedule after ISI_SetBaseFeatures

                                                             v.      Install Exec Condition:  BALANCE_SWITCH=”ACTIVE”

  1.  
    1. Custom Action Name:  ISI_SetAuditing

                                                               i.      Property Name: ADDLOCAL

                                                             ii.      Property Value:  [ADDLOCAL],Balance_AuditMonitor

                                                            iii.      Execution Scheduling: Always Execute

                                                           iv.      Install Exec Sequence:  Schedule after ISI_SetBalance

                                                             v.      Install Exec Condition:  AUDIT_SWITCH=”ACTIVE”

 

 

Basically, I took the MSI Property “ADDLOCAL” and initialized it to the features that I considered mandatory – in this case the feature “CommonFiles”.  

From this point on, each Custom Action would append another feature to the MSI Property when the condition was met. 

 

In the above examples, if the user chose the checkbox in the dialog “Auditing”, then after the script ran the MSI Property “AUDIT_SWITCH” was set to “ACTIVE”.  That triggers the condition in Custom Action “ISI_SetAuditing” so that the feature name “Balance_AuditMonitor” will be appended to the MSI Property “ADDLOCAL” (Note: the use of apostrophe in the value!).  Another feature has been activated.

 

 

Hope this sheds some light on how to make InstallShield work for you!

January 13, 2009

Taking the complexity out of reading a WI log file

Filed under: Reference Materials — shieldmaster @ 1:12 am

Taking the complexity out of reading a Windows installer Verbose log file

 

Recently a fellow MSI consultant - Mike Snodgrass of Snodgrass Engineering, (http://snodgrassengineering.com) sent me the “WiLogUtil” the MSI Log utility from the Windows SDK.  A great tool in helping to taking the complexity out of reading a very obscure log file.  Being a non-Code developer, I rarely take the time to scope out the SDK offerings – so thanks Chris!

 

I have been dissecting MSI Log files for quite a while, using them to debug if and when my Custom Actions fired and what the results were.  (Hint:  use a unique name prefix such as “ISI_CustomActionName” to both differentiate and allow you to find your Custom Actions easily).

 

wilogutil_ui1

 

 

The Analyze feature offers some good insight into the various client/server States with an excellent MSI Properties snapshot capability.

 

 

 

The selling feature in the MSI Log utility is the button “HTML Log” which will convert the log into color coded sections.  The legend is in the top menu – makes evaluation easier if you are new to the MSI Logs.

 

 wilogutil

 

 

Link

 

Here is a link within the MSDN site to the resource http://msdn.microsoft.com/en-us/library/aa372811.aspx – it allows you to reference directly the correct Windows Installer SDK.


There is a nice – but compact topic to reading the Log file available from the button

 

 

 

 

January 7, 2009

What a ride!

Filed under: Uncategorized — shieldmaster @ 12:48 am

Yes it has been quite a while since I last posted on the Blog - amazing to think that it was over a year ago. 

I started a new consulting opportunity in Roswell, GA.  They were in need of a InstallShield specialist to handle some problems with a IS v6.3 Object installation.  I took on the challenge and spent the next six months literally up to my ears in the installation – resolving problems they had with it.  I was able to slow down in early March – since I had pretty much had to give up golf when I took this job. 

Then my son’s wife delivered twins prematurely – almost two months! Now I never realized the focus on these two little babies (he was 4.5 lbs, she was 3.5 lbs) – feeding every 3 hours around the clock!  My wife and I took to spending the nights there separately and taking the overnight feedings as well as helping over the weekends.  We were pretty much exhausted as well.  Did not seem to let up for 5 months! 

Then the consulting opportunity ended when I was offered a full time position – which I was very honored to take.  I immediately was “drowned” in opportunity when I took on the challenge to rebuild the original installation using a newer Installshield – but convert to a Basic MSI project with InstallShield Custom Actions.  Over 35,000 lines of scripting and 27 InstallShield Objects to review and rebuild.  Again I became heads down with little time for anything else (no golf, no blogging, no life…).  Just work and babysitting babies (still a lot of fun – I can challenge anyone to a diapering contest!)

Now I still haven’t played a round of golf since October 2007, but I have a beautiful 25 month old granddaughter and her 8 month old baby sister and brother. So it has been a good trade-off. 

I will be including some pictures of them periodically.  When I started this blog, I wanted to keep it professional – just discuss InstallShield topics.  I will venture out of the area occasionally as time and opportunity permits.  Life has taken different directions!

Cheers!

August 15, 2007

Installing to PALM Devices using InstallShield MSI

Filed under: Palm Device, Techniques — shieldmaster @ 11:27 pm

I started a project to create a Basic MSI installation to deliver some client files on a workstation. Not a problem, but the kicker was that in addition, I needed to install a PALM .PRC to a PALM user, and then install a Conduit.

I spent dozens of hours researching this topic, using the Google message boards, and the PALM reference documentation. I have finally succeeded in accomplishing all of my objectives. The final objective was to put out on the Blog what needed to be done. Well here it is!

Note: I created a Basic MSI project using InstallShield X.5 with Custom Actions created using InstallScript – but all the steps could have been done in an earlier/later version, or an InstallScript version. In fact you will note that in one aspect using InstallScript may have been the better choice.

Step 1: Before User dialogs are presented

Determine if PALM Desktop is loaded – cancel install if not present

This Custom Action should be run before any Dialogs are presented; run CondMgr.dll with the function:

nError = CmGetHotSyncExecPath (szPath, p_nvSize);

RC = 0 means PALM Desktop was found and valid path returned, (along with HOTSYNC.exe appended…)

Parse the szPath to obtain just the path:

ParsePath ( gPALMHotSyncPath, szPath, PATH );

Note: Carry these DLLs in your SupportArea. For the first C.A., use the CondMgr.dll that you carry to determine the HotSync path. From that point on, always attempt to load the DLL from the HotSync path, if it fails, then use the one in your SupportArea.

The path is where the HotSync binaries will be found, and can be used in APP PATH registry to create a path to the HS Binaries for your application. All further UseDLL commands should attempt to use the DLL within this path first.

Note: Run C.A. as Immediate Action, but ensure C.A. is run at least once in either the UI or Execute sequence because install might be run silently and then dialogs won’t be presented.

Step 2: During or just before Dialogs are presented

If you have a .PRC file that needs to be installed to the PALM Desktop for synchronization to the PDA, you need to create Custom Actions that will:

Retrieve all users defined to PALM Desktop
Reject any Profiles
Create STRINGLIST or write temporary records to MSI database ListBox

This Custom Action will be running InstAide.dll to retrieve the users; unfortunately it doesn’t distinguish between PALM users or profiles.

To get the users defined to the PALM Desktop, first you need to obtain the total users:
nNumUsers = PltGetUserCount ();

The value in nNumUsers will be a total count of Users and Profiles defined. Create a loop to retrieve each user using a counter from 0 to (nNumUsers -1). For example, if nNumUsers = 12, the first counter will be 0, the final counter value will be 11.

nzUserNameSize = PltGetUser (nCounter, szUserName, p_nvSize);

Each call to the function PltGetUser will return the User/Profile name defined. Now you need to call the function PltIsUserProfile with the user name to determine whether it is a User name versus a Profile.
nResult = PltIsUserProfile(szUserName);

if (nResult = 0) then this user is a defined “User”

Once you have the PALM users, you have two options available with a MSI Basic* install.

First, you can create a STRINGLIST of all PALM Users and install the PRC file to all of the Users. This might be an option for when you may be running a Silent installation, where the user running the installation doesn’t have the ability to choose one user.

ListGetFirstString (gListUsers, svSelectedUser);
while (nResult != END_OF_LIST)
nError = PltInstallFile (svSelectedUser, szPLogAppFilePath);
if (nError = 0) then
….
else
szMsg = “ERROR! PALM HotSync would not install %s!\n” +
“Attempt to install this file for the selected User: %s ” +
“failed.\n\nPlease manually install this application onto the PDA”;
MessageBox (szMsg, WARNING);
endif;
ListGetNextString (gListUsers, svSelectedUser);
endwhile;

Second, you write each user to the LISTBOX table, using a temporary entry to the MSI database. These entries will then appear in the Dialog LISTBOX screen for the user to choose one entry. After the Dialogs have completed, you can retrieve the selected user from the property associated with the LISTBOX and install the PRC file to this user.

////////////////////////////////////////////////////////////////////////////////
// This script populates the LISTALLPALMUSERS control in the ISI_ListBox
// dialog with the current values from the STRINGLIST gListUsers
// The end user’s selection for the ListBox is stored in LISTALLPALMUSERS
//
////////////////////////////////////////////////////////////////////////////////

// open view into ListBox table
MsiDatabaseOpenView(ISMSI_HANDLE,
“SELECT * FROM `ListBox` WHERE `Property`=’LISTALLPALMUSERS’”,
hViewlist);
MsiViewExecute(hViewlist, NULL);

r = 0;

// Get the first string in the list.
nResult = ListGetFirstString (gListUsers, szUserName);

// Loop while list items continue to be retrieved.
while (nResult != END_OF_LIST)

nBuffer = 256; // set size buffer
MsiRecordGetString(hRecordprop, 1, szUserName, nBuffer);
nBuffer = 256; // reset size buffer
//MsiGetProperty(ISMSI_HANDLE, svPropname, svPropvalue, nBuffer);
r = r + 1;
hRecordlist = MsiCreateRecord(4);

MsiRecordSetString(hRecordlist, 1, “LISTALLPALMUSERS”);
MsiRecordSetInteger(hRecordlist, 2, r);
MsiRecordSetString(hRecordlist, 3, szUserName);
MsiRecordSetString(hRecordlist, 4, szUserName);

// can only temporarily modify running .msi database
MsiViewModify(hViewlist, MSIMODIFY_INSERT_TEMPORARY, hRecordlist);
// Get the next string in the list.
nResult = ListGetNextString (gListUsers, szUserName);
endwhile;

MsiViewClose(hViewlist);
MsiViewClose(hViewprop);

Note: Run C.A. as Immediate Action, but ensure C.A. is run at least once in either the UI or Execute sequence because install might be run silently and then dialogs won’t be presented.

palm-listbox.jpg

* MSI Basic – the ListBox has a severe Windows Installer limitation in that you can only select one entry from the ListBox. The Standard InstallScript project’s ListBox will allow multiple selections to be made… If this is critical it should be your guidance as to whether to create the project using InstallScript over Basic MSI.

Step 3: Install PRC file

Obtain PALM user selected for PRC Installation
Install PRC to selected PALM user using the InstAide.Dll

nError = PltInstallFile (svSelectedUser, szAppFilePath);

Step 4: Install Conduit file

• Install a Conduit (if required) using CondMgr.dll

nResult = CmInstallCreator( szConduitName, nzConduit_Application);

nResult = CmSetCreatorName( szConduitName, szConduitFileName);

There may be other items to be required to install the Conduit – determine what they are and pass them by the developers just in case…

Issue a restart to HotSync for it to recognize the installed PRC using HSAPI.dll

nError = HsSetAppStatus (HSRESTART, HSFLAG_NONE);

Note: Run C.A. as Deferred Action

Step 5: Uninstall Process

Remove the Conduit (if required) using CondMgr.dll

nResult = CmRemoveConduitByCreatorID( szConduitName);

July 16, 2007

MSI Tip: Writing to a MSI Log file from InstallScript Custom Action

Filed under: Reference Materials — shieldmaster @ 10:44 pm

Much has been written about logging to the MSI log, including new requirements levied by Windows Vista – custom actions should write startup and shutdown information.

InstallShield has created a TIP topic “MSI Tip: Writing to the Log File from a Custom Action” and discussed various methods available.

I have been using the MSI log for diagnostic analysis since DevStudio v9 – granted it has a complex structure, but with practice comes an easier ability to delve in the log to solve install issues. 

But what if many times, analysis could be done with a simpler install log?  I have found that the majority of problems can easily be identified if you log critical information into an install log, which is always created when your install kicks off.  Many times when your install is running onsite, they don’t have MSI Logging activated (see previous posting) – so a valuable technical tool has been lost. 

Even more valuable to the InstallShield Specialist is the ability to review an install log and verify that each Custom Action performed as expected – even if the install was successful you could have scripting errors that miss conditions critical to success.

Sample Install Log Output

ISI–> ***************************************************************
ISI–> ** LogFile Created by ABC Skeleton Package Install
ISI–> ** LogFile Created on 6-23-2007 at 12:59:43
ISI–> ***************************************************************
ISI–> INFO: Entering ISI_Fn_AppSearch Function
ISI–> ABC AppSearch – Must find the ABC ‘ABC_Skeleton’ application
with registry key file of ‘Motorola\ABC_Skeleton’
ISI–> ABC AppSearch – Found the ABC ‘ABC_Skeleton’ application with
registry key file of ‘Motorola\ABC_Skeleton’
ISI–> INFO: Entering ISI_Fn_SkeletonPreReq Function

ISI–> INFO: Entering ISI_Fn_CheckWin2003Svr Function
ISI–> Operating System is Windows 2003 Server Service pack installed
was ‘1′ which is approved!
ISI–> PASSED – Windows 2003 Server SP1 (or greater) was found! Passed Windows 2003 Server Check!
ISI–> INFO: Exiting ISI_Fn_CheckWin2003Svr Function

ISI–> INFO: Entering ISI_Fn_Verify_WSE_Installed Function
ISI–> Microsoft WSE ‘Microsoft.Web.Services3.dll’ will be searched in
directory or sub-directories
‘C:\Program Files\Microsoft WSE\v3.0′.
ISI–> PASSED – Microsoft WSE version 3.0.5305.0 was found installed! ISI–> INFO: Exiting ISI_Fn_Verify_WSE_Installed

ISI–> INFO: Entering ISI_Fn_RegToGAC Function
ISI–> INFO: Retrieved value of InstallDir, which was
‘C:\Program Files\Motorola\CSR\’ from registry using key of
‘SOFTWARE\Motorola\CSR_Framework’
ISI–> ERROR: Bad return code: ‘2′ from GAC Registration of file: ‘”C:\Program Files\ABC\CSR\ABC.Skeleton.Ajax.dll”‘
ISI–> ERROR: Bad return code: ‘2′ from GAC Registration of file: ‘”C:\Program Files\ABC\CSR\ABC.Skeleton.WebSpider.dll”‘
ISI–> ERROR: Bad return code: ‘2′ from GAC Registration of file: ‘”C:\Program Files\ABC\CSR\ABC.Skeleton.WSE.dll”‘
ISI–> INFO: Exiting ISI_Fn_RegToGAC Function

For Extra Credit! 

When you create the log entry for the Install Log, you can also trigger an entry into the MSI Log using the ‘SprintfMsiLog’ command.  That way the log comments are found in both locations!

Hope this helps!

Charles

p.s. if anyone wants some sample script that accomplishes this, please send an email to charles@installsolutionsinc.com and I will markup some script for you use!

Older Posts »

Blog at WordPress.com.