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.

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