Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Tools

Examining the InstallShield SDK Edition


September 1996: Examining Room

Don't underestimate the installation process

Joe works for IBM Software Solutions in Research Triangle Park, NC, although he currently lives in Warsaw, Poland. He can be contacted at [email protected] or 102344,[email protected].


Diligent programmers spend hours or days manipulating user interfaces to get them exactly right. After all, if the UI doesn't look professional or is hard to manipulate, users will find another application with similar functionality. Still, a user's first impression of your application comes with the installation process, not the UI.

Unfortunately, even commercial applications often have insufficient or unusable installation routines. We've all seen commercial Windows applications that use DOS batch-file installs (or no install at all), leaving it up to users to copy one or more diskettes to a hard drive, install program icons, and so forth-all from a command prompt. Clearly, a standardized installation process is an asset to any application. In this article, I'll present such a process that uses InstallShield SDK Edition (SE), an integrated installation/distribution program included with Microsoft Visual C++ 4.1.

InstallShield SE, which is located in the ISHIELD directory of Visual C++ 4.1 or MSDN 2 Win32 SDK CD-ROM, is a customized subset of the standalone InstallShield3. VC++ 4.1 also includes InstallShield Express, a customized 32-bit visual-installation system that's a subset of InstallShield Express Professional (also a stand-alone tool). Customized versions of InstallShield Express are also shipped with Visual Basic 4.1, Borland's C++ 5.0, Delphi 2.0, Paradox 7.0, and Powersoft's Optima++.

While I'll use VC++ and the version of InstallShield SE shipped on the January 1996 MSDN 2/3 Win32 SDK CD-ROM, the methodology I describe can be implemented with virtually any development environment and installation/distribution system. For the purpose of illustration, I'll discuss the design and creation of the installation scripts and diskette for a tool called "WinDebug32," which uses Win32 debug APIs to debug Windows applications. WinDebug32 (available electronically;) ships with a readme file and sample app named "DeadMan32." (WinDebug32 itself will be discussed in a future DDJ article.) This installation script (also available electronically) was developed under Windows NT 3.51, although I've done some testing under Windows 95.

The Registry

The Registry is a collection of keys and values stored in a Win32 hierarchical database. Many of the values stored in the Registry, such as application paths, application state information such as user preferences, and so forth previously would have been stored in an .INI file or one of the DOS configuration files (config.sys or autoexec.bat) under 16-bit Windows. The Registry is viewed and accessed as a single database. The number, names, and locations of registry files may differ depending on your version of Windows. These registry files are not editable directly; you need a Registry editor (such as REGEDT32.EXE). Be sure to make backup copies before attempting to edit them (corrupting these files can make your Windows system unbootable). Since Registry information is extremely important for installation and deinstallation using InstallShield, I'll describe the basic setup and use of the Registry.

The key hierarchy in the Registry forms a path (from a root key to a subkey) that allows access to information stored in the Registry. Unlike in the file-system hierarchy, the Registry key hierarchy contains six default keys that can be viewed as application entry points into the Registry.

Each key in the Registry has a name and a default value. Other name/value combinations can also be added. My copy of VC++, for example, installs lists of most recently used files and projects in the registry under HKEY_CURRENT_USER\Software\Microsoft\Developer\Recent File List\.

File1:REG_SZ:C:\MSDEV\PROJECTS\

MYPROJ\MYPROJ.CPP FileCount:REG_DWORD:0x02. HKEY_CURRENT_USER is the root key through which you access this information. Software, Microsoft, Developer, and Recent File List are subkeys. I've listed two of the value entries for the aforementioned key here: the value name File1, which is of data type string and contains the value c:\msdev\projects\myproj\myproj.cpp; and the value name FileCount, which is of type dword and contains the numeric value 2. The information found in the HKEY_CURRENT_USER section of the Registry always takes precedence over that found in HKEY_LOCAL_MACHINE.

Microsoft recommends that applications store generic information under the HKEY_LOCAL_MACHINE. Information specific to a user (such as the Recent File List) should be stored under HKEY_CURRENT_USER (which is actually a subset of HKEY_USERS). In either case, information should be stored under the subkey path \software\COMPANYNAME\PRODUCTNAME\RELEASE.

HKEY_CLASSES_ROOT is the root key used to store application icon information, application file extensions, icon commands (pop-up menu commands), and so forth. This key points to HKEY_LOCAL_MACHINE\Software\Classes.

HKEY_CURRENT_CONFIG and HKEY_DYN_DATA root keys are used to access hardware-specific information and point to subsets of the HKEY_LOCAL_MACHINE root key. HKEY_CURRENT_CONFIG points to HKEY_LOCAL_MACHINE\CONFIG. HKEY_DYN_DATA is cached while Windows is actually running to permit extremely fast access to hardware state information.

Win32 applications should use the Registry for storing information. Microsoft states that .INI files should only be used if application state data in the Registry would exceed 1000 bytes.

Designing the Installation Process

Before writing your first installation script, you need to identify what files to install, where to install them, and how your install will differ from the standard install. Once you've written the installation script, you'll build images of the installation disks and test your installation. This process is iterative. When you are satisfied that the installation process is working as required, your last set of installation disks become the "Golden Master" diskettes for a given release.

The files you install might include those from your build process (help files and executables), text files (such as a readme file), executables (a tutorial program, compiler libraries or other redistributables), image or graphic files (bitmaps or document files saved in nontext formats), or other specialized files. In the WinDebug32 scenario, you'll need to install three files-a readme file from the build directory and two executables (windebug32.exe and deadman32.exe) from the build\exe directory. At this stage, you do not include files that you'll ship that are not part of the application, such as setup.exe.

Next, you must decide where each file from your first stage will be installed in your application subdirectory on the target machine. For example, you might have program files in the application subdirectory itself. If you share DLLs between a number of apps, you might place them in a directory common to all apps, not in every individual application directory. This means that installations after the first app take up less space (as multiple copies of the shared libraries aren't installed). A common directory also permits you to upgrade common code for multiple applications with a single product installation.

If the software includes samples, you might place them in a subdirectory off of your application directory. If your application includes online documentation, you might include that in a separate subdirectory. If you ship both retail and debug versions (for developers), you might place each in its own directory. Careful use of a subdirectory structure helps users find their way around your installed application files. Create too many subdirectories, however, and you've complicated things. Also remember not to install your application files to the root (or top-level) directory due to limitations in the number of files that can be placed here.

Keep in mind that certain pieces of your app may need to be installed in a particular directory for reasons unrelated to the application itself. For example, library files should be installed so that they are accessible to Windows during program execution. Refer to the Win32 SDK documentation for information on where Windows will look for these types of files. For small applications, installing everything to a single directory is probably an acceptable solution. In the WinDebug32 scenario, I'll place all files in a single subdirectory on the user machine during installation.

In the next stage of the installation process, decide what installation options users should have. A standard install might include a typical install for nontechnical users. This installs all pieces of the application needed by most users. This guarantees a working system (barring installation failure of some kind).

Compact installs are for users with little room on the installation machine. Laptops, with small hard drives and little space for apps, often require this type of installation. As before, users do not need to select which pieces of the application should be installed, and (barring installation failure) are guaranteed a working system.

Custom installs are for advanced users. Depending on the installation options you permit users to choose and which options the user selects, the installation may not result in a working system. You should give users as many options as possible, grouping related files into a single check box. If sample files are included, for example, you might install all of them if the sample check box is checked, and none if it is not.

Remember to let users know which files are required for a working system. They may elect not to install them at their own risk. For example, they may elect not to install shared library files if they know that these files are already installed on their system by another app in the product suite. At this stage of the installation process, consider which (if any) parts of your application can be considered optional and if there are any prerequisites to installation (required operating systems, video drivers, and so forth) that users will need to check for.

In the WinDebug32 scenario, I use all three installation scenarios. A typical install includes the readme, windebug32.exe, and tester application. A compact install includes only the readme and windebug32.exe. A custom install lets users choose windebug32.exe with readme (the program selection) and/or the debugging tool.

In the fourth stage of the installation process, you design installation UI objects-the dialogs and message boxes presented to users during installation. If your app requires Windows NT (perhaps your application uses OpenGL, for example, which is not currently supported under the current release of Windows 95 or Win32s), you need to design a dialog informing users of the operating system incompatibility if they attempt to install your software on Windows 95 or Win32s.

These dialogs and message boxes should be rough drafts. You use them to select similar dialog boxes from the support within InstallShield SE. Only a limited number of dialogs are available in InstallShield SE, and user-defined dialog routines are not permitted; the MessageBox() routine documents only INFORMATION, SEVERE, and WARNING styles, but SDK styles may also be used.

Even in the SDK version, the InstallShield dialog routines included are powerful:

  • AskDestPath() can display a dialog box that asks users to select a path, which could be used to set the destination path of your app.
  • AskOptions() can display a dialog box containing radio buttons or check boxes that users can select from. A dialog with check boxes can implement the custom- installation option described earlier.
  • AskText() can display a dialog that requests a single line of text from users. This dialog might be used to request users to enter their name or company's name during installation.
  • AskYesNo() can display a dialog that asks a single yes/no question. For example, if users cancel installation before completion, this function can confirm that they want to exit the install process.
  • MessageBox() can display a modal dialog box (one that requires immediate user interaction). This routine only supports message boxes of type MB_OK, unlike the SDK function of the same name. You might use this function to warn users that installation was unsuccessful due to an error.
  • SelectFolder() can display a dialog requesting that users choose a folder (program group under WinNT 3.x), either by selecting a preexisting folder or creating a new one. You might use this function to select the folder in which application icons should be created.
  • SetDialogTitle() changes the default title for dialogs of a given type. It should be called before requesting the dialog function whose default title you wish to change. This function call affects all future function calls of this type during the current installation.
  • SetupType() creates the setup options dialog (containing Typical, Compact, and Custom selections).
  • Welcome() creates a standard splash screen/welcome dialog at the beginning of installation.
The WinDebug32 scenario uses a variety of these functions to create its UI.

At the fifth stage of the installation process, you develop your setup script's flow of execution using InstallScript, the InstallShield programming language. (Install scripts are simple text files that commonly have an .RUL extension. InstallScript is a Basic-like, case-sensitive language. A basic description of InstallScript is available electronically.) Your script should also set registry variables relative to your installed software. To properly set up application-registry variables using InstallShield, you must call both the InstallationInfo() and the DeinstallStart() APIs before manipulating the Registry.

Win32 applications should store program variables only in the Registry; Windows .INI files and functions should not be used. You can view the contents of your Registry using the REGEDT32 program that comes with WinNT. The main installation script of an application script normally is called "setup.rul."

The following pseudocode is a brief description of the install script used in the WinDebug32 scenario. The prefix User: indicates a section of the script that requires user response.

1.Initialize global variables.

2.Initialize InstallShield (via InstallInfo()).

3.User: Display welcome window.

4.Check user hardware.

5.User: Ask where to install to.

6.User: Get type of install (typical, compact, or custom).

7.Check user available space.

8.User: Ask what folder or group to create for the program.

9.Initialize InstallShield undelete processing (via DeinstallStart()).

10.Set basic Registry keys and values.

11.Define file set for file transfer to user system.

12.Execute file set.

13.Final registry updates.

14.Update shell (create program group).

15.User: Tell user that the install is done.

The pseudocode is not entirely accurate because the installation process is not always sequential. Users may move backward to previously seen dialogs or abort the installation process entirely, which is not shown in the pseudocode.

At the sixth stage of the installation process, you create the installation diskettes for installing the software for testing. To begin, you'll need to create the subdirectory structure from which you'll build your product. For this discussion, assume that the files are stored under a top-level \install subdirectory. In the WinDebug32 scenario, I use the subdirectories build, tools, disk1, disk2, and setup.

build. This directory is where application files are copied: The readme file is in the build directory itself, and the program files are in the .exe subdirectory directly beneath it. This subdirectory structure is a convenience during installation-disk creation and has no relationship to the directory structure you'll use during installation.

setup. This directory is where you maintain the application setup scripts and other installation data files. It includes setup.rul (the source for our installation script) and setup.lst (the source for our setup package file). The object files setup.ins (the compiled form of setup.rul) and setup.pkg (the compiled form of setup.lst) will also be built in this directory.

The package file is used to tell InstallShield which installation disk contains a particular file needed during installation. This file is required if your installation script uses file sets.

tools. This directory contains those InstallShield binaries for building and installing the app. Some files will be copied to disk by an installation disk, and some are used only to build installation object (binary) files. My directory contains:

    compile.exe // build only

    icomp.exe // build only

    packlist.exe // build only

    setup.exe // install only

    _setup.lib // install only

    _setup.dll // install only

    split.exe // build only

    uninst.exe // install only

These files are InstallShield SE executables, so they are not available online. Copy them from the InstallShield binaries directory (normally\ishield\program) into your TOOLS directory before building.

The Compressed File

In the WinDebug32 scenario, I use a single compressed file, windeb32.z, to store all application files. This file is created by the ICOMP command, which compresses, uncompresses, and examines compressed files. I compress all files in the build directory and all subdirectories into the \install\windeb32.z file with the command ICOMP-i build\*.* windeb32.z.

Splitting the Compress File

The InstallShield binaries used during install (setup.exe, _setup.dll, _setup.lib, and uninst.exe) are about 700 KB in size. Since all of these files need to be found on disk1, only about 700 KB are left on a 1.44-MB diskette. While the WinDebug32.z compressed file is small enough to fit on this disk too, you might need to use the split tool to split your compressed file into diskette-sized pieces. Assuming that you had only 700 KB of free space on disk1 and want to install from 1.44-MB diskettes, you would use the command split.exe -f1370 -d1@700 YourCompressedFile.z. This creates YourCompressedFile.1 ... YourCompressedFile.n data files, where n is the total number of diskettes needed for that particular compressed file. (Your installation may or may not have more than one compressed file, so these numbers may or may not translate to the number of the installation diskettes that will contain them.)

The Package File

The package file contains a list of all the non-InstallShield files used during installation and tells InstallShield on which installation diskette they will be found. In the WinDebug32 scenario, the install directory (the parent directory of SETUP) contains the main compression file (windeb32.z), so the source package file in the setup directory contains the lines:

1;

..\windebug32.z

2;

..\windebug32.z

This package file states that disk1 will contain files from the windeb32.z compression file, and disk2 will contain files from the same compression file. You give a relative path to the compression file, which is in the parent directory of the directory containing the setup.lst file. (This source package file assumes that WinDeb32.z is oversized for our installation media and was split into two files.) A package file always contains the original (unsplit) version of the compressed file name.

If your installation contains more than one diskette, each diskette must contain a diskN.id file, where N is the sequential number of the installation diskette. Each id file should be copied to the given diskN directory under the install directory. The id files shipped with the InstallShield sample app contain three bytes-a carriage return/line feed, and EOF character. These files are used during file-set processing to identify the diskette actually inserted by users.

Creating Diskette Images

After using ICOMP.EXE to create your compressed file(s), COMPILE.EXE to create your setup.ins file, and PACKLIST.EXE to create your setup.pkg file, you'll copy the output of these commands to the appropriate diskette subdirectories. In the WinDebug32 scenario, all of these files are copied to the disk1 directory, which contains the following:

setup.exe

_setup.dll

_setup.lib

uninst.exe

windeb32.z

setup.ins

setup.pkg

You can modify the included build.cmd file, which automates much of the

installation-disk creation process. This is a Windows NT batch file (change the name to build.bat under Win95). Finally, copy each of the diskN directories to formatted disks of the appropriate type. In the WinDebug32 scenario, each directory should be copied to formatted, empty 1.44-MB diskettes.

Test Your Installation Script

To test your application installation, run setup.exe from the disk1 directory you created, which may be on a CD-ROM or hard disk. In the WinDebug32 scenario, however, this file is found on the floppy disk built for the product. You should be testing your application installation on every individual platform your application supports. If using Windows 95, remember to test both installation from diskette and from Add/Remove Programs in the Control Panel; also test deinstallation from your group/folder and from Add/Remove Programs in the Control Panel.

It is important to test all paths of execution available for users, including all possible custom paths. Remember to test all return ("Back") and cancel options, also. You'll find the UI rough drafts and pseudocode helpful at this stage.

If your install tests perfectly and your app has passed all necessary tests for release, then your test diskettes become the Golden Master diskettes, and you can begin to ship this release. Congratulations!

If your install tests perfectly, but your app still needs work before release, then you will need to continue to test your installation while making application changes. Remember, you'll also need to potentially rework (and retest) your installation if application file sizes change (you may need to move files to another disk or split the first disk differently), or if the files in your installation change (new files are added to your build tree or existing files are removed).

If your install doesn't test properly, you'll need to reiterate the installation process to correct the deficiencies, then retest.

Debugging InstallShield Scripts

InstallShield SE does not include an integrated debugger. You can use the #if and #ifdef directives to build debug and retail versions of your scripts, however.

Compile your rule file using the -D option to define a variable DEBUG, for example, then use #if or #ifdef to test for your definition in your InstallScript procedure; see Example 1. You can also use WriteLine() to write strings to a log file. A useful technique for debugging file-set problems during installation is to use the ICOMP command with the -l option to view the names of files stored in a compressed file.

Uninstalling Your Application

If your application uses shared DLLs, keep a count of how many applications are using these DLLs in the Registry, or suggest to users that they might need to be deleted if uninstalling.

Your application should place the following value entries in HKEY_LOCAL_ MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\APPNAME.EXE, (where appname.exe is the name of your application's main executable):

  • DisplayName, a string that is displayed to users in the Add/Remove Programs property sheet of the Control Panel.
  • UninstallString, a string containing a fully qualified path to the deinstallation utility, including all parameters necessary for it to deinstall your app.

This will be done by the InstallShield DeinstallStart() API. InstallShield also copies the uninst.exe file off your diskette to the Windows directory on the installation machine. Don't forget to create the icon (in your folder or group) that permits the user to deinstall your app.

Other Versions of Win32 Setup Software

Previous releases of VC++ have included setup software that is incompatible with what I've just described. However, the software-installation design process that I've discussed here may still be used. If you wish to use another setup tool, simply substitute the relevant commands (such as the disk layout tools) as outlined in your documentation. I strongly recommend upgrading your installation software to InstallShield if you are still using the earlier setup tool that shipped with previous versions of VC++.

When to Develop Your Installation Process

It is not necessary to develop your installation process early on in your development cycle. You should not, however, wait too long to begin thinking about installation. At the absolute latest, you should have a working installation process and setup script before your software begins beta testing.

Why? Because, even though tools like InstallShield SE remove much of the complexity of product installation, things can still go wrong. A frequent source of problems are outside of the install script. For example, you might be copying files from the wrong section of your build tree during diskette creation, or failing to copy an optional file that isn't normally installed. These are easy problems to miss if you're creating installation routines at the last minute.

Final Comments

However well developed and well tested your installation process, there is always the possibility of error. Perhaps your installation media are faulty, or maybe there are problems with your installation on a particular type of hardware. It's a good idea to ship your readme file as a plain-text file, uncompressed and on your first disk, and supply at least minimal printed documentation describing the basic installation process and giving basic customer-support information (phone number or e-mail address). This will let users get help even if they can't uncompress your installation files or read the diskette. Remember, if they can't install your software, they can't use it!

For More Information

InstallShield Corp.

1100 Woodfield Road, Suite 108

Schaumburg, IL 60713

847-240-9111

http://www.installshield.com

Example 1: Compiling the rule file using the -D option to define a

variable DEBUG.

#if DEBUG=1   // compile with -DDEBUG=1 to include,
             // -DDEBUG=0 or not defined at all to skip
     MessageBox( "Error in <some routine>" ) ;
#endif


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.