InstallShield Tips and Techniques

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!

July 14, 2007

Should you use CustomActionData?

Filed under: Reference Materials — shieldmaster @ 10:58 am
InstallShield 12 can be the bane of Deployment architects everywhere if there are existing MSI projects with InstallScript Custom Actions that need to be migrated to this new version!  All of their carefully worked Custom Action scripts created for earlier IS versions, will need to be re-evaluated after migrating to version 12.A severe problem that I have seen is that Custom Action written in InstallScript that are set to run Deferred will not have access to any MSI Property - there are very few exceptions, one MSI property accessable will be “CustomActionData”. So MSI Properties like “INSTALLDIR” and “PROGRAMFILES” are not accessible - no warning will be issues, just any attempt to retrieve data will result in a NULL value received.  Kind of destroys your script coding logic!

In my scripts, I tend to evaluate the workstation using InstallScript Custom Actions (Immediate Execution) and stash data in public MSI properties.  For example if I determine that Adobe Acrobat was installed, I store a boolean value (TRUE/FALSE) in an MSI Property, and the install path in another MSI Property.  Later when I want to launch the release notes, I have a InstallScript Custom Action set to Deferred to evaluate the MSI properties and take appropriate action.

With InstallShield 12 these InstallScript Custom Actions will no longer work correctly.  I will need to rework the Custom Action to store the data in the MSI Property CustomActionData.  Check out Christopher Painter’s blog notes on CustomActionData and its issues.  Normally the field would be used for a single value, but Christopher offers a technique to ’stuff’ multiple values in the field for retrieval. 

Technically a great solution, but hard to implement and a bear in long term maintenance.I feel that there is a better solution for modifying existing/legacy scripts, simply by using the registry as your sandbox.  For example, take a section of the HKLM\SOFTWARE, which is normally suggested that you place specs on your Company Name (see entries for Adobe).  Use it as a sandbox and stash installation variables gleaned during the UI Sequence and later retrieve them during the Install Execute sequence.   Here is an example of the technique that I use:

Prime RegistryJust after the dialogs have completed create a InstallScript Custom Action that will allow you to gather up all of your special MSI Properties that were initialized during previous CA’s and write them to the registry.  Here is a script extract:

RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE ); 
szRegKey = “SOFTWARE\\Install Solutions\\Framework”; 
nvType = REGDB_STRING;

szRegSubKey =   “InstallDir”;
szProgramFilesDir = INSTALLDIR;
nResult = RegDBSetKeyValueEx(szRegKey, szRegSubKey, nvType, szInstallDir,-1);
if (nResult < 0 )then
   szBuffer = “ISI–>  ERROR - szInstallDir Directory” + could not be updated in registry:  ‘%s’” ;
 Sprintf (szLogMessage, szBuffer, szRegKey);
 ISI_Fn_WriteLogFile (szLogMessage);      
else
 szBuffer = “ISI–>  INFO - szInstallDir Directory location ‘%s’ updated in registry: ‘%s’ with key of ‘%s’ “;
 Sprintf (szLogMessage, szBuffer, szInstallDir, szRegKey, szRegSubKey);
 ISI_Fn_WriteLogFile (szLogMessage);      
endif;   
RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE ); 
szRegKey = “SOFTWARE\\Install Solutions\\Framework”; 
nvType = REGDB_STRING;

// Obtain MSI Property for CustomerName and update Registry
nBuffSize = 256;
szMSIProperty = “ISI_CUSTNAME”;
szRegSubKey   = “CustomerName”;
  MsiGetProperty (ISMSI_HANDLE, szMSIProperty, svValue, nBuffSize);
  //Update the CustomerName Key.
  nResult = RegDBSetKeyValueEx(szRegKey, szRegSubKey, nvType, svValue, -1);
 if (nResult < 0 )then
   szBuffer=”ISI–>  ERROR-MSI Property ‘%s’ could not be updated in registry:  ‘%s’” ;
  Sprintf (szLogMessage, szBuffer, szMSIProperty, szRegKey);
  ISI_Fn_WriteLogFile (szLogMessage);      
 else
  szBuffer=”ISI–>INFO-MSI Property ‘%s’ updated in registry: ‘%s’ w/value of ‘%s’ “;
  Sprintf (szLogMessage, szBuffer, szMSIProperty, szRegKey, svValue);
  ISI_Fn_WriteLogFile (szLogMessage);      
 endif;   

Retrieve Registry ValuesIn each InstallScript Custom Action, simply add this script at the beginning to retrieve the values from the registry and store them into variables.  It should flow seamlessly into your existing script - here is some sample script that I use:

nvSize=256;  

RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE); 

szKey=”SOFTWARE\\Install Solutions\\Framework”;nType=REGDB_STRING;  

//Get the InstallDir Key.

RegDBGetKeyValueEx(szKey,”InstallDir”, nType, svInstallDir, nvSize);     

szBuffer = “Retrieved from registry key ‘%s’ the InstallDir key which was ‘%s’ “;      Sprintf (szLogMessage, szBuffer, szKey, svInstallDir );     

ISI_Fn_WriteLogFile (szLogMessage);               

//Get the Customer Name.RegDBGetKeyValueEx(szKey,”ISI_CustName”,nType,szCustName,nvSize);     

szBuffer=”Retrieved from registry key ‘%s’ the ISI_CustName key which was ‘%s’ “;     

Sprintf (szLogMessage, szBuffer, szKey, szCustName );     

ISI_Fn_WriteLogFile (szLogMessage);    

After the install has been completed, should the install variables placed in the registry be deleted?  Not necessarily, it could have use in the uninstall process.  But remember to delete them when the uninstall has completed. 

Hope this helps! 

Charles  

Enable MSI logging

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

The use of the MSI log cannot be underestimated in its ability to resolve technical issues.  It can be complicated to review the contents, so much so there are tools available to assist you.  

But first you must ensure that a MSI log is generated for your installs - here is the best method  to have one generated each time your install is run.  Add this registry entry to the workstation/server:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Installer]
“Logging”=”voicewarmer”

Hint:  take the above text and save as “MSILogging.reg” and then double-click it.

Now whenever a MSI install is run - even if you perform a Modify/Repair/Remove from the Add/Remove Program Control Panel, a verbose MSI log is generated.  The log is created in the Windows Temp directory (use %TEMP% in the Start | Run dialog box to access).  Look for a recent file named MSI9999.log (where 9999 is a random number).

This is much easier to accomplish instead of creating the complex batch statement to create a MSI log during execution.

Charles

July 8, 2007

Soliciting suggestions!

Filed under: Uncategorized — shieldmaster @ 11:32 pm

I have just a few ideas for tips and techniques remaining that I will be posting soon. 

If anyone has a special request for something that I may be able to assist - please just add a comment and request it.

Best Regards

Charles

July 6, 2007

Creating Common Scripts for InstallShield projects

Filed under: Techniques — shieldmaster @ 12:30 am

Let’s talk about creating common scripts for InstallShield projects.  EVERYBODY creates script functions in the same directory as the Setup.RUL - but when you have multiple projects that use the same script functions, then the replication will cause code regression issues.  For example:

I have 9 active InstallShield projects, everyone of them uses the same script function “Adobe.rul”.  This script function is run as a Custom Action and will look to see if Adobe is installed.  If installed, it will verify the specific version of Adobe installed - our documentation uses features that won’t work for anything prior to version 6.0 of Adobe Reader.  The script did other things, like snare the installdir value for the launching of the ReadMe at the end - it also hid the checkbox/text field if they did not have Adobe, and elected not to install it. 

So I found myself with 9 copies of the same RUL file in 9 locations.  Obviously I would encounter a logic bug!  I found out later that I only corrected the logic bug in 7 of the 9 copies!  After the release, I was determine to come up with a better solution.

Common Scripts

I wanted to store the Adobe.RUL script function only once and reference it with all of the projects.  The critical thing is that I wanted to have access to the script function in the InstallShield IDE - which is what was a really issue to contend with! 

I ended up creating a directory “Common Scripts” under my InstallShield Reference directory - and stored all of the common scripts there.  I defined common script to the extreme - every script function would be stored there, the only exception was the Setup.RUL would be stored with the InstallShield project.

I did create a naming standard - to differenciate between the scripts used for any project versus the scripts that were specific to one project.  For example:

  • ISI_Adobe.RUL
  • ISI_Engine_RegFiles.RUL
  • ISI_Fn_RegFiles.RUL

My naming standard added Fn to indicate a that the script was called by another script function, such as the Custom Action called “ISI_Engine_RegFiles”, which registered certain Engine files by calling the routine “ISI_Fn_RegFiles” which had the generic registering script.  Another Custom Action called “ISI_Adobe” which performed the script as described above. 

Usage in InstallShield Project 

There is no difference in the usage of the Prototype statements:

export prototype ISI_Adobe(HWND);
export prototype ISI_Engine_RegFiles(HWND);
prototype ISI_Fn_RegFiles (BOOL, STRING, STRING, BOOL);

There is a difference in how you include the external script file for compiling:

#include “..\..\..\Reference Files\CommonScripts\ISI_Adobe.rul”
#include “..\..\..\Reference Files\CommonScripts\ISI_Engine_RegFiles.rul”
#include “..\..\..\Reference Files\CommonScripts\ISI_Fn_RegFiles.rul”

Notice that I used the relative DOS Path reference to locate the script functions - critical difference is that I need to offset from the location of the Setup.RUL - not the .ISM file.  (See earlier post for how to accomplish this).

Finally - if you want to see the script file in your IDE, you need to right-click on the Setup.rul and select “Insert Script files”, and navigate to the Common Scripts directory and select the ”.RUL” to add.  Now the script will appear exactly like any normal included script for viewing and editing by the IDE.

Issues 

Of course there will be issues!  Biggest one is that when the InstallShield project is open, and you made edits to the scripts then when you compile the scripts are rewritten back into the Common Files directory.  Not a big deal - but if you have two project open at once, then when you compile the second project - it will overwrite the changes you just did in the first project.   Apparently a copy is stored in memory and will refresh/rewrite the scripts back. 

So open and change only one at at time.  NEVER open a project and then use another editor to quickly apply a change to the common script.  Again it will be overwritten!

Hope this helps!

CharlesInstallShield Tips and Techniques
InstallShield Consulting
InstallShield Tips and Techniques
InstallShield Consulting
InstallShield Tips and Techniques
InstallShield Consulting
InstallShield Tips and Techniques
InstallShield Consulting
InstallShield Tips and Techniques
InstallShield Consulting

July 3, 2007

Make an MSI run multiple times

Filed under: Techniques — shieldmaster @ 11:55 pm

One of the options that was available to you with installations prior to Windows Installer emergence was the ability to rerun an installation multiple times.  By this I mean running the setup again without entering Maintenance Mode - as if it had never been run before.

You can still use InstallShield to create an InstallScript using the  option and then select the Multi-Instance option which lets your end users rerun an installation multiple times as a first-time installation rather than as a maintenance installation. 

But as you know, I studiously avoid InstallScript projects - I use Basic MSI Projects, so how do you make a Basic MSI Project eligible to be rerun?

Look at this dialog extract from the Sequences Table for the Install Execute Sequence:

 rerun.jpg

Note that there are four Standard MSI actions that are the primary method by which the MSI Application is registered under the Windows Installer that we need to be concerned with: 

  • RegisterUser
  • RegisterProduct
  • PublishFeatures
  • PublishProduct

Alter the condition on each of these Standard Actions to use zero - which means the condition will never be set true and the Standard Action will never run.  I recommend you alter the comment to reflect the change - as I have shown above.

Impact

The usage of this technique means the product will not be registered under Windows Installer - nor will it appear in the Add/Remove Programs Control Panel.   Use only if you have a specific requirement!

Usage Scenarios

I have encountered two separate situation where this technique served admirably.  

Once a vendor was creating unique sales video/slideshow presentations to sell to his customers.  After a few customers used his services, he encountered a situation where the same end-client was attempting to install the presentations from two of his customers.  The dreaded Maintenance mode was disrupting the end-client from installing the second presentation.   I was able to make the install rerunable - and used a scripted Custom Action to read a special file delivered with each presentation.  This information allowed me to install the unique files, create shortcuts to access the presentation and create a uninstall technique to allow the end-user to remove the files when no longer required.

Another vendor needed to be able to allow an unlimited amount of customers to be established on the server.  Each customer would have a unique IIS Virtual Directory with the same files installed.  XML documents that were specially configured during the install would maintain the customer data within the Virtual Directory.  A very complex Visual Studio .NET solution was involved to support the customer processes.  Each customer install used a rerunable Basic MSI Webproject to deliver the files and create the Virtual Directory.

Warning!

I don’t recommend you do this to simply to avoid the Maintenance Mode!  A great technique if you have a specific requirement - but you will lose so much functionality that Windows Installer/MSI packages offer.
Charles

June 26, 2007

Dress up the dialogs with customized bitmaps

Filed under: Dialogs — shieldmaster @ 12:05 am

I absolute detest the generic bitmaps that InstallShield provides with the dialog screens.  For a market leading product - why are the bitmaps so kindergarden looking? 

There are two distinct types of bitmaps used with the product line:  the dialog bitmap and the banner bitmap.  The dialog bitmap is used on the “exterior” dialogs, typically the Welcome and Summary - but is also found on the Maintenance dialog screen.  Here is a sample image:

exterior_bitmap_orig.jpg

 There is another bitmap used as the banner on all of the interior screens, here is a sample image:

 interior_bitmap_orig.jpg

There is a lengthly document that has been posted on the InstallShield Tips and Tricks webpage

http://www.installshield.com/news/newsletter/details.asp?source=isd 

Here is the specific link to the article: 

http://www.installshield.com/news/newsletter/0301-articles/DialogBitmaps.asp

Unfortunately it is very confusing to read, so I will attempt to boil the process down to the essentials.

How to change all Exterior Bitmaps

Navigate to the Direct Editor and look at the contents of the binary table - here is a sample:

directeditor_binary.jpg

Look for any entry that has “ISDialogBitmap.ibd”  - which is the bitmap used in the InstallShield exterior dialogs (they use the legacy extension “.IBD” instead of “.BMP”.  If you replace the path entry with a path to your customized bitmaps they will appear in all of the exterior bitmaps.

How to change all Interior Bitmaps

Look for any entry that has “ISDialogBanner.ibd”  - which is the bitmap used in the InstallShield interior dialogs (they use the legacy extension “.IBD” instead of “.BMP”.  If you replace the path entry with a path to your customized bitmaps they will appear in all of the interior bitmaps.

Bitmaps specifics

I recommend that you take a copy of the “ISDialogBitmap.ibd” and “ISDialogBanner.ibd” bitmaps (rename them to .BMP) and have the Graphics group get the specifics on the attributes.  Note that on the bitmap for the exterior dialogs, the image can only be on the left side of the bitmap.  Everything in white will be transparent in the dialog and all of your text will be superimposed.

Here is the location for these default bitmaps on a InstallShield v11.0 project:

C:\Program Files\InstallShield 11\Redist\Language Independent\OS Independent

Customized Bitmap Storage

If you read my post on “Path Variables and Project Organization” then you realize the best approach would be to store the bitmaps in a location that any InstallShield project can access.

I typically create a storage location and place all components used accross multiple InstallShield projects.  Here is a sample structure of reference files stored along side the InstallShield projects. 

ref_directory.jpg

I can store the customized bitmaps in this location:

C:\Project Source\Reference Files\Bitmaps\Dialog Bitmaps

 If I use the technique discussed about Path Variables, then I would add a new Path Variable to the project “PATH_TO_DIALOG_BITMAPS” and create a path reference such as:

<ISProjectFolder>..\..\..\..\Reference Files\Bitmaps\Dialog Bitmaps

Then within the Direct Editor, I would simply alter the source path to reflect this:

 directeditor_binary2.jpg

Imported Dialogs

Doesn’t seem to be on topic, but guess what happens if you export one of your dialogs that has a customized bitmap?  Turns out when you import the dialog into another InstallShield project, you will see a strange file “InteriorBin1″ littered somewhere in your project structure.  This is the way InstallShield attempts to handle the customized interior bitmap.  Don’t believe me - just take the file and add the .BMP extension and open it with Paint.  If you want to get rid of it, simply go back into the Direct Editor and alter the path reference for this to be your customized interior banner bitmap and rebuild.

Hope this helps!

Charles

June 21, 2007

Path Variables and Project Organization

Filed under: Reference Materials — shieldmaster @ 9:23 pm

Did you ever open a project and find that various components (binary files, .RUL, etc. ) were missing? 

Typically you will discover that the last person who maintained the InstallShield project did not take care of organizing the project carefully - letting components be littered accross the network. 

For example, here is a image of a complex project with files being pulled from who knows where…

pathvariables_1.jpg

With files being pulled from such a myriad of locations, it is bound to lose some over time. 

 Solution - Organize and use Path Variables correctly.  Let’s first discuss how best to organize your project files. 

 Project Files Organization

 Look at how I organize a typical project

projectdirectory_1.jpg

Under the Project directory will be the InstallShield .ISM project, with all supporting files found within the store directory. 

If you have full control of the source staging, then stash it under the Source directory.  Typically the source will be staged in a specific directory after a build process.   Ensure all components are placed within the Source Management repository for ensuring the ability to rebuild the project for future upgrades.

But what happens if the next person places the project structure on a different drive? Or a different directory structure?  If you utilize Path Variables correctly, then you can shift the project around and never encounter a problem when you go to rebuild the project.

Path Variables 

When you look in the InstallShield project at the Path Variables panel, notice that you have a constant reference point.  That is where the project .ISM resides - which is referenced by the Path Variable <ISProjectFolder>.  No matter where the project structure is placed (on a network or buried in sub-directories), if you set your Path variables up to have a reference to the ISProjectFolder then any file can be found.

The easiest method to determine this is to count the directory up from the project .ISM file.  For example, for the bitmaps used as replacements for the basic interior/exterior dialogs, they exist in the sub-directory “..\TestProject\packages\store\Bitmaps_Icons\Dialog Bitmaps”.  To reference them I will need to go up one directory from the .ISM, and then drive down into the “store” sub-directory until we get to the dialogs.   Bottom line, the path reference would be:

<ISProjectFolder>..\store\Bitmaps_Icons\Dialog Bitmaps

Now look how the other path variables can be resolved to reference everything else in the projct structure:

pathvariables_2.jpg

Well, I hope this helps you to organize your project files so that when you get to pass on a project for maintenance, the next guy can find everything - right where you left it.

Charles
InstallShield Tips and Techniques
InstallShield Consulting
InstallShield Tips and Techniques
InstallShield Consulting

June 18, 2007

Top 10 Issues in InstallShield that will bite you!

Filed under: Reference Materials — shieldmaster @ 9:17 pm
  1. Never use Dynamic File linking.  Never, NEVER!  Causes severe problems when attempting Upgrades/Patches.  More posts have been written on how to work around issues caused by this. 
  2. When creating Custom Actions, always name it unique (i.e, ISI_StopServices, ISI_ModifyRegistry) – this will assist you in quickly determining if the C.A. was successful within the MSI logging.  
  3. When referring to the same file numerous times (for example a specific version of a Release Notes) try to make a string value and reference the string value (@Release_Notes).  This will prevent having to locate each and every occurrence when the name changes.
  4. Caution when using SQL within project – default will attempt to uninstall scripts at application removal, which will destroy customer data.  Always leave database data populated - let the DBA handle deletion. 
  5. Issues with XML within project working – most Developers cannot get it working correctly – check the message boards.  If you use XML query to grab values during a AppSearch, expect excessive time delay. 
  6. Have staging for binaries separate from the compile output directories to ensure only specific items are handled within project.  This will ensure that when a build process fails, the last good compile is not incorrectly incorporated into the InstallShield CAB files.
  7. COM Extraction
    1. Concept works most of the time – but must guard against developer hard include of ATL code, and situations which end up having the developer workstation machineIDs incorporated into web server configs.
    2. Never run COM Extract at build time – extract and verify and freeze.  Granted, this runs the risk of developers adding functionality without notifying IS Developer who will need to extract COM again. But when they do this, you may encounter possibly new Microsoft Redistributables need to be included as well. 
    3. Personnally I recommend never do COM extraction.  Use scripting instead to register/unregister all files for ease in specifying sequence.  Yes, you could use properties to select registration – but then need to use DirectEdit on the ISSelfReg table to specify sequence – which applies to both install and uninstall.  Think of long term maintenance aspects - Keep It Simple, Simpleton! NT Services
    1. Again the issues with COM Extract has caused me serious problems with hard includes of ATL code
    2. I cannot easily specify which other Services to stop/start in specific order when I have more than one service – consequently I use scripting to Stop/Start the services when required
    3. I use scripting to create the services and then unregister the service on uninstall.  
  8. Windows Installer “Repair” capability has issues.  Although typically the restoration of a DLL/Executable has been flawless (when used with Static File Linking), the Repair process also will drive in the InstallShield project registry.  In my situation, the registry template carried in the IS Project will have properties (Version, INSTALLDIR, [PropertyValue]) that are reflected within the project registry - I also take customer input from the dialogs and translate that into fields to update the registry after it has been applied to the workstation.  Since the “Repair” process does not present dialogs - so it doesn’t resolve the property values – the resulting registry is essentially corrupt because of missing values.  To resolve, I have created Custom Actions that run before a “Repair” to archive the registry to a file, and another Custom Action that runs after the “Repair” to delete the registry and restore from the archived file. 
  9. InstallShield version 12 has been radically restructured and you may encounter serious issues within your project’s scripts when you upgrade. For example there are the issues that I have encountered:
    1. Global variables will no longer pass information to scripts – but no message is given, either during compile or execution – just blank values received.
    2. Within the “Execution Sequence”, the ability to extract values from predefined directories (INSTALLDIR, SETUPEXEDIR, PROGRAMFILES) will no longer work.  Again, no message is given, either during compile or execution – just blank values received. 
    3. Within the “Execution Sequence”, the ability to extract values from MSI Properties that were defined during the “UI Sequence” will no longer work. Again, no message is given, either during compile or execution – just blank values received. 
    4. Conceptually, the use of the MSI Property “CustomActionData” is allowed – but severe gyrations required to pass multi-value string into the MSI Property during the “UI Sequence” for retrieval during the “Execution Sequence”.  I ended up writing all of the values needed in the “Execution Sequence” to a registry while they are accessible during the “UI Sequence”.  Then during the “Execution Sequence” when I need a value (i.e,., INSTALLDIR), I extract the values from the registry. 

InstallShield Tips and Techniques
InstallShield Consulting
InstallShield Tips and Techniques
InstallShield Consulting

Older Posts »

Blog at WordPress.com.