User Accounts with Fast User Switching and Remote Desktop
Windows XP user accounts enable multiple users to be logged on simultaneously, each with his or her own settings and each running his or her own applications. Because one user does not have to log off to allow access to another user, each user's desktop is easily accessed using the fast user switching feature. User accounts also include the Personal Terminal Server feature, or Remote Desktop, which enables users to access their desktop account from remote systems.
The following topics are discussed.
- Infrastructure Usage Requirements
- Compatibility with Existing Applications
- Registering for Session Switching Notification
- Ensuring Only One Instance of Your Application Is Running
- Shutting Down Your Application Across All Sessions
- Interaction with System Services
- Remote Desktop and Bandwidth
Underlying infrastructure inherited from Windows 2000 supports state separation of user data, user settings, and computer settings. Taking advantage of this infrastructure, the following are required to successfully run your application under Windows XP.
- Default to the My Documents folder for storage of user-created data.
- Classify and store application data correctly.
- Degrade gracefully on "Access Denied" messages.
Temporary files, memory-mapped files, and documents should all be stored in the appropriate subdirectory of the user's profile directory. Use SHGetFolderLocation or SHGetFolderPath to determine the appropriate storage location for these files. Passing the CSIDL_APPDATA flag to these functions returns the path of a file system directory that serves as a common repository for application-specific data. Use the flag CSIDL_LOCAL_APPDATA in place of CSIDL_APPDATA for data that should change when the user changes, such as temporary files.
The requirements listed above are a subset of those in the Microsoft Certification program. For more information, see the Certified for Windows Program page at http://www.microsoft.com/windowsserver2003/partners/isvs/cfw.mspx.
Both fast user switching and Personal Terminal Server use Terminal Services technology and therefore are compatible with most earlier Microsoft Win32 applications. If an application is Windows 2000 Logo compliant, implementing basic profile separation and power management features, that application should run properly under individual Windows XP user accounts.
Typically, an application does not need to be notified when a desktop switch occurs. However, applications that must be notified when the account under which they are running is the current desktop, such as applications that access the serial port or other shared resources, can register for desktop switch notification. To register for a notification, use the WTSRegisterSessionNotification function.
Once that function has been called, the window with handle hWnd is registered to receive a WM_WTSSESSION_CHANGE message through its WndProc function. The session ID is sent in the lParam parameter, and a code that indicates the event that generated the message is sent in wParam as one of the following flags.
Applications can use this message to track their state, as well as to release and acquire console-specific resources. User desktops can be dynamically switched between remote and console control. Applications should use the WM_WTSSESSION_CHANGE message to synchronize with the remote or local connection state.
When your process no longer requires these notifications or is terminating, it should call WTSUnRegisterSessionNotification to unregister its notification.
Important The hWnd values passed to WTSRegisterSessionNotification are reference counted, so you must make an equal number of calls to WTSUnRegisterSessionNotification to ensure the release of all allocated resources.
Many applications must ensure that they have only one instance running. There are several ways to do this in Windows XP. Among them are the following:
- Use FindWindow or FindWindowEx to search for a known window that your application opens. If that window is already open, you can use that as an indication that the application is already running.
- Create a mutex or semaphore object when your application is opened, and close that object when the application terminates. The global object namespace is separated for each desktop, allowing a unique list of mutex and semaphore objects for each.
An application might need to shut itself down across all sessions. For example, an application running in two or more sessions simultaneously might download a new file from the web. Then it might need to close itself and restart with the updated bits. This, of course, would need to be done in all running sessions. Your application should be written so that it exits cleanly when a notification is received.
From a programmatic standpoint, the following cases need to be addressed.
The server process receives a direct request from a client process.
In this case, the message is probably transmitted using a local procedure call (LPC) or a remote procedure call (RPC). There are APIs for either LPC or RPC that enable retrieval of the client token. Once the client token is obtained, the server can use it in a call to CreateProcessAsUser. This brings up the process on the correct window station, assuming that the client user token has a session tag, which it should.
Note CreateProcessAsUser does not support handle inheritance across sessions at this time.
The server process receives a notification and needs to display the UI, but the display does not have to be in the current user's context.
In this case, the server process can duplicate its primary process token and change the session identifier in question to match the current session identifier. The current session identifier can be obtained by using the WTSGetActiveConsoleSessionId function.
Note To set the token session ID, you need the SE_TCB_PRIVILEGE. You will have this only as a service running in NT AUTHORITY\SYSTEM.
With the addition of the Remote Desktop feature to Windows XP, applications should make an effort not to use more bandwidth than needed, avoiding extensive screen drawings and animation effects if the desktop is connected remotely. To determine whether the current session is remote, you can call GetSystemMetrics with SM_REMOTESESSION. Be aware, however, that this call does not distinguish between remote and disconnected.