|
|
/*************************************************************************
Module: DeskSwitch.c
Copyright (C) 1997-2000 by Microsoft Corporation. All rights reserved. *************************************************************************/ #ifdef _WIN32_IE
#undef _WIN32_IE
#endif
#define _WIN32_IE 0x0600
#include <shlwapi.h> // for IsOS
#include <shlwapip.h> // for IsOS
////////////////////////////////////////////////////////////////////////////
// Helper functions and globals for detecting desktop switch
//
// Usage: Call InitWatchDeskSwitch() with an hWnd and message during
// initialization. The message will be posted to hWnd whenever
// a desktop switch has occurred. When the message is received
// the desktop switch has taken place already.
//
// Call TermWatchDeskSwitch() to stop watching for desktop
// switches.
////////////////////////////////////////////////////////////////////////////
HANDLE g_hDesktopSwitchThread = 0; HANDLE g_hDesktopSwitchEvent = 0; HANDLE g_hTerminateEvent = 0;
typedef struct MsgInfo { HWND hWnd; DWORD dwMsg; DWORD dwTIDMain; DWORD fPostMultiple; } MSG_INFO; MSG_INFO g_MsgInfo;
void Cleanup() { if (g_hDesktopSwitchEvent) { CloseHandle(g_hDesktopSwitchEvent); g_hDesktopSwitchEvent = 0; } if (g_hTerminateEvent) { CloseHandle(g_hTerminateEvent); g_hTerminateEvent = 0; } }
#ifndef DESKTOP_ACCESSDENIED
#define DESKTOP_ACCESSDENIED 0
#define DESKTOP_DEFAULT 1
#define DESKTOP_SCREENSAVER 2
#define DESKTOP_WINLOGON 3
#define DESKTOP_TESTDISPLAY 4
#define DESKTOP_OTHER 5
#endif
int GetDesktopType() { HDESK hdesk; TCHAR szName[100]; DWORD nl; int iCurrentDesktop = DESKTOP_OTHER;
hdesk = OpenInputDesktop(0, FALSE, MAXIMUM_ALLOWED); if (!hdesk) { hdesk = OpenDesktop(TEXT("Winlogon"), 0, FALSE, MAXIMUM_ALLOWED); if (!hdesk) { // fails when ap has insufficient permission on secure desktop
return DESKTOP_ACCESSDENIED; } } GetUserObjectInformation(hdesk, UOI_NAME, szName, 100, &nl); CloseDesktop(hdesk);
if (!lstrcmpi(szName, TEXT("Default"))) { iCurrentDesktop = DESKTOP_DEFAULT; } else if (!lstrcmpi(szName, TEXT("Winlogon"))) { iCurrentDesktop = DESKTOP_WINLOGON; } return iCurrentDesktop; }
// WatchDesktopProc - waits indefinitely for a desktop switch. When
// it gets one, it posts a message to the window
// specified in InitWatchDeskSwitch. It also waits
// on an event that signals the procedure to exit.
//
DWORD WatchDesktopProc(LPVOID pvData) { BOOL fCont = TRUE; DWORD dwEventIndex; HANDLE ahEvents[2]; int iDesktopT, iCurrentDesktop = GetDesktopType();
SetThreadDesktop(GetThreadDesktop(g_MsgInfo.dwTIDMain));
ahEvents[0] = g_hDesktopSwitchEvent; ahEvents[1] = g_hTerminateEvent; while (fCont) { iDesktopT = GetDesktopType(); if (iDesktopT == iCurrentDesktop) { DBPRINTF(TEXT("Wait for desktop switch or exit on desktop = %d\r\n"), iCurrentDesktop); dwEventIndex = WaitForMultipleObjects(2, ahEvents, FALSE, INFINITE); dwEventIndex -= WAIT_OBJECT_0; } else { // missed a desktop switch so handle it
dwEventIndex = 0; }
switch (dwEventIndex) { case 0: // With a FUS there is a spurious switch to Winlogon
iDesktopT = GetDesktopType(); DBPRINTF(TEXT("desktop switch from %d to %d\r\n"), iCurrentDesktop, iDesktopT); if (iDesktopT != iCurrentDesktop) { iCurrentDesktop = iDesktopT;
// Handle desk switch event
DBPRINTF(TEXT("WatchDesktopProc: PostMessage(0x%x, %d...) desktop %d\r\n"), g_MsgInfo.hWnd, g_MsgInfo.dwMsg, iCurrentDesktop); PostMessage(g_MsgInfo.hWnd, g_MsgInfo.dwMsg, iCurrentDesktop, 0); } else DBPRINTF(TEXT("WatchDesktopProc: Ignore switch to %d\r\n"), iDesktopT); break;
case 1: // Handle terminate thread event
fCont = FALSE; DBPRINTF(TEXT("WatchDesktopProc: got terminate event\r\n")); break;
default: // Unexpected event
fCont = FALSE; DBPRINTF(TEXT("WatchDesktopProc unexpected event %d\r\n"), dwEventIndex + WAIT_OBJECT_0); break; } }
Cleanup();
DBPRINTF(TEXT("WatchDesktopProc returning...\r\n")); return 0; }
// InitWatchDeskSwitch - starts a thread to watch for desktop switches
//
// hWnd [in] - window handle to post message to
// dwMsg [in] - message to post on desktop switch
//
// Call this function after the window has been created whenever it
// is to wait for a desktop switch.
//
void InitWatchDeskSwitch(HWND hWnd, DWORD dwMsg) { DWORD dwTID;
if (g_hDesktopSwitchThread || g_hDesktopSwitchEvent) return; // don't do this again if it's already running
// Create an unnamed event used to signal the thread to terminate
g_hTerminateEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
// and open the desktop switch event. If utility manager is
// running then we will wait on it's desktop switch event otherwise
// wait on the system desktop switch event. If waiting on utilman
// then only post one switch message.
g_hDesktopSwitchEvent = OpenEvent(SYNCHRONIZE , FALSE , TEXT("UtilMan_DesktopSwitch")); g_MsgInfo.fPostMultiple = FALSE;
if (!g_hDesktopSwitchEvent) { g_hDesktopSwitchEvent = OpenEvent(SYNCHRONIZE , FALSE , TEXT("WinSta0_DesktopSwitch")); g_MsgInfo.fPostMultiple = TRUE; }
if (g_hDesktopSwitchEvent && g_hTerminateEvent) { g_MsgInfo.hWnd = hWnd; g_MsgInfo.dwMsg = dwMsg; g_MsgInfo.dwTIDMain = GetCurrentThreadId();
DBPRINTF(TEXT("InitWatchDeskSwitch(0x%x, %d, %d)\r\n"), g_MsgInfo.hWnd, g_MsgInfo.dwMsg, g_MsgInfo.dwTIDMain); g_hDesktopSwitchThread = CreateThread( NULL, 0 , WatchDesktopProc , &g_MsgInfo, 0 , &dwTID); }
// cleanup if failed to create thread
if (!g_hDesktopSwitchThread) { DBPRINTF(TEXT("InitWatchDeskSwitch failed!\r\n")); Cleanup(); } }
// TermWatchDeskSwitch - cleans up after a desktop switch
//
// Call this function to terminate the thread that is watching
// for desktop switches (if it is running) and to clean up the
// event handle.
//
void TermWatchDeskSwitch() { DBPRINTF(TEXT("TermWatchDeskSwitch...\r\n")); if (g_hDesktopSwitchThread) { SetEvent(g_hTerminateEvent); DBPRINTF(TEXT("TermWatchDeskSwitch: SetEvent(0x%x)\r\n"), g_hDesktopSwitchThread); g_hDesktopSwitchThread = 0; } else DBPRINTF(TEXT("TermWatchDeskSwitch: g_hDesktopSwitchThread = 0\r\n")); }
////////////////////////////////////////////////////////////////////////////
// helper functions for detecting if UtilMan is running (in
// which case this applets is being managed by it)
////////////////////////////////////////////////////////////////////////////
__inline BOOL IsUtilManRunning() { HANDLE hEvent = OpenEvent(SYNCHRONIZE, FALSE, TEXT("UtilityManagerIsActiveEvent")); if (hEvent != NULL) { CloseHandle(hEvent); return TRUE; } return FALSE; }
__inline BOOL CanLockDesktopWithoutDisconnect() { // This function may have to change if UI is added to Whistler that
// allows switching users for computers that are part of a domain.
// For now, domain users may have FUS enabled because TS allows remote
// logon which can result in multiple sessions on a machine (a form
// of FUS) even though Start/Logoff doesn't allow the "Switch User"
// option. In this case, the user can lock their desktop without
// causing their session to disconnect. If FUS is explicitly off
// in the registry then "Switch User" is not a Logoff option nor can
// a remote logon happen and the user can lock their desktop without
// causing their session to disconnect.
return (IsOS(OS_DOMAINMEMBER) || !IsOS(OS_FASTUSERSWITCHING)); }
////////////////////////////////////////////////////////////////////////////
// RunSecure - helper function to tell accessibility UI when to run secure
// (no help, no active URL links, etc...). Accessibility UI
// should run in secure mode if it is running on the winlogon
// desktop or as SYSTEM.
////////////////////////////////////////////////////////////////////////////
BOOL RunSecure(DWORD dwDesktop) { BOOL fOK = TRUE; BOOL fIsLocalSystem = TRUE; SID_IDENTIFIER_AUTHORITY siaLocalSystem = SECURITY_NT_AUTHORITY; PSID psidSystem = 0;
if (dwDesktop == DESKTOP_WINLOGON) return TRUE;
if (AllocateAndInitializeSid(&siaLocalSystem, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &psidSystem) && psidSystem) { fOK = CheckTokenMembership(NULL, psidSystem, &fIsLocalSystem); FreeSid(psidSystem); }
return (fOK && fIsLocalSystem); }
|