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.

2929 lines
77 KiB

  1. #ifndef SECURITY_WIN32
  2. #define SECURITY_WIN32
  3. #endif
  4. #include <nt.h>
  5. #include <ntrtl.h>
  6. #include <nturtl.h>
  7. #include <windows.h>
  8. #include <initguid.h>
  9. #include <windowsx.h>
  10. #include <winuserp.h>
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <assert.h>
  14. #include <mdcommsg.h>
  15. #include <lm.h>
  16. #include <shlobj.h>
  17. #include <Cmnquery.h>
  18. #include <dsclient.h>
  19. #include <Dsquery.h>
  20. #include <htmlhelp.h>
  21. #include <reason.h>
  22. #include <regstr.h>
  23. #include "resource.h"
  24. #ifndef WARNING_DIRTY_REBOOT
  25. #define WARNING_DIRTY_REBOOT 0x80000434L
  26. #endif
  27. //#define SNAPSHOT_TEST
  28. #ifdef SNAPSHOT_TEST
  29. #define TESTMSG(x) \
  30. WriteToConsole((x))
  31. #else
  32. #define TESTMSG(x)
  33. #endif //SNAPSHOT_TEST
  34. #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
  35. #define ERROR_WITH_SZ(id, sz, code) \
  36. { \
  37. LPWSTR szBuf = LoadWString(id);\
  38. if (szBuf)\
  39. {\
  40. if (sz && wcslen(sz) > 0) \
  41. {\
  42. LPWSTR szBuf1 = (LPWSTR)LocalAlloc(LMEM_FIXED, (wcslen(szBuf) + wcslen(sz) + 20) * sizeof(WCHAR));\
  43. if (szBuf1)\
  44. {\
  45. if (code != 0) \
  46. wsprintf(szBuf1, L"%s: %s(%d)\n", sz, szBuf, code);\
  47. else \
  48. wsprintf(szBuf1, L"%s: %s\n", sz, szBuf);\
  49. WriteToError(szBuf1);\
  50. LocalFree(szBuf1);\
  51. }\
  52. }\
  53. else\
  54. {\
  55. LPWSTR szBuf1 = (LPWSTR)LocalAlloc(LMEM_FIXED, (wcslen(szBuf) + 20) * sizeof(WCHAR));\
  56. if (szBuf1)\
  57. {\
  58. if (code != 0) \
  59. wsprintf(szBuf1, L"%s(%d)\n", szBuf, code);\
  60. else \
  61. wsprintf(szBuf1, L"%s\n", szBuf);\
  62. WriteToError(szBuf1);\
  63. LocalFree(szBuf1);\
  64. }\
  65. }\
  66. LocalFree(szBuf);\
  67. }\
  68. }
  69. //
  70. // Default warning state for warning user check button
  71. //
  72. #define DEFAULTWARNINGSTATE BST_CHECKED
  73. #define TITLEWARNINGLEN 32
  74. #define MINCOMMENTLEN 0
  75. #define MAX_TIMEOUT 60*10 // 10 min.
  76. #define DEFAULT_TIMEOUT 30
  77. // Name of the executable
  78. LPWSTR g_lpszProgramName = NULL;
  79. // Help dir.
  80. LPWSTR g_lpszHelpdir = NULL;
  81. LPWSTR g_lpszHelpdirHlp = NULL;
  82. LPWSTR g_lpszHelpdirChm = NULL;
  83. LPWSTR g_lpszHelpdirWindows = NULL;
  84. // Name of help file.
  85. LPWSTR HELP_FILE = L"rrc.hlp";
  86. LPWSTR CHM_FILE = L"rrc.chm";
  87. LPWSTR WINDOWS_HELP = L"Windows.hlp";
  88. LPWSTR CHM_MAIN = L"::/rrcHowToShutdownRemotely.htm";
  89. LPWSTR g_lpszDefaultTimeout = L"30";
  90. LPWSTR g_lpszMaxTimeout = L"600";
  91. // original edit control win proc.
  92. WNDPROC wpOrigEditProc;
  93. //
  94. // Help ids
  95. //
  96. DWORD ShutdownDialogHelpIds[] =
  97. {
  98. IDOK, 28443,
  99. IDCANCEL, 28444,
  100. IDHELP, 28445 ,
  101. IDC_COMBOACTION, IDH_SHUTDOWN_COMBOACTION,
  102. IDC_COMBOOPTION, IDH_SHUTDOWN_COMBOOPTION,
  103. IDC_LISTSELECTEDCOMPUTERS, IDH_SHUTDOWN_SELECTEDCOMPUTERS,
  104. IDC_BUTTONREMOVE, IDH_SHUTDOWN_BUTTONREMOVE,
  105. IDC_BUTTONBROWSE, IDH_SHUTDOWN_BUTTONBROWSE,
  106. IDC_CHECKWARNING, IDH_SHUTDOWN_CHECKWARNING,
  107. IDC_EDITTIMEOUT, IDH_SHUTDOWN_EDITTIMEOUT,
  108. IDC_EDITCOMMENT, IDH_SHUTDOWN_EDITCOMMENT,
  109. IDC_BUTTONADDNEW, IDH_SHUTDOWN_BUTTONADDNEW,
  110. IDC_CHECK_PLANNED, IDH_SHUTDOWN_CHECK_PLANNED,
  111. 0, 0
  112. };
  113. DWORD AddNewDialogHelpIds[] =
  114. {
  115. IDOK, 28443,
  116. IDCANCEL, 28444,
  117. IDC_EDIT_ADDCOMPUTERS_COMPUTERS, IDH_ADDNEW_COMPUTERS,
  118. 0, 0
  119. };
  120. //
  121. // Enum for all of the actions.
  122. //
  123. enum
  124. {
  125. ACTION_SHUTDOWN = 0,
  126. ACTION_RESTART = 1,
  127. ACTION_ANNOTATE,
  128. ACTION_LOGOFF,
  129. ACTION_STANDBY,
  130. ACTION_DISCONNECT,
  131. ACTION_ABORT
  132. };
  133. //
  134. // Resource IDs for actions.
  135. //
  136. DWORD g_dwActions[] =
  137. {
  138. IDS_ACTION_SHUTDOWN,
  139. IDS_ACTION_RESTART,
  140. // IDS_ACTION_LOGOFF,
  141. IDS_ACTION_ANNOTATE
  142. //IDS_ACTION_STANDBY,
  143. //IDS_ACTION_DISCONNECT,
  144. //IDS_ACTION_ABORT
  145. };
  146. enum
  147. {
  148. OPTION_ABORT = 0,
  149. OPTION_ANNOTATE,
  150. OPTION_HIBERNATE,
  151. OPTION_LOGOFF,
  152. OPTION_POWEROFF,
  153. OPTION_RESTART,
  154. OPTION_SHUTDOWN,
  155. FLAG_COMMENT = 0,
  156. FLAG_REASON,
  157. FLAG_MACHINE,
  158. FLAG_FORCE
  159. };
  160. //
  161. // Number of actions and the action strings loaded from resource.
  162. //
  163. const int g_nActions = sizeof(g_dwActions) / sizeof(DWORD);
  164. WCHAR g_lppszActions[g_nActions][MAX_PATH];
  165. LPWSTR g_lpszNewComputers = NULL;
  166. WCHAR g_lpszDefaultDomain[MAX_PATH] = L"";
  167. WCHAR g_lpszLocalComputerName[MAX_PATH] = L"";
  168. WCHAR g_lpszTitleWarning[TITLEWARNINGLEN];
  169. BOOL g_bAssumeShutdown = FALSE;
  170. BOOL g_bDirty = FALSE;
  171. struct _PROVIDER{
  172. LPWSTR szName;
  173. DWORD dwLen;
  174. };
  175. typedef struct _SHUTDOWNREASON
  176. {
  177. DWORD dwCode;
  178. WCHAR lpName[MAX_REASON_NAME_LEN];
  179. WCHAR lpDesc[MAX_REASON_DESC_LEN];
  180. } SHUTDOWNREASON, *PSHUTDOWNREASON;
  181. DWORD g_dwReasonSelect;
  182. DWORD g_dwActionSelect;
  183. typedef struct _SHUTDOWNCACHEDHWNDS
  184. {
  185. HWND hwndShutdownDialog;
  186. HWND hwndListSelectComputers;
  187. HWND hwndEditComment;
  188. HWND hwndStaticDesc;
  189. HWND hwndEditTimeout;
  190. HWND hwndButtonWarning;
  191. HWND hwndComboAction;
  192. HWND hwndComboOption;
  193. HWND hwndBtnAdd;
  194. HWND hwndBtnRemove;
  195. HWND hwndBtnBrowse;
  196. HWND hwndChkPlanned;
  197. HWND hwndButtonOK;
  198. HWND hwndStaticComment;
  199. } SHUTDOWNCACHEDHWNDS, *PSHUTDOWNCACHEDHWNDS;
  200. SHUTDOWNCACHEDHWNDS g_wins;
  201. enum
  202. {
  203. POWER_OPTION_HIBERNATE,
  204. POWER_OPTION_POWEROFF
  205. };
  206. HMODULE g_hDllInstance = NULL;
  207. typedef BOOL (*REASONBUILDPROC)(REASONDATA *, BOOL, BOOL);
  208. typedef VOID (*REASONDESTROYPROC)(REASONDATA *);
  209. BOOL GetComputerNameFromPath(LPWSTR szPath, LPWSTR szName);
  210. VOID AdjustWindowState();
  211. INT_PTR
  212. CALLBACK Shutdown_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam,
  213. LPARAM lParam);
  214. INT_PTR
  215. CALLBACK AddNew_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam,
  216. LPARAM lParam);
  217. INT_PTR
  218. CALLBACK Browse_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam,
  219. LPARAM lParam);
  220. BOOL Shutdown_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify);
  221. BOOL AddNew_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify);
  222. BOOL Browse_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify);
  223. BOOL Shutdown_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam);
  224. BOOL Browse_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam);
  225. BOOL PowerOptionEnabled(UINT option);
  226. BOOL Annotate(LPCWSTR lpMachine, LPDWORD lpdwReason, LPCWSTR lpComment, LPDWORD lpdwErr);
  227. VOID report_error(DWORD error_code, LPCWSTR pwszComputer);
  228. BOOL GetTokenHandle(PHANDLE pTokenHandle);
  229. BOOL GetUserSid(PTOKEN_USER *ppTokenUser);
  230. BOOL IsStaticControl (HWND hwnd);
  231. WCHAR* LoadWString(int resid);
  232. LRESULT APIENTRY EditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  233. typedef void (*PSetThreadUILanguage)(DWORD);
  234. class ShutdownHelp
  235. {
  236. DWORD dwCookie;
  237. public:
  238. ShutdownHelp():dwCookie(NULL)
  239. {
  240. HtmlHelp(NULL, NULL, HH_INITIALIZE, (ULONG_PTR)(&dwCookie));
  241. }
  242. ~ShutdownHelp()
  243. {
  244. // HtmlHelp(NULL, NULL, HH_CLOSE_ALL, 0);
  245. HtmlHelp(NULL, NULL, HH_UNINITIALIZE, dwCookie);
  246. }
  247. };
  248. class Reasons
  249. {
  250. public:
  251. PSHUTDOWNREASON m_lpReasons;
  252. int m_cReasons;
  253. int m_dwReasonSelect;
  254. WCHAR m_lpszDefaultTitle[MAX_REASON_NAME_LEN];
  255. Reasons():m_lpReasons(NULL),m_cReasons(0),m_dwReasonSelect(-1)
  256. {
  257. HMODULE hUser32;
  258. REASONBUILDPROC buildProc;
  259. REASONDESTROYPROC DestroyProc;
  260. WCHAR lpReasonName[MAX_REASON_NAME_LEN];
  261. REASONDATA Reasons;
  262. m_lpszDefaultTitle[0] = L'\0';
  263. hUser32 = LoadLibraryW(L"user32.dll");
  264. if(hUser32 != NULL)
  265. {
  266. //
  267. // We are using the user32.dll to get and destroy the reasons.
  268. // The reasons are added to the option combo and also cached for later use.
  269. //
  270. LoadStringW(hUser32, IDS_REASON_DEFAULT_TITLE, m_lpszDefaultTitle, MAX_REASON_NAME_LEN);
  271. m_lpszDefaultTitle[MAX_REASON_NAME_LEN-1] = L'\0';
  272. buildProc = (REASONBUILDPROC)GetProcAddress(hUser32, "BuildReasonArray");
  273. DestroyProc = (REASONDESTROYPROC)GetProcAddress(hUser32, "DestroyReasons");
  274. if(!buildProc || !DestroyProc)
  275. {
  276. FreeLibrary(hUser32);
  277. hUser32 = NULL;
  278. return;
  279. }
  280. if(!(*buildProc)(&Reasons, FALSE, FALSE))
  281. {
  282. report_error( GetLastError( ), NULL);
  283. FreeLibrary(hUser32);
  284. return;
  285. }
  286. if (Reasons.cReasons == 0)
  287. {
  288. (*DestroyProc)(&Reasons);
  289. //
  290. // BUG 592702: shutdown.exe .NET - no reasons listed when running on XP.
  291. // ON XP if both Clean and Dirty flags are FALSE, user32 won't build
  292. // any reason and return success, so we will retry it with Clean
  293. // and Dirty both are set to TRUE.
  294. //
  295. if(!(*buildProc)(&Reasons, TRUE, TRUE))
  296. {
  297. report_error( GetLastError( ), NULL);
  298. FreeLibrary(hUser32);
  299. return;
  300. }
  301. }
  302. }
  303. else
  304. {
  305. report_error( GetLastError( ), NULL);
  306. return;
  307. }
  308. //
  309. // Alloc space for reasons.
  310. //
  311. m_lpReasons = (PSHUTDOWNREASON)LocalAlloc(LMEM_FIXED, Reasons.cReasons * sizeof(SHUTDOWNREASON));
  312. if(!m_lpReasons)
  313. {
  314. (*DestroyProc)(&Reasons);
  315. report_error( GetLastError( ), NULL);
  316. FreeLibrary(hUser32);
  317. return;
  318. }
  319. //
  320. // Now populate the combo according the current check state and action.
  321. //
  322. for (int iOption = 0; iOption < (int)Reasons.cReasons; iOption++)
  323. {
  324. wcscpy(m_lpReasons[iOption].lpName, Reasons.rgReasons[iOption]->szName);
  325. wcscpy(m_lpReasons[iOption].lpDesc, Reasons.rgReasons[iOption]->szDesc);
  326. m_lpReasons[iOption].dwCode = Reasons.rgReasons[iOption]->dwCode;
  327. }
  328. m_cReasons = (int)Reasons.cReasons;
  329. (*DestroyProc)(&Reasons);
  330. FreeLibrary(hUser32);
  331. }
  332. ~Reasons()
  333. {
  334. if(m_lpReasons)
  335. LocalFree(m_lpReasons);
  336. }
  337. BOOL RequireComment(DWORD dwReason, BOOL isDirty = FALSE)
  338. {
  339. DWORD dwFlag = isDirty ? SHTDN_REASON_FLAG_DIRTY_PROBLEM_ID_REQUIRED : SHTDN_REASON_FLAG_COMMENT_REQUIRED;
  340. DWORD dwDirtyOrClean = isDirty ? SHTDN_REASON_FLAG_DIRTY_UI : SHTDN_REASON_FLAG_CLEAN_UI;
  341. DWORD dwAll = SHTDN_REASON_FLAG_DIRTY_PROBLEM_ID_REQUIRED | SHTDN_REASON_FLAG_COMMENT_REQUIRED
  342. | SHTDN_REASON_FLAG_DIRTY_UI | SHTDN_REASON_FLAG_CLEAN_UI;
  343. if (!m_lpReasons)
  344. return FALSE;
  345. if (dwReason & dwFlag)
  346. return TRUE;
  347. for(int i = 0; i < m_cReasons; i++)
  348. {
  349. if(m_lpReasons[i].dwCode & dwFlag)
  350. {
  351. if ( ((m_lpReasons[i].dwCode & ~dwAll) == (dwReason & ~dwAll))
  352. && (m_lpReasons[i].dwCode & dwDirtyOrClean) )
  353. return TRUE;
  354. }
  355. }
  356. return FALSE;
  357. }
  358. BOOL RequireComment(DWORD dwMajor, DWORD dwMinor, BOOL isDirty, BOOL isPlanned, BOOL isUserDefined)
  359. {
  360. DWORD dwReason = dwMinor;
  361. dwReason <<= 20;
  362. dwReason &= dwMajor;
  363. if(isPlanned)
  364. dwReason &= SHTDN_REASON_FLAG_PLANNED;
  365. if(isUserDefined)
  366. dwReason &= SHTDN_REASON_FLAG_USER_DEFINED;
  367. return RequireComment (dwReason, isDirty);
  368. }
  369. VOID FillCombo(HWND hwnd, BOOL isDirty, BOOL isPlanned, HWND hwndStatic)
  370. {
  371. int iOption;
  372. int iFirst = -1;
  373. DWORD dwPlanned = isPlanned ? SHTDN_REASON_FLAG_PLANNED : 0;
  374. DWORD dwDirty = isDirty ? SHTDN_REASON_FLAG_DIRTY_UI : SHTDN_REASON_FLAG_CLEAN_UI;
  375. if(! hwnd)
  376. return;
  377. //
  378. // Remove all items from combo
  379. //
  380. while (ComboBox_GetCount(hwnd))
  381. ComboBox_DeleteString(hwnd, 0);
  382. //
  383. // Now populate the combo according the current check state.
  384. //
  385. for (iOption = 0; iOption < (int)m_cReasons; iOption++)
  386. {
  387. if(((m_lpReasons[iOption].dwCode & SHTDN_REASON_FLAG_PLANNED) == dwPlanned)
  388. && ((m_lpReasons[iOption].dwCode & dwDirty) == dwDirty))
  389. {
  390. ComboBox_AddString(hwnd, m_lpReasons[iOption].lpName);
  391. if (iFirst == -1)
  392. iFirst = iOption;
  393. }
  394. }
  395. if(iFirst != -1)
  396. {
  397. ComboBox_SelectString(hwnd, -1, m_lpReasons[iFirst].lpName);
  398. if (hwndStatic)
  399. SetWindowTextW(hwndStatic, m_lpReasons[iFirst].lpDesc);
  400. }
  401. m_dwReasonSelect = iFirst;
  402. }
  403. VOID SetDesc(HWND hCombo, HWND hDesc)
  404. {
  405. WCHAR szName[MAX_REASON_NAME_LEN];
  406. if(!hCombo || !hDesc)
  407. return;
  408. GetWindowText(hCombo, (LPWSTR)szName, MAX_REASON_NAME_LEN);
  409. szName[MAX_REASON_NAME_LEN-1] = '\0';
  410. for(DWORD dwIndex = 0; dwIndex < (DWORD)m_cReasons; dwIndex++)
  411. {
  412. if(lstrcmp(szName, m_lpReasons[dwIndex].lpName) == 0)
  413. {
  414. SetWindowTextW(hDesc, m_lpReasons[dwIndex].lpDesc);
  415. m_dwReasonSelect = dwIndex;
  416. break;
  417. }
  418. }
  419. }
  420. VOID GetReasonTitle(DWORD dwReason, LPWSTR szBuf, DWORD dwSize)
  421. {
  422. DWORD dwFlagBits = SHTDN_REASON_FLAG_CLEAN_UI | SHTDN_REASON_FLAG_DIRTY_UI;
  423. if(!szBuf || dwSize == 0)
  424. return;
  425. for(int i = 0; i < m_cReasons; i++)
  426. {
  427. if ((dwReason & SHTDN_REASON_VALID_BIT_MASK) == (m_lpReasons[i].dwCode & SHTDN_REASON_VALID_BIT_MASK))
  428. {
  429. if ((!(dwReason & dwFlagBits) && !(m_lpReasons[i].dwCode & dwFlagBits))
  430. || (dwReason & SHTDN_REASON_FLAG_CLEAN_UI && m_lpReasons[i].dwCode & SHTDN_REASON_FLAG_CLEAN_UI)
  431. || (dwReason & SHTDN_REASON_FLAG_DIRTY_UI && m_lpReasons[i].dwCode & SHTDN_REASON_FLAG_DIRTY_UI) ) { // check flag bits.
  432. lstrcpynW(szBuf, m_lpReasons[i].lpName, dwSize - 1);
  433. szBuf[dwSize - 1] = '\0';
  434. return;
  435. }
  436. }
  437. }
  438. wcsncpy(szBuf, m_lpszDefaultTitle, dwSize - 1);
  439. szBuf[dwSize - 1] = '\0';
  440. }
  441. } g_reasons;
  442. //
  443. // Check whether a string is all white spaces.
  444. //
  445. BOOL
  446. IsEmpty(LPCWSTR lpCWSTR)
  447. {
  448. if(!lpCWSTR)
  449. return TRUE;
  450. while(*lpCWSTR && (*lpCWSTR == '\n' || *lpCWSTR == '\t' || *lpCWSTR == '\r' || *lpCWSTR == ' '))
  451. lpCWSTR++;
  452. if(*lpCWSTR)
  453. return FALSE;
  454. return TRUE;
  455. }
  456. // Write the string to console
  457. VOID
  458. WriteOutput(
  459. LPWSTR pszMsg,
  460. DWORD nStdHandle
  461. )
  462. {
  463. HANDLE hConsole = GetStdHandle( nStdHandle );
  464. if ( !pszMsg || !*pszMsg )
  465. return;
  466. DWORD dwStrLen = lstrlenW( pszMsg );
  467. LPSTR pszAMsg = NULL;
  468. DWORD dwBytesWritten = 0;
  469. DWORD dwMode = 0;
  470. if ( (GetFileType ( hConsole ) & FILE_TYPE_CHAR ) &&
  471. GetConsoleMode( hConsole, &dwMode ) )
  472. {
  473. WriteConsoleW( hConsole, pszMsg, dwStrLen, &dwBytesWritten, 0 );
  474. return;
  475. }
  476. // console redirect to a file.
  477. if ( !(pszAMsg = (LPSTR)LocalAlloc(LMEM_FIXED, (dwStrLen + 1) * sizeof(WCHAR) ) ) )
  478. {
  479. return;
  480. }
  481. if (WideCharToMultiByte(GetConsoleOutputCP(),
  482. 0,
  483. pszMsg,
  484. -1,
  485. pszAMsg,
  486. dwStrLen * sizeof(WCHAR),
  487. NULL,
  488. NULL) != 0
  489. && hConsole)
  490. {
  491. WriteFile( hConsole,
  492. pszAMsg,
  493. lstrlenA(pszAMsg),
  494. &dwBytesWritten,
  495. NULL );
  496. }
  497. LocalFree( pszAMsg );
  498. }
  499. // Write the string to stdout
  500. VOID
  501. WriteToConsole(
  502. LPWSTR pszMsg
  503. )
  504. {
  505. WriteOutput(pszMsg, STD_OUTPUT_HANDLE);
  506. }
  507. // Write the string to stderr
  508. VOID
  509. WriteToError(
  510. LPWSTR pszMsg
  511. )
  512. {
  513. WriteOutput(pszMsg, STD_ERROR_HANDLE);
  514. }
  515. // Report error.
  516. VOID
  517. report_error(
  518. DWORD error_code,
  519. LPCWSTR szComputer
  520. )
  521. {
  522. LPVOID msgBuf = 0;
  523. LPWSTR szBuf = NULL;
  524. int len = 0;
  525. if (error_code == 997 || error_code == 0)
  526. return;
  527. if (error_code == ERROR_NOT_READY)
  528. {
  529. ERROR_WITH_SZ(IDS_ERROR_NOT_READY, szComputer, error_code);
  530. return;
  531. }
  532. else if (error_code == ERROR_BAD_NETPATH || error_code == WSAHOST_NOT_FOUND)
  533. {
  534. ERROR_WITH_SZ(IDS_ERROR_NOT_AVAILABLE, szComputer, error_code);
  535. return;
  536. }
  537. else
  538. FormatMessageW(
  539. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  540. FORMAT_MESSAGE_FROM_SYSTEM |
  541. FORMAT_MESSAGE_IGNORE_INSERTS,
  542. NULL,
  543. error_code,
  544. MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), // Default language
  545. reinterpret_cast< wchar_t* >( &msgBuf ),
  546. 0,
  547. NULL);
  548. if (msgBuf)
  549. {
  550. // remove end newline.
  551. len = wcslen(reinterpret_cast< wchar_t* >( msgBuf ));
  552. reinterpret_cast< wchar_t* >( msgBuf )[len - 2] = L'\0';
  553. if (szComputer && wcslen(szComputer) > 0)
  554. {
  555. LPWSTR szBuf1 = (LPWSTR)LocalAlloc(LMEM_FIXED,
  556. (len + wcslen(szComputer) + 20) * sizeof(WCHAR));
  557. if (szBuf1)
  558. {
  559. wsprintf(szBuf1, L"%s: %s(%d)\n", szComputer, reinterpret_cast< wchar_t* >( msgBuf ), error_code);
  560. WriteToError(szBuf1);
  561. LocalFree(szBuf1);
  562. }
  563. }
  564. else
  565. {
  566. LPWSTR szBuf1 = (LPWSTR)LocalAlloc(LMEM_FIXED,
  567. (len + 20) * sizeof(WCHAR));
  568. if (szBuf1)
  569. {
  570. wsprintf(szBuf1, L"%s(%d)\n", reinterpret_cast< wchar_t* >( msgBuf ), error_code);
  571. WriteToError(szBuf1);
  572. LocalFree(szBuf1);
  573. }
  574. }
  575. LocalFree( msgBuf );
  576. }
  577. }
  578. BOOL
  579. parse_reason_code(
  580. LPCWSTR arg,
  581. LPDWORD lpdwReason
  582. )
  583. {
  584. // Code consists of flags;major;minor
  585. // Qingboz: Now we make major and minor code mandatory
  586. //
  587. BOOL fMajor = FALSE;
  588. BOOL fMinor = FALSE;
  589. BOOL fUserDefined = FALSE;
  590. int major = 0;
  591. int minor = 0;
  592. const int state_start = 0;
  593. const int state_flags = 0;
  594. const int state_major = 1;
  595. const int state_minor = 2;
  596. const int state_null = 3;
  597. const int state_done = 4;
  598. for( int i = 0, state = state_start; state != state_done; ++i )
  599. {
  600. switch( state )
  601. {
  602. case state_flags :
  603. // Expecting flags
  604. switch( arg[ i ] ) {
  605. case L'U' : case L'u' :
  606. if(fUserDefined)
  607. {
  608. //
  609. // Already set.
  610. //
  611. return FALSE;
  612. }
  613. fUserDefined = TRUE;
  614. break;
  615. case L'P' : case L'p' :
  616. if(*lpdwReason & 0x80000000)
  617. {
  618. //
  619. // Already set.
  620. //
  621. return FALSE;
  622. }
  623. *lpdwReason |= 0x80000000; // SHTDN_REASON_FLAG_PLANNED
  624. break;
  625. case L':' :
  626. if(i == 0) // ':' cannot be the first one now.
  627. return FALSE;
  628. state = state_major;
  629. break;
  630. case L'0':
  631. case L'1':
  632. case L'2':
  633. case L'3':
  634. case L'4':
  635. case L'5':
  636. case L'6':
  637. case L'7':
  638. case L'8':
  639. case L'9':
  640. if(i != 0) // A number here must be the first one.
  641. return FALSE;
  642. state = state_major;
  643. i--; // Go back one.
  644. break;
  645. default :
  646. return FALSE;
  647. }
  648. break;
  649. case state_major :
  650. // Expecting major
  651. if( arg[ i ] >= L'0' && arg[ i ] <= L'9' ) {
  652. fMajor = TRUE;
  653. major = major * 10 + arg[ i ] - L'0';
  654. }
  655. else {
  656. if(!fMajor)
  657. return FALSE;
  658. // Make sure we only have 8 bits
  659. if( major > 0xff ) return FALSE;
  660. if (major >= 64)
  661. *lpdwReason |= SHTDN_REASON_FLAG_USER_DEFINED;
  662. *lpdwReason |= major << 16;
  663. if( arg[ i ] != L':') {
  664. // missing minor reason.
  665. return FALSE;
  666. }
  667. state = state_minor;
  668. }
  669. break;
  670. case state_minor :
  671. // Expecting minor reason
  672. if( arg[ i ] >= L'0' && arg[ i ] <= L'9' ) {
  673. fMinor = TRUE;
  674. minor = minor * 10 + arg[ i ] - L'0';
  675. }
  676. else {
  677. if(!fMinor)
  678. return FALSE;
  679. // Make sure we only have 16 bits
  680. if( minor > 0xffff ) return FALSE;
  681. *lpdwReason = ( *lpdwReason & 0xffff0000 ) | minor;
  682. if( arg[ i ] != 0 )
  683. return FALSE;
  684. return TRUE;
  685. }
  686. break;
  687. default :
  688. return FALSE;
  689. }
  690. }
  691. return FALSE;
  692. }
  693. // Parses an integer if it is in decimal notation.
  694. // Returns FALSE if it is malformed.
  695. BOOL
  696. parse_int(
  697. const wchar_t* arg,
  698. LPDWORD lpdwInt
  699. )
  700. {
  701. *lpdwInt = 0;
  702. while( *arg ) {
  703. if( *arg >= L'0' && *arg <= L'9' ) {
  704. *lpdwInt = *lpdwInt * 10 + int( *arg++ - L'0' );
  705. }
  706. else {
  707. return FALSE;
  708. }
  709. }
  710. return TRUE;
  711. }
  712. // Parse options.
  713. // Returns FALSE if the option strings are malformed. This causes the usage to be printed.
  714. BOOL
  715. parse_options(
  716. int argc,
  717. wchar_t *argv[],
  718. LPBOOL lpfLogoff,
  719. LPBOOL lpfForce,
  720. LPBOOL lpfReboot,
  721. LPBOOL lpfHibernate,
  722. LPBOOL lpfAbort,
  723. LPBOOL lpfPoweroff,
  724. LPBOOL lpfAnnotate,
  725. LPWSTR *ppServerName,
  726. LPWSTR *ppMessage,
  727. LPDWORD lpdwTimeout,
  728. LPDWORD lpdwReason
  729. )
  730. {
  731. BOOL fShutdown = FALSE;
  732. BOOL fTimeout = FALSE;
  733. BOOL fComment = FALSE;
  734. BOOL fMachine = FALSE;
  735. BOOL fReason = FALSE;
  736. DWORD dwOption = 0;
  737. DWORD dwFlag = 0;
  738. *lpfLogoff = FALSE;
  739. *lpfForce = FALSE;
  740. *lpfReboot = FALSE;
  741. *lpfHibernate = FALSE;
  742. *lpfAbort = FALSE;
  743. *lpfPoweroff = FALSE;
  744. *lpfAnnotate = FALSE;
  745. *ppServerName = NULL;
  746. *ppMessage = NULL;
  747. *lpdwTimeout = DEFAULT_TIMEOUT;
  748. *lpdwReason = 0xff;
  749. //
  750. // Set default reason to be planned
  751. //
  752. *lpdwReason |= SHTDN_REASON_FLAG_PLANNED;
  753. for( int i = 1; i < argc; ++i )
  754. {
  755. wchar_t* arg = argv[ i ];
  756. switch( arg[ 0 ] )
  757. {
  758. case L'/' : case L'-' :
  759. switch( arg[ 1 ] )
  760. {
  761. case L'L' : case L'l' :
  762. if (*lpfLogoff)
  763. return FALSE;
  764. *lpfLogoff = TRUE;
  765. if (arg[2] != 0) return FALSE;
  766. dwOption++;
  767. break;
  768. case L'S' : case L's' :
  769. //
  770. // Use server name if supplied (i.e. do nothing here)
  771. //
  772. if(fShutdown)
  773. return FALSE;
  774. fShutdown = TRUE;
  775. if( arg[ 2 ] != 0 ) return FALSE;
  776. dwOption++;
  777. break;
  778. case L'F' : case L'f' :
  779. if (*lpfForce)
  780. return FALSE;
  781. *lpfForce = TRUE;
  782. if( arg[ 2 ] != 0 ) return FALSE;
  783. break;
  784. case L'H' : case L'h' :
  785. if (*lpfHibernate)
  786. return FALSE;
  787. *lpfHibernate = TRUE;
  788. if( arg[ 2 ] != 0 ) return FALSE;
  789. dwOption++;
  790. break;
  791. case L'R' : case L'r' :
  792. if (*lpfReboot)
  793. return FALSE;
  794. *lpfReboot = TRUE;
  795. if( arg[ 2 ] != 0 ) return FALSE;
  796. dwOption++;
  797. break;
  798. case L'A' : case L'a' :
  799. if (*lpfAbort)
  800. return FALSE;
  801. *lpfAbort = TRUE;
  802. if( arg[ 2 ] != 0 ) return FALSE;
  803. dwOption++;
  804. break;
  805. case L'P' : case L'p' :
  806. if (*lpfPoweroff)
  807. return FALSE;
  808. *lpfPoweroff = TRUE;
  809. if( arg[ 2 ] != 0 ) return FALSE;
  810. dwOption++;
  811. break;
  812. case L'E' : case L'e' :
  813. if (*lpfAnnotate)
  814. return FALSE;
  815. *lpfAnnotate = TRUE;
  816. if( arg[ 2 ] != 0 ) return FALSE;
  817. dwOption++;
  818. break;
  819. case L'T' : case L't' :
  820. //
  821. // Next arg should be number of seconds
  822. //
  823. if(fTimeout) // Already did.
  824. {
  825. return FALSE;
  826. }
  827. if (++i == argc)
  828. {
  829. return FALSE;
  830. }
  831. arg = argv[i];
  832. if( arg[ 0 ] < L'0' || arg[ 0 ] > L'9' ) return FALSE;
  833. if( !parse_int( arg, lpdwTimeout )) return FALSE;
  834. if(*lpdwTimeout > MAX_TIMEOUT)
  835. return FALSE;
  836. fTimeout = TRUE;
  837. break;
  838. case L'Y' : case L'y' :
  839. // Ignore this option.
  840. break;
  841. case L'D' : case L'd' :
  842. //
  843. // Next arg should be reason code
  844. //
  845. if (fReason)
  846. return FALSE;
  847. if (++i == argc)
  848. {
  849. return FALSE;
  850. }
  851. arg = argv[i];
  852. //
  853. //If reason code is given, we clear the planned bit.
  854. //
  855. *lpdwReason = (DWORD)0xFF;
  856. if( !parse_reason_code( arg, lpdwReason ))
  857. {
  858. return FALSE;
  859. }
  860. fReason = TRUE;
  861. break;
  862. case L'C' : case L'c' :
  863. //
  864. // Next arg should be shutdown message. Make
  865. // sure only one is specified.
  866. //
  867. if (fComment)
  868. return FALSE;
  869. if (++i == argc || *ppMessage)
  870. {
  871. return FALSE;
  872. }
  873. arg = argv[i];
  874. if(wcslen(arg) > MAX_REASON_COMMENT_LEN - 1 || wcslen(arg) <= MINCOMMENTLEN)
  875. return FALSE;
  876. *ppMessage = arg;
  877. fComment = TRUE;
  878. break;
  879. case L'M' : case L'm' :
  880. //
  881. // Next arg should be machine name. Make
  882. // sure only one is specified.
  883. //
  884. if (fMachine)
  885. return FALSE;
  886. if (++i == argc || *ppServerName)
  887. {
  888. return FALSE;
  889. }
  890. arg = argv[i];
  891. if (arg[0] == L'\\' && arg[1] == L'\\')
  892. {
  893. *ppServerName = arg + 2;
  894. }
  895. else
  896. {
  897. *ppServerName = arg;
  898. }
  899. fMachine = TRUE;
  900. break;
  901. case L'?' : default :
  902. return FALSE;
  903. }
  904. break;
  905. default :
  906. //
  907. // Junk
  908. //
  909. return FALSE;
  910. }
  911. }
  912. //
  913. // Check for mutually exclusive options
  914. //
  915. if (dwOption > 1)
  916. return FALSE;
  917. //
  918. // Default is to logoff
  919. //
  920. if (dwOption == 0)
  921. {
  922. *lpfLogoff = TRUE;
  923. }
  924. //
  925. // Only -f can go with -l
  926. //
  927. if (*lpfLogoff && (fTimeout || fReason || fComment || fMachine))
  928. return FALSE;
  929. //
  930. // -a can only take -m
  931. //
  932. if (*lpfAbort && (fTimeout || fReason || *lpfForce || fComment))
  933. return FALSE;
  934. //
  935. // -h only with -f
  936. //
  937. if (*lpfHibernate && (fTimeout || fReason || fComment || fMachine))
  938. return FALSE;
  939. //
  940. // -p can only take -d
  941. //
  942. if (*lpfPoweroff && (fTimeout || *lpfForce || fComment || fMachine))
  943. return FALSE;
  944. //
  945. // -e must have -d.
  946. //
  947. if (*lpfAnnotate)
  948. {
  949. if (*lpfForce || fTimeout)
  950. return FALSE;
  951. if (! fReason)
  952. return FALSE;
  953. }
  954. //
  955. // Shutdown and reboot the same, comment must require a reason.
  956. // Removed upon request.
  957. //
  958. #if 0
  959. if (fShutdown || *lpfReboot)
  960. {
  961. if (fComment && !fReason)
  962. return FALSE;
  963. }
  964. #endif
  965. //
  966. // Add the clean or dirty flag.
  967. //
  968. if (*lpfAnnotate)
  969. *lpdwReason |= SHTDN_REASON_FLAG_DIRTY_UI;
  970. else
  971. *lpdwReason |= SHTDN_REASON_FLAG_CLEAN_UI;
  972. return TRUE;
  973. }
  974. // Print out usage help string.
  975. VOID
  976. usage(
  977. VOID
  978. )
  979. {
  980. HMODULE hModule = GetModuleHandle( NULL );
  981. HMODULE hUser32;
  982. REASONBUILDPROC buildProc;
  983. REASONDESTROYPROC DestroyProc;
  984. WCHAR lpReasonName[MAX_PATH];
  985. REASONDATA Reasons;
  986. if( hModule == NULL )
  987. {
  988. report_error( GetLastError(), NULL);
  989. return;
  990. }
  991. for (DWORD i = IDS_USAGE0; i < IDS_USAGE_END; i++)
  992. {
  993. WCHAR *szBuf = LoadWString(i);
  994. if(!szBuf)
  995. continue;
  996. if (i == IDS_USAGE0)
  997. {
  998. LPWSTR msg = (LPWSTR) LocalAlloc(LMEM_FIXED, (lstrlenW(szBuf) + lstrlenW( g_lpszProgramName ) + 2) * sizeof(WCHAR));
  999. if(!msg)
  1000. {
  1001. LocalFree(szBuf);
  1002. report_error( GetLastError(), NULL);
  1003. return;
  1004. }
  1005. swprintf(msg, szBuf, g_lpszProgramName );
  1006. WriteToConsole( msg );
  1007. LocalFree(msg);
  1008. }
  1009. else
  1010. {
  1011. WriteToConsole( szBuf );
  1012. }
  1013. LocalFree(szBuf);
  1014. }
  1015. //
  1016. // Now print out the reasons.
  1017. //
  1018. WCHAR szCode[MAX_PATH];
  1019. WCHAR *szTitle = LoadWString(IDS_REASONLISTTITLE);
  1020. if(szTitle)
  1021. {
  1022. WriteToConsole(szTitle);
  1023. LocalFree(szTitle);
  1024. }
  1025. for (int iOption = 0; iOption < (int)g_reasons.m_cReasons; iOption++)
  1026. {
  1027. WriteToConsole(L"\n");
  1028. if(g_reasons.m_lpReasons[iOption].dwCode & SHTDN_REASON_FLAG_CLEAN_UI)
  1029. WriteToConsole(L"E");
  1030. else
  1031. WriteToConsole(L" ");
  1032. if(g_reasons.m_lpReasons[iOption].dwCode & SHTDN_REASON_FLAG_DIRTY_UI)
  1033. WriteToConsole(L"U");
  1034. else
  1035. WriteToConsole(L" ");
  1036. if(g_reasons.m_lpReasons[iOption].dwCode & SHTDN_REASON_FLAG_PLANNED)
  1037. WriteToConsole(L"P");
  1038. else
  1039. WriteToConsole(L" ");
  1040. if(g_reasons.m_lpReasons[iOption].dwCode & SHTDN_REASON_FLAG_USER_DEFINED)
  1041. WriteToConsole(L"C");
  1042. else
  1043. WriteToConsole(L" ");
  1044. swprintf(szCode, L"\t%d\t%d\t", (g_reasons.m_lpReasons[iOption].dwCode & 0x00ff0000)>>16,
  1045. g_reasons.m_lpReasons[iOption].dwCode & 0x0000ffff);
  1046. WriteToConsole(szCode);
  1047. WriteToConsole(g_reasons.m_lpReasons[iOption].lpName);
  1048. }
  1049. if(iOption)
  1050. WriteToConsole(L"\n");
  1051. }
  1052. // We need shutdown privileges enabled to be able to shut down our machines.
  1053. BOOL
  1054. enable_privileges(
  1055. LPCWSTR lpServerName,
  1056. BOOL fLogoff
  1057. )
  1058. {
  1059. NTSTATUS Status = STATUS_SUCCESS;
  1060. NTSTATUS Status1 = STATUS_SUCCESS;
  1061. BOOLEAN fWasEnabled;
  1062. if (fLogoff)
  1063. {
  1064. //
  1065. // No privileges to get
  1066. //
  1067. return TRUE;
  1068. }
  1069. //
  1070. // We will always enable both privileges so
  1071. // it can work for telnet sessions.
  1072. //
  1073. Status = RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE,
  1074. TRUE,
  1075. FALSE,
  1076. &fWasEnabled);
  1077. Status1 = RtlAdjustPrivilege(SE_REMOTE_SHUTDOWN_PRIVILEGE,
  1078. TRUE,
  1079. FALSE,
  1080. &fWasEnabled);
  1081. return TRUE;
  1082. }
  1083. BOOL
  1084. PowerOptionEnabled(
  1085. UINT option
  1086. )
  1087. // --------------------------------------------------------------------------
  1088. // PowerOptionEnabled
  1089. //
  1090. // Arguments: option
  1091. //
  1092. // Returns: TRUE indicates the option is enabled.
  1093. //
  1094. // Purpose: Detects if the specified power option is enabled on the system.
  1095. //
  1096. // --------------------------------------------------------------------------
  1097. {
  1098. NTSTATUS status;
  1099. SYSTEM_POWER_CAPABILITIES spc;
  1100. BOOL RetVal = FALSE;
  1101. status = NtPowerInformation(SystemPowerCapabilities,
  1102. NULL,
  1103. 0,
  1104. &spc,
  1105. sizeof(spc));
  1106. switch (option)
  1107. {
  1108. case POWER_OPTION_HIBERNATE:
  1109. if (NT_SUCCESS(status) && spc.HiberFilePresent){
  1110. RetVal = TRUE;
  1111. }
  1112. break;
  1113. case POWER_OPTION_POWEROFF:
  1114. if (NT_SUCCESS(status) && spc.SystemS5){
  1115. RetVal = TRUE;
  1116. }
  1117. break;
  1118. default:
  1119. break;
  1120. }
  1121. return(RetVal);
  1122. }
  1123. BOOL WINAPI ConsoleHandlerRoutine(
  1124. DWORD dwCtrlType
  1125. )
  1126. // --------------------------------------------------------------------------
  1127. //
  1128. // Ignore the Ctrl-C and Ctrl-Break.
  1129. //
  1130. // Arguments: type of the control signal
  1131. //
  1132. // Returns: TRUE if the function handles the control.
  1133. // if return FALSE, the next handler function in the list is used.
  1134. //
  1135. // --------------------------------------------------------------------------
  1136. {
  1137. if ( dwCtrlType == CTRL_BREAK_EVENT ||
  1138. dwCtrlType == CTRL_C_EVENT )
  1139. return TRUE;
  1140. return FALSE;
  1141. }
  1142. int __cdecl
  1143. wmain(
  1144. int argc,
  1145. wchar_t *argv[]
  1146. )
  1147. {
  1148. BOOL fLogoff;
  1149. BOOL fForce;
  1150. BOOL fReboot;
  1151. BOOL fAbort;
  1152. BOOL fPoweroff;
  1153. BOOL fAnnotate;
  1154. BOOL fHibernate;
  1155. LPWSTR lpServerName;
  1156. LPWSTR lpMessage;
  1157. DWORD dwTimeout;
  1158. DWORD dwReason = 0;
  1159. DWORD dwRet = 0;
  1160. INT_PTR hResult;
  1161. NTSTATUS Status;
  1162. WCHAR szComment[MAX_REASON_COMMENT_LEN];
  1163. HINSTANCE hInstance;
  1164. //
  1165. // ignore any control-c / control-break
  1166. //
  1167. SetConsoleCtrlHandler(ConsoleHandlerRoutine, TRUE);
  1168. if ( (hInstance = LoadLibrary( L"kernel32.dll" ) ) )
  1169. {
  1170. PSetThreadUILanguage SetThreadUILang = (PSetThreadUILanguage)GetProcAddress( hInstance, "SetThreadUILanguage" );
  1171. if ( SetThreadUILang )
  1172. (*SetThreadUILang)( 0 );
  1173. FreeLibrary( hInstance );
  1174. }
  1175. if(!GetEnvironmentVariableW(L"COMPUTERNAME", g_lpszLocalComputerName, MAX_PATH))
  1176. {
  1177. report_error(GetLastError(), NULL);
  1178. return 1;
  1179. }
  1180. g_hDllInstance = GetModuleHandle(NULL);
  1181. if (!g_hDllInstance)
  1182. {
  1183. report_error(GetLastError(), g_lpszLocalComputerName);
  1184. return 1;
  1185. }
  1186. // We use the program name for reporting errors.
  1187. g_lpszProgramName = argv[ 0 ];
  1188. //
  1189. // Userdomain is used as the default domain.
  1190. //
  1191. if(!GetEnvironmentVariableW(L"USERDOMAIN", g_lpszDefaultDomain, MAX_PATH))
  1192. {
  1193. report_error(GetLastError(), g_lpszLocalComputerName);
  1194. return 1;
  1195. }
  1196. //
  1197. // if there is no arguments, we will display help.
  1198. //
  1199. if(argc == 1)
  1200. {
  1201. usage();
  1202. return 0;
  1203. }
  1204. //
  1205. // If the first argument is -i or /i, we pop up UI.
  1206. //
  1207. if(wcsncmp(argv[1], L"-i", 2) == 0 || wcsncmp(argv[1], L"/i", 2) == 0
  1208. || wcsncmp(argv[1], L"-I", 2) == 0 || wcsncmp(argv[1], L"/I", 2) == 0)
  1209. {
  1210. if(g_hDllInstance)
  1211. {
  1212. ShutdownHelp shutdownHelp;
  1213. int len = GetEnvironmentVariableW(L"SystemRoot", g_lpszHelpdir, 0);
  1214. if(len)
  1215. {
  1216. g_lpszHelpdir = new WCHAR[len + 6];
  1217. if(g_lpszHelpdir)
  1218. {
  1219. GetEnvironmentVariableW(L"SystemRoot", g_lpszHelpdir, len+6);
  1220. wcscat(g_lpszHelpdir, L"\\");
  1221. wcscat(g_lpszHelpdir, L"Help\\");
  1222. }
  1223. else
  1224. {
  1225. dwRet = ERROR_OUTOFMEMORY;
  1226. goto exit;
  1227. }
  1228. g_lpszHelpdirHlp = new WCHAR[wcslen(g_lpszHelpdir) + wcslen(HELP_FILE) + 1];
  1229. if (g_lpszHelpdirHlp)
  1230. {
  1231. wcscpy(g_lpszHelpdirHlp, g_lpszHelpdir);
  1232. wcscat(g_lpszHelpdirHlp, HELP_FILE);
  1233. }
  1234. else
  1235. {
  1236. dwRet = ERROR_OUTOFMEMORY;
  1237. goto exit;
  1238. }
  1239. g_lpszHelpdirChm = new WCHAR[wcslen(g_lpszHelpdir) + wcslen(CHM_FILE) + wcslen(CHM_MAIN) + 1];
  1240. if (g_lpszHelpdirChm)
  1241. {
  1242. wcscpy(g_lpszHelpdirChm, g_lpszHelpdir);
  1243. wcscat(g_lpszHelpdirChm, CHM_FILE);
  1244. wcscat(g_lpszHelpdirChm, CHM_MAIN);
  1245. }
  1246. else
  1247. {
  1248. dwRet = ERROR_OUTOFMEMORY;
  1249. goto exit;
  1250. }
  1251. g_lpszHelpdirWindows = new WCHAR[wcslen(g_lpszHelpdir) + wcslen(WINDOWS_HELP) + 1];
  1252. if (g_lpszHelpdirWindows)
  1253. {
  1254. wcscpy(g_lpszHelpdirWindows, g_lpszHelpdir);
  1255. wcscat(g_lpszHelpdirWindows, WINDOWS_HELP);
  1256. }
  1257. else
  1258. {
  1259. dwRet = ERROR_OUTOFMEMORY;
  1260. goto exit;
  1261. }
  1262. }
  1263. hResult = DialogBoxParam(g_hDllInstance, MAKEINTRESOURCE(IDD_DIALOGSHUTDOWN), NULL, Shutdown_DialogProc, NULL);
  1264. dwRet = (DWORD)HRESULTTOWIN32(hResult);
  1265. exit:
  1266. if(g_lpszHelpdir)
  1267. delete [] g_lpszHelpdir;
  1268. if(g_lpszHelpdirHlp)
  1269. delete [] g_lpszHelpdirHlp;
  1270. if(g_lpszHelpdirChm)
  1271. delete [] g_lpszHelpdirChm;
  1272. if(g_lpszHelpdirWindows)
  1273. delete [] g_lpszHelpdirWindows;
  1274. if (dwRet != 0)
  1275. report_error(dwRet, NULL);
  1276. WinHelpW((HWND)0, NULL, HELP_QUIT, 0) ;
  1277. }
  1278. return dwRet;
  1279. }
  1280. // Parse the options.
  1281. if( !parse_options( argc,
  1282. argv,
  1283. &fLogoff,
  1284. &fForce,
  1285. &fReboot,
  1286. &fHibernate,
  1287. &fAbort,
  1288. &fPoweroff,
  1289. &fAnnotate,
  1290. &lpServerName,
  1291. &lpMessage,
  1292. &dwTimeout,
  1293. &dwReason ))
  1294. {
  1295. usage();
  1296. return 1;
  1297. }
  1298. //
  1299. // Add the comment field for the reason.
  1300. //
  1301. if (g_reasons.RequireComment(dwReason, fAnnotate))
  1302. {
  1303. if (fAnnotate)
  1304. dwReason |= SHTDN_REASON_FLAG_DIRTY_PROBLEM_ID_REQUIRED;
  1305. else
  1306. dwReason |= SHTDN_REASON_FLAG_COMMENT_REQUIRED;
  1307. }
  1308. //
  1309. // Promote (no more)for comment if it is required and not given
  1310. //
  1311. if (g_reasons.RequireComment(dwReason, fAnnotate) && (!lpMessage || wcslen(lpMessage) == 0))
  1312. {
  1313. lpMessage = NULL;
  1314. }
  1315. // Get all privileges so that we can shutdown the machine.
  1316. enable_privileges( lpServerName, fLogoff );
  1317. // Do the work.
  1318. if( fAbort )
  1319. {
  1320. if( !AbortSystemShutdownW( lpServerName ))
  1321. {
  1322. dwRet = GetLastError();
  1323. report_error( dwRet, lpServerName);
  1324. }
  1325. }
  1326. else if (fLogoff)
  1327. {
  1328. if (!ExitWindowsEx(fForce ? (EWX_LOGOFF | EWX_FORCE) : (EWX_LOGOFF | EWX_FORCEIFHUNG),
  1329. 0))
  1330. {
  1331. dwRet = GetLastError();
  1332. report_error( dwRet, g_lpszLocalComputerName);
  1333. }
  1334. }
  1335. else if (fHibernate)
  1336. {
  1337. if (!PowerOptionEnabled(POWER_OPTION_HIBERNATE))
  1338. {
  1339. ERROR_WITH_SZ(IDS_ERR_HIBERNATE_NOT_ENABLED, lpServerName, GetLastError());
  1340. }
  1341. else
  1342. {
  1343. Status = NtInitiatePowerAction(
  1344. PowerActionHibernate,
  1345. PowerSystemSleeping1,
  1346. fForce
  1347. ? POWER_ACTION_CRITICAL
  1348. : POWER_ACTION_QUERY_ALLOWED,
  1349. FALSE);
  1350. if (!NT_SUCCESS(Status))
  1351. {
  1352. dwRet = RtlNtStatusToDosError(Status);
  1353. report_error( dwRet, lpServerName);
  1354. }
  1355. }
  1356. }
  1357. else if (fPoweroff)
  1358. {
  1359. //
  1360. // Special case, we call ExitWindowsEx
  1361. // Check whether power off is supported, if not just shutdown the machine.
  1362. // Although we fixed ExitWindowsEx, but we will leave this so it will work
  1363. // with older builds.
  1364. //
  1365. if(PowerOptionEnabled(POWER_OPTION_POWEROFF))
  1366. {
  1367. if (!ExitWindowsEx(EWX_POWEROFF, dwReason))
  1368. {
  1369. dwRet = GetLastError();
  1370. report_error( dwRet, lpServerName);
  1371. }
  1372. }
  1373. else
  1374. {
  1375. if (!ExitWindowsEx(EWX_SHUTDOWN, dwReason))
  1376. {
  1377. dwRet = GetLastError();
  1378. report_error( dwRet, lpServerName);
  1379. }
  1380. }
  1381. }
  1382. else if (fAnnotate)
  1383. {
  1384. //
  1385. // Annotate dirty shutdown.
  1386. //
  1387. Annotate(lpServerName, &dwReason, lpMessage, &dwRet);
  1388. }
  1389. else
  1390. {
  1391. // Do the normal form.
  1392. if( !InitiateSystemShutdownExW( lpServerName,
  1393. lpMessage,
  1394. dwTimeout,
  1395. fForce,
  1396. fReboot,
  1397. dwReason ))
  1398. {
  1399. dwRet = GetLastError();
  1400. report_error( dwRet, lpServerName);
  1401. }
  1402. }
  1403. return dwRet;
  1404. }
  1405. //
  1406. // Get computername from ADSI path
  1407. // Here we only handle WinNT, LDAP, NWCOMPAT, and NDS.
  1408. //
  1409. BOOL GetComputerNameFromPath(LPWSTR szPath, LPWSTR szName)
  1410. {
  1411. static _PROVIDER p[] =
  1412. {
  1413. {L"LDAP://", 7},
  1414. {L"WinNT://", 8},
  1415. {L"NWCOMPAT://", 11},
  1416. {L"NDS://", 6}
  1417. };
  1418. static UINT np = sizeof(p)/sizeof(_PROVIDER);
  1419. LPWSTR lpsz = NULL;
  1420. if(!szPath || !szName)
  1421. return FALSE;
  1422. for(UINT i = 0; i < np; i++)
  1423. {
  1424. if(wcsncmp(szPath, p[i].szName, p[i].dwLen) == 0)
  1425. {
  1426. switch(i)
  1427. {
  1428. case 0: // LDAP
  1429. lpsz = wcsstr(szPath, L"CN=");
  1430. if(!lpsz)
  1431. return FALSE;
  1432. lpsz += 3;
  1433. while(*lpsz && *lpsz != ',')
  1434. *szName++ = *lpsz++;
  1435. *szName = 0;
  1436. return TRUE;
  1437. case 1: // WinNT
  1438. case 2: // NWCOMPAT
  1439. lpsz = szPath + p[i].dwLen;
  1440. //
  1441. // skip domain or provider path
  1442. //
  1443. while(*lpsz && *lpsz != '/')
  1444. lpsz++;
  1445. lpsz++;
  1446. while(*lpsz && *lpsz != '/')
  1447. *szName++ = *lpsz++;
  1448. *szName = 0;
  1449. return TRUE;
  1450. case 3: // NDS
  1451. lpsz = wcsstr(szPath, L"CN=");
  1452. if(!lpsz)
  1453. return FALSE;
  1454. lpsz += 3;
  1455. while(*lpsz && *lpsz != '/')
  1456. *szName++ = *lpsz++;
  1457. *szName = 0;
  1458. return TRUE;
  1459. default:
  1460. return FALSE;
  1461. }
  1462. }
  1463. }
  1464. return FALSE;
  1465. }
  1466. //
  1467. // A centralized place for adjusting window states.
  1468. //
  1469. VOID AdjustWindowState()
  1470. {
  1471. if(g_dwActionSelect == ACTION_SHUTDOWN || g_dwActionSelect == ACTION_RESTART || g_dwActionSelect == ACTION_ANNOTATE)
  1472. {
  1473. if (g_dwActionSelect == ACTION_ANNOTATE)
  1474. {
  1475. EnableWindow(g_wins.hwndButtonWarning, FALSE);
  1476. EnableWindow(g_wins.hwndEditTimeout, FALSE);
  1477. }
  1478. else
  1479. {
  1480. EnableWindow(g_wins.hwndButtonWarning, TRUE);
  1481. if (IsDlgButtonChecked(g_wins.hwndShutdownDialog, IDC_CHECKWARNING) == BST_CHECKED)
  1482. EnableWindow(g_wins.hwndEditTimeout, TRUE);
  1483. else
  1484. EnableWindow(g_wins.hwndEditTimeout, FALSE);
  1485. }
  1486. EnableWindow(g_wins.hwndEditComment, TRUE);
  1487. if(g_bAssumeShutdown)
  1488. {
  1489. EnableWindow(g_wins.hwndComboOption, FALSE);
  1490. EnableWindow(g_wins.hwndChkPlanned, FALSE);
  1491. EnableWindow(g_wins.hwndButtonOK, TRUE);
  1492. }
  1493. else
  1494. {
  1495. EnableWindow(g_wins.hwndComboOption, TRUE);
  1496. EnableWindow(g_wins.hwndChkPlanned, TRUE);
  1497. if((g_reasons.m_dwReasonSelect != -1)
  1498. && g_reasons.RequireComment(g_reasons.m_lpReasons[g_reasons.m_dwReasonSelect].dwCode, g_dwActionSelect == ACTION_ANNOTATE))
  1499. {
  1500. LPWSTR szStaticComment = LoadWString(IDS_COMMENT_REQUIRED);
  1501. if(szStaticComment)
  1502. {
  1503. SetWindowTextW(g_wins.hwndStaticComment, szStaticComment);
  1504. LocalFree(szStaticComment);
  1505. }
  1506. if(Edit_GetTextLength(g_wins.hwndEditComment) > MINCOMMENTLEN
  1507. && ListBox_GetCount(g_wins.hwndListSelectComputers) > 0)
  1508. EnableWindow(g_wins.hwndButtonOK, TRUE);
  1509. else
  1510. EnableWindow(g_wins.hwndButtonOK, FALSE);
  1511. }
  1512. else
  1513. {
  1514. LPWSTR szStaticComment = LoadWString(IDS_COMMENT_OPTIONAL);
  1515. if(szStaticComment)
  1516. {
  1517. SetWindowTextW(g_wins.hwndStaticComment, szStaticComment);
  1518. LocalFree(szStaticComment);
  1519. }
  1520. if (g_reasons.m_dwReasonSelect == -1)
  1521. EnableWindow(g_wins.hwndComboOption, FALSE);
  1522. if(ListBox_GetCount(g_wins.hwndListSelectComputers) > 0)
  1523. EnableWindow(g_wins.hwndButtonOK, TRUE);
  1524. else
  1525. EnableWindow(g_wins.hwndButtonOK, FALSE);
  1526. }
  1527. }
  1528. EnableWindow(g_wins.hwndBtnAdd, TRUE);
  1529. EnableWindow(g_wins.hwndBtnBrowse, TRUE);
  1530. {
  1531. int cItems = 1024;
  1532. int lpItems[1024];
  1533. int cActualItems;
  1534. //
  1535. // Get the number of selected items.
  1536. //
  1537. cActualItems = ListBox_GetSelItems(g_wins.hwndListSelectComputers, cItems, lpItems);
  1538. if(cActualItems > 0)
  1539. EnableWindow(g_wins.hwndBtnRemove, TRUE);
  1540. else
  1541. EnableWindow(g_wins.hwndBtnRemove, FALSE);
  1542. }
  1543. EnableWindow(g_wins.hwndListSelectComputers, TRUE);
  1544. }
  1545. else
  1546. {
  1547. EnableWindow(g_wins.hwndChkPlanned, FALSE);
  1548. EnableWindow(g_wins.hwndButtonWarning, FALSE);
  1549. EnableWindow(g_wins.hwndBtnAdd, FALSE);
  1550. EnableWindow(g_wins.hwndBtnBrowse, FALSE);
  1551. EnableWindow(g_wins.hwndBtnRemove, FALSE);
  1552. EnableWindow(g_wins.hwndComboOption, FALSE);
  1553. EnableWindow(g_wins.hwndEditComment, FALSE);
  1554. EnableWindow(g_wins.hwndEditTimeout, FALSE);
  1555. EnableWindow(g_wins.hwndListSelectComputers, FALSE);
  1556. EnableWindow(g_wins.hwndButtonOK, TRUE);
  1557. }
  1558. }
  1559. //
  1560. // Init dialog handler for the shutdown dialog.
  1561. //
  1562. BOOL Shutdown_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
  1563. {
  1564. int i;
  1565. //
  1566. // Init all of the dialog items so we dont have to find
  1567. // them everytime we need them.
  1568. //
  1569. g_wins.hwndShutdownDialog = hwnd;
  1570. g_wins.hwndButtonWarning = GetDlgItem(hwnd, IDC_CHECKWARNING);
  1571. g_wins.hwndComboAction = GetDlgItem(hwnd, IDC_COMBOACTION);
  1572. g_wins.hwndComboOption = GetDlgItem(hwnd, IDC_COMBOOPTION);
  1573. g_wins.hwndEditComment = GetDlgItem(hwnd, IDC_EDITCOMMENT);
  1574. g_wins.hwndStaticDesc = GetDlgItem(hwnd, IDC_STATICDESCRIPTION);
  1575. g_wins.hwndEditTimeout = GetDlgItem(hwnd, IDC_EDITTIMEOUT);
  1576. g_wins.hwndListSelectComputers = GetDlgItem(hwnd, IDC_LISTSELECTEDCOMPUTERS);
  1577. g_wins.hwndBtnAdd = GetDlgItem(hwnd, IDC_BUTTONADDNEW);
  1578. g_wins.hwndBtnBrowse = GetDlgItem(hwnd, IDC_BUTTONBROWSE);
  1579. g_wins.hwndBtnRemove = GetDlgItem(hwnd, IDC_BUTTONREMOVE);
  1580. g_wins.hwndChkPlanned = GetDlgItem(hwnd, IDC_CHECK_PLANNED);
  1581. g_wins.hwndButtonOK = GetDlgItem(hwnd, IDOK);
  1582. g_wins.hwndStaticComment = GetDlgItem(hwnd, IDC_STATIC_COMMENT);
  1583. if(g_wins.hwndButtonWarning == NULL
  1584. || g_wins.hwndComboAction == NULL
  1585. || g_wins.hwndComboOption == NULL
  1586. || g_wins.hwndEditComment == NULL
  1587. || g_wins.hwndStaticDesc == NULL
  1588. || g_wins.hwndEditTimeout == NULL
  1589. || g_wins.hwndListSelectComputers == NULL
  1590. || g_wins.hwndBtnAdd == NULL
  1591. || g_wins.hwndBtnBrowse == NULL
  1592. || g_wins.hwndBtnRemove == NULL
  1593. || g_wins.hwndChkPlanned == NULL)
  1594. {
  1595. report_error( GetLastError( ), NULL);
  1596. EndDialog(hwnd, (int)-1);
  1597. return FALSE;
  1598. }
  1599. LoadString(g_hDllInstance, IDS_DIALOGTITLEWARNING, g_lpszTitleWarning, TITLEWARNINGLEN);
  1600. // Subclass the edit control.
  1601. wpOrigEditProc = (WNDPROC) SetWindowLongPtr(g_wins.hwndEditTimeout,
  1602. GWLP_WNDPROC, (LONG_PTR) EditSubclassProc);
  1603. // Limit timeout to 3 chars.
  1604. SendMessage(g_wins.hwndEditTimeout, EM_LIMITTEXT, (WPARAM)3, 0);
  1605. //
  1606. // Default timeout is set to 30 seconds.
  1607. //
  1608. Edit_SetText(g_wins.hwndEditTimeout, g_lpszDefaultTimeout);
  1609. if(! CheckDlgButton(hwnd, IDC_CHECKWARNING, DEFAULTWARNINGSTATE))
  1610. {
  1611. report_error( GetLastError( ), NULL);
  1612. EndDialog(hwnd, (int)-1);
  1613. return FALSE;
  1614. }
  1615. //
  1616. // The for loop will load all of the actions into action combo.
  1617. // in the meantime we save them for later use.
  1618. //
  1619. for(i = 0; i < g_nActions; i++)
  1620. {
  1621. LoadString(g_hDllInstance, g_dwActions[i], g_lppszActions[i], MAX_PATH - 1);
  1622. ComboBox_AddString(g_wins.hwndComboAction, g_lppszActions[i]);
  1623. if(g_dwActions[i] == IDS_ACTION_RESTART)
  1624. {
  1625. ComboBox_SelectString(g_wins.hwndComboAction, -1, g_lppszActions[i]);
  1626. g_dwActionSelect = ACTION_RESTART;
  1627. }
  1628. }
  1629. if(g_reasons.m_cReasons)
  1630. g_bAssumeShutdown = FALSE;
  1631. else
  1632. g_bAssumeShutdown = TRUE;
  1633. //
  1634. // Set the default to be planned.
  1635. //
  1636. CheckDlgButton(hwnd, IDC_CHECK_PLANNED, BST_CHECKED);
  1637. g_reasons.FillCombo(g_wins.hwndComboOption, g_bDirty,
  1638. IsDlgButtonChecked(hwnd, IDC_CHECK_PLANNED) == BST_CHECKED, g_wins.hwndStaticDesc);
  1639. //
  1640. // Setup the comment box.
  1641. // We must fix the maximum characters.
  1642. //
  1643. SendMessage( g_wins.hwndEditComment, EM_LIMITTEXT, (WPARAM)MAX_REASON_COMMENT_LEN-1, (LPARAM)0 );
  1644. AdjustWindowState();
  1645. return TRUE;
  1646. }
  1647. //
  1648. // Init dialog handler for browse dialog
  1649. //
  1650. BOOL Browse_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
  1651. {
  1652. HWND hwndDomain = NULL;
  1653. int cItems = 1024;
  1654. int lpItems[1024];
  1655. int cActualItems;
  1656. WCHAR lpDomain[MAX_PATH];
  1657. hwndDomain = GetDlgItem(hwnd, IDC_EDITDOMAIN);
  1658. if(!hwndDomain)
  1659. return FALSE;
  1660. Edit_SetText(hwndDomain, g_lpszDefaultDomain);;
  1661. return TRUE;
  1662. }
  1663. //
  1664. // winproc for shutdown dialog
  1665. //
  1666. INT_PTR CALLBACK Shutdown_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam,
  1667. LPARAM lParam)
  1668. {
  1669. switch (uMsg)
  1670. {
  1671. HANDLE_MSG(hwnd, WM_INITDIALOG, Shutdown_OnInitDialog);
  1672. HANDLE_MSG(hwnd, WM_COMMAND, Shutdown_OnCommand);
  1673. case WM_SYSCOMMAND:
  1674. return (Shutdown_OnCommand(hwnd, (int)(LOWORD(wParam)), (HWND)(lParam), (UINT)HIWORD(wParam)), 0L);
  1675. case WM_HELP: // F1
  1676. if(g_lpszHelpdirHlp)
  1677. {
  1678. LPHELPINFO phinfo = (LPHELPINFO) lParam;
  1679. DWORD dwHelpID = 0;
  1680. if (IsStaticControl((HWND)phinfo->hItemHandle))
  1681. return (TRUE);
  1682. for(int i = 0; i < sizeof(ShutdownDialogHelpIds)/sizeof(DWORD); i++)
  1683. {
  1684. if(ShutdownDialogHelpIds[i] == phinfo->iCtrlId)
  1685. {
  1686. dwHelpID = ShutdownDialogHelpIds[++i];
  1687. break;
  1688. }
  1689. i++;
  1690. }
  1691. if ( i == sizeof(ShutdownDialogHelpIds)/sizeof(DWORD))
  1692. return TRUE;
  1693. if (dwHelpID == 28443 || dwHelpID == 28444 || dwHelpID == 28445) // special case.
  1694. WinHelpW((HWND)phinfo->hItemHandle, g_lpszHelpdirWindows, HELP_CONTEXTPOPUP,dwHelpID);
  1695. else
  1696. WinHelpW((HWND)phinfo->hItemHandle, g_lpszHelpdirHlp, HELP_CONTEXTPOPUP,dwHelpID);
  1697. }
  1698. return (TRUE);
  1699. case WM_CONTEXTMENU: // right mouse click
  1700. if (IsStaticControl((HWND)wParam))
  1701. return (TRUE);
  1702. if(g_lpszHelpdirHlp)
  1703. WinHelpW((HWND)wParam, g_lpszHelpdirHlp, HELP_CONTEXTMENU,(DWORD_PTR)(LPSTR)&ShutdownDialogHelpIds[6]);
  1704. return (TRUE);
  1705. case WM_DESTROY:
  1706. // Remove the subclass from the edit control.
  1707. SetWindowLongPtr(g_wins.hwndEditTimeout, GWLP_WNDPROC,
  1708. (LONG_PTR)wpOrigEditProc);
  1709. //
  1710. // Continue the cleanup procedure.
  1711. //
  1712. break;
  1713. }
  1714. return FALSE;
  1715. }
  1716. //
  1717. // winproc for AddNew dialog
  1718. //
  1719. INT_PTR CALLBACK AddNew_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam,
  1720. LPARAM lParam)
  1721. {
  1722. switch (uMsg)
  1723. {
  1724. HANDLE_MSG(hwnd, WM_COMMAND, AddNew_OnCommand);
  1725. case WM_HELP: // F1
  1726. if (GetDlgCtrlID((HWND)wParam) == IDC_STATIC)
  1727. return (TRUE);
  1728. if(g_lpszHelpdirHlp)
  1729. {
  1730. LPHELPINFO phinfo = (LPHELPINFO) lParam;
  1731. DWORD dwHelpID = 0;
  1732. if (IsStaticControl((HWND)phinfo->hItemHandle))
  1733. return (TRUE);
  1734. for(int i = 0; i < sizeof(AddNewDialogHelpIds)/sizeof(DWORD); i++)
  1735. {
  1736. if(AddNewDialogHelpIds[i] == phinfo->iCtrlId)
  1737. {
  1738. dwHelpID = AddNewDialogHelpIds[++i];
  1739. break;
  1740. }
  1741. i++;
  1742. }
  1743. if ( i == sizeof(AddNewDialogHelpIds)/sizeof(DWORD))
  1744. return TRUE;
  1745. if (dwHelpID == 28443 || dwHelpID == 28444 || dwHelpID == 28445) // special case.
  1746. WinHelpW((HWND)phinfo->hItemHandle, g_lpszHelpdirWindows, HELP_CONTEXTPOPUP,dwHelpID);
  1747. else
  1748. WinHelpW((HWND)phinfo->hItemHandle, g_lpszHelpdirHlp, HELP_CONTEXTPOPUP,dwHelpID);
  1749. }
  1750. return (TRUE);
  1751. case WM_CONTEXTMENU: // right mouse click
  1752. if (IsStaticControl((HWND)wParam))
  1753. return (TRUE);
  1754. if(g_lpszHelpdirHlp)
  1755. WinHelpW((HWND)wParam, g_lpszHelpdirHlp, HELP_CONTEXTMENU,(DWORD_PTR)(LPSTR)&AddNewDialogHelpIds[4]);
  1756. return (TRUE);
  1757. }
  1758. return FALSE;
  1759. }
  1760. //
  1761. // Command handler for the shutdown dialog.
  1762. //
  1763. BOOL Shutdown_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
  1764. {
  1765. BOOL fHandled = FALSE;
  1766. DWORD dwDlgResult = 0;
  1767. HINSTANCE h;
  1768. switch (id)
  1769. {
  1770. case IDCANCEL:
  1771. if (codeNotify == BN_CLICKED)
  1772. {
  1773. EndDialog(hwnd, (int) dwDlgResult);
  1774. }
  1775. fHandled = TRUE;
  1776. break;
  1777. case SC_CLOSE:
  1778. EndDialog(hwnd, (int) dwDlgResult);
  1779. fHandled = TRUE;
  1780. break;
  1781. case IDC_BUTTONREMOVE:
  1782. if (codeNotify == BN_CLICKED)
  1783. {
  1784. int cItems = 1024;
  1785. int lpItems[1024];
  1786. int cActualItems;
  1787. WCHAR lpServerName[MAX_PATH];
  1788. //
  1789. // Get the number of selected items. If there is any remove them one by one.
  1790. //
  1791. cActualItems = ListBox_GetSelItems(g_wins.hwndListSelectComputers, cItems, lpItems);
  1792. if(cActualItems > 0)
  1793. {
  1794. int i;
  1795. for(i = cActualItems-1; i >= 0; i--)
  1796. {
  1797. ListBox_DeleteString(g_wins.hwndListSelectComputers, lpItems[i]);
  1798. }
  1799. AdjustWindowState();
  1800. SetFocus(g_wins.hwndListSelectComputers);
  1801. }
  1802. fHandled = TRUE;
  1803. }
  1804. break;
  1805. case IDC_CHECK_PLANNED:
  1806. if (codeNotify == BN_CLICKED)
  1807. {
  1808. int iOption;
  1809. int iFirst = -1;
  1810. DWORD dwCheckState = 0x0;
  1811. //
  1812. // Get check button state.
  1813. //
  1814. if (IsDlgButtonChecked(hwnd, IDC_CHECK_PLANNED) == BST_CHECKED)
  1815. dwCheckState = SHTDN_REASON_FLAG_PLANNED;
  1816. g_reasons.FillCombo(g_wins.hwndComboOption, g_bDirty,
  1817. IsDlgButtonChecked(hwnd, IDC_CHECK_PLANNED) == BST_CHECKED, g_wins.hwndStaticDesc);
  1818. AdjustWindowState();
  1819. fHandled = TRUE;
  1820. }
  1821. break;
  1822. case IDC_EDITCOMMENT:
  1823. if( codeNotify == EN_CHANGE)
  1824. {
  1825. if(g_bAssumeShutdown)
  1826. {
  1827. EnableWindow(g_wins.hwndButtonOK, TRUE);
  1828. }
  1829. else if(g_reasons.m_dwReasonSelect != -1 &&
  1830. (g_reasons.m_lpReasons[g_reasons.m_dwReasonSelect].dwCode & SHTDN_REASON_FLAG_COMMENT_REQUIRED))
  1831. {
  1832. if(Edit_GetTextLength(g_wins.hwndEditComment) > MINCOMMENTLEN
  1833. && ListBox_GetCount(g_wins.hwndListSelectComputers) > 0)
  1834. EnableWindow(g_wins.hwndButtonOK, TRUE);
  1835. else
  1836. EnableWindow(g_wins.hwndButtonOK, FALSE);
  1837. }
  1838. else
  1839. {
  1840. if(ListBox_GetCount(g_wins.hwndListSelectComputers) > 0)
  1841. EnableWindow(g_wins.hwndButtonOK, TRUE);
  1842. else
  1843. EnableWindow(g_wins.hwndButtonOK, FALSE);
  1844. }
  1845. fHandled = TRUE;
  1846. }
  1847. break;
  1848. case IDC_EDITTIMEOUT:
  1849. if( codeNotify == EN_KILLFOCUS)
  1850. {
  1851. WCHAR szTimeout[8];
  1852. int len = GetWindowTextW(g_wins.hwndEditTimeout, szTimeout, 7);
  1853. fHandled = TRUE;
  1854. if (_wtoi(szTimeout) > MAX_TIMEOUT)
  1855. SetWindowTextW(g_wins.hwndEditTimeout, g_lpszMaxTimeout);
  1856. }
  1857. break;
  1858. case IDC_BUTTONADDNEW:
  1859. if (codeNotify == BN_CLICKED)
  1860. {
  1861. WCHAR lpServerName[MAX_PATH];
  1862. LPWSTR lpBuffer;
  1863. DWORD dwIndex = 0;
  1864. INT_PTR hResult;
  1865. //
  1866. // Will pop up the addnew dialog. User can type in computer names seperated
  1867. // by white space. After click on OK, we will parse the computer names and
  1868. // add them to the selected computer list. No duplicates will be added.
  1869. //
  1870. hResult = DialogBoxParam(g_hDllInstance, MAKEINTRESOURCE(IDD_DIALOG_ADDNEW), hwnd, AddNew_DialogProc, NULL);
  1871. if(g_lpszNewComputers)
  1872. {
  1873. lpBuffer = g_lpszNewComputers;
  1874. while(*lpBuffer)
  1875. {
  1876. lpServerName[dwIndex] = '\0';
  1877. while(*lpBuffer && *lpBuffer != '\t' && *lpBuffer != '\n' && *lpBuffer != '\r' && *lpBuffer != ' ')
  1878. lpServerName[dwIndex++] = *lpBuffer++;
  1879. lpServerName[dwIndex] = '\0';
  1880. if(dwIndex > 0 && LB_ERR == ListBox_FindStringExact(g_wins.hwndListSelectComputers, -1, lpServerName))
  1881. ListBox_AddString(g_wins.hwndListSelectComputers, lpServerName);
  1882. dwIndex = 0;
  1883. while(*lpBuffer && (*lpBuffer == '\t' || *lpBuffer == '\n' || *lpBuffer == '\r' || *lpBuffer == ' '))
  1884. lpBuffer++;
  1885. }
  1886. AdjustWindowState();
  1887. LocalFree((HLOCAL)g_lpszNewComputers);
  1888. g_lpszNewComputers = NULL;
  1889. }
  1890. fHandled = TRUE;
  1891. }
  1892. break;
  1893. case IDOK:
  1894. //
  1895. // Here we gather all of the information and do the action.
  1896. //
  1897. if (codeNotify == BN_CLICKED)
  1898. {
  1899. int cItems = 1024;
  1900. int lpItems[1024];
  1901. int cActualItems;
  1902. BOOL fLogoff = FALSE;
  1903. BOOL fAbort = FALSE;
  1904. BOOL fForce = FALSE;
  1905. BOOL fReboot = FALSE;
  1906. BOOL fDisconnect = FALSE;
  1907. BOOL fStandby = FALSE;
  1908. BOOL fAnnotate = FALSE;
  1909. DWORD dwTimeout = 0;
  1910. DWORD dwReasonCode = 0;
  1911. WCHAR lpServerName[MAX_PATH];
  1912. WCHAR lpMsg[MAX_REASON_COMMENT_LEN] = L"";
  1913. DWORD dwCnt = 0;
  1914. DWORD dwActionCode = g_dwActionSelect;
  1915. WCHAR lpNotSupported[MAX_PATH];
  1916. WCHAR lpRes[MAX_PATH * 2];
  1917. WCHAR lpFailed[MAX_PATH];
  1918. WCHAR lpSuccess[MAX_PATH];
  1919. //
  1920. // The default reason code is 0 and default comment is L"".
  1921. //
  1922. if(IsDlgButtonChecked(hwnd, IDC_CHECKWARNING))
  1923. {
  1924. fForce = FALSE;
  1925. lpServerName[0] = '\0';
  1926. GetWindowText(g_wins.hwndEditTimeout, lpServerName, MAX_PATH);
  1927. if(lstrlen(lpServerName) == 0)
  1928. dwTimeout = 0;
  1929. else dwTimeout = _wtoi(lpServerName);
  1930. if(dwTimeout > MAX_TIMEOUT)
  1931. dwTimeout = MAX_TIMEOUT;
  1932. }
  1933. else
  1934. {
  1935. fForce = TRUE;
  1936. }
  1937. LoadString(g_hDllInstance, IDS_ACTIONNOTSUPPORTED, lpNotSupported, MAX_PATH);
  1938. GetWindowText(g_wins.hwndEditComment, lpMsg, MAX_REASON_COMMENT_LEN);
  1939. lpMsg[MAX_REASON_COMMENT_LEN-1] = 0;
  1940. if(dwActionCode == ACTION_LOGOFF)
  1941. {
  1942. fLogoff = TRUE;
  1943. }
  1944. else if (dwActionCode == ACTION_RESTART)
  1945. {
  1946. fReboot = TRUE;
  1947. }
  1948. else if (dwActionCode == ACTION_ANNOTATE)
  1949. fAnnotate = TRUE;
  1950. //
  1951. // Logoff is only for the local computer.
  1952. // Everything else will ingored.
  1953. //
  1954. if(fLogoff)
  1955. {
  1956. if (!ExitWindowsEx(fForce ? EWX_LOGOFF : (EWX_LOGOFF | EWX_FORCE),
  1957. 0))
  1958. {
  1959. report_error(GetLastError(), g_lpszLocalComputerName);
  1960. }
  1961. EndDialog(hwnd, (int) dwDlgResult);
  1962. break;
  1963. }
  1964. if(! g_bAssumeShutdown)
  1965. {
  1966. dwReasonCode = g_reasons.m_lpReasons[g_reasons.m_dwReasonSelect].dwCode;
  1967. }
  1968. else if (fAnnotate)
  1969. break;
  1970. dwCnt = ListBox_GetCount(g_wins.hwndListSelectComputers);
  1971. if(dwCnt > 0)
  1972. {
  1973. DWORD i;
  1974. for(i = 0; i < dwCnt; i++)
  1975. {
  1976. ListBox_GetText(g_wins.hwndListSelectComputers, i, lpServerName);
  1977. //
  1978. // Get all privileges so that we can shutdown the machine.
  1979. //
  1980. enable_privileges(lpServerName, fLogoff);
  1981. //
  1982. // Do the work.
  1983. //
  1984. if( fAbort )
  1985. {
  1986. if( !AbortSystemShutdown( lpServerName ))
  1987. {
  1988. report_error( GetLastError( ), lpServerName);
  1989. }
  1990. }
  1991. else if (fAnnotate)
  1992. {
  1993. DWORD err;
  1994. Annotate(lpServerName, &dwReasonCode, lpMsg, &err);
  1995. }
  1996. else
  1997. {
  1998. //
  1999. // Do the normal form.
  2000. //
  2001. if( !InitiateSystemShutdownEx( lpServerName,
  2002. lpMsg,
  2003. dwTimeout,
  2004. fForce,
  2005. fReboot,
  2006. dwReasonCode ))
  2007. {
  2008. report_error( GetLastError( ), lpServerName);
  2009. }
  2010. }
  2011. }
  2012. }
  2013. else
  2014. {
  2015. //
  2016. // We will keep the dialog up in case user forget to add computers.
  2017. //
  2018. break;
  2019. }
  2020. EndDialog(hwnd, (int) dwDlgResult);
  2021. }
  2022. break;
  2023. case IDC_CHECKWARNING:
  2024. //
  2025. // The checkbutton state decides the state of the timeout edit box.
  2026. //
  2027. if (codeNotify == BN_CLICKED)
  2028. {
  2029. if(BST_CHECKED == IsDlgButtonChecked(hwnd, IDC_CHECKWARNING))
  2030. {
  2031. EnableWindow(g_wins.hwndEditTimeout, TRUE);
  2032. }
  2033. else
  2034. {
  2035. EnableWindow(g_wins.hwndEditTimeout, FALSE);
  2036. }
  2037. fHandled = TRUE;
  2038. }
  2039. break;
  2040. case IDC_BUTTONBROWSE:
  2041. //
  2042. // Simply pop up the browse dialog. That dialog will be responsible
  2043. // for adding the user selection to the selected computer list.
  2044. //
  2045. if (codeNotify == BN_CLICKED)
  2046. {
  2047. HRESULT hr;
  2048. ICommonQuery* pcq;
  2049. OPENQUERYWINDOW oqw = { 0 };
  2050. DSQUERYINITPARAMS dqip = { 0 };
  2051. IDataObject *pdo;
  2052. FORMATETC fmte = {(CLIPFORMAT)RegisterClipboardFormat(CFSTR_DSOBJECTNAMES),
  2053. NULL,
  2054. DVASPECT_CONTENT,
  2055. -1,
  2056. TYMED_HGLOBAL};
  2057. FORMATETC fmte2 = {(CLIPFORMAT)RegisterClipboardFormat(CFSTR_DSQUERYPARAMS),
  2058. NULL,
  2059. DVASPECT_CONTENT,
  2060. -1,
  2061. TYMED_HGLOBAL};
  2062. STGMEDIUM medium = { TYMED_NULL, NULL, NULL };
  2063. DSOBJECTNAMES *pdon;
  2064. DSQUERYPARAMS *pdqp;
  2065. CoInitialize(NULL);
  2066. //
  2067. // Windows 2000: Always use IID_ICommonQueryW explicitly. IID_ICommonQueryA is not supported.
  2068. //
  2069. hr = CoCreateInstance(CLSID_CommonQuery, NULL, CLSCTX_INPROC_SERVER, IID_ICommonQuery, (void**)&pcq);
  2070. if (FAILED(hr)) {
  2071. //
  2072. // if failed return.
  2073. //
  2074. CoUninitialize();
  2075. DbgPrint("Cannot create ICommonQuery, return.\n");
  2076. break;
  2077. }
  2078. //
  2079. // Initialize the OPENQUERYWINDOW structure to indicate
  2080. // we want to do a Directory Service
  2081. // Query, the default form is printers and the search
  2082. // should start once the window is initialized.
  2083. //
  2084. oqw.cbStruct = sizeof(oqw);
  2085. oqw.dwFlags = OQWF_OKCANCEL|OQWF_DEFAULTFORM|OQWF_HIDEMENUS|OQWF_REMOVEFORMS;
  2086. oqw.clsidHandler = CLSID_DsQuery;
  2087. oqw.pHandlerParameters = &dqip;
  2088. oqw.clsidDefaultForm = CLSID_DsFindComputer;
  2089. //
  2090. // Now initialize the handler specific parameters,
  2091. // in this case, the File/Save menu item is removed
  2092. //
  2093. dqip.cbStruct = sizeof(dqip);
  2094. dqip.dwFlags = DSQPF_NOSAVE;
  2095. //
  2096. // Call OpenQueryWindow, it will block until
  2097. // the Query Window is dismissed,
  2098. //
  2099. hr = pcq->OpenQueryWindow(hwnd, &oqw, &pdo);
  2100. if (FAILED(hr)) {
  2101. //
  2102. // if failed we return.
  2103. //
  2104. pcq->Release();
  2105. CoUninitialize();
  2106. break;
  2107. }
  2108. if (!pdo) {
  2109. //
  2110. // if cancelled,nothing needs to be done.
  2111. //
  2112. pcq->Release();
  2113. CoUninitialize();
  2114. break;
  2115. }
  2116. //
  2117. // Get the CFSTR_DSOBJECTNAMES data. For each selected, the data
  2118. // includes the object class and an ADsPath to the selected object.
  2119. //
  2120. hr = pdo->GetData(&fmte, &medium);
  2121. if(! FAILED(hr))
  2122. {
  2123. pdon = (DSOBJECTNAMES*)GlobalLock(medium.hGlobal);
  2124. if ( pdon )
  2125. {
  2126. WCHAR szName[MAX_PATH];
  2127. LPWSTR lpsz = NULL;
  2128. UINT i;
  2129. for (i = 0; i < pdon->cItems; i++)
  2130. {
  2131. if(!GetComputerNameFromPath((LPWSTR) ((PBYTE) pdon + pdon->aObjects[i].offsetName), szName))
  2132. continue;
  2133. //
  2134. // We don't add dups.
  2135. //
  2136. if(LB_ERR == ListBox_FindStringExact(g_wins.hwndListSelectComputers, -1, szName))
  2137. {
  2138. ListBox_AddString(g_wins.hwndListSelectComputers, szName);
  2139. }
  2140. }
  2141. GlobalUnlock(medium.hGlobal);
  2142. }
  2143. else
  2144. {
  2145. DbgPrint("GlobalLock on medium failed.\n");
  2146. }
  2147. ReleaseStgMedium(&medium);
  2148. }
  2149. else
  2150. {
  2151. DbgPrint("pdo->GetData failed: 0x%x\n", hr);
  2152. }
  2153. //
  2154. // Release resources.
  2155. //
  2156. pdo->Release();
  2157. pcq->Release();
  2158. CoUninitialize();
  2159. AdjustWindowState();
  2160. fHandled = TRUE;
  2161. }
  2162. break;
  2163. case IDC_COMBOOPTION:
  2164. //
  2165. // Here is where you select shutdown reasons.
  2166. //
  2167. if (codeNotify == CBN_SELCHANGE)
  2168. {
  2169. g_reasons.SetDesc(g_wins.hwndComboOption, g_wins.hwndStaticDesc);
  2170. AdjustWindowState();
  2171. fHandled = TRUE;
  2172. }
  2173. break;
  2174. case IDC_COMBOACTION:
  2175. //
  2176. // Select user action here.
  2177. // according to the action. some item will be disabled or enabled.
  2178. //
  2179. if (codeNotify == CBN_SELCHANGE)
  2180. {
  2181. WCHAR name[MAX_PATH];
  2182. DWORD dwIndex;
  2183. DWORD dwOldActionSelect = g_dwActionSelect;
  2184. DWORD dwCheckState = 0x0;
  2185. int iFirst = -1;
  2186. if (IsDlgButtonChecked(hwnd, IDC_CHECK_PLANNED) == BST_CHECKED)
  2187. dwCheckState = SHTDN_REASON_FLAG_PLANNED;
  2188. GetWindowText(g_wins.hwndComboAction, (LPWSTR)name, MAX_PATH);
  2189. for(dwIndex = 0; dwIndex < g_nActions; dwIndex++)
  2190. {
  2191. if(lstrcmp(name, g_lppszActions[dwIndex]) == 0)
  2192. {
  2193. g_dwActionSelect = dwIndex;
  2194. if(g_dwActionSelect == ACTION_ANNOTATE)
  2195. g_bDirty = TRUE;
  2196. else
  2197. g_bDirty = FALSE;
  2198. //
  2199. // If change from clean to dirty or vsv, repopulate the combo.
  2200. //
  2201. if (dwOldActionSelect != g_dwActionSelect
  2202. && (dwOldActionSelect == ACTION_ANNOTATE || g_dwActionSelect == ACTION_ANNOTATE))
  2203. {
  2204. g_reasons.FillCombo(g_wins.hwndComboOption, g_bDirty,
  2205. dwCheckState == SHTDN_REASON_FLAG_PLANNED, g_wins.hwndStaticDesc);
  2206. }
  2207. AdjustWindowState();
  2208. break;
  2209. }
  2210. }
  2211. fHandled = TRUE;
  2212. }
  2213. break;
  2214. case IDC_LISTSELECTEDCOMPUTERS:
  2215. //
  2216. // When selection change, update the remove button state.
  2217. //
  2218. if (codeNotify == LBN_SELCHANGE)
  2219. {
  2220. AdjustWindowState();
  2221. fHandled = TRUE;
  2222. }
  2223. else if (codeNotify == WM_MOUSEMOVE)
  2224. {
  2225. MessageBox(hwnd, L"Mouse move", NULL, 0);
  2226. fHandled = TRUE;
  2227. }
  2228. break;
  2229. case IDHELP:
  2230. //
  2231. // Open the .chm file.
  2232. //
  2233. if (codeNotify == BN_CLICKED)
  2234. {
  2235. if(g_lpszHelpdirChm)
  2236. HtmlHelpW(/*hwnd*/0, g_lpszHelpdirChm, HH_DISPLAY_TOPIC,(DWORD)0);
  2237. }
  2238. }
  2239. return fHandled;
  2240. }
  2241. //
  2242. // Command handler for the addnew dialog.
  2243. // It simply copy the text into a allocated buffer when OK is clicked.
  2244. //
  2245. BOOL AddNew_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
  2246. {
  2247. BOOL fHandled = FALSE;
  2248. DWORD dwDlgResult = 0;
  2249. HINSTANCE h;
  2250. switch (id)
  2251. {
  2252. case IDOK:
  2253. if (codeNotify == BN_CLICKED)
  2254. {
  2255. HWND hwndEdit;
  2256. DWORD dwTextlen = 0;
  2257. hwndEdit = GetDlgItem(hwnd, IDC_EDIT_ADDCOMPUTERS_COMPUTERS);
  2258. if(hwndEdit != NULL)
  2259. {
  2260. dwTextlen = Edit_GetTextLength(hwndEdit);
  2261. if(dwTextlen)
  2262. {
  2263. g_lpszNewComputers = (LPWSTR)LocalAlloc(LMEM_FIXED, sizeof(TCHAR) * (dwTextlen + 1));
  2264. if(g_lpszNewComputers){
  2265. Edit_GetText(hwndEdit, g_lpszNewComputers, dwTextlen + 1);
  2266. }
  2267. }
  2268. }
  2269. EndDialog(hwnd, (int) dwDlgResult);
  2270. }
  2271. break;
  2272. case IDCANCEL:
  2273. if (codeNotify == BN_CLICKED)
  2274. {
  2275. EndDialog(hwnd, (int) dwDlgResult);
  2276. }
  2277. break;
  2278. }
  2279. return fHandled;
  2280. }
  2281. //
  2282. // Annotate dirty shutdown on remote machine.
  2283. BOOL
  2284. Annotate(
  2285. LPCWSTR lpMachine,
  2286. LPDWORD lpdwReason,
  2287. LPCWSTR lpComment,
  2288. LPDWORD lpdwErr)
  2289. {
  2290. HKEY hRemote = NULL;
  2291. HKEY hKey = NULL;
  2292. HANDLE hEventLog = NULL;
  2293. PTOKEN_USER pTokenUser = NULL;
  2294. BOOL res = TRUE;
  2295. if(lpMachine && wcslen(lpMachine) > 1)
  2296. {
  2297. WCHAR szMachine[MAX_PATH];
  2298. szMachine[0] = '\0';
  2299. if(lpMachine[0] != '\\')
  2300. {
  2301. wcscpy(szMachine, L"\\\\");
  2302. }
  2303. wcsncat(szMachine, lpMachine, MAX_PATH - 3);
  2304. szMachine[MAX_PATH - 1] = '\0';
  2305. RegConnectRegistryW(szMachine, HKEY_LOCAL_MACHINE, &hRemote);
  2306. if(!hRemote)
  2307. {
  2308. *lpdwErr = GetLastError();
  2309. ERROR_WITH_SZ(IDS_FAILED_REG_CONN, lpMachine, *lpdwErr);
  2310. goto fail;
  2311. }
  2312. RegOpenKeyExW(hRemote,
  2313. REGSTR_PATH_RELIABILITY,
  2314. NULL,
  2315. KEY_ALL_ACCESS | KEY_WOW64_64KEY,
  2316. &hKey);
  2317. if(!hKey)
  2318. {
  2319. *lpdwErr = GetLastError();
  2320. ERROR_WITH_SZ(IDS_FAILED_REG_OPEN, lpMachine, *lpdwErr);
  2321. goto fail;
  2322. }
  2323. }
  2324. else // local machine
  2325. {
  2326. lpMachine = g_lpszLocalComputerName;
  2327. RegOpenKeyExW(HKEY_LOCAL_MACHINE,
  2328. REGSTR_PATH_RELIABILITY,
  2329. NULL,
  2330. KEY_ALL_ACCESS | KEY_WOW64_64KEY,
  2331. &hKey);
  2332. if(!hKey)
  2333. {
  2334. *lpdwErr = GetLastError();
  2335. ERROR_WITH_SZ(IDS_FAILED_REG_OPEN, lpMachine, *lpdwErr);
  2336. goto fail;
  2337. }
  2338. }
  2339. DWORD dwDirtyVal;
  2340. DWORD dwType;
  2341. DWORD dwSize = sizeof(DWORD);
  2342. static LPCWSTR lpszDirtyValName = L"DirtyShutdown";
  2343. if( ERROR_SUCCESS != RegQueryValueExW(hKey, lpszDirtyValName, NULL, &dwType, (LPBYTE)&dwDirtyVal,&dwSize))
  2344. {
  2345. *lpdwErr = GetLastError();
  2346. ERROR_WITH_SZ(IDS_NO_DIRTY_SHUTDOWN, lpMachine, *lpdwErr);
  2347. goto fail;
  2348. }
  2349. if (dwDirtyVal)
  2350. {
  2351. PSID pUserSid = NULL;
  2352. DWORD dwSidSize = sizeof(SID), dwEventID;
  2353. WCHAR szReason[MAX_REASON_NAME_LEN + 10];
  2354. LPCWSTR lpStrings[8];
  2355. WORD wEventType, wStringCnt;
  2356. WCHAR szMinorReason[32];
  2357. WCHAR szName[MAX_PATH + 1];
  2358. WCHAR szDomain[MAX_PATH + 1];
  2359. DWORD dwNameLen = MAX_PATH + 1;
  2360. DWORD dwDomainLen = MAX_PATH + 1;
  2361. SID_NAME_USE eUse;
  2362. // Get the user's SID so we can output their account name to the event log.
  2363. if (GetUserSid(&pTokenUser)) {
  2364. pUserSid = pTokenUser->User.Sid;
  2365. }
  2366. if ((hEventLog = RegisterEventSourceW(lpMachine, L"USER32")) == NULL) {
  2367. *lpdwErr = GetLastError();
  2368. ERROR_WITH_SZ(IDS_FAILED_EVENT_REG, lpMachine, *lpdwErr);
  2369. goto fail;
  2370. }
  2371. g_reasons.GetReasonTitle(*lpdwReason, szReason, ARRAY_SIZE(szReason));
  2372. // Get User name.
  2373. if (!LookupAccountSidW(NULL, pUserSid, szName, &dwNameLen, szDomain,
  2374. &dwDomainLen, &eUse)) {
  2375. goto fail;
  2376. }
  2377. szName[MAX_PATH] = 0;
  2378. szDomain[MAX_PATH] = 0;
  2379. // We need to pack into a buffer of MAX_PATH + 1 in the form L"domain\\username"
  2380. if (wcslen(szDomain) + wcslen(szName) > MAX_PATH - 1) {
  2381. goto fail;
  2382. }
  2383. if (wcslen(szDomain) > 0) {
  2384. wcscat(szDomain, L"\\");
  2385. }
  2386. wcscat(szDomain, szName);
  2387. // The minor reason is the low-order word of the reason code.
  2388. wsprintf(szMinorReason, L"0x%x", *lpdwReason);
  2389. wEventType = EVENTLOG_WARNING_TYPE;
  2390. dwEventID = WARNING_DIRTY_REBOOT;
  2391. wStringCnt = 6;
  2392. lpStrings[0] = szReason;
  2393. lpStrings[1] = szMinorReason;
  2394. lpStrings[2] = NULL;
  2395. lpStrings[3] = NULL;
  2396. lpStrings[4] = lpComment;
  2397. lpStrings[5] = szDomain;
  2398. if ( (*lpdwErr = RegDeleteValueW(hKey, lpszDirtyValName)) != ERROR_SUCCESS )
  2399. {
  2400. ERROR_WITH_SZ(IDS_NO_DIRTY_SHUTDOWN, lpMachine, *lpdwErr);
  2401. goto fail;
  2402. }
  2403. if(! ReportEventW(hEventLog, wEventType, 1, dwEventID, pUserSid,
  2404. wStringCnt, sizeof(DWORD),
  2405. lpStrings, lpdwReason))
  2406. {
  2407. DWORD dwDirtyShutdownFlag = 1;
  2408. *lpdwErr = GetLastError();
  2409. ERROR_WITH_SZ(IDS_FAILED_EVENT_REPORT, lpMachine, *lpdwErr);
  2410. RegSetValueEx( hKey,
  2411. lpszDirtyValName,
  2412. 0,
  2413. REG_DWORD,
  2414. (PUCHAR) &dwDirtyShutdownFlag,
  2415. sizeof(DWORD));
  2416. goto fail;
  2417. }
  2418. }
  2419. else
  2420. {
  2421. RegDeleteValueW(hKey, lpszDirtyValName);
  2422. ERROR_WITH_SZ(IDS_NO_DIRTY_SHUTDOWN, lpMachine, 0);
  2423. }
  2424. goto exit;
  2425. fail:
  2426. res = FALSE;
  2427. exit:
  2428. if (pTokenUser != NULL) {
  2429. LocalFree(pTokenUser);
  2430. }
  2431. if(hEventLog)
  2432. DeregisterEventSource(hEventLog);
  2433. if(hKey)
  2434. RegCloseKey(hKey);
  2435. if(hRemote)
  2436. RegCloseKey(hRemote);
  2437. return res;
  2438. }
  2439. //
  2440. // Subclass procedure for edit box.
  2441. //
  2442. LRESULT APIENTRY EditSubclassProc(
  2443. HWND hwnd,
  2444. UINT uMsg,
  2445. WPARAM wParam,
  2446. LPARAM lParam)
  2447. {
  2448. if (uMsg == WM_PASTE)
  2449. return TRUE;
  2450. if (uMsg == WM_CONTEXTMENU)
  2451. {
  2452. if(g_lpszHelpdir)
  2453. {
  2454. LPWSTR szHelp = new WCHAR[wcslen(g_lpszHelpdir) + 128];
  2455. if(szHelp)
  2456. {
  2457. wcscpy(szHelp, g_lpszHelpdir);
  2458. wcscat(szHelp, HELP_FILE);
  2459. WinHelpW(hwnd, szHelp, HELP_CONTEXTMENU,(DWORD_PTR)(LPSTR)ShutdownDialogHelpIds);
  2460. delete [] szHelp;
  2461. }
  2462. }
  2463. return TRUE;
  2464. }
  2465. return CallWindowProc(wpOrigEditProc, hwnd, uMsg,
  2466. wParam, lParam);
  2467. }
  2468. BOOL
  2469. GetUserSid(
  2470. PTOKEN_USER *ppTokenUser)
  2471. {
  2472. HANDLE TokenHandle;
  2473. PTOKEN_USER pTokenUser = NULL;
  2474. DWORD cbTokenUser = 0;
  2475. DWORD cbNeeded;
  2476. BOOL bRet = FALSE;
  2477. if (!GetTokenHandle(&TokenHandle)) {
  2478. return FALSE;
  2479. }
  2480. bRet = GetTokenInformation(TokenHandle,
  2481. TokenUser,
  2482. pTokenUser,
  2483. cbTokenUser,
  2484. &cbNeeded);
  2485. /*
  2486. * We've passed a NULL pointer and 0 for the amount of memory
  2487. * allocated. We expect to fail with bRet = FALSE and
  2488. * GetLastError = ERROR_INSUFFICIENT_BUFFER. If we do not
  2489. * have these conditions we will return FALSE.
  2490. */
  2491. if (!bRet && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
  2492. pTokenUser = (PTOKEN_USER)LocalAlloc(LPTR, cbNeeded);
  2493. if (pTokenUser == NULL) {
  2494. goto GetUserSidDone;
  2495. }
  2496. cbTokenUser = cbNeeded;
  2497. bRet = GetTokenInformation(TokenHandle,
  2498. TokenUser,
  2499. pTokenUser,
  2500. cbTokenUser,
  2501. &cbNeeded);
  2502. } else {
  2503. /*
  2504. * Any other case -- return FALSE
  2505. */
  2506. bRet = FALSE;
  2507. }
  2508. GetUserSidDone:
  2509. if (bRet == TRUE) {
  2510. *ppTokenUser = pTokenUser;
  2511. } else if (pTokenUser != NULL) {
  2512. LocalFree(pTokenUser);
  2513. }
  2514. CloseHandle(TokenHandle);
  2515. return bRet;
  2516. }
  2517. BOOL
  2518. GetTokenHandle(
  2519. PHANDLE pTokenHandle)
  2520. {
  2521. if (!OpenThreadToken(GetCurrentThread(),
  2522. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  2523. TRUE,
  2524. pTokenHandle)) {
  2525. if (GetLastError() == ERROR_NO_TOKEN) {
  2526. /* This means we are not impersonating anybody.
  2527. * Instead, lets get the token out of the process.
  2528. */
  2529. if (!OpenProcessToken(GetCurrentProcess(),
  2530. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  2531. pTokenHandle)) {
  2532. return FALSE;
  2533. }
  2534. } else {
  2535. return FALSE;
  2536. }
  2537. }
  2538. return TRUE;
  2539. }
  2540. WCHAR*
  2541. LoadWString(int resid)
  2542. {
  2543. DWORD len, curlen = MAX_PATH;
  2544. LPWSTR szBuf = NULL;
  2545. szBuf = (LPWSTR)LocalAlloc(LMEM_FIXED, sizeof(WCHAR) * MAX_PATH);
  2546. if(!szBuf)
  2547. return NULL;
  2548. len = LoadStringW( g_hDllInstance, resid, szBuf, curlen);
  2549. while (len + 1 == curlen)
  2550. {
  2551. LocalFree(szBuf);
  2552. szBuf = (LPWSTR)LocalAlloc(LMEM_FIXED, curlen * 2 * sizeof(WCHAR));
  2553. if(!szBuf)
  2554. return NULL;
  2555. curlen *= 2;
  2556. len = LoadStringW( g_hDllInstance, resid, szBuf, curlen);
  2557. }
  2558. szBuf[len] = '\0';
  2559. return szBuf;
  2560. }
  2561. BOOL
  2562. IsStaticControl (HWND hwnd)
  2563. {
  2564. WCHAR name[128];
  2565. if (GetClassName(hwnd, name, 128)
  2566. && (_wcsicmp(name, L"Static") == 0 || _wcsicmp(name, L"#32770") == 0))
  2567. {
  2568. // MessageBox(NULL, name, NULL, 0);
  2569. return TRUE;
  2570. }
  2571. // MessageBox(NULL, name, NULL, 0);
  2572. return FALSE;
  2573. }