The Unofficial Newsletter of Delphi Users - by Robert Vivrette



Controlling Application Startup in Delphi 3

by Evan Simpson - esimpson@eramp.net

For many programs, having more than one instance running at the same time isn't a problem.  It may even be a desirable feature, in SDI applications like Notepad, for instance.  Often, though, the program will read and write data files (or registry keys) in a way which will cause corruption if another copy is launched, or it may simply not make any sense to have multiple instances running.  In these cases it is valuable to have a simple mechanism to detect and control instance launches, especially with Windows 98 and its single-click launch interface.

Under 16 bit Windows, the solution was simple; Just examine the previous instance global variable to see if a copy is already running, and do the right thing.  Under Win32, things are a bit more complicated.  Several solutions are available on the Web, including one on the Borland Tips page, but I still felt compelled to write my own for several reasons.  First, I needed to transmit the command line parameters of a second launch attempt to the primary instance in one program I wrote (it processes BMP files dragged onto its Explorer icon).  Second, I wanted a plug-in unit which required minimal alteration from one program to the next, and little or no foolery in my DPR file.  Third, I wanted it to be secure, reliable, and fast; In particular, it should run before any other VCL code initializes or allocates anything.

To meet the first requirement, I used WM_COPYDATA on the command line string.  This in turn required me to get a window handle from the primary instance to use as a target for the message.  FindWindow handles this nicely, but I couldn't use the automatic application window or any other standard window of the application, because of the third requirement.

The second requirement led me to place all of the code into a unit which is simply placed in the DPR "uses" clause.  The actual instance management code runs in the unit's initialization.  Global variables in the interface part provide the event hook and passed data storage.

Due to the third requirement, the unit must be the very first unit used by the DPR, and could not use any other application unit.  In particular, almost every unit is likely to use Forms, and Forms is normally the first unit used by a DPR, but Forms sets up and initializes the whole Application framework.

The result of all this is the InstanceManager unit below.  Simply make it the first unit in your program's DPR's uses list, and edit the constant declarations to fit your needs.  Note that by using the same string constant for two or more different programs, you can create a "family" of executables which share instance management - I use this ability in a timeclock program, which not only should not run more than once, but cannot run at the same time as its administative utility.  Also, this unit doesn't just prevent a second instance from running.  It can call a notification event, which can decide on a case-by-case basis whether to allow the other instance to run, perhaps by examining the command line.