Application considerations

From ISXKB

Revision as of 14:08, 28 August 2007 by Markus (Talk | contribs)
(diff) ←Older revision | Current revision (diff) | Newer revision→ (diff)
Jump to: navigation, search

Contents

Introduction

Windows application developers sometimes release their products without considering all effects afterwards. This can make it difficult, for instance, to provide updates, and the application may fail under certain circumstances. The purpose of this article is to cover some of the most common pitfalls.

Application working directory

On Windows there are many different ways of starting an application. Although most users may start the program via the Windows start menu, others may use a command line or an Explorer window. Therefore, the working directory may not always point to the folder where the application's executable resides.

If an application needs to read additional files from the start up folder, for example configuration files, direct link libraries (DLLs), etc, it will fail if the working directory points to somewhere else.

A user can set the working directory by altering the field 'Start in' in the shortcut's properties as shown in the picture on the right.

Inno Setup does not fill in this information automatically, hence an [Icons] section like

[Icons]
Name: "{group}\My Program"; Filename: "{app}\MYPROG.EXE"

would leave the 'Start in' field (the working directory) blank. Of course, Windows uses a default working directory, but this folder varies between different versions of Windows. That makes the start up folder somewhat random for developers.

If an application relies on that folder it will fail to find its configuration files or DLLs.

There is at least one way to fix this issue and one way to work it around.

The [Icons] section entry of the Inno Setup script can be altered so that a 'Workingdir:' parameter is specified. That's the workaround.

[Icons]
Name: "{group}\My Program"; Filename: "{app}\MYPROG.EXE"; WorkingDir: "{app}"

This does not help much if the user starts MYPROG.EXE from a command line window which has a working directory pointing to somewhere else. To finally fix this issue and make it work in all cases the applation itself needs to be changed unless the program is meant to run with different configuration files/DLLs from different working directories.

The Windows API GetModuleFileName () can be used to retrieve the application's executable module file path before any configuration files or DLLs are loaded. Developers can then separate the folder information from the executable's file name and use this directory whenever a configuration file or a DLL is to be loaded, or even change the current directory immediately.

Here's a quick example in C, but better use _splitpath or _wsplitpath. For improvements have a look at Security Development Lifecycle (SDL) Banned Function Calls as well.

char chAppPath [1000];
char *chBackSlash;

if (GetModuleFileName (NULL, chAppPath, 1000 - 1))
{
    chBackSlash = strrchr (chAppPath, '\\');
    if (chBackSlash)
    {
        if (strlen (chAppPath) > 2)
        {
            if (*(chAppPath + 1) == ':'
                *(chBackSlash) = '\0';
            else
                *(chBackSlash + 1) = '\0';
        }
        SetCurrentDirectory] (chAppPath));
    }
}

Examples for splitting up the path retrieved by GetModuleFileName () in different programming languages:

  • C++: SplitPath on Code Project
  • Delphi: ProcessPath on Delphi Basics
  • Visual Basic: SplitPath for Visual Basic on Tek Tips
  • Java/C#: SplitPath for Java and C+ on the same page as a comparison

Some languages, mostly interpreters, provide macros or constants for the executable or script directory. AutoIt, for example, provides the macro @ScriptDir.

Application versioning

There will almost certainly be a day in the future where an application needs to be updated.

Every new version will probably have its own installation program created with Inno Setup or any other setup generator. A user could try install an older version over a more recent one.

How can the setup program determine whether the installed version is more recent than the installation package or whether it needs to be replaced?

A date/time stamp is not a very good indicator as it can easily be changed by the user or other circumstances.

Windows provides a VERSIONINFO resource for that case. Applications that contain a correct version info resource are automatically handled by Inno Setup and other installers. The resource can be accessed on the 'Version' page of the 'Properties' dialog window (picture on the right).
[Files]
Source: "MYPROG.EXE"; DestDir: "{app}"

Inno Setup can also ignore the version info but that would spoil the whole idea of version management:

[Files]
Source: "MYPROG.EXE"; DestDir: "{app}"; Flags: ignoreversion

The VERSIONINFO has to get into the program somehow. Here are some links for different languages:

Application is running

When trying to apply an update or to reinstall the application the user could have the program running. Because running executable modules are normally locked by the operating system (there are exceptions, but they are negligible) the installer can't replace it, hence the update or reinstallation fails.

Windows provides a whole bunch of options to check whether an application is running. The article Detect if an application is running discusses some of them.

For GUI programs that require user interactions a mutex object seems to be the most reliable and least intruding method. Mutexes can be used for many things but in this case Inno Setup can detect an existing mutex which will indicate that the application is currently running.

By default Inno Setup supports application mutexes by asking the user to close the program first before applying the update or the reinstallation.

[Setup]
AppMutex=TheUniqueMutexNameForMyProgram

Inno Setup can only detect a mutex (ie. a running application) if the program has created one. This should take place right at the start of the program. The mutex object is automatically destroyed upon application termination. The operating system takes care of the removal.

The text 'TheUniqueMutexNameForMyProgram' should be replaced by some unique name. The description for lpName of CreateMutex () provides more details on how to name a mutex object.

Because it takes only one Windows API call without significant overhead every GUI application should create a mutex on start up.

To create the mutex object in different programming languages the following examples can be used.

C/C++:

CreateMutex (NULL, FALSE, "TheUniqueMutexNameForMyProgram");

Delphi:

CreateMutex (nil, False, 'TheUniqueMutexNameForMyProgram');

Visual Basic (this code has been 'stolen' from Inno Setup's help file and was submitted by Peter Young):

'Place in Declarations section:
Private Declare Function CreateMutex Lib "kernel32" _
        Alias "CreateMutexA" _
       (ByVal lpMutexAttributes As Long, _
        ByVal bInitialOwner As Long, _
        ByVal lpName As String) As Long

'Place in startup code (Form_Load or Sub Main):
CreateMutex 0&, 0&, "TheUniqueMutexNameForMyProgram"

See also

Detect if an application is running

External links

Examples for splitting up the path retrieved by GetModuleFileName () in different programming languages:

Examples and discussions on how to set and retrieve an executable module's VERSIONINFO resource:

Personal tools
Ads: