Application considerations

From ISXKB

(Difference between revisions)
Jump to: navigation, search
(Category:Process Functions added)
Current revision (12:45, 4 September 2009) (view source)
m (External links: C#, not C+)
 
(10 intermediate revisions not shown.)
Line 18: Line 18:
If an application relies on that folder it will fail to find its configuration files or DLLs.
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.
+
There is at least one way to fix this issue, one way to work it around, and one no-go.
 +
 
 +
The 'Path' environment variable could be changed to point to the application directory. This would solve the problem only for DLLs and executable files, hence that's the 'no go' (see [[Avoiding the Path environment variable]]), so don't do that.
The [Icons] section entry of the Inno Setup script can be altered so that a 'Workingdir:' parameter is specified. That's the workaround.
The [Icons] section entry of the Inno Setup script can be altered so that a 'Workingdir:' parameter is specified. That's the workaround.
Line 46: Line 48:
}
}
</pre>
</pre>
-
Examples for splitting up the path retrieved by GetModuleFileName () in different programming languages:
+
Examples for splitting up the path retrieved by GetModuleFileName () or similar functions in different programming languages:
 +
* AutoIt: [http://www.autoitscript.com/autoit3/docs/macros.htm @ScriptDir] macro
* C++: [http://www.codeproject.com/file/SplitPath.asp?print=true SplitPath] on Code Project
* C++: [http://www.codeproject.com/file/SplitPath.asp?print=true SplitPath] on Code Project
 +
* Delphi: [http://www.jrsoftware.org/isfaq.php#workingdir Workingdir] in Inno Setup's FAQ
 +
* Delphi: [http://www.delphibasics.co.uk/RTL.asp?Name=ExtractFilePath ExtractPath] on Delphi Basics
* Delphi: [http://www.delphibasics.co.uk/RTL.asp?Name=ProcessPath ProcessPath] on Delphi Basics
* Delphi: [http://www.delphibasics.co.uk/RTL.asp?Name=ProcessPath ProcessPath] on Delphi Basics
* Visual Basic: [http://www.freevbcode.com/ShowCode.asp?ID=878 A better App.Path] on FreeVBcode.com
* Visual Basic: [http://www.freevbcode.com/ShowCode.asp?ID=878 A better App.Path] on FreeVBcode.com
* Visual Basic: [http://www.tek-tips.com/faqs.cfm?fid=2357 SplitPath] for Visual Basic on Tek Tips
* Visual Basic: [http://www.tek-tips.com/faqs.cfm?fid=2357 SplitPath] for Visual Basic on Tek Tips
* Visual Basic: [http://techrepublic.com.com/5208-6230-0.html?forumID=102&threadID=202601&start=0 Locate the executable path] using Visual Basic
* Visual Basic: [http://techrepublic.com.com/5208-6230-0.html?forumID=102&threadID=202601&start=0 Locate the executable path] using Visual Basic
-
* Java/C#: [http://www.javacamp.org/javavscsharp/outparam.html SplitPath] for Java and C++ on the same page as a comparison
+
* Java/C#: [http://www.javacamp.org/javavscsharp/outparam.html 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. [http://www.autoitscript.com AutoIt], for example, provides the macro [http://www.autoitscript.com/autoit3/docs/macros.htm @ScriptDir]. Inno Setup itself provides the constant {src} for the folder in which the setup.exe resides.
Some languages, mostly interpreters, provide macros or constants for the executable or script directory. [http://www.autoitscript.com AutoIt], for example, provides the macro [http://www.autoitscript.com/autoit3/docs/macros.htm @ScriptDir]. Inno Setup itself provides the constant {src} for the folder in which the setup.exe resides.
Line 81: Line 86:
== Application is running ==
== 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.
+
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, reinstallation, or removal, 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.
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.
Line 87: Line 92:
For [http://en.wikipedia.org/wiki/GUI GUI] programs that require user interactions a [http://msdn2.microsoft.com/en-us/library/ms684266.aspx mutex object] seems to be the most reliable and least intruding method. Mutexes can be used for [http://msdn2.microsoft.com/en-us/library/ms686927.aspx many things] but in this case  Inno Setup can detect an existing mutex which will indicate that the application is currently running.
For [http://en.wikipedia.org/wiki/GUI GUI] programs that require user interactions a [http://msdn2.microsoft.com/en-us/library/ms684266.aspx mutex object] seems to be the most reliable and least intruding method. Mutexes can be used for [http://msdn2.microsoft.com/en-us/library/ms686927.aspx 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.
+
By default Inno Setup supports application mutexes by asking the user to close the program first before applying the update, the reinstallation, or uninstallation. See [Setup] [http://www.jrsoftware.org/ishelp/topic_setup_appmutex.htm AppMutex=] in Inno Setup's help file online.
 +
 
<pre>
<pre>
[Setup]
[Setup]
Line 123: Line 129:
CreateMutex 0&, 0&, "TheUniqueMutexNameForMyProgram"
CreateMutex 0&, 0&, "TheUniqueMutexNameForMyProgram"
</pre>
</pre>
 +
 +
See also [http://www.jrsoftware.org/iskb.php?mutexsessions this Inno KB entry] for information on how to detect when the application is still running from a different login than the one where the installer is being run.
== See also ==
== See also ==
 +
*[Setup] [http://www.jrsoftware.org/ishelp/topic_setup_appmutex.htm AppMutex=] in Inno Setup's help file online.
 +
*[[Avoiding the Path environment variable]]
*[[Detect if an application is running]]
*[[Detect if an application is running]]
*[[Installation Considerations]]
*[[Installation Considerations]]
Line 139: Line 149:
*[http://en.wikipedia.org/wiki/GUI GUI] = Graphical User Interface on Wikipedia
*[http://en.wikipedia.org/wiki/GUI GUI] = Graphical User Interface on Wikipedia
-
Examples for splitting up the path retrieved by GetModuleFileName () in different programming languages:
+
Examples for splitting up the path retrieved by GetModuleFileName () or similiar functions in different programming languages:
* AutoIt: [http://www.autoitscript.com/autoit3/docs/macros.htm @ScriptDir] macro
* AutoIt: [http://www.autoitscript.com/autoit3/docs/macros.htm @ScriptDir] macro
* C++: [http://www.codeproject.com/file/SplitPath.asp?print=true SplitPath] on Code Project
* C++: [http://www.codeproject.com/file/SplitPath.asp?print=true SplitPath] on Code Project
 +
* Delphi: [http://www.jrsoftware.org/isfaq.php#workingdir Workingdir] in Inno Setup's FAQ
 +
* Delphi: [http://www.delphibasics.co.uk/RTL.asp?Name=ExtractFilePath ExtractPath] on Delphi Basics
* Delphi: [http://www.delphibasics.co.uk/RTL.asp?Name=ProcessPath ProcessPath] on Delphi Basics
* Delphi: [http://www.delphibasics.co.uk/RTL.asp?Name=ProcessPath ProcessPath] on Delphi Basics
* Visual Basic: [http://www.freevbcode.com/ShowCode.asp?ID=878 A better App.Path] on FreeVBcode.com
* Visual Basic: [http://www.freevbcode.com/ShowCode.asp?ID=878 A better App.Path] on FreeVBcode.com
* Visual Basic: [http://www.tek-tips.com/faqs.cfm?fid=2357 SplitPath] for Visual Basic on Tek Tips
* Visual Basic: [http://www.tek-tips.com/faqs.cfm?fid=2357 SplitPath] for Visual Basic on Tek Tips
* Visual Basic: [http://techrepublic.com.com/5208-6230-0.html?forumID=102&threadID=202601&start=0 Locate the executable path] using Visual Basic
* Visual Basic: [http://techrepublic.com.com/5208-6230-0.html?forumID=102&threadID=202601&start=0 Locate the executable path] using Visual Basic
-
* Java/C#: [http://www.javacamp.org/javavscsharp/outparam.html SplitPath] for Java and C+ on the same page as a comparison
+
* Java/C#: [http://www.javacamp.org/javavscsharp/outparam.html SplitPath] for Java and C# on the same page as a comparison
Examples and discussions on how to set and retrieve an executable module's VERSIONINFO resource:
Examples and discussions on how to set and retrieve an executable module's VERSIONINFO resource:
Line 155: Line 167:
[[Category:Applications]]
[[Category:Applications]]
[[Category:Basics]]
[[Category:Basics]]
-
[[Category:Process Functions]]
+
[[Category:Process functions]]
 +
[[Category:Updates]]

Current revision

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, one way to work it around, and one no-go.

The 'Path' environment variable could be changed to point to the application directory. This would solve the problem only for DLLs and executable files, hence that's the 'no go' (see Avoiding the Path environment variable), so don't do that.

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 application 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)
            *(chBackSlash + 1) = '\0';
        SetCurrentDirectory (chAppPath);
    }
}

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

Some languages, mostly interpreters, provide macros or constants for the executable or script directory. AutoIt, for example, provides the macro @ScriptDir. Inno Setup itself provides the constant {src} for the folder in which the setup.exe resides.

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, reinstallation, or removal, 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, the reinstallation, or uninstallation. See [Setup] AppMutex= in Inno Setup's help file online.

[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 this Inno KB entry for information on how to detect when the application is still running from a different login than the one where the installer is being run.

See also

External links

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

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

Personal tools
Ads: