Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

290 lines
9.0 KiB

  1. /*************************************************************************
  2. Module: DeskSwitch.c
  3. Copyright (C) 1997-2000 by Microsoft Corporation. All rights reserved.
  4. *************************************************************************/
  5. #ifdef _WIN32_IE
  6. #undef _WIN32_IE
  7. #endif
  8. #define _WIN32_IE 0x0600
  9. #include <shlwapi.h> // for IsOS
  10. #include <shlwapip.h> // for IsOS
  11. ////////////////////////////////////////////////////////////////////////////
  12. // Helper functions and globals for detecting desktop switch
  13. //
  14. // Usage: Call InitWatchDeskSwitch() with an hWnd and message during
  15. // initialization. The message will be posted to hWnd whenever
  16. // a desktop switch has occurred. When the message is received
  17. // the desktop switch has taken place already.
  18. //
  19. // Call TermWatchDeskSwitch() to stop watching for desktop
  20. // switches.
  21. ////////////////////////////////////////////////////////////////////////////
  22. HANDLE g_hDesktopSwitchThread = 0;
  23. HANDLE g_hDesktopSwitchEvent = 0;
  24. HANDLE g_hTerminateEvent = 0;
  25. typedef struct MsgInfo {
  26. HWND hWnd;
  27. DWORD dwMsg;
  28. DWORD dwTIDMain;
  29. DWORD fPostMultiple;
  30. } MSG_INFO;
  31. MSG_INFO g_MsgInfo;
  32. void Cleanup()
  33. {
  34. if (g_hDesktopSwitchEvent)
  35. {
  36. CloseHandle(g_hDesktopSwitchEvent);
  37. g_hDesktopSwitchEvent = 0;
  38. }
  39. if (g_hTerminateEvent)
  40. {
  41. CloseHandle(g_hTerminateEvent);
  42. g_hTerminateEvent = 0;
  43. }
  44. }
  45. #ifndef DESKTOP_ACCESSDENIED
  46. #define DESKTOP_ACCESSDENIED 0
  47. #define DESKTOP_DEFAULT 1
  48. #define DESKTOP_SCREENSAVER 2
  49. #define DESKTOP_WINLOGON 3
  50. #define DESKTOP_TESTDISPLAY 4
  51. #define DESKTOP_OTHER 5
  52. #endif
  53. int GetDesktopType()
  54. {
  55. HDESK hdesk;
  56. TCHAR szName[100];
  57. DWORD nl;
  58. int iCurrentDesktop = DESKTOP_OTHER;
  59. hdesk = OpenInputDesktop(0, FALSE, MAXIMUM_ALLOWED);
  60. if (!hdesk)
  61. {
  62. hdesk = OpenDesktop(TEXT("Winlogon"), 0, FALSE, MAXIMUM_ALLOWED);
  63. if (!hdesk)
  64. {
  65. // fails when ap has insufficient permission on secure desktop
  66. return DESKTOP_ACCESSDENIED;
  67. }
  68. }
  69. GetUserObjectInformation(hdesk, UOI_NAME, szName, 100, &nl);
  70. CloseDesktop(hdesk);
  71. if (!lstrcmpi(szName, TEXT("Default")))
  72. {
  73. iCurrentDesktop = DESKTOP_DEFAULT;
  74. } else if (!lstrcmpi(szName, TEXT("Winlogon")))
  75. {
  76. iCurrentDesktop = DESKTOP_WINLOGON;
  77. }
  78. return iCurrentDesktop;
  79. }
  80. // WatchDesktopProc - waits indefinitely for a desktop switch. When
  81. // it gets one, it posts a message to the window
  82. // specified in InitWatchDeskSwitch. It also waits
  83. // on an event that signals the procedure to exit.
  84. //
  85. DWORD WatchDesktopProc(LPVOID pvData)
  86. {
  87. BOOL fCont = TRUE;
  88. DWORD dwEventIndex;
  89. HANDLE ahEvents[2];
  90. int iDesktopT, iCurrentDesktop = GetDesktopType();
  91. SetThreadDesktop(GetThreadDesktop(g_MsgInfo.dwTIDMain));
  92. ahEvents[0] = g_hDesktopSwitchEvent;
  93. ahEvents[1] = g_hTerminateEvent;
  94. while (fCont)
  95. {
  96. iDesktopT = GetDesktopType();
  97. if (iDesktopT == iCurrentDesktop)
  98. {
  99. DBPRINTF(TEXT("Wait for desktop switch or exit on desktop = %d\r\n"), iCurrentDesktop);
  100. dwEventIndex = WaitForMultipleObjects(2, ahEvents, FALSE, INFINITE);
  101. dwEventIndex -= WAIT_OBJECT_0;
  102. } else
  103. {
  104. // missed a desktop switch so handle it
  105. dwEventIndex = 0;
  106. }
  107. switch (dwEventIndex)
  108. {
  109. case 0:
  110. // With a FUS there is a spurious switch to Winlogon
  111. iDesktopT = GetDesktopType();
  112. DBPRINTF(TEXT("desktop switch from %d to %d\r\n"), iCurrentDesktop, iDesktopT);
  113. if (iDesktopT != iCurrentDesktop)
  114. {
  115. iCurrentDesktop = iDesktopT;
  116. // Handle desk switch event
  117. DBPRINTF(TEXT("WatchDesktopProc: PostMessage(0x%x, %d...) desktop %d\r\n"), g_MsgInfo.hWnd, g_MsgInfo.dwMsg, iCurrentDesktop);
  118. PostMessage(g_MsgInfo.hWnd, g_MsgInfo.dwMsg, iCurrentDesktop, 0);
  119. } else DBPRINTF(TEXT("WatchDesktopProc: Ignore switch to %d\r\n"), iDesktopT);
  120. break;
  121. case 1:
  122. // Handle terminate thread event
  123. fCont = FALSE;
  124. DBPRINTF(TEXT("WatchDesktopProc: got terminate event\r\n"));
  125. break;
  126. default:
  127. // Unexpected event
  128. fCont = FALSE;
  129. DBPRINTF(TEXT("WatchDesktopProc unexpected event %d\r\n"), dwEventIndex + WAIT_OBJECT_0);
  130. break;
  131. }
  132. }
  133. Cleanup();
  134. DBPRINTF(TEXT("WatchDesktopProc returning...\r\n"));
  135. return 0;
  136. }
  137. // InitWatchDeskSwitch - starts a thread to watch for desktop switches
  138. //
  139. // hWnd [in] - window handle to post message to
  140. // dwMsg [in] - message to post on desktop switch
  141. //
  142. // Call this function after the window has been created whenever it
  143. // is to wait for a desktop switch.
  144. //
  145. void InitWatchDeskSwitch(HWND hWnd, DWORD dwMsg)
  146. {
  147. DWORD dwTID;
  148. if (g_hDesktopSwitchThread || g_hDesktopSwitchEvent)
  149. return; // don't do this again if it's already running
  150. // Create an unnamed event used to signal the thread to terminate
  151. g_hTerminateEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  152. // and open the desktop switch event. If utility manager is
  153. // running then we will wait on it's desktop switch event otherwise
  154. // wait on the system desktop switch event. If waiting on utilman
  155. // then only post one switch message.
  156. g_hDesktopSwitchEvent = OpenEvent(SYNCHRONIZE
  157. , FALSE
  158. , TEXT("UtilMan_DesktopSwitch"));
  159. g_MsgInfo.fPostMultiple = FALSE;
  160. if (!g_hDesktopSwitchEvent)
  161. {
  162. g_hDesktopSwitchEvent = OpenEvent(SYNCHRONIZE
  163. , FALSE
  164. , TEXT("WinSta0_DesktopSwitch"));
  165. g_MsgInfo.fPostMultiple = TRUE;
  166. }
  167. if (g_hDesktopSwitchEvent && g_hTerminateEvent)
  168. {
  169. g_MsgInfo.hWnd = hWnd;
  170. g_MsgInfo.dwMsg = dwMsg;
  171. g_MsgInfo.dwTIDMain = GetCurrentThreadId();
  172. DBPRINTF(TEXT("InitWatchDeskSwitch(0x%x, %d, %d)\r\n"), g_MsgInfo.hWnd, g_MsgInfo.dwMsg, g_MsgInfo.dwTIDMain);
  173. g_hDesktopSwitchThread = CreateThread(
  174. NULL, 0
  175. , WatchDesktopProc
  176. , &g_MsgInfo, 0
  177. , &dwTID);
  178. }
  179. // cleanup if failed to create thread
  180. if (!g_hDesktopSwitchThread)
  181. {
  182. DBPRINTF(TEXT("InitWatchDeskSwitch failed!\r\n"));
  183. Cleanup();
  184. }
  185. }
  186. // TermWatchDeskSwitch - cleans up after a desktop switch
  187. //
  188. // Call this function to terminate the thread that is watching
  189. // for desktop switches (if it is running) and to clean up the
  190. // event handle.
  191. //
  192. void TermWatchDeskSwitch()
  193. {
  194. DBPRINTF(TEXT("TermWatchDeskSwitch...\r\n"));
  195. if (g_hDesktopSwitchThread)
  196. {
  197. SetEvent(g_hTerminateEvent);
  198. DBPRINTF(TEXT("TermWatchDeskSwitch: SetEvent(0x%x)\r\n"), g_hDesktopSwitchThread);
  199. g_hDesktopSwitchThread = 0;
  200. } else DBPRINTF(TEXT("TermWatchDeskSwitch: g_hDesktopSwitchThread = 0\r\n"));
  201. }
  202. ////////////////////////////////////////////////////////////////////////////
  203. // helper functions for detecting if UtilMan is running (in
  204. // which case this applets is being managed by it)
  205. ////////////////////////////////////////////////////////////////////////////
  206. __inline BOOL IsUtilManRunning()
  207. {
  208. HANDLE hEvent = OpenEvent(SYNCHRONIZE, FALSE, TEXT("UtilityManagerIsActiveEvent"));
  209. if (hEvent != NULL)
  210. {
  211. CloseHandle(hEvent);
  212. return TRUE;
  213. }
  214. return FALSE;
  215. }
  216. __inline BOOL CanLockDesktopWithoutDisconnect()
  217. {
  218. // This function may have to change if UI is added to Whistler that
  219. // allows switching users for computers that are part of a domain.
  220. // For now, domain users may have FUS enabled because TS allows remote
  221. // logon which can result in multiple sessions on a machine (a form
  222. // of FUS) even though Start/Logoff doesn't allow the "Switch User"
  223. // option. In this case, the user can lock their desktop without
  224. // causing their session to disconnect. If FUS is explicitly off
  225. // in the registry then "Switch User" is not a Logoff option nor can
  226. // a remote logon happen and the user can lock their desktop without
  227. // causing their session to disconnect.
  228. return (IsOS(OS_DOMAINMEMBER) || !IsOS(OS_FASTUSERSWITCHING));
  229. }
  230. ////////////////////////////////////////////////////////////////////////////
  231. // RunSecure - helper function to tell accessibility UI when to run secure
  232. // (no help, no active URL links, etc...). Accessibility UI
  233. // should run in secure mode if it is running on the winlogon
  234. // desktop or as SYSTEM.
  235. ////////////////////////////////////////////////////////////////////////////
  236. BOOL RunSecure(DWORD dwDesktop)
  237. {
  238. BOOL fOK = FALSE;
  239. BOOL fIsLocalSystem = FALSE;
  240. SID_IDENTIFIER_AUTHORITY siaLocalSystem = SECURITY_NT_AUTHORITY;
  241. PSID psidSystem = 0;
  242. if (dwDesktop == DESKTOP_WINLOGON)
  243. return TRUE;
  244. if (AllocateAndInitializeSid(&siaLocalSystem,
  245. 1,
  246. SECURITY_LOCAL_SYSTEM_RID,
  247. 0, 0, 0, 0, 0, 0, 0,
  248. &psidSystem) && psidSystem)
  249. {
  250. fOK = CheckTokenMembership(NULL, psidSystem, &fIsLocalSystem);
  251. FreeSid(psidSystem);
  252. }
  253. return (fOK && fIsLocalSystem);
  254. }