How To Design a Service to Interact with Multiple User Sessions


This article describes how to design a Windows service application to interact with users through a graphical user interface (GUI) on a multiuser system.

The architecture that is described in this article is intended to be used on services that run on the following operating systems:
  • Microsoft Windows NT 4.0 Terminal Server Edition
  • Windows 2000 with Terminal Services
  • Microsoft Windows XP with fast user switching
  • Microsoft Windows Server 2003
This architecture will also work well for single-user systems (non-Terminal Services servers).

More Information

The general architecture for an interactive service on a multiuser system is described in the following section. However, it may be helpful for you to first read the section later in this article titled "Understanding Services and Terminal Server". That section provides terms and architectural information that pertain to this design.

Designing an Interactive Service for Terminal Server

If a service that is running on a multiuser system must interact with the logged-on user, Microsoft recommends that the service interact by means of a separate GUI application that runs in the user's session. Microsoft recommends that this GUI application be designed to communicate with the service through some method of interprocess communication, such as through a named pipe.

Note This is a client/server architecture. You can configure the client process (the GUI application) to run in each user session as a hidden process. The easiest way to cause the client to run in each session is to add the client process to the Run key in the HKEY_LOCAL_MACHINE hive of the registry.
For additional information, click the following article number to view the article in the Microsoft Knowledge Base:
137367 Definition of the RunOnce Keys in the Registry
The server process (your service) then communicates with the appropriate client through some means of interprocess communication to tell the client when to display the GUI. The client, in turn, communicates the results of the user's interaction back to the service so that the service can act appropriately.

Because there will be multiple clients running on the system (a separate client running in each user session), the service must have a well-defined method to distinguish the clients. The most common method to distinguish clients is to name the channel of communication by using the client's session ID.

For example, if the client is running in session 4, the client may create a pipe whose name is a concatenation of an unpublished GUID, followed by "Channel_4". The client will then pass its session ID to the service (perhaps by connecting to another pipe that is created by the service) so that the service knows to connect to the "Channel_4" pipe. The client can obtain its session ID by calling WTSQuerySessionInformation() with WTSSessionId as the information class.

Important For maximum security, the client must specify FILE_FLAG_FIRST_PIPE_INSTANCE in the dwOpenMode parameter when calling CreateNamedPipe(). This protects against attempts by rogue applications to connect to a process that runs in the LocalSystem account.

When you are designing the client and service applications, a final consideration is the sharing of named kernel objects (for example, events, mutexes, semaphores, file mapping objects, and other objects). By default, a kernel object is accessible only in the session where the object was created. This is named the local session namespace. If the client application and the service application must both access the same kernel object, you must create the object in the global namespace. To create an object in the global namespace, prefix the object name with "Global\". Global objects are accessible across Terminal Services sessions.

Note By default, pipes are global. Therefore, the "Global\" prefix is not required on the pipe name. To determine whether the "Global\" prefix is required for an object, see the Platform SDK documentation for the object.

Understanding Services and Terminal Server

A service is an application that can execute even when no user is logged on to the system. A service typically runs under a special user account named the LocalSystem account. Applications that run under the LocalSystem account have special privileges that give them a lot of power on the local computer. Under most circumstances, you do not want to give a user to this kind of power (it can be used to bypass system security).

To additionally isolate a service from the interactive user, the service typically runs in a noninteractive window station. This means that even if the service does display a GUI, the interface will not be visible to the user.

Before Terminal Server, if a service had to display a GUI, the service was installed as an interactive service. In this way, the service ran under the LocalSystem account on the interactive window station. On a single-user system, a GUI that is displayed by an interactive service appears on the desktop of the interactive user.

Terminal Services-based servers use the concept of a user session. When multiple users log on to the Terminal Services-based server, there are multiple user sessions. Each session is identified by a unique session ID (beginning at session 0 and incrementing by one for each session), and each session receives its own interactive window station. When a user logs on to a Terminal Services-based server, the user connects to an existing session. At that point, the system creates a new session to accept the next connection. If a user logs off the Terminal Services-based computer, the user's session is destroyed (unless it is session 0), and the session ID is available for reuse.

A user can log on to a Terminal Services server either locally or remotely:
  • To log on locally, the user is physically present at the Terminal Services-based server computer and logs on to the console session.
  • To log on remotely, the user connects to the Terminal Services-based server across a network through a Terminal Services client application.
On Windows NT 4.0 and Windows 2000, the console session always has a session ID of 0, and remote sessions always have a session ID that is greater than 0. On Windows XP, however, the console session can have any session ID (including a session ID greater than 0). Likewise, remote sessions can have any session ID (including session 0).

When you design a service, keep in mind that all services run in session 0. Therefore, if an interactive service displays a GUI, it will be visible only to the user who is connected to session 0.

Note A service cannot interact directly with any session except session 0.

Because there is no way to guarantee that the interactive user is connected to session 0, Microsoft recommends that a service not be configured as an interactive service on Terminal Services-based servers.

Note Windows XP introduced a feature named fast user switching (FUS). This feature is an implementation of Terminal Services that allows multiple users to share a single computer. When FUS is turned on, the user does not have to log off before another user dynamically initiates a new user session (or switches to an existing user session) on the same computer. This creates the dilemma where there is no way to know whether the current interactive user is connected to session 0. Therefore, Microsoft recommends that a service that is designed for Windows XP not be configured as an interactive service.

ID articol: 308403 - Ultima examinare: 21 nov. 2006 - Revizie: 1