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.

880 lines
20 KiB

  1. //____________________________________________________________________________
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1995 - 1996.
  5. //
  6. // File: SchState.cxx
  7. //
  8. // Contents:
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // History: 3/27/1996 RaviR Created
  15. //
  16. //____________________________________________________________________________
  17. #include "..\pch\headers.hxx"
  18. #pragma hdrstop
  19. #include "dbg.h"
  20. #include "macros.h"
  21. #include "..\inc\common.hxx"
  22. #include "..\inc\resource.h"
  23. #include "..\inc\misc.hxx"
  24. #include "resource.h"
  25. #include "..\schedui\schedui.hxx"
  26. #define MAX_MSGLEN 300
  27. #define MAX_SCHED_START_WAIT 60 // seconds
  28. #ifdef _CHICAGO_
  29. #define TIMEOUT_INTERVAL 10000
  30. #define TIMEOUT_INCREMENT 10000
  31. #define TIMEOUT_INTERVAL_MAX (5 * 60 * 1000) // 5 minutes
  32. //____________________________________________________________________________
  33. //
  34. // Function: I_SendMsgTimeout
  35. //
  36. // Synopsis: Uses SendMessageTimeout to send the message with SMTO_BLOCK
  37. // option. If SendMessageTimeout fails due to timeout error,
  38. // we prompt the user for retry.
  39. //
  40. // Arguments: [hwnd] -- IN
  41. // [uMsg] -- IN
  42. // [pdwRes] -- IN
  43. //
  44. // Returns: BOOL
  45. //
  46. // History: 3/29/1996 RaviR Created
  47. //
  48. //____________________________________________________________________________
  49. BOOL
  50. I_SendMsgTimeout(
  51. HWND hwnd,
  52. UINT uMsg,
  53. DWORD * pdwRes)
  54. {
  55. UINT uTimeOut = TIMEOUT_INTERVAL;
  56. int idsErr = 0;
  57. TCHAR szErrMsg[MAX_MSGLEN] = TEXT("");
  58. TCHAR szErrCaption[MAX_MSGLEN] = TEXT("");
  59. switch (uMsg)
  60. {
  61. case SCHED_WIN9X_GETSVCSTATE: idsErr = IERR_GETSVCSTATE; break;
  62. case SCHED_WIN9X_STOPSVC: idsErr = IERR_STOPSVC; break;
  63. case SCHED_WIN9X_PAUSESVC: idsErr = IERR_PAUSESVC; break;
  64. case SCHED_WIN9X_CONTINUESVC: idsErr = IERR_CONTINUESVC; break;
  65. }
  66. while (1)
  67. {
  68. if (SendMessageTimeout(hwnd, uMsg, 0L, 0L, SMTO_BLOCK,
  69. uTimeOut, pdwRes)
  70. == TRUE)
  71. {
  72. return TRUE;
  73. }
  74. if (szErrMsg[0] == TEXT('\0'))
  75. {
  76. UINT iCur = 0;
  77. if (idsErr != 0)
  78. {
  79. LoadString(g_hInstance, idsErr, szErrMsg, MAX_MSGLEN);
  80. iCur = lstrlen(szErrMsg);
  81. szErrMsg[iCur++] = TEXT(' ');
  82. }
  83. LoadString(g_hInstance, IERR_SCHEDSVC, &szErrMsg[iCur],
  84. MAX_MSGLEN - iCur);
  85. LoadString(g_hInstance, IDS_SCHEDULER_NAME, szErrCaption,
  86. MAX_MSGLEN);
  87. }
  88. int iReply = MessageBox(hwnd, szErrMsg, szErrCaption, MB_YESNO);
  89. if (iReply == IDNO)
  90. {
  91. return FALSE;
  92. }
  93. if (uTimeOut < TIMEOUT_INTERVAL_MAX)
  94. {
  95. uTimeOut += TIMEOUT_INCREMENT;
  96. }
  97. }
  98. return FALSE;
  99. }
  100. #endif // _CHICAGO_
  101. //____________________________________________________________________________
  102. //
  103. // Function: GetSchSvcState
  104. //
  105. // Synopsis: returns the schedul service status
  106. //
  107. // Arguments: [dwState] -- IN
  108. //
  109. // Returns: HRESULT
  110. //
  111. // History: 3/29/1996 RaviR Created
  112. //
  113. //____________________________________________________________________________
  114. HRESULT
  115. GetSchSvcState(
  116. DWORD &dwState)
  117. {
  118. #ifdef _CHICAGO_
  119. HWND hwnd = FindWindow(SCHED_CLASS, SCHED_TITLE);
  120. if (hwnd == NULL)
  121. {
  122. dwState = SERVICE_STOPPED;
  123. }
  124. else
  125. {
  126. if (I_SendMsgTimeout(hwnd, SCHED_WIN9X_GETSVCSTATE, &dwState) == FALSE)
  127. {
  128. return E_FAIL;
  129. }
  130. }
  131. return S_OK;
  132. #else // _NT1X_
  133. SC_HANDLE hSchSvc = NULL;
  134. HRESULT hr = S_OK;
  135. do
  136. {
  137. hSchSvc = OpenScheduleService(SERVICE_QUERY_STATUS);
  138. if (hSchSvc == NULL)
  139. {
  140. hr = HRESULT_FROM_WIN32(GetLastError());
  141. DEBUG_OUT_LASTERROR;
  142. break;
  143. }
  144. SERVICE_STATUS SvcStatus;
  145. if (QueryServiceStatus(hSchSvc, &SvcStatus) == FALSE)
  146. {
  147. hr = HRESULT_FROM_WIN32(GetLastError());
  148. DEBUG_OUT_LASTERROR;
  149. break;
  150. }
  151. dwState = SvcStatus.dwCurrentState;
  152. } while (0);
  153. if (hSchSvc != NULL)
  154. {
  155. CloseServiceHandle(hSchSvc);
  156. }
  157. return hr;
  158. #endif // _NT1X_
  159. }
  160. //____________________________________________________________________________
  161. //
  162. // Function: StartScheduler
  163. //
  164. // Synopsis: Start the schedule service
  165. //
  166. // Returns: HRESULT
  167. //
  168. // History: 3/29/1996 RaviR Created
  169. //
  170. //____________________________________________________________________________
  171. HRESULT
  172. StartScheduler(void)
  173. {
  174. #ifdef _CHICAGO_
  175. //
  176. // Persist the change.
  177. //
  178. AutoStart(TRUE);
  179. //
  180. // See if it is running.
  181. //
  182. HWND hwnd = FindWindow(SCHED_CLASS, SCHED_TITLE);
  183. if (hwnd != NULL)
  184. {
  185. // It is already running.
  186. return S_OK;
  187. }
  188. //
  189. // Create a process to open the log.
  190. //
  191. STARTUPINFO sui;
  192. PROCESS_INFORMATION pi;
  193. ZeroMemory(&sui, sizeof(sui));
  194. sui.cb = sizeof (STARTUPINFO);
  195. TCHAR szApp[MAX_PATH];
  196. LPTSTR pszFilePart;
  197. DWORD dwRet = SearchPath(NULL, SCHED_SERVICE_APP_NAME, NULL, MAX_PATH,
  198. szApp, &pszFilePart);
  199. if (dwRet == 0)
  200. {
  201. DEBUG_OUT_LASTERROR;
  202. return HRESULT_FROM_WIN32(GetLastError());
  203. }
  204. BOOL fRet = CreateProcess(
  205. szApp, // lpszImageName
  206. NULL, // lpszCommandLine
  207. NULL, // lpsaProcess - security attributes
  208. NULL, // lpsaThread - security attributes
  209. FALSE, // fInheritHandles
  210. CREATE_NEW_CONSOLE // fdwCreate - creation flags
  211. | CREATE_NEW_PROCESS_GROUP,
  212. NULL, // lpvEnvironment
  213. NULL, // lpszCurDir
  214. &sui, // lpsiStartInfo
  215. &pi ); // lppiProcInfo
  216. if (fRet == 0)
  217. {
  218. DEBUG_OUT_LASTERROR;
  219. return HRESULT_FROM_WIN32(GetLastError());
  220. }
  221. CloseHandle(pi.hProcess);
  222. CloseHandle(pi.hThread);
  223. return S_OK;
  224. #else // _NT1X_
  225. SC_HANDLE hSchSvc = NULL;
  226. HRESULT hr = S_OK;
  227. do
  228. {
  229. hSchSvc = OpenScheduleService(
  230. SERVICE_CHANGE_CONFIG | SERVICE_START |
  231. SERVICE_QUERY_STATUS);
  232. if (hSchSvc == NULL)
  233. {
  234. hr = HRESULT_FROM_WIN32(GetLastError());
  235. DEBUG_OUT_LASTERROR;
  236. break;
  237. }
  238. SERVICE_STATUS SvcStatus;
  239. if (QueryServiceStatus(hSchSvc, &SvcStatus) == FALSE)
  240. {
  241. hr = HRESULT_FROM_WIN32(GetLastError());
  242. DEBUG_OUT_LASTERROR;
  243. break;
  244. }
  245. if (SvcStatus.dwCurrentState == SERVICE_RUNNING)
  246. {
  247. // The service is already running.
  248. break;
  249. }
  250. if (StartService(hSchSvc, 0, NULL) == FALSE)
  251. {
  252. hr = HRESULT_FROM_WIN32(GetLastError());
  253. DEBUG_OUT_LASTERROR;
  254. break;
  255. }
  256. //
  257. // Persist the change. Since the service started successfully,
  258. // don't complain if this fails.
  259. //
  260. HRESULT hrAuto = AutoStart(TRUE);
  261. CHECK_HRESULT(hrAuto);
  262. } while (0);
  263. if (hSchSvc != NULL)
  264. {
  265. CloseServiceHandle(hSchSvc);
  266. }
  267. return hr;
  268. #endif // _NT1X_
  269. }
  270. //____________________________________________________________________________
  271. //
  272. // Function: StopScheduler
  273. //
  274. // Synopsis: Stops the schedule service
  275. //
  276. // Returns: HRESULT
  277. //
  278. // History: 3/29/1996 RaviR Created
  279. //
  280. //____________________________________________________________________________
  281. HRESULT
  282. StopScheduler(void)
  283. {
  284. #ifdef _CHICAGO_
  285. //
  286. // Persist the change.
  287. //
  288. AutoStart(FALSE);
  289. //
  290. // See if it is running or not.
  291. //
  292. HWND hwnd = FindWindow(SCHED_CLASS, SCHED_TITLE);
  293. if (hwnd == NULL)
  294. {
  295. // already stopped
  296. return S_OK;
  297. }
  298. else if (I_SendMsgTimeout(hwnd, SCHED_WIN9X_STOPSVC, NULL) == TRUE)
  299. {
  300. return S_OK;
  301. }
  302. return E_FAIL;
  303. #else // _NT1X_
  304. SC_HANDLE hSchSvc = NULL;
  305. HRESULT hr = S_OK;
  306. do
  307. {
  308. hSchSvc = OpenScheduleService(
  309. SERVICE_CHANGE_CONFIG | SERVICE_STOP |
  310. SERVICE_QUERY_STATUS);
  311. if (hSchSvc == NULL)
  312. {
  313. hr = HRESULT_FROM_WIN32(GetLastError());
  314. DEBUG_OUT_LASTERROR;
  315. break;
  316. }
  317. SERVICE_STATUS SvcStatus;
  318. if (QueryServiceStatus(hSchSvc, &SvcStatus) == FALSE)
  319. {
  320. hr = HRESULT_FROM_WIN32(GetLastError());
  321. DEBUG_OUT_LASTERROR;
  322. break;
  323. }
  324. if (SvcStatus.dwCurrentState == SERVICE_STOPPED)
  325. {
  326. // The service is already stopped.
  327. break;
  328. }
  329. if (ControlService(hSchSvc, SERVICE_CONTROL_STOP, &SvcStatus) == FALSE)
  330. {
  331. hr = HRESULT_FROM_WIN32(GetLastError());
  332. DEBUG_OUT_LASTERROR;
  333. break;
  334. }
  335. //
  336. // Persist the change. Since the service was stopped successfully,
  337. // don't complain if this fails.
  338. //
  339. HRESULT hrAuto = AutoStart(FALSE);
  340. CHECK_HRESULT(hrAuto);
  341. } while (0);
  342. if (hSchSvc != NULL)
  343. {
  344. CloseServiceHandle(hSchSvc);
  345. }
  346. return hr;
  347. #endif // _NT1X_
  348. }
  349. //____________________________________________________________________________
  350. //
  351. // Function: PauseScheduler
  352. //
  353. // Synopsis: If fPause==TRUE requests the schedule service to pauses,
  354. // else to continue.
  355. //
  356. // Arguments: [fPause] -- IN
  357. //
  358. // Returns: HRESULT
  359. //
  360. // History: 3/29/1996 RaviR Created
  361. //
  362. //____________________________________________________________________________
  363. HRESULT
  364. PauseScheduler(
  365. BOOL fPause)
  366. {
  367. #ifdef _CHICAGO_
  368. HWND hwnd = FindWindow(SCHED_CLASS, SCHED_TITLE);
  369. UINT uMsg = fPause ? SCHED_WIN9X_PAUSESVC : SCHED_WIN9X_CONTINUESVC;
  370. if ((hwnd != NULL) && (I_SendMsgTimeout(hwnd, uMsg, NULL) == TRUE))
  371. {
  372. return S_OK;
  373. }
  374. return E_FAIL;
  375. #else // _NT1X_
  376. SC_HANDLE hSchSvc = NULL;
  377. HRESULT hr = S_OK;
  378. do
  379. {
  380. hSchSvc = OpenScheduleService(
  381. SERVICE_PAUSE_CONTINUE | SERVICE_QUERY_STATUS);
  382. if (hSchSvc == NULL)
  383. {
  384. hr = HRESULT_FROM_WIN32(GetLastError());
  385. DEBUG_OUT_LASTERROR;
  386. break;
  387. }
  388. SERVICE_STATUS SvcStatus;
  389. if (QueryServiceStatus(hSchSvc, &SvcStatus) == FALSE)
  390. {
  391. hr = HRESULT_FROM_WIN32(GetLastError());
  392. DEBUG_OUT_LASTERROR;
  393. break;
  394. }
  395. if (fPause == TRUE)
  396. {
  397. if ((SvcStatus.dwCurrentState == SERVICE_PAUSED) ||
  398. (SvcStatus.dwCurrentState == SERVICE_PAUSE_PENDING))
  399. {
  400. // Nothing to do here.
  401. break;
  402. }
  403. else if ((SvcStatus.dwCurrentState == SERVICE_STOPPED) ||
  404. (SvcStatus.dwCurrentState == SERVICE_STOP_PENDING))
  405. {
  406. Win4Assert(0 && "Unexpected");
  407. hr = E_UNEXPECTED;
  408. CHECK_HRESULT(hr);
  409. break;
  410. }
  411. else
  412. {
  413. if (ControlService(hSchSvc, SERVICE_CONTROL_PAUSE, &SvcStatus)
  414. == FALSE)
  415. {
  416. hr = HRESULT_FROM_WIN32(GetLastError());
  417. DEBUG_OUT_LASTERROR;
  418. break;
  419. }
  420. }
  421. }
  422. else // continue
  423. {
  424. if ((SvcStatus.dwCurrentState == SERVICE_RUNNING) ||
  425. (SvcStatus.dwCurrentState == SERVICE_CONTINUE_PENDING))
  426. {
  427. // Nothing to do here.
  428. break;
  429. }
  430. else if ((SvcStatus.dwCurrentState == SERVICE_STOPPED) ||
  431. (SvcStatus.dwCurrentState == SERVICE_STOP_PENDING))
  432. {
  433. Win4Assert(0 && "Unexpected");
  434. hr = E_UNEXPECTED;
  435. CHECK_HRESULT(hr);
  436. break;
  437. }
  438. else
  439. {
  440. if (ControlService(hSchSvc, SERVICE_CONTROL_CONTINUE,
  441. &SvcStatus)
  442. == FALSE)
  443. {
  444. hr = HRESULT_FROM_WIN32(GetLastError());
  445. DEBUG_OUT_LASTERROR;
  446. break;
  447. }
  448. }
  449. }
  450. } while (0);
  451. if (hSchSvc != NULL)
  452. {
  453. CloseServiceHandle(hSchSvc);
  454. }
  455. return hr;
  456. #endif // _NT1X_
  457. }
  458. //+--------------------------------------------------------------------------
  459. //
  460. // Function: UserCanChangeService
  461. //
  462. // Synopsis: Returns TRUE if the UI should allow the user to invoke
  463. // service start, stop, pause/continue, or at account options.
  464. //
  465. // Returns: TRUE if focus is local machine and OS is win95 or it is NT
  466. // and the user is an admin.
  467. //
  468. // History: 4-16-1997 DavidMun Created
  469. //
  470. //---------------------------------------------------------------------------
  471. BOOL
  472. UserCanChangeService(
  473. LPCTSTR pszServerFocus)
  474. {
  475. if (pszServerFocus)
  476. {
  477. return FALSE;
  478. }
  479. #if defined(_CHICAGO_)
  480. return TRUE;
  481. #else
  482. //
  483. // Determine if user is an admin. If not, some items under the
  484. // advanced menu will be disabled.
  485. // BUGBUG A more accurate way to do this would be to attempt to open
  486. // the relevant registry keys and service handle.
  487. //
  488. return IsThreadCallerAnAdmin(NULL);
  489. #endif // !defined(_CHICAGO_)
  490. }
  491. //+--------------------------------------------------------------------------
  492. //
  493. // Function: PromptForServiceStart
  494. //
  495. // Synopsis: If the service is not started or is paused, prompt the user
  496. // to allow us to start/continue it.
  497. //
  498. // Returns: S_OK - service was already running, or was successfully
  499. // started or continued.
  500. // S_FALSE - user elected not to start/continue service
  501. // E_* - error starting/continuing service
  502. //
  503. // History: 4-16-1997 DavidMun Created
  504. //
  505. //---------------------------------------------------------------------------
  506. HRESULT
  507. PromptForServiceStart(
  508. HWND hwnd)
  509. {
  510. HRESULT hr = S_OK;
  511. do
  512. {
  513. //
  514. // Get the current service state
  515. //
  516. DWORD dwState = SERVICE_STOPPED;
  517. hr = GetSchSvcState(dwState);
  518. if (FAILED(hr))
  519. {
  520. dwState = SERVICE_STOPPED;
  521. hr = S_OK; // reset
  522. }
  523. //
  524. // Determine the required action
  525. //
  526. UINT uMsg = 0;
  527. if (dwState == SERVICE_STOPPED ||
  528. dwState == SERVICE_STOP_PENDING)
  529. {
  530. uMsg = IDS_START_SERVICE;
  531. }
  532. else if (dwState == SERVICE_PAUSED ||
  533. dwState == SERVICE_PAUSE_PENDING)
  534. {
  535. uMsg = IDS_CONTINUE_SERVICE;
  536. }
  537. else if (dwState == SERVICE_START_PENDING)
  538. {
  539. uMsg = IDS_START_PENDING;
  540. }
  541. //
  542. // If the service is running, there's nothing to do.
  543. //
  544. if (!uMsg)
  545. {
  546. hr = S_OK;
  547. break;
  548. }
  549. if (uMsg == IDS_START_PENDING)
  550. {
  551. SchedUIMessageDialog(hwnd,
  552. uMsg,
  553. MB_SETFOREGROUND |
  554. MB_TASKMODAL |
  555. MB_ICONINFORMATION |
  556. MB_OK,
  557. NULL);
  558. }
  559. else
  560. {
  561. if (SchedUIMessageDialog(hwnd, uMsg,
  562. MB_SETFOREGROUND |
  563. MB_TASKMODAL |
  564. MB_ICONQUESTION |
  565. MB_YESNO,
  566. NULL)
  567. == IDNO)
  568. {
  569. hr = S_FALSE;
  570. break;
  571. }
  572. }
  573. CWaitCursor waitCursor;
  574. if (uMsg == IDS_START_SERVICE)
  575. {
  576. hr = StartScheduler();
  577. if (FAILED(hr))
  578. {
  579. SchedUIErrorDialog(hwnd, IERR_STARTSVC, (LPTSTR)NULL);
  580. break;
  581. }
  582. // Give the schedule service time to start up.
  583. Sleep(2000);
  584. }
  585. else if (uMsg == IDS_CONTINUE_SERVICE)
  586. {
  587. PauseScheduler(FALSE);
  588. }
  589. for (int count=0; count < 60; count++)
  590. {
  591. GetSchSvcState(dwState);
  592. if (dwState == SERVICE_RUNNING)
  593. {
  594. break;
  595. }
  596. Sleep(1000); // Sleep for 1 seconds.
  597. }
  598. if (dwState != SERVICE_RUNNING)
  599. {
  600. //
  601. // unable to start/continue the service.
  602. //
  603. SchedUIErrorDialog(hwnd,
  604. (uMsg == IDS_START_SERVICE) ? IERR_STARTSVC
  605. : IERR_CONTINUESVC,
  606. (LPTSTR)NULL);
  607. hr = E_FAIL;
  608. break;
  609. }
  610. } while (0);
  611. return hr;
  612. }
  613. //+--------------------------------------------------------------------------
  614. //
  615. // Function: QuietStartContinueService
  616. //
  617. // Synopsis: Start or continue the service without requiring user
  618. // interaction.
  619. //
  620. // Returns: S_OK - service running
  621. // E_FAIL - timeout or failure
  622. //
  623. // History: 5-19-1997 DavidMun Created
  624. //
  625. //---------------------------------------------------------------------------
  626. HRESULT
  627. QuietStartContinueService()
  628. {
  629. HRESULT hr = S_OK;
  630. DWORD dwState = SERVICE_STOPPED;
  631. do
  632. {
  633. hr = GetSchSvcState(dwState);
  634. if (FAILED(hr))
  635. {
  636. dwState = SERVICE_STOPPED;
  637. hr = S_OK; // reset
  638. }
  639. //
  640. // If the service is running, there's nothing to do.
  641. //
  642. if (dwState == SERVICE_RUNNING)
  643. {
  644. break;
  645. }
  646. //
  647. // If it's stopped, request a start. If it's paused, request
  648. // continue.
  649. //
  650. CWaitCursor waitCursor;
  651. switch (dwState)
  652. {
  653. case SERVICE_STOPPED:
  654. case SERVICE_STOP_PENDING:
  655. hr = StartScheduler();
  656. break;
  657. case SERVICE_PAUSED:
  658. case SERVICE_PAUSE_PENDING:
  659. hr = PauseScheduler(FALSE);
  660. break;
  661. }
  662. if (FAILED(hr))
  663. {
  664. CHECK_HRESULT(hr);
  665. break;
  666. }
  667. //
  668. // Wait for its state to change to running
  669. //
  670. for (int count=0; count < MAX_SCHED_START_WAIT; count++)
  671. {
  672. GetSchSvcState(dwState);
  673. if (dwState == SERVICE_RUNNING)
  674. {
  675. break;
  676. }
  677. Sleep(1000); // Sleep for 1 seconds.
  678. }
  679. if (dwState != SERVICE_RUNNING)
  680. {
  681. //
  682. // unable to start/continue the service.
  683. //
  684. hr = E_FAIL;
  685. CHECK_HRESULT(hr);
  686. }
  687. } while (0);
  688. return hr;
  689. }
  690. //____________________________________________________________________________
  691. //
  692. // Function: OpenScheduleService
  693. //
  694. // Synopsis: Opens a handle to the "Schedule" service
  695. //
  696. // Arguments: [dwDesiredAccess] -- desired access
  697. //
  698. // Returns: Handle; if NULL, use GetLastError()
  699. //
  700. // History: 15-Nov-1996 AnirudhS Created
  701. //
  702. //____________________________________________________________________________
  703. #ifndef _CHICAGO_
  704. SC_HANDLE
  705. OpenScheduleService(DWORD dwDesiredAccess)
  706. {
  707. SC_HANDLE hSC = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  708. if (hSC == NULL)
  709. {
  710. DEBUG_OUT_LASTERROR;
  711. return NULL;
  712. }
  713. SC_HANDLE hSchSvc = OpenService(hSC, SCHED_SERVICE_NAME, dwDesiredAccess);
  714. CloseServiceHandle(hSC);
  715. if (hSchSvc == NULL)
  716. {
  717. DEBUG_OUT_LASTERROR;
  718. }
  719. return hSchSvc;
  720. }
  721. #endif // !_CHICAGO_