Leaked source code of windows server 2003
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.

448 lines
14 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1998
  5. //
  6. // File: status.c
  7. //
  8. // Contents: Status UI
  9. //
  10. // History: 11-19-98 EricFlo Created
  11. //
  12. //----------------------------------------------------------------------------
  13. #include "msgina.h"
  14. #define WM_HIDEOURSELVES (WM_USER + 1000)
  15. //*************************************************************
  16. //
  17. // StatusMessageDlgProc()
  18. //
  19. // Purpose: Dialog box procedure for the status dialog
  20. //
  21. // Parameters: hDlg - handle to the dialog box
  22. // uMsg - window message
  23. // wParam - wParam
  24. // lParam - lParam
  25. //
  26. // Return: TRUE if message was processed
  27. // FALSE if not
  28. //
  29. // Comments:
  30. //
  31. // History: Date Author Comment
  32. // 11/19/98 EricFlo Created
  33. //
  34. //*************************************************************
  35. INT_PTR APIENTRY StatusMessageDlgProc (HWND hDlg, UINT uMsg,
  36. WPARAM wParam, LPARAM lParam)
  37. {
  38. switch (uMsg) {
  39. case WM_INITDIALOG:
  40. {
  41. RECT rc;
  42. DWORD dwAnimationTimeSlice;
  43. PGLOBALS pGlobals = (PGLOBALS) lParam;
  44. SetWindowLongPtr (hDlg, DWLP_USER, (LONG_PTR) pGlobals);
  45. SizeForBranding(hDlg, FALSE);
  46. CentreWindow (hDlg);
  47. pGlobals->xStatusBandOffset = 0;
  48. if (GetClientRect(hDlg, &rc)) {
  49. pGlobals->cxStatusBand = rc.right-rc.left;
  50. } else {
  51. pGlobals->cxStatusBand = 100;
  52. }
  53. if (_Shell_LogonStatus_Exists())
  54. {
  55. SetWindowPos(hDlg, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOZORDER);
  56. PostMessage(hDlg, WM_HIDEOURSELVES, 0, 0);
  57. }
  58. if ((pGlobals->dwStatusOptions & STATUSMSG_OPTION_NOANIMATION) == 0) {
  59. dwAnimationTimeSlice = GetAnimationTimeInterval(pGlobals);
  60. SetTimer(hDlg, 0, dwAnimationTimeSlice, NULL);
  61. }
  62. }
  63. return TRUE;
  64. case WM_HIDEOURSELVES:
  65. ShowWindow(hDlg, SW_HIDE);
  66. break;
  67. case WM_TIMER:
  68. if (wParam == 0)
  69. {
  70. PGLOBALS pGlobals = (PGLOBALS) GetWindowLongPtr(hDlg, DWLP_USER);
  71. HDC hDC;
  72. if (pGlobals)
  73. {
  74. pGlobals->xStatusBandOffset = (pGlobals->xStatusBandOffset+5) % pGlobals->cxStatusBand;
  75. hDC = GetDC(hDlg);
  76. if ( hDC )
  77. {
  78. PaintBranding(hDlg, hDC, pGlobals->xStatusBandOffset, TRUE, FALSE, COLOR_BTNFACE);
  79. ReleaseDC(hDlg, hDC);
  80. }
  81. }
  82. }
  83. break;
  84. case WM_ERASEBKGND:
  85. {
  86. PGLOBALS pGlobals = (PGLOBALS) GetWindowLongPtr(hDlg, DWLP_USER);
  87. if (pGlobals) {
  88. return PaintBranding(hDlg, (HDC)wParam, pGlobals->xStatusBandOffset, FALSE, FALSE, COLOR_BTNFACE);
  89. }
  90. return 0;
  91. }
  92. case WM_QUERYNEWPALETTE:
  93. return BrandingQueryNewPalete(hDlg);
  94. case WM_PALETTECHANGED:
  95. return BrandingPaletteChanged(hDlg, (HWND)wParam);
  96. case WM_DESTROY:
  97. KillTimer (hDlg, 0);
  98. break;
  99. default:
  100. break;
  101. }
  102. return FALSE;
  103. }
  104. //*************************************************************
  105. //
  106. // StatusMessageThread()
  107. //
  108. // Purpose: Status message thread
  109. //
  110. // Parameters: hDesktop - Desktop handle to put UI on
  111. //
  112. // Return: void
  113. //
  114. // History: Date Author Comment
  115. // 11/19/98 EricFlo Created
  116. //
  117. //*************************************************************
  118. void StatusMessageThread (PGLOBALS pGlobals)
  119. {
  120. HANDLE hInstDll;
  121. MSG msg;
  122. DWORD dwResult;
  123. HANDLE hObjects[2];
  124. hInstDll = LoadLibrary (TEXT("msgina.dll"));
  125. if (pGlobals->hStatusDesktop) {
  126. SetThreadDesktop (pGlobals->hStatusDesktop);
  127. }
  128. pGlobals->hStatusDlg = CreateDialogParam (hDllInstance,
  129. MAKEINTRESOURCE(IDD_STATUS_MESSAGE_DIALOG),
  130. NULL, StatusMessageDlgProc,
  131. (LPARAM) pGlobals);
  132. SetEvent (pGlobals->hStatusInitEvent);
  133. if (pGlobals->hStatusDlg) {
  134. hObjects[0] = pGlobals->hStatusTermEvent;
  135. while (TRUE) {
  136. dwResult = MsgWaitForMultipleObjectsEx (1, hObjects, INFINITE,
  137. (QS_ALLPOSTMESSAGE | QS_ALLINPUT),
  138. MWMO_INPUTAVAILABLE);
  139. if (dwResult == WAIT_FAILED) {
  140. break;
  141. }
  142. if (dwResult == WAIT_OBJECT_0) {
  143. break;
  144. }
  145. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
  146. if (!IsDialogMessage (pGlobals->hStatusDlg, &msg)) {
  147. TranslateMessage(&msg);
  148. DispatchMessage(&msg);
  149. }
  150. if (WaitForSingleObject (pGlobals->hStatusTermEvent, 0) == WAIT_OBJECT_0) {
  151. goto ExitLoop;
  152. }
  153. }
  154. }
  155. ExitLoop:
  156. DestroyWindow(pGlobals->hStatusDlg);
  157. pGlobals->hStatusDlg = NULL;
  158. }
  159. if (hInstDll) {
  160. FreeLibraryAndExitThread(hInstDll, TRUE);
  161. } else {
  162. ExitThread (TRUE);
  163. }
  164. }
  165. //
  166. // Creates and displays the initial status message
  167. //
  168. // Set in WlxInitialize
  169. DWORD g_dwMainThreadId = 0; // Creation or removal of the status dialog is not thread safe.
  170. // It is kind of difficult to fix with a critsec because of
  171. // the mix of objects and windows messages. one can't hold
  172. // a critsec accross a window message call as it would introduce
  173. // the possibility of deadlocks
  174. BOOL
  175. WINAPI
  176. WlxDisplayStatusMessage(PVOID pWlxContext,
  177. HDESK hDesktop,
  178. DWORD dwOptions,
  179. PWSTR pTitle,
  180. PWSTR pMessage)
  181. {
  182. PGLOBALS pGlobals = (PGLOBALS) pWlxContext;
  183. DWORD dwThreadId;
  184. HANDLE hProcess;
  185. if (!pGlobals) {
  186. SetLastError(ERROR_INVALID_PARAMETER);
  187. return FALSE;
  188. }
  189. if (g_dwMainThreadId == GetCurrentThreadId()) // Denies creation/deletion on other threads
  190. { // than the main thread of winlogon
  191. if (!pGlobals->hStatusDlg) {
  192. if (!ReadWinlogonBoolValue(DISABLE_STATUS_MESSAGES, FALSE)) {
  193. pGlobals->hStatusInitEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
  194. pGlobals->hStatusTermEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
  195. if (pGlobals->hStatusInitEvent && pGlobals->hStatusTermEvent) {
  196. hProcess = GetCurrentProcess();
  197. if ( FALSE == DuplicateHandle(
  198. hProcess,
  199. hDesktop,
  200. hProcess,
  201. &(pGlobals->hStatusDesktop),
  202. 0, // ignored, DUPLICATE_SAME_ACCESS is set
  203. FALSE, // no inherit on the handle
  204. DUPLICATE_SAME_ACCESS) )
  205. {
  206. DebugLog((DEB_ERROR, "DuplicateHandle failed: %#x", GetLastError()));
  207. return FALSE;
  208. }
  209. //
  210. // Set the globals here so that StatusMessageDlgProc can look at them in WM_INITDIALOG.
  211. //
  212. pGlobals->dwStatusOptions = dwOptions;
  213. pGlobals->hStatusThread = CreateThread (NULL,
  214. 0,
  215. (LPTHREAD_START_ROUTINE) StatusMessageThread,
  216. (LPVOID) pGlobals,
  217. 0,
  218. &dwThreadId);
  219. if (pGlobals->hStatusThread) {
  220. DWORD dwWaitResult;
  221. do {
  222. dwWaitResult = WaitForSingleObject(pGlobals->hStatusInitEvent, 0);
  223. if (dwWaitResult != WAIT_OBJECT_0) {
  224. dwWaitResult = MsgWaitForMultipleObjects(1,
  225. &pGlobals->hStatusInitEvent,
  226. FALSE,
  227. INFINITE,
  228. QS_ALLPOSTMESSAGE | QS_ALLINPUT);
  229. if (dwWaitResult == WAIT_OBJECT_0 + 1) {
  230. MSG msg;
  231. if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
  232. TranslateMessage(&msg);
  233. DispatchMessage(&msg);
  234. }
  235. }
  236. }
  237. } while (dwWaitResult == WAIT_OBJECT_0 + 1);
  238. }
  239. }
  240. }
  241. }
  242. }
  243. if (pGlobals->hStatusDlg) {
  244. if (pTitle) {
  245. SetWindowText (pGlobals->hStatusDlg, pTitle);
  246. }
  247. SetDlgItemText (pGlobals->hStatusDlg, IDC_STATUS_MESSAGE_TEXT, pMessage);
  248. _Shell_LogonStatus_ShowStatusMessage(pMessage);
  249. if (dwOptions & STATUSMSG_OPTION_SETFOREGROUND) {
  250. SetForegroundWindow (pGlobals->hStatusDlg);
  251. }
  252. }
  253. return TRUE;
  254. }
  255. //
  256. // Gets the current status message
  257. //
  258. BOOL
  259. WINAPI
  260. WlxGetStatusMessage(PVOID pWlxContext,
  261. DWORD *pdwOptions,
  262. PWSTR pMessage,
  263. DWORD dwBufferSize)
  264. {
  265. PGLOBALS pGlobals = (PGLOBALS) pWlxContext;
  266. DWORD dwLen;
  267. if (!pGlobals || !pMessage) {
  268. SetLastError(ERROR_INVALID_PARAMETER);
  269. return FALSE;
  270. }
  271. dwLen = (DWORD) SendDlgItemMessage (pGlobals->hStatusDlg, IDC_STATUS_MESSAGE_TEXT,
  272. WM_GETTEXTLENGTH, 0, 0);
  273. if (dwBufferSize < dwLen) {
  274. SetLastError (ERROR_INSUFFICIENT_BUFFER);
  275. return FALSE;
  276. }
  277. GetDlgItemText (pGlobals->hStatusDlg, IDC_STATUS_MESSAGE_TEXT,
  278. pMessage, dwBufferSize);
  279. if (pdwOptions) {
  280. *pdwOptions = pGlobals->dwStatusOptions;
  281. }
  282. return TRUE;
  283. }
  284. //
  285. // Removes the status dialog
  286. //
  287. BOOL
  288. WINAPI
  289. WlxRemoveStatusMessage(PVOID pWlxContext)
  290. {
  291. PGLOBALS pGlobals = (PGLOBALS) pWlxContext;
  292. if (!pGlobals) {
  293. SetLastError(ERROR_INVALID_PARAMETER);
  294. return FALSE;
  295. }
  296. if (g_dwMainThreadId != GetCurrentThreadId()) { // Denies creation/deletion on other threads
  297. return FALSE;
  298. }
  299. if (pGlobals->hStatusTermEvent) {
  300. SetEvent(pGlobals->hStatusTermEvent);
  301. if (pGlobals->hStatusThread) {
  302. if (pGlobals->hStatusDlg) {
  303. DWORD dwWaitResult;
  304. do {
  305. dwWaitResult = WaitForSingleObject(pGlobals->hStatusThread, 0);
  306. if (dwWaitResult != WAIT_OBJECT_0) {
  307. dwWaitResult = MsgWaitForMultipleObjects(1,
  308. &pGlobals->hStatusThread,
  309. FALSE,
  310. 10000,
  311. QS_ALLPOSTMESSAGE | QS_ALLINPUT);
  312. if (dwWaitResult == WAIT_OBJECT_0 + 1) {
  313. MSG msg;
  314. if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
  315. TranslateMessage(&msg);
  316. DispatchMessage(&msg);
  317. }
  318. }
  319. }
  320. } while (dwWaitResult == WAIT_OBJECT_0 + 1);
  321. }
  322. CloseHandle (pGlobals->hStatusThread);
  323. }
  324. CloseHandle (pGlobals->hStatusTermEvent);
  325. }
  326. if (pGlobals->hStatusInitEvent) {
  327. CloseHandle (pGlobals->hStatusInitEvent);
  328. }
  329. pGlobals->hStatusInitEvent = NULL;
  330. pGlobals->hStatusTermEvent = NULL;
  331. pGlobals->hStatusThread = NULL;
  332. if (pGlobals->hStatusDesktop)
  333. {
  334. //
  335. // We duplicate the handle so we should always close
  336. //
  337. // OLD COMMENT:
  338. // Close the desktop handle here. Since the status thread
  339. // was using it, Winlogon was unable to close the handle
  340. // itself so we have to do it now.
  341. //
  342. CloseDesktop(pGlobals->hStatusDesktop);
  343. pGlobals->hStatusDesktop = NULL;
  344. }
  345. pGlobals->hStatusDlg = NULL;
  346. return TRUE;
  347. }