Re: Windows Service - Fast User Switching - Find Active Desktop Problem

From: Eduardo Francos (efrancos_at_wanadoo.fr)
Date: 04/18/05


Date: Mon, 18 Apr 2005 08:12:44 +0200

Peter Boulton wrote:
> Hi,
>
> I am writing a Windows Service, which is allowed to interact with the
> desktop. (I realise that this is not recommended, but it is currently a
> constraint.) It needs to post advice windows on the desktop of whoever
> is logged in. With fast user switching this could be any one of any
> number of concurrent sessions. My service needs to post the windows to
> the active session, so that the active user can interact with it.
>
> The code in my service is:
>
> while( ::WaitForSingleObject(m_hStop, 10) != WAIT_OBJECT_0 ) {
>
> // TODO: Enter your service's real functionality here
> m_ServerPipe.ConnectClient();
> if(m_ServerPipe.Read(message, _BUFFSIZE, nBytesRead) == TRUE)
> {
>
> DWORD dwThreadId;
> HWINSTA hwinstaSave;
> HDESK hdeskSave;
> HWINSTA hwinstaUser;
> HDESK hdeskUser;
>
> // Ensure connection to service window station and desktop, and
> // save their handles.
>
> GetDesktopWindow();
> hwinstaSave = GetProcessWindowStation();
> dwThreadId = GetCurrentThreadId();
> hdeskSave = GetThreadDesktop(dwThreadId);
>
> // Impersonate the client and connect to the User's
> // window station and desktop.
> m_ServerPipe.ImpersonateNamedPipeClient();
>
>
>
> hwinstaUser = OpenWindowStation("WinSta0", FALSE, MAXIMUM_ALLOWED);
> if (hwinstaUser == NULL)
> {
> m_ServerPipe.RevertToSelf();
> return;
> }
> SetProcessWindowStation(hwinstaUser);
> hdeskUser = OpenDesktop("Default", 0, FALSE, MAXIMUM_ALLOWED);
> if (hdeskUser == NULL)
> {
> SetProcessWindowStation(hwinstaSave);
> CloseWindowStation(hwinstaUser);
> return;
> }
>
>
>
> SetThreadDesktop(hdeskUser);
>
> // Display message box.
> AfxMessageBox(message);
>
> // Restore window station and desktop.
>
> SetThreadDesktop(hdeskSave);
> SetProcessWindowStation(hwinstaSave);
> CloseDesktop(hdeskUser);
> CloseWindowStation(hwinstaUser);
>
>
>
> // DISCONNECT
> m_ServerPipe.RevertToSelf();
> m_ServerPipe.DisconnectClient();
> }
> }
>
> (The AfxMessageBox(); bit is inserted to replace my irrelevant stuff
> which puts up my own advice window).
>
> This code does not seem to work - the windows are always launched on the
> screen of the user who first logs in. If I log in as myself as usual,
> then switch to Guest, for example, and cause the service to post the
> advice window it still appears on my session, not the active (Guest) one.
>
> I'd be very grateful for any suggestions / specific code corrections
> which would help me get going. Thanks.
>
> (I already know that a better architecture would be to launch a process
> in the security context of the logged on user - however, I'm having a
> bit of a problem with that as well, so bear with me!)
>
> Many thanks,
>
> Pete

AFAIK services are always run in the console terminal session, Session
0. Addressing WinSta0 from a service will then always point to that session.

Running a program within the security context of the user can be done
simple by adding a UI client program in the Run key of HKLM or HKCU,
then use whatever IPC scheme that suits your needs to communicate with
the service.
You may use the WTSRegisterSessionNotification related API group to know
when user sessions are activated/deactivated so the service knows which
client to notify. Alternatively the service can notify all connected
clients and have the client UI decide whether to interact with its user
or not.

For further information you can refer to "How To Design a Service to
Interact with Multiple User Sessions"
http://support.microsoft.com/default.aspx?scid=kb;en-us;308403

or "Fast User Switching: Issues for Assistive Technology Vendors"
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnanchor/html/accessibility.asp

Eduardo