Pages

Wednesday, March 5, 2008

Controlling Running Instances

It is common for applications to control their startup so that only a single instance may be running on a machine at any given time. There are many valid reasons for doing this: licensing restrictions, required dedicated access to specific hardware resources, and perhaps even enforcing data integrity. However, with multiple users on the same machine, it might be desirable to allow multiple users-each with their own instance-to work with (for example) a personal finance program as long as their data remains isolated. At this point, the commonly used mechanisms for controlling running instances may exhibit some unwanted side effects when operating under Windows XP's fast user switching or remote desktop.
The most common method for discovering whether another instance is running is to use the FindWindow or FindWindowEx APIs to search for a window that, if your application is running, you know to be open. Somewhat unexpectedly, both of these APIs work in a single user session only. So using this method won't prevent another instance of your application from being started by another user.
A more robust method for controlling multiple instances is to use one of the NT kernel objects: events, semaphores, mutexes, waitable timers, file-mapping objects, and job objects can all be used with Global\ or Local\ prefixes on Windows 2000 and Windows XP. By default, each user (terminal service) session will have its own namespace for kernel objects. By creating a Global\ object-for instance, a mutex or semaphore-when your application is started (and closing it upon exit), your application can detect running instances across multiple user (terminal service) sessions. Of course, you can't just switch to the previous instance: It may be in another session! What typically happens in that case is the user clicks on an icon and then nothing appears to happen (since the app thinks it's located another running instance). At a minimum, you should warn the user that there's another instance running.

What about sound? Well, the terminal services in Windows XP have been designed to configure sound to both the interactive and disconnected sessions. While it may be difficult to imagine at first, there may be valid scenarios where it would desirable to output multiple audio streams. For instance, what if you used a sound card in one user session to output audio to the home stereo system and at the same time the active user wanted to hold an interactive meeting with sound? In this case, you certainly would not want to blend the two streams. And neither would you want to suspend the audio stream in the disconnected session. Getting this right can be particularly important when working with shared media devices like DVD players.

One general guideline is to do "as little as possible, as much as necessary" when you are the disconnected session. To do this, it can be helpful to know when a session switch occurs. While most applications won't need to be notified, if your application accesses a shared resource-such as a serial port or other hardware device-you may want to know when the machine switches between user sessions. To be notified when a session switch occurs, you must register to receive the WM_WTSSESSION_CHANGE message by calling the WTSRegisterConsoleNotification API. Using this function, you can choose to be notified for a single session or for all sessions, and when either local or remote sessions connect or disconnect. When you no longer require notification, you should unregister using the WTSUnRegisterConsoleNotification API.

1 comment: