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.

464 lines
14 KiB

  1. #include "msgina.h"
  2. // This gives me a yucky feeling, but we
  3. // use CRT all over the place in gina.
  4. #include <stdio.h>
  5. #include <windowsx.h>
  6. #include <regstr.h>
  7. #include <help.h>
  8. #include <Wtsapi32.h>
  9. #include "shtdnp.h"
  10. typedef struct _DIRTYDLGDATA
  11. {
  12. REASONDATA ReasonData;
  13. DWORD dwFlags;
  14. BOOL fEndDialogOnActivate;
  15. } DIRTYDLGDATA, *PDIRTYDLGDATA;
  16. // Internal function prototypes
  17. BOOL Dirty_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam);
  18. BOOL Dirty_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify);
  19. BOOL Dirty_OnEraseBkgnd(HWND hwnd, HDC hdc);
  20. INT_PTR CALLBACK Dirty_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam,
  21. LPARAM lParam);
  22. INT_PTR DialogItemToGinaResult(DWORD dwDialogItem, BOOL fAutoPowerdown);
  23. // Enable the OK button based on the selected reason code and the comments / bug id.
  24. void Enable_OK( HWND hwnd, PDIRTYDLGDATA pdata ) {
  25. if( ReasonCodeNeedsComment( pdata->ReasonData.dwReasonSelect )) {
  26. // See if we have a comment.
  27. if( pdata->ReasonData.cCommentLen == 0 ) {
  28. EnableWindow( GetDlgItem( hwnd, IDOK ), FALSE );
  29. return;
  30. }
  31. }
  32. if( ReasonCodeNeedsBugID( pdata->ReasonData.dwReasonSelect )) {
  33. // See if we have a BugID.
  34. if( pdata->ReasonData.cBugIDLen == 0 ) {
  35. EnableWindow( GetDlgItem( hwnd, IDOK ), FALSE );
  36. return;
  37. }
  38. }
  39. EnableWindow( GetDlgItem( hwnd, IDOK ), TRUE );
  40. }
  41. BOOL Dirty_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
  42. {
  43. PDIRTYDLGDATA pdata = (PDIRTYDLGDATA) lParam;
  44. HWND hwndCombo;
  45. int iOption;
  46. int iComboItem;
  47. int nComboItemCnt;
  48. SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) lParam);
  49. if (!(pdata->dwFlags & SHTDN_NOBRANDINGBITMAP))
  50. {
  51. // Move all our controls down so the branding fits
  52. SizeForBranding(hwnd, FALSE);
  53. }
  54. // Set up the reason data.
  55. // Add the items specified to the combo box
  56. hwndCombo = GetDlgItem(hwnd, IDC_DIRTYREASONS_COMBO);
  57. for (iOption = 0; iOption < pdata->ReasonData.cReasons; iOption ++)
  58. {
  59. // Add the option
  60. iComboItem = ComboBox_AddString(hwndCombo,
  61. pdata->ReasonData.rgReasons[iOption]->szName);
  62. if (iComboItem != (int) CB_ERR)
  63. {
  64. // Store a pointer to the option
  65. ComboBox_SetItemData(hwndCombo, iComboItem,
  66. pdata->ReasonData.rgReasons[iOption]);
  67. // See if we should select this option
  68. if (pdata->ReasonData.rgReasons[iOption]->dwCode == pdata->ReasonData.dwReasonSelect)
  69. {
  70. ComboBox_SetCurSel(hwndCombo, iComboItem);
  71. }
  72. }
  73. }
  74. nComboItemCnt = ComboBox_GetCount(hwndCombo);
  75. if(nComboItemCnt > 0 && pdata->ReasonData.cCommentLen != 0)
  76. {
  77. int iItem;
  78. for(iItem = 0; iItem < nComboItemCnt; iItem++)
  79. {
  80. PREASON pReason = (PREASON) ComboBox_GetItemData(hwndCombo, iItem);
  81. if(pReason->dwCode == (UDIRTYUI | SHTDN_REASON_MAJOR_SYSTEM | SHTDN_REASON_MINOR_BLUESCREEN))
  82. {
  83. ComboBox_SetCurSel(hwndCombo, iItem);
  84. Edit_SetText(GetDlgItem(hwnd, IDC_DIRTYREASONS_COMMENT), pdata->ReasonData.szComment);
  85. EnableWindow( GetDlgItem( hwnd, IDOK ), TRUE );
  86. break;
  87. }
  88. }
  89. SetReasonDescription(hwndCombo,
  90. GetDlgItem(hwnd, IDC_DIRTYREASONS_DESCRIPTION));
  91. }
  92. else
  93. {
  94. // If we don't have a selection in the combo, do a default selection
  95. if (ComboBox_GetCurSel(hwndCombo) == CB_ERR)
  96. {
  97. pdata->ReasonData.dwReasonSelect = pdata->ReasonData.rgReasons[ 0 ]->dwCode;
  98. ComboBox_SetCurSel(hwndCombo, 0);
  99. }
  100. SetReasonDescription(hwndCombo,
  101. GetDlgItem(hwnd, IDC_DIRTYREASONS_DESCRIPTION));
  102. // Enable the OK button
  103. Enable_OK( hwnd, pdata );
  104. }
  105. // Setup the comment box and BugId boxes
  106. // We must fix the maximum characters.
  107. SendMessage( GetDlgItem(hwnd, IDC_DIRTYREASONS_COMMENT), EM_LIMITTEXT, (WPARAM)MAX_REASON_COMMENT_LEN, (LPARAM)0 );
  108. SendMessage( GetDlgItem(hwnd, IDC_DIRTYREASONS_BUGID), EM_LIMITTEXT, (WPARAM)MAX_REASON_BUGID_LEN, (LPARAM)0 );
  109. // If we get an activate message, dismiss the dialog, since we just lost
  110. // focus
  111. pdata->fEndDialogOnActivate = TRUE;
  112. CentreWindow(hwnd);
  113. return TRUE;
  114. }
  115. BOOL Dirty_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
  116. {
  117. BOOL fHandled = FALSE;
  118. DWORD dwDlgResult = TRUE;
  119. PDIRTYDLGDATA pdata = (PDIRTYDLGDATA) GetWindowLongPtr(hwnd, GWLP_USERDATA);
  120. switch (id)
  121. {
  122. case IDOK:
  123. if (codeNotify == BN_CLICKED)
  124. {
  125. pdata->ReasonData.dwReasonSelect = 0;
  126. pdata->ReasonData.dwReasonSelect = GetReasonSelection(GetDlgItem(hwnd, IDC_DIRTYREASONS_COMBO));
  127. if (pdata->ReasonData.dwReasonSelect == SHTDN_REASON_UNKNOWN ) {
  128. break;
  129. }
  130. // Fill the comment field with the Problem Id followed by the comment on a new line.
  131. pdata->ReasonData.cBugIDLen = GetWindowText( GetDlgItem(hwnd, IDC_DIRTYREASONS_BUGID), pdata->ReasonData.szComment, MAX_REASON_BUGID_LEN );
  132. lstrcat(pdata->ReasonData.szComment + pdata->ReasonData.cBugIDLen,L"\n");
  133. pdata->ReasonData.cBugIDLen += lstrlen(L"\n");
  134. pdata->ReasonData.cCommentLen = GetWindowText( GetDlgItem(hwnd, IDC_DIRTYREASONS_COMMENT),
  135. pdata->ReasonData.szComment + pdata->ReasonData.cBugIDLen,
  136. MAX_REASON_COMMENT_LEN - pdata->ReasonData.cBugIDLen);
  137. pdata->ReasonData.cCommentLen += pdata->ReasonData.cBugIDLen ;
  138. pdata->fEndDialogOnActivate = FALSE;
  139. fHandled = TRUE;
  140. EndDialog(hwnd, (int) dwDlgResult);
  141. }
  142. break;
  143. case IDC_DIRTYREASONS_COMBO:
  144. if (codeNotify == CBN_SELCHANGE)
  145. {
  146. SetReasonDescription(hwndCtl,
  147. GetDlgItem(hwnd, IDC_DIRTYREASONS_DESCRIPTION));
  148. pdata->ReasonData.dwReasonSelect = GetReasonSelection(hwndCtl);
  149. Enable_OK( hwnd, pdata );
  150. fHandled = TRUE;
  151. }
  152. break;
  153. case IDC_DIRTYREASONS_COMMENT:
  154. if( codeNotify == EN_CHANGE)
  155. {
  156. pdata->ReasonData.cCommentLen = GetWindowTextLength( GetDlgItem(hwnd, IDC_DIRTYREASONS_COMMENT));
  157. Enable_OK( hwnd, pdata );
  158. fHandled = TRUE;
  159. }
  160. break;
  161. case IDC_DIRTYREASONS_BUGID:
  162. if( codeNotify == EN_CHANGE)
  163. {
  164. pdata->ReasonData.cBugIDLen = GetWindowTextLength( GetDlgItem(hwnd, IDC_DIRTYREASONS_BUGID));
  165. Enable_OK( hwnd, pdata );
  166. fHandled = TRUE;
  167. }
  168. break;
  169. case IDHELP:
  170. if (codeNotify == BN_CLICKED)
  171. {
  172. WinHelp(hwnd, TEXT("windows.hlp>proc4"), HELP_CONTEXT, (DWORD) IDH_TRAY_SHUTDOWN_HELP);
  173. }
  174. break;
  175. }
  176. return fHandled;
  177. }
  178. BOOL Dirty_OnEraseBkgnd(HWND hwnd, HDC hdc)
  179. {
  180. BOOL fRet;
  181. PDIRTYDLGDATA pdata = (PDIRTYDLGDATA) GetWindowLongPtr(hwnd, GWLP_USERDATA);
  182. // Draw the branding bitmap
  183. if (!(pdata->dwFlags & SHTDN_NOBRANDINGBITMAP))
  184. {
  185. fRet = PaintBranding(hwnd, hdc, 0, FALSE, FALSE, COLOR_BTNFACE);
  186. }
  187. else
  188. {
  189. fRet = FALSE;
  190. }
  191. return fRet;
  192. }
  193. INT_PTR CALLBACK Dirty_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam,
  194. LPARAM lParam)
  195. {
  196. switch (uMsg)
  197. {
  198. HANDLE_MSG(hwnd, WM_INITDIALOG, Dirty_OnInitDialog);
  199. HANDLE_MSG(hwnd, WM_COMMAND, Dirty_OnCommand);
  200. HANDLE_MSG(hwnd, WM_ERASEBKGND, Dirty_OnEraseBkgnd);
  201. case WLX_WM_SAS:
  202. {
  203. // If this is someone hitting C-A-D, swallow it.
  204. if (wParam == WLX_SAS_TYPE_CTRL_ALT_DEL)
  205. return TRUE;
  206. // Other SAS's (like timeout), return FALSE and let winlogon
  207. // deal with it.
  208. return FALSE;
  209. }
  210. break;
  211. case WM_INITMENUPOPUP:
  212. {
  213. EnableMenuItem((HMENU)wParam, SC_MOVE, MF_BYCOMMAND|MF_GRAYED);
  214. }
  215. break;
  216. case WM_SYSCOMMAND:
  217. // Blow off moves (only really needed for 32bit land).
  218. if ((wParam & ~0x0F) == SC_MOVE)
  219. return TRUE;
  220. break;
  221. }
  222. return FALSE;
  223. }
  224. /****************************************************************************
  225. WinlogonDirtyDialog
  226. --------------
  227. Launches the shutdown dialog.
  228. If hWlx and pfnWlxDialogBoxParam are non-null, pfnWlxDialogBoxParam will
  229. be used to launch the dialog box so we can intelligently respond to WLX
  230. messages. Only if WinLogon is the caller should this be done.
  231. Other flags are listed in shtdndlg.h.
  232. ****************************************************************************/
  233. INT_PTR
  234. WinlogonDirtyDialog(
  235. HWND hwndParent,
  236. PGLOBALS pGlobals
  237. )
  238. {
  239. // Array of shutdown options - the dialog data
  240. DIRTYDLGDATA data;
  241. DWORD dwResult = TRUE;
  242. HKEY hKey = 0;
  243. DWORD rc;
  244. DWORD ShowReasonUI = 0x0;
  245. DWORD DirtyShutdownHappened;
  246. DWORD ShouldClearDirtyShutdownValue = TRUE;
  247. DWORD ValueSize = sizeof (DWORD);
  248. DWORD dwBugcheckStringSize = MAX_REASON_COMMENT_LEN * sizeof(WCHAR);
  249. BOOL fFromPolicy = FALSE;
  250. // Set the initially selected item
  251. data.ReasonData.dwReasonSelect = 0;
  252. data.ReasonData.rgReasons = 0;
  253. data.ReasonData.cReasons = 0;
  254. data.ReasonData.cReasonCapacity = 0;
  255. //
  256. // See if we need to show this dialog.
  257. // We need to check the group policy first. If the group policy
  258. // does not exist we will fall back on the reliabiltiy key.
  259. //
  260. rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, RELIABILITY_POLICY_KEY, 0, KEY_ALL_ACCESS, &hKey);
  261. if(rc == ERROR_SUCCESS)
  262. {
  263. rc = RegQueryValueEx (hKey, RELIABILITY_POLICY_SHUTDOWNREASONUI, NULL, NULL, (UCHAR *)&ShowReasonUI, &ValueSize);
  264. RegCloseKey (hKey);
  265. hKey = 0;
  266. //
  267. // Now check the sku to decide whether we should show the dialog
  268. //
  269. if(rc == ERROR_SUCCESS)
  270. {
  271. OSVERSIONINFOEX osVersionInfoEx;
  272. osVersionInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  273. if(ShowReasonUI == POLICY_SHOWREASONUI_NEVER || ShowReasonUI == POLICY_SHOWREASONUI_ALWAYS)
  274. {
  275. //do nothing.
  276. }
  277. else if(GetVersionEx( (LPOSVERSIONINFOW) &osVersionInfoEx ))
  278. {
  279. //
  280. // if ShowReasonUI is anything other than 2 or 3, we think it is 0.
  281. //
  282. switch ( osVersionInfoEx.wProductType )
  283. {
  284. case VER_NT_WORKSTATION:
  285. if(ShowReasonUI == POLICY_SHOWREASONUI_WORKSTATIONONLY)
  286. ShowReasonUI = 1;
  287. else
  288. ShowReasonUI = 0;
  289. break;
  290. default:
  291. if(ShowReasonUI == POLICY_SHOWREASONUI_SERVERONLY)
  292. ShowReasonUI = 1;
  293. else
  294. ShowReasonUI = 0;
  295. break;
  296. }
  297. }
  298. else
  299. {
  300. //
  301. // If we fail, assume not showing.
  302. //
  303. ShowReasonUI = 0;
  304. }
  305. }
  306. }
  307. if(rc != ERROR_SUCCESS) //we failed to get the policy
  308. {
  309. rc = RegCreateKeyEx (HKEY_LOCAL_MACHINE, REGSTR_PATH_RELIABILITY, 0, NULL, REG_OPTION_NON_VOLATILE,
  310. KEY_ALL_ACCESS, NULL, &hKey, NULL);
  311. }
  312. else
  313. {
  314. fFromPolicy = TRUE;
  315. }
  316. if (rc == ERROR_SUCCESS) {
  317. if(!fFromPolicy)
  318. {
  319. rc = RegQueryValueEx (hKey, REGSTR_VAL_SHOWREASONUI, NULL, NULL, (UCHAR *)&ShowReasonUI, &ValueSize);
  320. }
  321. if ( (rc == ERROR_SUCCESS) && (ShowReasonUI) ) {
  322. //
  323. // We need to open the reliability key if we have not yet.
  324. //
  325. if(fFromPolicy)
  326. {
  327. rc = RegCreateKeyEx (HKEY_LOCAL_MACHINE, REGSTR_PATH_RELIABILITY, 0, NULL, REG_OPTION_NON_VOLATILE,
  328. KEY_ALL_ACCESS, NULL, &hKey, NULL);
  329. }
  330. ValueSize = sizeof(DWORD);
  331. if(rc == ERROR_SUCCESS)
  332. {
  333. rc = RegQueryValueEx (hKey, L"DirtyShutDown", NULL, NULL, (UCHAR *)&DirtyShutdownHappened, &ValueSize);
  334. if ( (rc == ERROR_SUCCESS) && (DirtyShutdownHappened) ) {
  335. // We do need to show the dialog.
  336. // Read in the strings for the shutdown option names and descriptions
  337. if( BuildReasonArray( &data.ReasonData, FALSE, TRUE ))
  338. {
  339. data.ReasonData.szBugID[ 0 ] = 0;
  340. data.ReasonData.cBugIDLen = 0;
  341. //If a bugcheck happenned, get the bugcheck string from registry.
  342. rc = RegQueryValueEx (hKey, L"BugcheckString", NULL, NULL, (LPBYTE)data.ReasonData.szComment, &dwBugcheckStringSize);
  343. if(rc != ERROR_SUCCESS)
  344. {
  345. data.ReasonData.szComment[ 0 ] = 0;
  346. data.ReasonData.cCommentLen = 0;
  347. }
  348. else
  349. {
  350. RegDeleteValue( hKey, L"BugcheckString");
  351. data.ReasonData.cCommentLen = dwBugcheckStringSize;
  352. }
  353. // Display the dialog and return the user's selection
  354. // Figure out what flags to pass
  355. // for sure no help button
  356. data.dwFlags = SHTDN_NOHELP;
  357. // On terminal server, no branding bitmap either
  358. if( GetSystemMetrics( SM_REMOTESESSION ))
  359. {
  360. data.dwFlags |= SHTDN_NOBRANDINGBITMAP;
  361. }
  362. dwResult = ( DWORD )pWlxFuncs->WlxDialogBoxParam( pGlobals->hGlobalWlx,
  363. hDllInstance, MAKEINTRESOURCE( IDD_DIRTY_DIALOG ),
  364. hwndParent, Dirty_DialogProc, ( LPARAM )&data );
  365. // If we timed out then log the user off.
  366. if( dwResult != TRUE )
  367. {
  368. DestroyReasons( &data.ReasonData );
  369. // If we log them out successfully, then we don't clear the dirty shutdown value.
  370. ShouldClearDirtyShutdownValue = FALSE ;
  371. dwResult = WLX_SAS_ACTION_LOGOFF;
  372. }
  373. else
  374. {
  375. // Record the event.
  376. SHUTDOWN_REASON sr;
  377. sr.cbSize = sizeof(SHUTDOWN_REASON);
  378. sr.uFlags = EWX_SHUTDOWN;
  379. sr.dwReasonCode = data.ReasonData.dwReasonSelect;
  380. sr.dwEventType = SR_EVENT_DIRTY;
  381. sr.lpszComment = data.ReasonData.szComment;
  382. RecordShutdownReason(&sr);
  383. // Destroy the allocated data.
  384. DestroyReasons( &data.ReasonData );
  385. dwResult = TRUE;
  386. }
  387. }
  388. }
  389. // See if we should be clearing the dirty shutdown value in the registry.
  390. if( ShouldClearDirtyShutdownValue )
  391. {
  392. RegDeleteValue( hKey, L"DirtyShutDown" );
  393. }
  394. }
  395. }
  396. }
  397. if(hKey)
  398. RegCloseKey (hKey);
  399. return dwResult;
  400. }