HOWTO: Access the Application Desktop from a Service
ID: Q173687
|
The information in this article applies to:
-
Microsoft Win32 Application Programming Interface (API), used with:
-
Microsoft Windows NT versions 3.51, 4.0
-
Microsoft Windows 2000
SUMMARY
The configuration of a Windows NT service determines how it may access the
application desktop. The application desktop is named "default" and belongs
to the "WinSta0" Window station object. The application desktop is
associated with the interactively logged-on user. A process that has access
to the application desktop can display message boxes, windows, and dialog
boxes that can be seen visually by the interactively logged-on user. In
addition, a process with access to the application desktop can send
messages to other processes running on the desktop. The application desktop
is not destroyed when the interactively logged-on user logs off.
NOTE: Running interactive services under the LocalSystem account is a VERY
dangerous practice. This is especially true of the command processor and
batch files. A user who wants to control the system can just hit CTRL+C to
get an interactive system command prompt.
MORE INFORMATION
A service that is configured in the LocalSystem account and is interacting
with the desktop (the service type includes the SERVICE_INTERACTIVE_PROCESS
flag) has access to the application desktop.
A service that is configured in the LocalSystem account and is not
interacting with the desktop does not have access to the application
desktop by default. If the service needs to display information through a
message box, you can do this by specifying one of the following two flag
types:
MB_DEFAULT_DESKTOP_ONLY - The message box will appear on the application
desktop, for example, "winsta0\default".
MB_SERVICE_NOTIFICATION - The message box will appear on the currently
active desktop.
In addition, a service configured in the LocalSystem account can
reconfigure its thread to access the application desktop. This is
demonstrated in the following sample code. The sample code obtains handles
to the "WinSta0" window station and the "default" desktop. Then it re-
associates the current thread to the application desktop. Then the sample
will display a message box and, when access to the interactive desktop is
no longer needed, it resets the thread to the original window station and
desktop. This must be done for every thread that wants access to the
application desktop.
Sample Code
BOOL ThreadInteract(void)
{
HDESK hdeskCurrent;
HDESK hdesk;
HWINSTA hwinstaCurrent;
HWINSTA hwinsta;
//
// Save the current Window station
//
hwinstaCurrent = GetProcessWindowStation();
if (hwinstaCurrent == NULL)
return FALSE;
//
// Save the current desktop
//
hdeskCurrent = GetThreadDesktop(GetCurrentThreadId());
if (hdeskCurrent == NULL)
return FALSE;
//
// Obtain a handle to WinSta0 - service must be running
// in the LocalSystem account
//
hwinsta = OpenWindowStation("winsta0", FALSE,
WINSTA_ACCESSCLIPBOARD |
WINSTA_ACCESSGLOBALATOMS |
WINSTA_CREATEDESKTOP |
WINSTA_ENUMDESKTOPS |
WINSTA_ENUMERATE |
WINSTA_EXITWINDOWS |
WINSTA_READATTRIBUTES |
WINSTA_READSCREEN |
WINSTA_WRITEATTRIBUTES);
if (hwinsta == NULL)
return FALSE;
//
// Set the windowstation to be winsta0
//
if (!SetProcessWindowStation(hwinsta))
return FALSE;
//
// Get the default desktop on winsta0
//
hdesk = OpenDesktop("default", 0, FALSE,
DESKTOP_CREATEMENU |
DESKTOP_CREATEWINDOW |
DESKTOP_ENUMERATE |
DESKTOP_HOOKCONTROL |
DESKTOP_JOURNALPLAYBACK |
DESKTOP_JOURNALRECORD |
DESKTOP_READOBJECTS |
DESKTOP_SWITCHDESKTOP |
DESKTOP_WRITEOBJECTS);
if (hdesk == NULL)
return FALSE;
//
// Set the desktop to be "default"
//
if (!SetThreadDesktop(hdesk))
return FALSE;
//
// Do a message box
//
MessageBox(NULL, "MB_OK", "test_interact", MB_OK);
//
// Reset the Window station and desktop
//
if (!SetProcessWindowStation(hwinstaCurrent))
return FALSE;
if (!SetThreadDesktop(hdeskCurrent))
return FALSE;
//
// Close the windowstation and desktop handles
//
if (!CloseWindowStation(hwinsta))
return FALSE;
if (!CloseDesktop(hdesk))
return FALSE;
return TRUE;
}
A service configured for a user account can access the application desktop
through the message box types mentioned above. The above code will fail for
a service configured for a user account due to security reasons but it will
work for a service that impersonates the interactively logged-on user. For
example, impersonation can be done through a named pipe connection from a
process running on the application desktop. The service would have to
impersonate the named pipe client.
Additional query words:
Keywords : kbKernBase kbWinOS2000 kbSecurity kbService kbDSupport kbGrpKernBase
Version : winnt:3.51,4.0
Platform : winnt
Issue type : kbhowto