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.

1920 lines
47 KiB

  1. #include <nt.h>
  2. #include <ntrtl.h>
  3. #include <nturtl.h>
  4. #include <windows.h>
  5. #include <initguid.h>
  6. #include <windowsx.h>
  7. #include <winuserp.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <assert.h>
  11. #include <lm.h>
  12. #include <shlobj.h>
  13. #include <Cmnquery.h>
  14. #include <dsclient.h>
  15. #include <Dsquery.h>
  16. #include <reason.h>
  17. #include "resource.h"
  18. //#define SNAPSHOT_TEST
  19. #ifdef SNAPSHOT_TEST
  20. #define TESTMSG(x) \
  21. WriteToConsole((x))
  22. #else
  23. #define TESTMSG(x)
  24. #endif //SNAPSHOT_TEST
  25. //
  26. // Default warning state for warning user check button
  27. //
  28. #define DEFAULTWARNINGSTATE BST_CHECKED
  29. #define TITLEWARNINGLEN 32
  30. //
  31. // Name of the executable
  32. //
  33. LPWSTR g_lpszProgramName = NULL;
  34. //
  35. // Enum for all of the actions.
  36. //
  37. enum
  38. {
  39. ACTION_SHUTDOWN = 0,
  40. ACTION_RESTART = 1,
  41. ACTION_LOGOFF,
  42. ACTION_STANDBY,
  43. ACTION_DISCONNECT,
  44. ACTION_ABORT
  45. };
  46. //
  47. // Resource IDs for actions.
  48. //
  49. DWORD g_dwActions[] =
  50. {
  51. IDS_ACTION_SHUTDOWN,
  52. IDS_ACTION_RESTART,
  53. IDS_ACTION_LOGOFF
  54. //IDS_ACTION_STANDBY,
  55. //IDS_ACTION_DISCONNECT,
  56. //IDS_ACTION_ABORT
  57. };
  58. //
  59. // Number of actions and the action strings loaded from resource.
  60. //
  61. const int g_nActions = sizeof(g_dwActions) / sizeof(DWORD);
  62. WCHAR g_lppszActions[g_nActions][MAX_PATH];
  63. LPWSTR g_lpszNewComputers = NULL;
  64. WCHAR g_lpszDefaultDomain[MAX_PATH] = L"";
  65. WCHAR g_lpszLocalComputerName[MAX_PATH] = L"";
  66. WCHAR g_lpszTitleWarning[TITLEWARNINGLEN];
  67. BOOL g_bAssumeShutdown = FALSE;
  68. struct _PROVIDER{
  69. LPWSTR szName;
  70. DWORD dwLen;
  71. };
  72. typedef struct _SHUTDOWNREASON
  73. {
  74. DWORD dwCode;
  75. WCHAR lpName[MAX_REASON_NAME_LEN + 1];
  76. WCHAR lpDesc[MAX_REASON_DESC_LEN + 1];
  77. } SHUTDOWNREASON, *PSHUTDOWNREASON;
  78. PSHUTDOWNREASON g_lpReasons = NULL;
  79. DWORD g_dwReasons = 0;
  80. DWORD g_dwReasonSelect;
  81. DWORD g_dwActionSelect;
  82. typedef struct _SHUTDOWNCACHEDHWNDS
  83. {
  84. HWND hwndShutdownDialog;
  85. HWND hwndListSelectComputers;
  86. HWND hwndEditComment;
  87. HWND hwndStaticDesc;
  88. HWND hwndEditTimeout;
  89. HWND hwndButtonWarning;
  90. HWND hwndComboAction;
  91. HWND hwndComboOption;
  92. HWND hwndBtnAdd;
  93. HWND hwndBtnRemove;
  94. HWND hwndBtnBrowse;
  95. HWND hwndChkPlanned;
  96. HWND hwndButtonOK;
  97. } SHUTDOWNCACHEDHWNDS, *PSHUTDOWNCACHEDHWNDS;
  98. SHUTDOWNCACHEDHWNDS g_wins;
  99. HMODULE g_hDllInstance = NULL;
  100. typedef BOOL (*REASONBUILDPROC)(REASONDATA *, BOOL, BOOL);
  101. typedef VOID (*REASONDESTROYPROC)(REASONDATA *);
  102. BOOL GetNetworkComputers(HWND hwndList, HWND hwndProgress, LPCWSTR lpDomain);
  103. BOOL GetComputerNameFromPath(LPWSTR szPath, LPWSTR szName);
  104. VOID AdjustWindowState();
  105. INT_PTR
  106. CALLBACK Shutdown_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam,
  107. LPARAM lParam);
  108. INT_PTR
  109. CALLBACK AddNew_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam,
  110. LPARAM lParam);
  111. INT_PTR
  112. CALLBACK Browse_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam,
  113. LPARAM lParam);
  114. BOOL Shutdown_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify);
  115. BOOL AddNew_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify);
  116. BOOL Browse_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify);
  117. BOOL Shutdown_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam);
  118. BOOL Browse_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam);
  119. typedef void (*PSetThreadUILanguage)(DWORD);
  120. //
  121. // Check whether a string is all white spaces.
  122. //
  123. BOOL
  124. IsEmpty(LPCWSTR lpCWSTR)
  125. {
  126. if(!lpCWSTR)
  127. return TRUE;
  128. while(*lpCWSTR && (*lpCWSTR == '\n' || *lpCWSTR == '\t' || *lpCWSTR == '\r' || *lpCWSTR == ' '))
  129. lpCWSTR++;
  130. if(*lpCWSTR)
  131. return FALSE;
  132. return TRUE;
  133. }
  134. // Write the string to console
  135. VOID
  136. WriteToConsole(
  137. LPWSTR pszMsg
  138. )
  139. {
  140. HANDLE hConsole = GetStdHandle( STD_OUTPUT_HANDLE );
  141. if ( !pszMsg || !*pszMsg )
  142. return;
  143. DWORD dwStrLen = lstrlenW( pszMsg );
  144. LPSTR pszAMsg = NULL;
  145. DWORD dwBytesWritten = 0;
  146. DWORD dwMode = 0;
  147. if ( (GetFileType ( hConsole ) & FILE_TYPE_CHAR ) &&
  148. GetConsoleMode( hConsole, &dwMode ) )
  149. {
  150. WriteConsoleW( hConsole, pszMsg, dwStrLen, &dwBytesWritten, 0 );
  151. return;
  152. }
  153. // console redirect to a file.
  154. if ( !(pszAMsg = (LPSTR)LocalAlloc(LMEM_FIXED, (dwStrLen + 1) * sizeof(WCHAR) ) ) )
  155. {
  156. return;
  157. }
  158. if (WideCharToMultiByte(GetConsoleOutputCP(),
  159. 0,
  160. pszMsg,
  161. -1,
  162. pszAMsg,
  163. dwStrLen * sizeof(WCHAR),
  164. NULL,
  165. NULL) != 0
  166. && hConsole)
  167. {
  168. WriteFile( hConsole,
  169. pszAMsg,
  170. lstrlenA(pszAMsg),
  171. &dwBytesWritten,
  172. NULL );
  173. }
  174. LocalFree( pszAMsg );
  175. }
  176. // Report error.
  177. VOID
  178. report_error(
  179. DWORD error_code
  180. )
  181. {
  182. LPVOID msgBuf = 0;
  183. FormatMessageW(
  184. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  185. FORMAT_MESSAGE_FROM_SYSTEM |
  186. FORMAT_MESSAGE_IGNORE_INSERTS,
  187. NULL,
  188. error_code,
  189. MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), // Default language
  190. reinterpret_cast< wchar_t* >( &msgBuf ),
  191. 0,
  192. NULL);
  193. //fwprintf( stderr, L"%s : %s\n", g_lpszProgramName, reinterpret_cast< wchar_t* >( msgBuf ));
  194. WriteToConsole( reinterpret_cast<wchar_t*> (msgBuf) );
  195. LocalFree( msgBuf );
  196. }
  197. BOOL
  198. parse_reason_code(
  199. LPCWSTR arg,
  200. LPDWORD lpdwReason
  201. )
  202. {
  203. // Code consists of flags:major:minor
  204. int major = 0;
  205. int minor = 0;
  206. const int state_start = 0;
  207. const int state_flags = 0;
  208. const int state_major = 1;
  209. const int state_minor = 2;
  210. const int state_null = 3;
  211. const int state_done = 4;
  212. for( int i = 0, state = state_start; state != state_done; ++i )
  213. {
  214. switch( state )
  215. {
  216. case state_flags :
  217. // Expecting flags
  218. switch( arg[ i ] ) {
  219. case L'U' : case L'u' :
  220. *lpdwReason |= 0x40000000; // SHTDN_REASON_FLAG_USER_DEFINED
  221. break;
  222. case L'P' : case L'p' :
  223. *lpdwReason |= 0x80000000; // SHTDN_REASON_FLAG_PLANNED
  224. break;
  225. case L':' :
  226. state = state_major;
  227. break;
  228. case 0 :
  229. // End of string (use default major and minor).
  230. state = state_done;
  231. break;
  232. default :
  233. return FALSE;
  234. }
  235. break;
  236. case state_major :
  237. // Expecting major
  238. if( arg[ i ] >= L'0' && arg[ i ] <= L'9' ) {
  239. major = major * 10 + arg[ i ] - L'0';
  240. }
  241. else {
  242. // Make sure we only have 8 bits
  243. if( major > 0xff ) return FALSE;
  244. *lpdwReason |= major << 16;
  245. if( arg[ i ] == 0 ) {
  246. // use default minor reason.
  247. state = state_done;
  248. }
  249. if( arg[ i ] == L':' ) {
  250. state = state_minor;
  251. }
  252. else return FALSE;
  253. }
  254. break;
  255. case state_minor :
  256. // Expecting minor reason
  257. // Expecting major
  258. if( arg[ i ] >= L'0' && arg[ i ] <= L'9' ) {
  259. minor = minor * 10 + arg[ i ] - L'0';
  260. }
  261. else {
  262. // Make sure we only have 8 bits
  263. if( minor > 0xffff ) return FALSE;
  264. *lpdwReason = ( *lpdwReason & 0xffff0000 ) | minor;
  265. if( arg[ i ] == 0 ) {
  266. return state_done;
  267. }
  268. if( arg[ i ] == L':' ) {
  269. state = state_null;
  270. }
  271. else return FALSE;
  272. }
  273. break;
  274. case state_null :
  275. // Expecting end of string
  276. if( arg[ i ] != 0 ) return FALSE;
  277. state = state_done;
  278. default :
  279. return FALSE;
  280. }
  281. }
  282. return TRUE;
  283. }
  284. // Parses an integer if it is in decimal notation.
  285. // Returns FALSE if it is malformed.
  286. BOOL
  287. parse_int(
  288. const wchar_t* arg,
  289. LPDWORD lpdwInt
  290. )
  291. {
  292. *lpdwInt = 0;
  293. while( *arg ) {
  294. if( *arg >= L'0' && *arg <= L'9' ) {
  295. *lpdwInt = *lpdwInt * 10 + int( *arg++ - L'0' );
  296. }
  297. else {
  298. return FALSE;
  299. }
  300. }
  301. return TRUE;
  302. }
  303. // Parse options.
  304. // Returns FALSE if the option strings are malformed. This causes the usage to be printed.
  305. BOOL
  306. parse_options(
  307. int argc,
  308. wchar_t *argv[],
  309. LPBOOL lpfLogoff,
  310. LPBOOL lpfForce,
  311. LPBOOL lpfReboot,
  312. LPBOOL lpfAbort,
  313. LPWSTR *ppServerName,
  314. LPWSTR *ppMessage,
  315. LPDWORD lpdwTimeout,
  316. LPDWORD lpdwReason
  317. )
  318. {
  319. BOOL fShutdown = FALSE;
  320. *lpfLogoff = FALSE;
  321. *lpfForce = FALSE;
  322. *lpfReboot = FALSE;
  323. *lpfAbort = FALSE;
  324. *ppServerName = NULL;
  325. *ppMessage = NULL;
  326. *lpdwTimeout = 30;
  327. *lpdwReason = 0xFF;
  328. //
  329. // Set default reason to be planned
  330. //
  331. *lpdwReason |= 0x80000000; // SHTDN_REASON_FLAG_PLANNED
  332. for( int i = 1; i < argc; ++i )
  333. {
  334. wchar_t* arg = argv[ i ];
  335. switch( arg[ 0 ] )
  336. {
  337. case L'/' : case L'-' :
  338. switch( arg[ 1 ] )
  339. {
  340. case L'L' : case L'l' :
  341. *lpfLogoff = TRUE;
  342. if (arg[2] != 0) return FALSE;
  343. break;
  344. case L'S' : case L's' :
  345. //
  346. // Use server name if supplied (i.e. do nothing here)
  347. //
  348. fShutdown = TRUE;
  349. if( arg[ 2 ] != 0 ) return FALSE;
  350. break;
  351. case L'F' : case L'f' :
  352. *lpfForce = TRUE;
  353. if( arg[ 2 ] != 0 ) return FALSE;
  354. break;
  355. case L'R' : case L'r' :
  356. *lpfReboot = TRUE;
  357. if( arg[ 2 ] != 0 ) return FALSE;
  358. break;
  359. case L'A' : case L'a' :
  360. *lpfAbort = TRUE;
  361. if( arg[ 2 ] != 0 ) return FALSE;
  362. break;
  363. case L'T' : case L't' :
  364. //
  365. // Next arg should be number of seconds
  366. //
  367. if (++i == argc)
  368. {
  369. return FALSE;
  370. }
  371. arg = argv[i];
  372. if( arg[ 0 ] < L'0' || arg[ 0 ] > L'9' ) return FALSE;
  373. if( !parse_int( arg, lpdwTimeout )) return FALSE;
  374. break;
  375. case L'Y' : case L'y' :
  376. // Ignore this option.
  377. break;
  378. case L'D' : case L'd' :
  379. //
  380. // Next arg should be reason code
  381. //
  382. if (++i == argc)
  383. {
  384. return FALSE;
  385. }
  386. arg = argv[i];
  387. //
  388. //If reason code is given, we clear the planned bit.
  389. //
  390. *lpdwReason &= ~(0x80000000); // SHTDN_REASON_FLAG_PLANNED
  391. if( !parse_reason_code( arg, lpdwReason ))
  392. {
  393. return FALSE;
  394. }
  395. break;
  396. case L'C' : case L'c' :
  397. //
  398. // Next arg should be shutdown message. Make
  399. // sure only one is specified.
  400. //
  401. if (++i == argc || *ppMessage)
  402. {
  403. return FALSE;
  404. }
  405. arg = argv[i];
  406. *ppMessage = arg;
  407. break;
  408. case L'M' : case L'm' :
  409. //
  410. // Next arg should be machine name. Make
  411. // sure only one is specified.
  412. //
  413. if (++i == argc || *ppServerName)
  414. {
  415. return FALSE;
  416. }
  417. arg = argv[i];
  418. if (arg[0] == L'\\' && arg[1] == L'\\')
  419. {
  420. *ppServerName = arg + 2;
  421. }
  422. else
  423. {
  424. *ppServerName = arg;
  425. }
  426. break;
  427. case L'H' : case L'h' : case L'?' : default :
  428. return FALSE;
  429. }
  430. break;
  431. default :
  432. //
  433. // Junk
  434. //
  435. return FALSE;
  436. }
  437. }
  438. //
  439. // Default is to logoff
  440. //
  441. if (!fShutdown && !*lpfReboot && !*lpfAbort)
  442. {
  443. *lpfLogoff = TRUE;
  444. }
  445. //
  446. // Check for mutually exclusive options
  447. //
  448. if (*lpfAbort && (*lpfLogoff || fShutdown || *lpfReboot || *lpfForce))
  449. {
  450. return FALSE;
  451. }
  452. if (*lpfLogoff && (*ppServerName || fShutdown || *lpfReboot))
  453. {
  454. return FALSE;
  455. }
  456. if (fShutdown && *lpfReboot)
  457. {
  458. return FALSE;
  459. }
  460. return TRUE;
  461. }
  462. // Print out usage help string.
  463. VOID
  464. usage(
  465. VOID
  466. )
  467. {
  468. HMODULE hModule = GetModuleHandle( NULL );
  469. int buf_len = MAX_PATH;
  470. int new_len = 0;
  471. LPWSTR buf = NULL;
  472. LPWSTR msg = NULL;
  473. if( hModule == NULL )
  474. {
  475. report_error( GetLastError() );
  476. return;
  477. }
  478. buf = (LPWSTR) LocalAlloc(LMEM_FIXED, buf_len * sizeof(WCHAR));
  479. if (buf == NULL)
  480. {
  481. report_error( GetLastError() );
  482. return;
  483. }
  484. new_len = LoadStringW( hModule, IDS_USAGE, buf, buf_len );
  485. //
  486. // Since LoadString doesn't tell you how much data you should have
  487. // if the buffer's too small, retry until we succeed.
  488. //
  489. while( new_len + 1 == buf_len )
  490. {
  491. LocalFree(buf);
  492. buf_len *= 2;
  493. buf = (LPWSTR) LocalAlloc(LMEM_FIXED, buf_len * sizeof(WCHAR));
  494. if (buf == NULL)
  495. {
  496. report_error( GetLastError() );
  497. return;
  498. }
  499. new_len = LoadStringW( hModule, IDS_USAGE, buf, buf_len );
  500. }
  501. if( 0 == new_len )
  502. {
  503. report_error( GetLastError() );
  504. LocalFree(buf);
  505. return;
  506. }
  507. //fwprintf( stderr, buf, g_lpszProgramName );
  508. new_len = lstrlenW( buf ) + lstrlenW( g_lpszProgramName ) + 1;
  509. if ( msg = (LPWSTR)LocalAlloc(LMEM_FIXED, new_len * sizeof(WCHAR) ) )
  510. {
  511. swprintf(msg, buf, g_lpszProgramName );
  512. WriteToConsole( msg );
  513. }
  514. else
  515. {
  516. report_error( GetLastError() );
  517. }
  518. LocalFree(buf);
  519. LocalFree(msg);
  520. }
  521. // We need shutdown privileges enabled to be able to shut down our machines.
  522. BOOL
  523. enable_privileges(
  524. LPCWSTR lpServerName,
  525. BOOL fLogoff
  526. )
  527. {
  528. NTSTATUS Status = STATUS_SUCCESS;
  529. NTSTATUS Status1 = STATUS_SUCCESS;
  530. BOOLEAN fWasEnabled;
  531. if (fLogoff)
  532. {
  533. //
  534. // No privileges to get
  535. //
  536. return TRUE;
  537. }
  538. //
  539. // We will always enable both privileges so
  540. // it can work for telnet sessions.
  541. //
  542. Status = RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE,
  543. TRUE,
  544. FALSE,
  545. &fWasEnabled);
  546. Status1 = RtlAdjustPrivilege(SE_REMOTE_SHUTDOWN_PRIVILEGE,
  547. TRUE,
  548. FALSE,
  549. &fWasEnabled);
  550. if (!NT_SUCCESS(Status) || !NT_SUCCESS(Status1))
  551. {
  552. report_error(RtlNtStatusToDosError(Status));
  553. report_error(RtlNtStatusToDosError(Status1));
  554. return FALSE;
  555. }
  556. return TRUE;
  557. }
  558. VOID __cdecl
  559. wmain(
  560. int argc,
  561. wchar_t *argv[]
  562. )
  563. {
  564. BOOL fLogoff;
  565. BOOL fForce;
  566. BOOL fReboot;
  567. BOOL fAbort;
  568. LPWSTR lpServerName;
  569. LPWSTR lpMessage;
  570. DWORD dwTimeout;
  571. DWORD dwReason;
  572. INT_PTR hResult;
  573. HINSTANCE hInstance = LoadLibrary( L"kernel32.dll" );
  574. if ( hInstance )
  575. {
  576. PSetThreadUILanguage SetThreadUILang = (PSetThreadUILanguage)GetProcAddress( hInstance, "SetThreadUILanguage" );
  577. if ( SetThreadUILang )
  578. (*SetThreadUILang)( 0 );
  579. FreeLibrary( hInstance );
  580. }
  581. // We use the program name for reporting errors.
  582. g_lpszProgramName = argv[ 0 ];
  583. //
  584. // Userdomain is used as the default domain.
  585. //
  586. GetEnvironmentVariableW(L"USERDOMAIN", g_lpszDefaultDomain, MAX_PATH);
  587. GetEnvironmentVariableW(L"COMPUTERNAME", g_lpszLocalComputerName, MAX_PATH);
  588. //
  589. // if there is no arguments, we will display help.
  590. //
  591. if(argc == 1)
  592. {
  593. usage();
  594. return;
  595. }
  596. //
  597. // If the first argument is -i or /i, we pop up UI.
  598. //
  599. if(wcsncmp(argv[1], L"-i", 2) == 0 || wcsncmp(argv[1], L"/i", 2) == 0
  600. || wcsncmp(argv[1], L"-I", 2) == 0 || wcsncmp(argv[1], L"/I", 2) == 0)
  601. {
  602. g_hDllInstance = GetModuleHandle(NULL);
  603. if(g_hDllInstance)
  604. {
  605. hResult = DialogBoxParam(g_hDllInstance, MAKEINTRESOURCE(IDD_DIALOGSHUTDOWN), NULL, Shutdown_DialogProc, NULL);
  606. if(g_lpReasons)
  607. LocalFree((HLOCAL)g_lpReasons);
  608. }
  609. return;
  610. }
  611. // Parse the options.
  612. if( !parse_options( argc,
  613. argv,
  614. &fLogoff,
  615. &fForce,
  616. &fReboot,
  617. &fAbort,
  618. &lpServerName,
  619. &lpMessage,
  620. &dwTimeout,
  621. &dwReason ))
  622. {
  623. usage();
  624. return;
  625. }
  626. // Get all privileges so that we can shutdown the machine.
  627. if( !enable_privileges( lpServerName, fLogoff ))
  628. {
  629. TESTMSG(L"enable_privileges failed\n");
  630. return;
  631. }
  632. // Do the work.
  633. if( fAbort )
  634. {
  635. if( !AbortSystemShutdownW( lpServerName ))
  636. {
  637. report_error( GetLastError( ));
  638. }
  639. }
  640. else if (fLogoff)
  641. {
  642. if (!ExitWindowsEx(fForce ? EWX_LOGOFF : (EWX_LOGOFF | EWX_FORCE),
  643. 0))
  644. {
  645. report_error(GetLastError());
  646. }
  647. }
  648. else
  649. {
  650. // Do the normal form.
  651. if( !InitiateSystemShutdownExW( lpServerName,
  652. lpMessage,
  653. dwTimeout,
  654. fForce,
  655. fReboot,
  656. dwReason ))
  657. {
  658. TESTMSG(L"InitiateSystemShutdownExW failed\n");
  659. report_error( GetLastError( ));
  660. }
  661. }
  662. }
  663. //
  664. // Get the computers in the spesified domain and populate the list box
  665. //
  666. BOOL GetNetworkComputers(HWND hwndList, HWND hwndProgress, LPCWSTR lpDomain)
  667. {
  668. LPSERVER_INFO_101 pBuf = NULL;
  669. LPSERVER_INFO_101 pTmpBuf;
  670. DWORD dwLevel = 101;
  671. DWORD dwPrefMaxLen = -1;
  672. DWORD dwEntriesRead = 0;
  673. DWORD dwTotalEntries = 0;
  674. DWORD dwTotalCount = 0;
  675. DWORD dwServerType = SV_TYPE_SERVER; // all servers
  676. DWORD dwResumeHandle = 0;
  677. NET_API_STATUS nStatus;
  678. LPWSTR pszServerName = NULL;
  679. WCHAR lpWSTR[MAX_PATH];
  680. DWORD i;
  681. WCHAR er[MAX_PATH];
  682. WCHAR wsz[MAX_PATH];
  683. LoadStringW(g_hDllInstance, IDS_GETCOMPUTERNAMEWAIT, er, MAX_PATH);
  684. LoadStringW(g_hDllInstance, IDS_GETCOMPUTERNAMEPROGRESS, wsz, MAX_PATH);
  685. SetWindowTextW(hwndProgress, er);
  686. nStatus = NetServerEnum(NULL,
  687. dwLevel,
  688. (LPBYTE *) &pBuf,
  689. dwPrefMaxLen,
  690. &dwEntriesRead,
  691. &dwTotalEntries,
  692. dwServerType,
  693. lpDomain,
  694. &dwResumeHandle);
  695. //
  696. // If the call succeeds,
  697. //
  698. if ((nStatus == NERR_Success) || (nStatus == ERROR_MORE_DATA))
  699. {
  700. if ((pTmpBuf = pBuf) != NULL)
  701. {
  702. //
  703. // Loop through the entries and
  704. // add each computer name to list.
  705. //
  706. for (i = 0; i < dwEntriesRead; i++)
  707. {
  708. if (pTmpBuf == NULL)
  709. {
  710. break;
  711. }
  712. wcscpy(lpWSTR, pTmpBuf->sv101_name);
  713. if(i+1 > 0 && (i+1) % 500 == 0){
  714. DWORD percentage = ((i+1)*100)/dwEntriesRead;
  715. swprintf(er, L"%d%% %s(%d)...", percentage, wsz, i+1);
  716. SetWindowTextW(hwndProgress, er);
  717. }
  718. //
  719. // We don't add dups.
  720. //
  721. if(LB_ERR == ListBox_FindString(hwndList, -1, lpWSTR))
  722. ListBox_AddString(hwndList, lpWSTR);
  723. pTmpBuf++;
  724. dwTotalCount++;
  725. }
  726. //
  727. // Display a warning if all available entries were
  728. // not enumerated, print the number actually
  729. // enumerated, and the total number available.
  730. //
  731. if (nStatus == ERROR_MORE_DATA)
  732. {
  733. LoadStringW(g_hDllInstance, IDS_GETCOMPUTERNAMEMOREDATA, er, MAX_PATH);
  734. SetWindowTextW(hwndProgress, er);
  735. }
  736. LoadStringW(g_hDllInstance, IDS_GETCOMPUTERNAMECOMPLETE, wsz, MAX_PATH);
  737. swprintf(er, L"%s %d)", wsz, dwTotalCount);
  738. SetWindowTextW(hwndProgress, er);
  739. }
  740. }
  741. else
  742. {
  743. LoadStringW(g_hDllInstance, IDS_GETCOMPUTERNAMEERROR, wsz, MAX_PATH);
  744. swprintf(er, L"%s: %d", wsz, nStatus);
  745. SetWindowTextW(hwndProgress, er);
  746. }
  747. //
  748. // Free the allocated buffer.
  749. //
  750. if (pBuf != NULL)
  751. NetApiBufferFree(pBuf);
  752. return TRUE;
  753. }
  754. //
  755. // Get computername from ADSI path
  756. // Here we only handle WinNT, LDAP, NWCOMPAT, and NDS.
  757. //
  758. BOOL GetComputerNameFromPath(LPWSTR szPath, LPWSTR szName)
  759. {
  760. static _PROVIDER p[] =
  761. {
  762. {L"LDAP://", 7},
  763. {L"WinNT://", 8},
  764. {L"NWCOMPAT://", 11},
  765. {L"NDS://", 6}
  766. };
  767. static UINT np = sizeof(p)/sizeof(_PROVIDER);
  768. LPWSTR lpsz = NULL;
  769. if(!szPath || !szName)
  770. return FALSE;
  771. for(UINT i = 0; i < np; i++)
  772. {
  773. if(wcsncmp(szPath, p[i].szName, p[i].dwLen) == 0)
  774. {
  775. switch(i)
  776. {
  777. case 0: // LDAP
  778. lpsz = wcsstr(szPath, L"CN=");
  779. if(!lpsz)
  780. return FALSE;
  781. lpsz += 3;
  782. while(*lpsz && *lpsz != ',')
  783. *szName++ = *lpsz++;
  784. *szName = 0;
  785. return TRUE;
  786. case 1: // WinNT
  787. case 2: // NWCOMPAT
  788. lpsz = szPath + p[i].dwLen;
  789. //
  790. // skip domain or provider path
  791. //
  792. while(*lpsz && *lpsz != '/')
  793. lpsz++;
  794. lpsz++;
  795. while(*lpsz && *lpsz != '/')
  796. *szName++ = *lpsz++;
  797. *szName = 0;
  798. return TRUE;
  799. case 3: // NDS
  800. lpsz = wcsstr(szPath, L"CN=");
  801. if(!lpsz)
  802. return FALSE;
  803. lpsz += 3;
  804. while(*lpsz && *lpsz != '/')
  805. *szName++ = *lpsz++;
  806. *szName = 0;
  807. return TRUE;
  808. default:
  809. return FALSE;
  810. }
  811. }
  812. }
  813. return FALSE;
  814. }
  815. //
  816. // A centralized place for adjusting window states.
  817. //
  818. VOID AdjustWindowState()
  819. {
  820. if(g_dwActionSelect == ACTION_SHUTDOWN || g_dwActionSelect == ACTION_RESTART)
  821. {
  822. EnableWindow(g_wins.hwndButtonWarning, TRUE);
  823. if (IsDlgButtonChecked(g_wins.hwndShutdownDialog, IDC_CHECKWARNING) == BST_CHECKED)
  824. EnableWindow(g_wins.hwndEditTimeout, TRUE);
  825. else
  826. EnableWindow(g_wins.hwndEditTimeout, FALSE);
  827. EnableWindow(g_wins.hwndEditComment, TRUE);
  828. if(g_bAssumeShutdown)
  829. {
  830. EnableWindow(g_wins.hwndComboOption, FALSE);
  831. EnableWindow(g_wins.hwndChkPlanned, FALSE);
  832. EnableWindow(g_wins.hwndButtonOK, TRUE);
  833. }
  834. else
  835. {
  836. EnableWindow(g_wins.hwndComboOption, TRUE);
  837. EnableWindow(g_wins.hwndChkPlanned, TRUE);
  838. if(g_dwReasonSelect != -1 && (g_lpReasons[g_dwReasonSelect].dwCode & SHTDN_REASON_FLAG_COMMENT_REQUIRED))
  839. {
  840. if(Edit_GetTextLength(g_wins.hwndEditComment) > 0)
  841. EnableWindow(g_wins.hwndButtonOK, TRUE);
  842. else
  843. EnableWindow(g_wins.hwndButtonOK, FALSE);
  844. }
  845. else
  846. {
  847. EnableWindow(g_wins.hwndButtonOK, TRUE);
  848. }
  849. }
  850. EnableWindow(g_wins.hwndBtnAdd, TRUE);
  851. EnableWindow(g_wins.hwndBtnBrowse, TRUE);
  852. EnableWindow(g_wins.hwndBtnRemove, TRUE);
  853. EnableWindow(g_wins.hwndListSelectComputers, TRUE);
  854. }
  855. else
  856. {
  857. EnableWindow(g_wins.hwndChkPlanned, FALSE);
  858. EnableWindow(g_wins.hwndButtonWarning, FALSE);
  859. EnableWindow(g_wins.hwndBtnAdd, FALSE);
  860. EnableWindow(g_wins.hwndBtnBrowse, FALSE);
  861. EnableWindow(g_wins.hwndBtnRemove, FALSE);
  862. EnableWindow(g_wins.hwndComboOption, FALSE);
  863. EnableWindow(g_wins.hwndEditComment, FALSE);
  864. EnableWindow(g_wins.hwndEditTimeout, FALSE);
  865. EnableWindow(g_wins.hwndListSelectComputers, FALSE);
  866. EnableWindow(g_wins.hwndButtonOK, TRUE);
  867. }
  868. }
  869. //
  870. // Init dialog handler for the shutdown dialog.
  871. //
  872. BOOL Shutdown_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
  873. {
  874. HMODULE hUser32;
  875. REASONBUILDPROC buildProc;
  876. REASONDESTROYPROC DestroyProc;
  877. WCHAR lpReasonName[MAX_PATH];
  878. REASONDATA Reasons;
  879. int i;
  880. //
  881. // Init all of the dialog items so we dont have to find
  882. // them everytime we need them.
  883. //
  884. g_wins.hwndShutdownDialog = hwnd;
  885. g_wins.hwndButtonWarning = GetDlgItem(hwnd, IDC_CHECKWARNING);
  886. g_wins.hwndComboAction = GetDlgItem(hwnd, IDC_COMBOACTION);
  887. g_wins.hwndComboOption = GetDlgItem(hwnd, IDC_COMBOOPTION);
  888. g_wins.hwndEditComment = GetDlgItem(hwnd, IDC_EDITCOMMENT);
  889. g_wins.hwndStaticDesc = GetDlgItem(hwnd, IDC_STATICDESCRIPTION);
  890. g_wins.hwndEditTimeout = GetDlgItem(hwnd, IDC_EDITTIMEOUT);
  891. g_wins.hwndListSelectComputers = GetDlgItem(hwnd, IDC_LISTSELECTEDCOMPUTERS);
  892. g_wins.hwndBtnAdd = GetDlgItem(hwnd, IDC_BUTTONADDNEW);
  893. g_wins.hwndBtnBrowse = GetDlgItem(hwnd, IDC_BUTTONBROWSE);
  894. g_wins.hwndBtnRemove = GetDlgItem(hwnd, IDC_BUTTONREMOVE);
  895. g_wins.hwndChkPlanned = GetDlgItem(hwnd, IDC_CHECK_PLANNED);
  896. g_wins.hwndButtonOK = GetDlgItem(hwnd, IDOK);
  897. if(g_wins.hwndButtonWarning == NULL
  898. || g_wins.hwndComboAction == NULL
  899. || g_wins.hwndComboOption == NULL
  900. || g_wins.hwndEditComment == NULL
  901. || g_wins.hwndStaticDesc == NULL
  902. || g_wins.hwndEditTimeout == NULL
  903. || g_wins.hwndListSelectComputers == NULL
  904. || g_wins.hwndBtnAdd == NULL
  905. || g_wins.hwndBtnBrowse == NULL
  906. || g_wins.hwndBtnRemove == NULL
  907. || g_wins.hwndChkPlanned == NULL)
  908. {
  909. report_error( GetLastError( ));
  910. EndDialog(hwnd, (int)-1);
  911. return FALSE;
  912. }
  913. LoadString(g_hDllInstance, IDS_DIALOGTITLEWARNING, g_lpszTitleWarning, TITLEWARNINGLEN);
  914. //
  915. // Default timeout is set to 20 seconds.
  916. //
  917. Edit_SetText(g_wins.hwndEditTimeout, L"20");
  918. if(! CheckDlgButton(hwnd, IDC_CHECKWARNING, DEFAULTWARNINGSTATE))
  919. {
  920. report_error( GetLastError( ));
  921. EndDialog(hwnd, (int)-1);
  922. return FALSE;
  923. }
  924. //
  925. // The for loop will load all of the actions into action combo.
  926. // in the meantime we save them for later use.
  927. //
  928. for(i = 0; i < g_nActions; i++)
  929. {
  930. LoadString(g_hDllInstance, g_dwActions[i], g_lppszActions[i], MAX_PATH - 1);
  931. ComboBox_AddString(g_wins.hwndComboAction, g_lppszActions[i]);
  932. if(g_dwActions[i] == IDS_ACTION_SHUTDOWN)
  933. {
  934. ComboBox_SelectString(g_wins.hwndComboAction, -1, g_lppszActions[i]);
  935. g_dwActionSelect = ACTION_SHUTDOWN;
  936. }
  937. }
  938. hUser32 = LoadLibraryW(L"user32.dll");
  939. if(hUser32 != NULL)
  940. {
  941. //
  942. // We are using the user32.dll to get and destroy the reasons.
  943. // The reasons are added to the option combo and also cached for later use.
  944. //
  945. buildProc = (REASONBUILDPROC)GetProcAddress(hUser32, "BuildReasonArray");
  946. DestroyProc = (REASONDESTROYPROC)GetProcAddress(hUser32, "DestroyReasons");
  947. if(!buildProc || !DestroyProc)
  948. {
  949. FreeLibrary(hUser32);
  950. hUser32 = NULL;
  951. g_bAssumeShutdown = TRUE;
  952. }
  953. }
  954. else
  955. {
  956. g_bAssumeShutdown = TRUE;
  957. }
  958. //
  959. // If we dont have BuildReasonArray() and DestroyReasons() is user32.dll (pre whistler)
  960. // we will disable he option combo box.
  961. //
  962. if(!g_bAssumeShutdown)
  963. {
  964. if(!(*buildProc)(&Reasons, TRUE, FALSE))
  965. {
  966. report_error( GetLastError( ));
  967. FreeLibrary(hUser32);
  968. EndDialog(hwnd, (int)-1);
  969. return FALSE;
  970. }
  971. else
  972. {
  973. int iOption;
  974. int iFirst = -1;
  975. DWORD dwCheckState = 0x0;
  976. //
  977. // Alloc space for reasons.
  978. //
  979. g_lpReasons = (PSHUTDOWNREASON)LocalAlloc(LMEM_FIXED, Reasons.cReasons * sizeof(SHUTDOWNREASON));
  980. if(!g_lpReasons)
  981. {
  982. report_error( GetLastError( ));
  983. FreeLibrary(hUser32);
  984. EndDialog(hwnd, (int)-1);
  985. return FALSE;
  986. }
  987. //
  988. // Set the default to be planned.
  989. //
  990. CheckDlgButton(hwnd, IDC_CHECK_PLANNED, BST_CHECKED);
  991. if (IsDlgButtonChecked(hwnd, IDC_CHECK_PLANNED) == BST_CHECKED)
  992. dwCheckState = SHTDN_REASON_FLAG_PLANNED;
  993. //
  994. // Init this guy number of reasons.
  995. //
  996. g_dwReasons = Reasons.cReasons;
  997. //
  998. // Now populate the combo according the current check state.
  999. //
  1000. for (iOption = 0; iOption < (int)Reasons.cReasons; iOption++)
  1001. {
  1002. wcscpy(g_lpReasons[iOption].lpName, Reasons.rgReasons[iOption]->szName);
  1003. wcscpy(g_lpReasons[iOption].lpDesc, Reasons.rgReasons[iOption]->szDesc);
  1004. g_lpReasons[iOption].dwCode = Reasons.rgReasons[iOption]->dwCode;
  1005. if(((Reasons.rgReasons[iOption]->dwCode) & SHTDN_REASON_FLAG_PLANNED) == dwCheckState)
  1006. {
  1007. if(iFirst == -1)
  1008. iFirst = iOption;
  1009. ComboBox_AddString(g_wins.hwndComboOption, g_lpReasons[iOption].lpName);
  1010. }
  1011. }
  1012. //
  1013. // do a default selection (the first one), and set the description.
  1014. //
  1015. g_dwReasonSelect = iFirst;
  1016. if(g_dwReasons > 0 && iFirst != -1)
  1017. {
  1018. ComboBox_SelectString(g_wins.hwndComboOption, -1, g_lpReasons[iFirst].lpName);
  1019. SetWindowTextW(g_wins.hwndStaticDesc, g_lpReasons[iFirst].lpDesc);
  1020. }
  1021. else
  1022. {
  1023. return FALSE;
  1024. }
  1025. //
  1026. // Setup the comment box.
  1027. // We must fix the maximum characters.
  1028. //
  1029. SendMessage( g_wins.hwndEditComment, EM_LIMITTEXT, (WPARAM)MAX_REASON_COMMENT_LEN, (LPARAM)0 );
  1030. (*DestroyProc)(&Reasons);
  1031. FreeLibrary(hUser32);
  1032. }
  1033. }
  1034. AdjustWindowState();
  1035. return TRUE;
  1036. }
  1037. //
  1038. // Init dialog handler for browse dialog
  1039. //
  1040. BOOL Browse_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
  1041. {
  1042. HWND hwndDomain = NULL;
  1043. int cItems = 1024;
  1044. int lpItems[1024];
  1045. int cActualItems;
  1046. WCHAR lpDomain[MAX_PATH];
  1047. hwndDomain = GetDlgItem(hwnd, IDC_EDITDOMAIN);
  1048. if(!hwndDomain)
  1049. return FALSE;
  1050. Edit_SetText(hwndDomain, g_lpszDefaultDomain);;
  1051. return TRUE;
  1052. }
  1053. //
  1054. // winproc for shutdown dialog
  1055. //
  1056. INT_PTR CALLBACK Shutdown_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam,
  1057. LPARAM lParam)
  1058. {
  1059. switch (uMsg)
  1060. {
  1061. HANDLE_MSG(hwnd, WM_INITDIALOG, Shutdown_OnInitDialog);
  1062. HANDLE_MSG(hwnd, WM_COMMAND, Shutdown_OnCommand);
  1063. case (WM_SYSCOMMAND):
  1064. return (Shutdown_OnCommand(hwnd, (int)(LOWORD(wParam)), (HWND)(lParam), (UINT)HIWORD(wParam)), 0L);
  1065. }
  1066. return FALSE;
  1067. }
  1068. //
  1069. // winproc for Browse dialog
  1070. //
  1071. INT_PTR CALLBACK Browse_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam,
  1072. LPARAM lParam)
  1073. {
  1074. switch (uMsg)
  1075. {
  1076. HANDLE_MSG(hwnd, WM_INITDIALOG, Browse_OnInitDialog);
  1077. HANDLE_MSG(hwnd, WM_COMMAND, Browse_OnCommand);
  1078. }
  1079. return FALSE;
  1080. }
  1081. //
  1082. // winproc for AddNew dialog
  1083. //
  1084. INT_PTR CALLBACK AddNew_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam,
  1085. LPARAM lParam)
  1086. {
  1087. switch (uMsg)
  1088. {
  1089. HANDLE_MSG(hwnd, WM_COMMAND, AddNew_OnCommand);
  1090. }
  1091. return FALSE;
  1092. }
  1093. //
  1094. // Command handler for the shutdown dialog.
  1095. //
  1096. BOOL Shutdown_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
  1097. {
  1098. BOOL fHandled = FALSE;
  1099. DWORD dwDlgResult = 0;
  1100. HINSTANCE h;
  1101. switch (id)
  1102. {
  1103. case IDCANCEL:
  1104. if (codeNotify == BN_CLICKED)
  1105. {
  1106. EndDialog(hwnd, (int) dwDlgResult);
  1107. }
  1108. fHandled = TRUE;
  1109. break;
  1110. case SC_CLOSE:
  1111. EndDialog(hwnd, (int) dwDlgResult);
  1112. fHandled = TRUE;
  1113. break;
  1114. case IDC_BUTTONREMOVE:
  1115. if (codeNotify == BN_CLICKED)
  1116. {
  1117. int cItems = 1024;
  1118. int lpItems[1024];
  1119. int cActualItems;
  1120. WCHAR lpServerName[MAX_PATH];
  1121. //
  1122. // Get the number of selected items. If there is any remove them one by one.
  1123. //
  1124. cActualItems = ListBox_GetSelItems(g_wins.hwndListSelectComputers, cItems, lpItems);
  1125. if(cActualItems > 0)
  1126. {
  1127. int i;
  1128. for(i = cActualItems-1; i >= 0; i--)
  1129. {
  1130. ListBox_DeleteString(g_wins.hwndListSelectComputers, lpItems[i]);
  1131. }
  1132. }
  1133. fHandled = TRUE;
  1134. }
  1135. break;
  1136. case IDC_CHECK_PLANNED:
  1137. if (codeNotify == BN_CLICKED)
  1138. {
  1139. int iOption;
  1140. int iFirst = -1;
  1141. DWORD dwCheckState = 0x0;
  1142. //
  1143. // Get check button state.
  1144. //
  1145. if (IsDlgButtonChecked(hwnd, IDC_CHECK_PLANNED) == BST_CHECKED)
  1146. dwCheckState = SHTDN_REASON_FLAG_PLANNED;
  1147. //
  1148. // Remove all items from combo
  1149. //
  1150. while (ComboBox_GetCount(g_wins.hwndComboOption))
  1151. ComboBox_DeleteString(g_wins.hwndComboOption, 0);
  1152. //
  1153. // Now populate the combo according the current check state.
  1154. //
  1155. for (iOption = 0; iOption < (int)g_dwReasons; iOption++)
  1156. {
  1157. if(((g_lpReasons[iOption].dwCode) & SHTDN_REASON_FLAG_PLANNED) == dwCheckState)
  1158. {
  1159. ComboBox_AddString(g_wins.hwndComboOption, g_lpReasons[iOption].lpName);
  1160. if(iFirst == -1)
  1161. iFirst = iOption;
  1162. }
  1163. }
  1164. //
  1165. // do a default selection (the first one), and set the description.
  1166. //
  1167. if(iFirst != -1)
  1168. {
  1169. ComboBox_SelectString(g_wins.hwndComboOption, -1, g_lpReasons[iFirst].lpName);
  1170. SetWindowTextW(g_wins.hwndStaticDesc, g_lpReasons[iFirst].lpDesc);
  1171. }
  1172. g_dwReasonSelect = iFirst;
  1173. AdjustWindowState();
  1174. fHandled = TRUE;
  1175. }
  1176. break;
  1177. case IDC_EDITCOMMENT:
  1178. if( codeNotify == EN_CHANGE)
  1179. {
  1180. if(g_dwReasonSelect != -1 && (g_lpReasons[g_dwReasonSelect].dwCode & SHTDN_REASON_FLAG_COMMENT_REQUIRED))
  1181. {
  1182. if(Edit_GetTextLength(g_wins.hwndEditComment) > 0)
  1183. EnableWindow(g_wins.hwndButtonOK, TRUE);
  1184. else
  1185. EnableWindow(g_wins.hwndButtonOK, FALSE);
  1186. }
  1187. else
  1188. {
  1189. EnableWindow(g_wins.hwndButtonOK, TRUE);
  1190. }
  1191. fHandled = TRUE;
  1192. }
  1193. break;
  1194. case IDC_BUTTONADDNEW:
  1195. if (codeNotify == BN_CLICKED)
  1196. {
  1197. WCHAR lpServerName[MAX_PATH];
  1198. LPWSTR lpBuffer;
  1199. DWORD dwIndex = 0;
  1200. INT_PTR hResult;
  1201. //
  1202. // Will pop up the addnew dialog. User can type in computer names seperated
  1203. // by white space. After click on OK, we will parse the computer names and
  1204. // add them to the selected computer list. No duplicates will be added.
  1205. //
  1206. hResult = DialogBoxParam(g_hDllInstance, MAKEINTRESOURCE(IDD_DIALOG_ADDNEW), hwnd, AddNew_DialogProc, NULL);
  1207. if(g_lpszNewComputers)
  1208. {
  1209. lpBuffer = g_lpszNewComputers;
  1210. while(*lpBuffer)
  1211. {
  1212. lpServerName[dwIndex] = '\0';
  1213. while(*lpBuffer && *lpBuffer != '\t' && *lpBuffer != '\n' && *lpBuffer != '\r' && *lpBuffer != ' ')
  1214. lpServerName[dwIndex++] = *lpBuffer++;
  1215. lpServerName[dwIndex] = '\0';
  1216. if(dwIndex > 0 && LB_ERR == ListBox_FindString(g_wins.hwndListSelectComputers, -1, lpServerName))
  1217. ListBox_AddString(g_wins.hwndListSelectComputers, lpServerName);
  1218. dwIndex = 0;
  1219. while(*lpBuffer && (*lpBuffer == '\t' || *lpBuffer == '\n' || *lpBuffer == '\r' || *lpBuffer == ' '))
  1220. lpBuffer++;
  1221. }
  1222. LocalFree((HLOCAL)g_lpszNewComputers);
  1223. g_lpszNewComputers = NULL;
  1224. }
  1225. fHandled = TRUE;
  1226. }
  1227. break;
  1228. case IDOK:
  1229. //
  1230. // Here we gather all of the information and do the action.
  1231. //
  1232. if (codeNotify == BN_CLICKED)
  1233. {
  1234. int cItems = 1024;
  1235. int lpItems[1024];
  1236. int cActualItems;
  1237. BOOL fLogoff = FALSE;
  1238. BOOL fAbort = FALSE;
  1239. BOOL fForce = FALSE;
  1240. BOOL fReboot = FALSE;
  1241. BOOL fDisconnect = FALSE;
  1242. BOOL fStandby = FALSE;
  1243. DWORD dwTimeout = 0;
  1244. DWORD dwReasonCode = 0;
  1245. WCHAR lpServerName[MAX_PATH];
  1246. WCHAR lpMsg[MAX_REASON_COMMENT_LEN] = L"";
  1247. DWORD dwCnt = 0;
  1248. DWORD dwActionCode = g_dwActionSelect;
  1249. WCHAR lpNoPrivilage[MAX_PATH];
  1250. WCHAR lpNotSupported[MAX_PATH];
  1251. WCHAR lpRes[MAX_PATH * 2];
  1252. WCHAR lpFailed[MAX_PATH];
  1253. WCHAR lpSuccess[MAX_PATH];
  1254. //
  1255. // The default reason code is 0 and default comment is L"".
  1256. //
  1257. if(IsDlgButtonChecked(hwnd, IDC_CHECKWARNING))
  1258. {
  1259. fForce = FALSE;
  1260. lpServerName[0] = '\0';
  1261. GetWindowText(g_wins.hwndEditTimeout, lpServerName, MAX_PATH);
  1262. if(lstrlen(lpServerName) == 0)
  1263. dwTimeout = 0;
  1264. else dwTimeout = _wtoi(lpServerName);
  1265. }
  1266. else
  1267. {
  1268. fForce = TRUE;
  1269. }
  1270. LoadString(g_hDllInstance, IDS_CANNOTGETPRIVILAGE, lpNoPrivilage, MAX_PATH);
  1271. LoadString(g_hDllInstance, IDS_ACTIONNOTSUPPORTED, lpNotSupported, MAX_PATH);
  1272. LoadString(g_hDllInstance, IDS_FAILED, lpFailed, MAX_PATH);
  1273. LoadString(g_hDllInstance, IDS_SUCCEEDED, lpSuccess, MAX_PATH);
  1274. GetWindowText(g_wins.hwndEditComment, lpMsg, MAX_REASON_COMMENT_LEN);
  1275. if(dwActionCode == ACTION_LOGOFF)
  1276. {
  1277. fLogoff = TRUE;
  1278. }
  1279. else if (dwActionCode == ACTION_RESTART)
  1280. {
  1281. fReboot = TRUE;
  1282. }
  1283. #if 0
  1284. else if (dwActionCode == ACTION_ABORT)
  1285. fAbort = TRUE;
  1286. else if (dwActionCode == ACTION_STANDBY)
  1287. {
  1288. fStandby = TRUE;
  1289. //lstrcat(lpNotSupported, lpServerName);
  1290. //MessageBox(hwnd, lpNotSupported, NULL, 0);
  1291. break;
  1292. }
  1293. else if (dwActionCode == ACTION_DISCONNECT)
  1294. {
  1295. fDisconnect = TRUE;
  1296. //lstrcat(lpNotSupported, lpServerName);
  1297. //MessageBox(hwnd, lpNotSupported, g_lpszTitleWarning, 0);
  1298. break;
  1299. }
  1300. #endif //0
  1301. //
  1302. // Logoff is only for the local computer.
  1303. // Everything else will ingored.
  1304. //
  1305. if(fLogoff)
  1306. {
  1307. if (!ExitWindowsEx(fForce ? EWX_LOGOFF : (EWX_LOGOFF | EWX_FORCE),
  1308. 0))
  1309. {
  1310. report_error(GetLastError());
  1311. }
  1312. EndDialog(hwnd, (int) dwDlgResult);
  1313. break;
  1314. }
  1315. if(! g_bAssumeShutdown)
  1316. {
  1317. dwReasonCode = g_lpReasons[g_dwReasonSelect].dwCode;
  1318. }
  1319. dwCnt = ListBox_GetCount(g_wins.hwndListSelectComputers);
  1320. if(dwCnt > 0)
  1321. {
  1322. DWORD i;
  1323. for(i = 0; i < dwCnt; i++)
  1324. {
  1325. ListBox_GetText(g_wins.hwndListSelectComputers, i, lpServerName);
  1326. //
  1327. // Get all privileges so that we can shutdown the machine.
  1328. //
  1329. if( !enable_privileges(lpServerName, fLogoff))
  1330. {
  1331. report_error( GetLastError( ));
  1332. wcscpy(lpRes, lpNoPrivilage);
  1333. wcscat(lpRes, L": ");
  1334. wcscat(lpRes, lpServerName);
  1335. wcscat(lpRes, L"\n");
  1336. WriteToConsole(lpRes);
  1337. continue;
  1338. }
  1339. //
  1340. // Do the work.
  1341. //
  1342. if( fAbort )
  1343. {
  1344. if( !AbortSystemShutdown( lpServerName ))
  1345. {
  1346. report_error( GetLastError( ));
  1347. }
  1348. }
  1349. else
  1350. {
  1351. //
  1352. // Do the normal form.
  1353. //
  1354. if( !InitiateSystemShutdownEx( lpServerName,
  1355. lpMsg,
  1356. dwTimeout,
  1357. fForce,
  1358. fReboot,
  1359. dwReasonCode ))
  1360. {
  1361. report_error( GetLastError( ));
  1362. wcscpy(lpRes, lpFailed);
  1363. wcscat(lpRes, L": ");
  1364. wcscat(lpRes, lpServerName);
  1365. wcscat(lpRes, L"\n");
  1366. WriteToConsole(lpRes);
  1367. }
  1368. else
  1369. {
  1370. wcscpy(lpRes, lpSuccess);
  1371. wcscat(lpRes, L": ");
  1372. wcscat(lpRes, lpServerName);
  1373. wcscat(lpRes, L"\n");
  1374. WriteToConsole(lpRes);
  1375. }
  1376. }
  1377. }
  1378. }
  1379. else
  1380. {
  1381. //
  1382. // We will keep the dialog up in case user forget to add computers.
  1383. //
  1384. LoadStringW(g_hDllInstance, IDS_EMPTYLISTMSG, lpMsg, MAX_REASON_COMMENT_LEN);
  1385. MessageBoxW(hwnd, lpMsg, g_lpszTitleWarning, 0);
  1386. break;
  1387. }
  1388. EndDialog(hwnd, (int) dwDlgResult);
  1389. }
  1390. break;
  1391. case IDC_CHECKWARNING:
  1392. //
  1393. // The checkbutton state decides the state of the timeout edit box.
  1394. //
  1395. if (codeNotify == BN_CLICKED)
  1396. {
  1397. if(BST_CHECKED == IsDlgButtonChecked(hwnd, IDC_CHECKWARNING))
  1398. {
  1399. EnableWindow(g_wins.hwndEditTimeout, TRUE);
  1400. }
  1401. else
  1402. {
  1403. EnableWindow(g_wins.hwndEditTimeout, FALSE);
  1404. }
  1405. fHandled = TRUE;
  1406. }
  1407. break;
  1408. case IDC_BUTTONBROWSE:
  1409. //
  1410. // Simply pop up the browse dialog. That dialog will be responsible
  1411. // for adding the user selection to the selected computer list.
  1412. //
  1413. if (codeNotify == BN_CLICKED)
  1414. {
  1415. //DialogBoxParam(g_hDllInstance, MAKEINTRESOURCE(IDD_DIALOG_BROWSE), hwnd, Browse_DialogProc, NULL);
  1416. HRESULT hr;
  1417. ICommonQuery* pcq;
  1418. OPENQUERYWINDOW oqw = { 0 };
  1419. DSQUERYINITPARAMS dqip = { 0 };
  1420. IDataObject *pdo;
  1421. FORMATETC fmte = {(CLIPFORMAT)RegisterClipboardFormat(CFSTR_DSOBJECTNAMES),
  1422. NULL,
  1423. DVASPECT_CONTENT,
  1424. -1,
  1425. TYMED_HGLOBAL};
  1426. FORMATETC fmte2 = {(CLIPFORMAT)RegisterClipboardFormat(CFSTR_DSQUERYPARAMS),
  1427. NULL,
  1428. DVASPECT_CONTENT,
  1429. -1,
  1430. TYMED_HGLOBAL};
  1431. STGMEDIUM medium = { TYMED_NULL, NULL, NULL };
  1432. DSOBJECTNAMES *pdon;
  1433. DSQUERYPARAMS *pdqp;
  1434. CoInitialize(NULL);
  1435. //
  1436. // Windows 2000: Always use IID_ICommonQueryW explicitly. IID_ICommonQueryA is not supported.
  1437. //
  1438. hr = CoCreateInstance(CLSID_CommonQuery, NULL, CLSCTX_INPROC_SERVER, IID_ICommonQuery, (void**)&pcq);
  1439. if (FAILED(hr)) {
  1440. //
  1441. // if failed we fall back on our browse dialog.
  1442. //
  1443. CoUninitialize();
  1444. DbgPrint("Cannot create ICommonQuery, fallback on simple browse.\n");
  1445. DialogBoxParam(g_hDllInstance, MAKEINTRESOURCE(IDD_DIALOG_BROWSE), hwnd, Browse_DialogProc, NULL);
  1446. break;
  1447. }
  1448. //
  1449. // Initialize the OPENQUERYWINDOW structure to indicate
  1450. // we want to do a Directory Service
  1451. // Query, the default form is printers and the search
  1452. // should start once the window is initialized.
  1453. //
  1454. oqw.cbStruct = sizeof(oqw);
  1455. oqw.dwFlags = OQWF_OKCANCEL|OQWF_DEFAULTFORM|OQWF_HIDEMENUS|OQWF_REMOVEFORMS;
  1456. oqw.clsidHandler = CLSID_DsQuery;
  1457. oqw.pHandlerParameters = &dqip;
  1458. oqw.clsidDefaultForm = CLSID_DsFindComputer;
  1459. //
  1460. // Now initialize the handler specific parameters,
  1461. // in this case, the File/Save menu item is removed
  1462. //
  1463. dqip.cbStruct = sizeof(dqip);
  1464. dqip.dwFlags = DSQPF_NOSAVE;
  1465. //
  1466. // Call OpenQueryWindow, it will block until
  1467. // the Query Window is dismissed,
  1468. //
  1469. hr = pcq->OpenQueryWindow(hwnd, &oqw, &pdo);
  1470. if (FAILED(hr)) {
  1471. //
  1472. // if failed we fall back on our browse dialog.
  1473. //
  1474. pcq->Release();
  1475. CoUninitialize();
  1476. DialogBoxParam(g_hDllInstance, MAKEINTRESOURCE(IDD_DIALOG_BROWSE), hwnd, Browse_DialogProc, NULL);
  1477. break;
  1478. }
  1479. if (!pdo) {
  1480. //
  1481. // if cancelled,nothing needs to be done.
  1482. //
  1483. pcq->Release();
  1484. CoUninitialize();
  1485. break;
  1486. }
  1487. //
  1488. // Get the CFSTR_DSOBJECTNAMES data. For each selected, the data
  1489. // includes the object class and an ADsPath to the selected object.
  1490. //
  1491. hr = pdo->GetData(&fmte, &medium);
  1492. if(! FAILED(hr))
  1493. {
  1494. pdon = (DSOBJECTNAMES*)GlobalLock(medium.hGlobal);
  1495. if ( pdon )
  1496. {
  1497. WCHAR szName[MAX_PATH];
  1498. LPWSTR lpsz = NULL;
  1499. UINT i;
  1500. for (i = 0; i < pdon->cItems; i++)
  1501. {
  1502. if(!GetComputerNameFromPath((LPWSTR) ((PBYTE) pdon + pdon->aObjects[i].offsetName), szName))
  1503. continue;
  1504. //
  1505. // We don't add dups.
  1506. //
  1507. if(LB_ERR == ListBox_FindString(g_wins.hwndListSelectComputers, -1, szName))
  1508. {
  1509. ListBox_AddString(g_wins.hwndListSelectComputers, szName);
  1510. }
  1511. }
  1512. GlobalUnlock(medium.hGlobal);
  1513. }
  1514. else
  1515. {
  1516. DbgPrint("GlobalLock on medium failed.\n");
  1517. }
  1518. ReleaseStgMedium(&medium);
  1519. }
  1520. else
  1521. {
  1522. DbgPrint("pdo->GetData failed: 0x%x\n", hr);
  1523. }
  1524. //
  1525. // Release resources.
  1526. //
  1527. pdo->Release();
  1528. pcq->Release();
  1529. CoUninitialize();
  1530. fHandled = TRUE;
  1531. }
  1532. break;
  1533. case IDC_COMBOOPTION:
  1534. //
  1535. // Here is where you select shutdown reasons.
  1536. //
  1537. if (codeNotify == CBN_SELCHANGE)
  1538. {
  1539. WCHAR name[MAX_REASON_NAME_LEN + 1];
  1540. DWORD dwIndex;
  1541. GetWindowText(g_wins.hwndComboOption, (LPWSTR)&name, MAX_REASON_NAME_LEN);
  1542. for(dwIndex = 0; dwIndex < g_dwReasons; dwIndex++)
  1543. {
  1544. if(lstrcmp(name, g_lpReasons[dwIndex].lpName) == 0)
  1545. {
  1546. SetWindowTextW(g_wins.hwndStaticDesc, g_lpReasons[dwIndex].lpDesc);
  1547. g_dwReasonSelect = dwIndex;
  1548. AdjustWindowState();
  1549. break;
  1550. }
  1551. }
  1552. fHandled = TRUE;
  1553. }
  1554. break;
  1555. case IDC_COMBOACTION:
  1556. //
  1557. // Select user action here.
  1558. // according to the action. some item will be disabled or enabled.
  1559. //
  1560. if (codeNotify == CBN_SELCHANGE)
  1561. {
  1562. WCHAR name[MAX_PATH];
  1563. DWORD dwIndex;
  1564. GetWindowText(g_wins.hwndComboAction, (LPWSTR)&name, MAX_PATH);
  1565. for(dwIndex = 0; dwIndex < g_nActions; dwIndex++)
  1566. {
  1567. if(lstrcmp(name, g_lppszActions[dwIndex]) == 0)
  1568. {
  1569. g_dwActionSelect = dwIndex;
  1570. AdjustWindowState();
  1571. break;
  1572. }
  1573. }
  1574. fHandled = TRUE;
  1575. }
  1576. break;
  1577. }
  1578. return fHandled;
  1579. }
  1580. //
  1581. // Command handler for the addnew dialog.
  1582. // It simply copy the text into a allocated buffer when OK is clicked.
  1583. //
  1584. BOOL AddNew_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
  1585. {
  1586. BOOL fHandled = FALSE;
  1587. DWORD dwDlgResult = 0;
  1588. HINSTANCE h;
  1589. switch (id)
  1590. {
  1591. case IDOK:
  1592. if (codeNotify == BN_CLICKED)
  1593. {
  1594. HWND hwndEdit;
  1595. DWORD dwTextlen = 0;
  1596. hwndEdit = GetDlgItem(hwnd, IDC_EDIT_ADDCOMPUTERS_COMPUTERS);
  1597. if(hwndEdit != NULL)
  1598. {
  1599. dwTextlen = Edit_GetTextLength(hwndEdit);
  1600. if(dwTextlen)
  1601. {
  1602. g_lpszNewComputers = (LPWSTR)LocalAlloc(LMEM_FIXED, sizeof(TCHAR) * (dwTextlen + 1));
  1603. if(g_lpszNewComputers){
  1604. Edit_GetText(hwndEdit, g_lpszNewComputers, dwTextlen + 1);
  1605. }
  1606. }
  1607. }
  1608. EndDialog(hwnd, (int) dwDlgResult);
  1609. }
  1610. break;
  1611. case IDCANCEL:
  1612. if (codeNotify == BN_CLICKED)
  1613. {
  1614. EndDialog(hwnd, (int) dwDlgResult);
  1615. }
  1616. break;
  1617. }
  1618. return fHandled;
  1619. }
  1620. //
  1621. //Command handler for the browse dialog.
  1622. //
  1623. BOOL Browse_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
  1624. {
  1625. BOOL fHandled = FALSE;
  1626. DWORD dwDlgResult = 0;
  1627. HINSTANCE h;
  1628. switch (id)
  1629. {
  1630. case IDOK:
  1631. //
  1632. // Get selected computer names and add them to
  1633. // selected computer list. No dups.
  1634. //
  1635. if (codeNotify == BN_CLICKED)
  1636. {
  1637. int cItems = 1024;
  1638. int lpItems[1024];
  1639. int cActualItems;
  1640. HWND hwndFromList;
  1641. WCHAR lpServerName[MAX_PATH];
  1642. hwndFromList = GetDlgItem(hwnd, IDC_LISTNETWORKCOMPUTERS);
  1643. assert(hwndFromList != NULL);
  1644. cActualItems = ListBox_GetSelItems(hwndFromList, cItems, lpItems);
  1645. if(cActualItems > 0)
  1646. {
  1647. int i;
  1648. for(i = 0; i < cActualItems; i++)
  1649. {
  1650. ListBox_GetText(hwndFromList, lpItems[i], lpServerName);
  1651. if(IsEmpty(lpServerName))
  1652. continue;
  1653. if(LB_ERR == ListBox_FindString(g_wins.hwndListSelectComputers, -1, lpServerName))
  1654. ListBox_AddString(g_wins.hwndListSelectComputers, lpServerName);
  1655. }
  1656. }
  1657. EndDialog(hwnd, (int) dwDlgResult);
  1658. fHandled = TRUE;
  1659. }
  1660. break;
  1661. case IDCANCEL:
  1662. if (codeNotify == BN_CLICKED)
  1663. {
  1664. EndDialog(hwnd, (int)0);
  1665. fHandled = TRUE;
  1666. }
  1667. break;
  1668. case IDC_BUTTON_REFRESH:
  1669. //
  1670. // List the computers in the specified domain.
  1671. //
  1672. if (codeNotify == BN_CLICKED)
  1673. {
  1674. WCHAR domain[MAX_PATH];
  1675. HWND hwndDomain;
  1676. HWND hwndComputers;
  1677. HWND hwndProgress;
  1678. hwndDomain = GetDlgItem(hwnd, IDC_EDITDOMAIN);
  1679. hwndComputers = GetDlgItem(hwnd, IDC_LISTNETWORKCOMPUTERS);
  1680. hwndProgress = GetDlgItem(hwnd, IDC_STATIC_PROGRESS);
  1681. assert(hwndDomain != NULL && hwndComputers != NULL && hwndProgress != NULL);
  1682. while(ComboBox_DeleteString(hwndComputers, 0));
  1683. lstrcpy(domain, g_lpszDefaultDomain);
  1684. Edit_GetText(hwndDomain, domain, MAX_PATH);
  1685. GetNetworkComputers(hwndComputers, hwndProgress, domain);
  1686. fHandled = TRUE;
  1687. }
  1688. break;
  1689. }
  1690. return fHandled;
  1691. }