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.

1469 lines
35 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1994 - 1996.
  5. //
  6. // File: util.cxx
  7. //
  8. // Contents: Miscellaneous utility functions.
  9. //
  10. // History: 04-04-95 DavidMun Created
  11. //
  12. //----------------------------------------------------------------------------
  13. #include <headers.hxx>
  14. #pragma hdrstop
  15. #include <msterr.h>
  16. #include "jt.hxx"
  17. //
  18. // Local constants
  19. //
  20. const ULONG MONTH_INDEX_JAN = 0;
  21. const ULONG MONTH_INDEX_FEB = 1;
  22. const ULONG MONTH_INDEX_MAR = 2;
  23. const ULONG MONTH_INDEX_APR = 3;
  24. const ULONG MONTH_INDEX_MAY = 4;
  25. const ULONG MONTH_INDEX_JUN = 5;
  26. const ULONG MONTH_INDEX_JUL = 6;
  27. const ULONG MONTH_INDEX_AUG = 7;
  28. const ULONG MONTH_INDEX_SEP = 8;
  29. const ULONG MONTH_INDEX_OCT = 9;
  30. const ULONG MONTH_INDEX_NOV = 10;
  31. const ULONG MONTH_INDEX_DEC = 11;
  32. const ULONG MONTHS_PER_YEAR = 12;
  33. //+---------------------------------------------------------------------------
  34. //
  35. // Function: GetPriorityString
  36. //
  37. // Synopsis: Return a human-readable string representing [dwPriority].
  38. //
  39. // Arguments: [dwPriority] - process priority
  40. //
  41. // Returns: static string
  42. //
  43. // History: 01-03-96 DavidMun Created
  44. //
  45. //----------------------------------------------------------------------------
  46. LPCSTR GetPriorityString(DWORD dwPriority)
  47. {
  48. switch (dwPriority)
  49. {
  50. case IDLE_PRIORITY_CLASS:
  51. return "IDLE";
  52. case NORMAL_PRIORITY_CLASS:
  53. return "NORMAL";
  54. case HIGH_PRIORITY_CLASS:
  55. return "HIGH";
  56. case REALTIME_PRIORITY_CLASS:
  57. return "REALTIME";
  58. }
  59. return "INVALID PRIORITY";
  60. }
  61. //+---------------------------------------------------------------------------
  62. //
  63. // Function: GetMonthsString
  64. //
  65. // Synopsis: Return a static string containing month names for each month
  66. // bit turned on in [rgfMonths]
  67. //
  68. // Arguments: [rgfMonths] - TASK_JANUARY | TASK_FEBRUARY | ... |
  69. // TASK_DECEMBER
  70. //
  71. // Returns: static string
  72. //
  73. // History: 03-07-96 DavidMun Created
  74. //
  75. //----------------------------------------------------------------------------
  76. LPCWSTR GetMonthsString(WORD rgfMonths)
  77. {
  78. static WCHAR s_wszMonths[MONTHS_PER_YEAR * MONTH_ABBREV_LEN + 1];
  79. s_wszMonths[0] = '\0';
  80. if (rgfMonths & TASK_JANUARY)
  81. {
  82. wcscat(s_wszMonths, g_awszMonthAbbrev[MONTH_INDEX_JAN]);
  83. }
  84. if (rgfMonths & TASK_FEBRUARY)
  85. {
  86. wcscat(s_wszMonths, g_awszMonthAbbrev[MONTH_INDEX_FEB]);
  87. }
  88. if (rgfMonths & TASK_MARCH)
  89. {
  90. wcscat(s_wszMonths, g_awszMonthAbbrev[MONTH_INDEX_MAR]);
  91. }
  92. if (rgfMonths & TASK_APRIL)
  93. {
  94. wcscat(s_wszMonths, g_awszMonthAbbrev[MONTH_INDEX_APR]);
  95. }
  96. if (rgfMonths & TASK_MAY)
  97. {
  98. wcscat(s_wszMonths, g_awszMonthAbbrev[MONTH_INDEX_MAY]);
  99. }
  100. if (rgfMonths & TASK_JUNE)
  101. {
  102. wcscat(s_wszMonths, g_awszMonthAbbrev[MONTH_INDEX_JUN]);
  103. }
  104. if (rgfMonths & TASK_JULY)
  105. {
  106. wcscat(s_wszMonths, g_awszMonthAbbrev[MONTH_INDEX_JUL]);
  107. }
  108. if (rgfMonths & TASK_AUGUST)
  109. {
  110. wcscat(s_wszMonths, g_awszMonthAbbrev[MONTH_INDEX_AUG]);
  111. }
  112. if (rgfMonths & TASK_SEPTEMBER)
  113. {
  114. wcscat(s_wszMonths, g_awszMonthAbbrev[MONTH_INDEX_SEP]);
  115. }
  116. if (rgfMonths & TASK_OCTOBER)
  117. {
  118. wcscat(s_wszMonths, g_awszMonthAbbrev[MONTH_INDEX_OCT]);
  119. }
  120. if (rgfMonths & TASK_NOVEMBER)
  121. {
  122. wcscat(s_wszMonths, g_awszMonthAbbrev[MONTH_INDEX_NOV]);
  123. }
  124. if (rgfMonths & TASK_DECEMBER)
  125. {
  126. wcscat(s_wszMonths, g_awszMonthAbbrev[MONTH_INDEX_DEC]);
  127. }
  128. if (s_wszMonths[0] == '\0')
  129. {
  130. wcscpy(s_wszMonths, L"None");
  131. }
  132. return s_wszMonths;
  133. }
  134. //+---------------------------------------------------------------------------
  135. //
  136. // Function: DumpJobFlags
  137. //
  138. // Synopsis: Dump description of [flJobFlags] to log.
  139. //
  140. // Arguments: [flJobFlags] - TASK_*
  141. //
  142. // History: 01-03-96 DavidMun Created
  143. //
  144. //----------------------------------------------------------------------------
  145. VOID DumpJobFlags(DWORD flJobFlags)
  146. {
  147. #ifndef RES_KIT
  148. g_Log.Write(
  149. LOG_TEXT,
  150. " Interactive = %u",
  151. (flJobFlags & TASK_FLAG_INTERACTIVE) != 0);
  152. #endif
  153. g_Log.Write(
  154. LOG_TEXT,
  155. " DeleteWhenDone = %u",
  156. (flJobFlags & TASK_FLAG_DELETE_WHEN_DONE) != 0);
  157. g_Log.Write(
  158. LOG_TEXT,
  159. " Suspend = %u",
  160. (flJobFlags & TASK_FLAG_DISABLED) != 0);
  161. g_Log.Write(
  162. LOG_TEXT,
  163. " StartOnlyIfIdle = %u",
  164. (flJobFlags & TASK_FLAG_START_ONLY_IF_IDLE) != 0);
  165. g_Log.Write(
  166. LOG_TEXT,
  167. " KillOnIdleEnd = %u",
  168. (flJobFlags & TASK_FLAG_KILL_ON_IDLE_END) != 0);
  169. g_Log.Write(
  170. LOG_TEXT,
  171. " RestartOnIdleResume = %u",
  172. (flJobFlags & TASK_FLAG_RESTART_ON_IDLE_RESUME) != 0);
  173. g_Log.Write(
  174. LOG_TEXT,
  175. " DontStartIfOnBatteries = %u",
  176. (flJobFlags & TASK_FLAG_DONT_START_IF_ON_BATTERIES) != 0);
  177. g_Log.Write(
  178. LOG_TEXT,
  179. " KillIfGoingOnBatteries = %u",
  180. (flJobFlags & TASK_FLAG_KILL_IF_GOING_ON_BATTERIES) != 0);
  181. g_Log.Write(
  182. LOG_TEXT,
  183. " RunOnlyIfLoggedOn = %u",
  184. (flJobFlags & TASK_FLAG_RUN_ONLY_IF_LOGGED_ON) != 0);
  185. g_Log.Write(
  186. LOG_TEXT,
  187. " SystemRequired = %u",
  188. (flJobFlags & TASK_FLAG_SYSTEM_REQUIRED) != 0);
  189. g_Log.Write(
  190. LOG_TEXT,
  191. " Hidden = %u",
  192. (flJobFlags & TASK_FLAG_HIDDEN) != 0);
  193. flJobFlags = flJobFlags &
  194. ~(TASK_FLAG_INTERACTIVE |
  195. TASK_FLAG_DELETE_WHEN_DONE |
  196. TASK_FLAG_DISABLED |
  197. TASK_FLAG_START_ONLY_IF_IDLE |
  198. TASK_FLAG_KILL_ON_IDLE_END |
  199. TASK_FLAG_RESTART_ON_IDLE_RESUME |
  200. TASK_FLAG_DONT_START_IF_ON_BATTERIES |
  201. TASK_FLAG_KILL_IF_GOING_ON_BATTERIES |
  202. TASK_FLAG_RUN_ONLY_IF_LOGGED_ON |
  203. TASK_FLAG_SYSTEM_REQUIRED |
  204. TASK_FLAG_HIDDEN);
  205. if (flJobFlags)
  206. {
  207. g_Log.Write(LOG_WARN, " Unrecognized bits = %x", flJobFlags);
  208. }
  209. }
  210. //+---------------------------------------------------------------------------
  211. //
  212. // Function: DumpTriggers
  213. //
  214. // Synopsis: Print all triggers to the log.
  215. //
  216. // Arguments: [fJob] - TRUE=>print g_pJob triggers, FALSE=> use g_pJobQueue
  217. //
  218. // Returns: S_OK - all triggers printed
  219. // E_* - error printing a trigger
  220. //
  221. // History: 01-10-96 DavidMun Created
  222. //
  223. //----------------------------------------------------------------------------
  224. HRESULT DumpTriggers(BOOL fJob)
  225. {
  226. HRESULT hr = S_OK;
  227. USHORT i;
  228. USHORT cTriggers;
  229. do
  230. {
  231. if (fJob)
  232. {
  233. hr = g_pJob->GetTriggerCount(&cTriggers);
  234. LOG_AND_BREAK_ON_FAIL(hr, "ITask::GetTriggerCount");
  235. }
  236. else
  237. {
  238. #ifdef NOT_YET
  239. hr = g_pJobQueue->GetTriggerCount(&cTriggers);
  240. LOG_AND_BREAK_ON_FAIL(hr, "ITaskQueue::GetTriggerCount");
  241. #endif // NOT_YET
  242. hr = E_NOTIMPL;
  243. }
  244. g_Log.Write(LOG_TEXT, "");
  245. if (!cTriggers)
  246. {
  247. g_Log.Write(LOG_TEXT, " No triggers");
  248. break;
  249. }
  250. g_Log.Write(
  251. LOG_TEXT,
  252. " %u Trigger%c",
  253. cTriggers,
  254. cTriggers == 1 ? ' ' : 's');
  255. for (i = 0; i < cTriggers; i++)
  256. {
  257. hr = DumpTrigger(fJob, i);
  258. }
  259. }
  260. while (0);
  261. return hr;
  262. }
  263. //+---------------------------------------------------------------------------
  264. //
  265. // Function: DumpJob
  266. //
  267. // Synopsis: Write all job properties to the log.
  268. //
  269. // Arguments: [pJob] - job to dump
  270. //
  271. // Returns: S_OK - printed
  272. // E_* - couldn't read all job properties
  273. //
  274. // History: 03-11-96 DavidMun Created
  275. //
  276. //----------------------------------------------------------------------------
  277. HRESULT DumpJob(ITask *pJob)
  278. {
  279. HRESULT hr = S_OK;
  280. CJobProp JobProperties;
  281. do
  282. {
  283. g_Log.Write(LOG_TRACE, "Printing all job properties");
  284. //
  285. // Print the properties of the job itself first
  286. //
  287. hr = JobProperties.InitFromActual(pJob);
  288. BREAK_ON_FAILURE(hr);
  289. JobProperties.Dump();
  290. }
  291. while (0);
  292. return hr;
  293. }
  294. //+---------------------------------------------------------------------------
  295. //
  296. // Function: DumpJobTriggers
  297. //
  298. // Synopsis: Write properties of all triggers on job to the log.
  299. //
  300. // Arguments: [pJob] - job for which to write trigger properties to log
  301. //
  302. // Returns: S_OK - information printed
  303. // E_* - couldn't read all trigger properties
  304. //
  305. // History: 03-11-96 DavidMun Created
  306. //
  307. //----------------------------------------------------------------------------
  308. HRESULT DumpJobTriggers(ITask *pJob)
  309. {
  310. HRESULT hr = S_OK;
  311. USHORT i;
  312. USHORT cTriggers;
  313. do
  314. {
  315. hr = pJob->GetTriggerCount(&cTriggers);
  316. LOG_AND_BREAK_ON_FAIL(hr, "ITask::GetTriggerCount");
  317. g_Log.Write(LOG_TEXT, "");
  318. if (!cTriggers)
  319. {
  320. g_Log.Write(LOG_TEXT, " No triggers");
  321. break;
  322. }
  323. g_Log.Write(
  324. LOG_TEXT,
  325. " %u Trigger%c",
  326. cTriggers,
  327. cTriggers == 1 ? ' ' : 's');
  328. for (i = 0; i < cTriggers; i++)
  329. {
  330. SpIJobTrigger spTrigger;
  331. CTrigProp TriggerProperties;
  332. hr = pJob->GetTrigger(i, &spTrigger);
  333. LOG_AND_BREAK_ON_FAIL(hr, "ITask::GetTrigger");
  334. hr = TriggerProperties.InitFromActual(spTrigger);
  335. BREAK_ON_FAILURE(hr);
  336. g_Log.Write(LOG_TEXT, "");
  337. g_Log.Write(LOG_TEXT, " Trigger %u:", i);
  338. TriggerProperties.Dump();
  339. }
  340. }
  341. while (0);
  342. return hr;
  343. }
  344. //+---------------------------------------------------------------------------
  345. //
  346. // Function: DumpTrigger
  347. //
  348. // Synopsis: Print a single trigger to the log
  349. //
  350. // Arguments: [fJob] - TRUE=>print g_pJob triggers,
  351. // FALSE=> use g_pJobQueue
  352. // [usTrigger] - 0-based trigger index
  353. //
  354. // Returns: S_OK - trigger printed
  355. // E_* - error printing a trigger
  356. //
  357. // History: 01-10-96 DavidMun Created
  358. //
  359. //----------------------------------------------------------------------------
  360. HRESULT DumpTrigger(BOOL fJob, USHORT usTrigger)
  361. {
  362. HRESULT hr = S_OK;
  363. SpIJobTrigger spTrigger;
  364. CTrigProp TriggerProperties;
  365. do
  366. {
  367. if (fJob)
  368. {
  369. hr = g_pJob->GetTrigger(usTrigger, &spTrigger);
  370. LOG_AND_BREAK_ON_FAIL(hr, "ITask::GetTrigger");
  371. }
  372. else
  373. {
  374. #ifdef NOT_YET
  375. hr = g_pJobQueue->GetTrigger(usTrigger, &spTrigger);
  376. LOG_AND_BREAK_ON_FAIL(hr, "ITaskQueue::GetTrigger");
  377. #endif // NOT_YET
  378. hr = E_NOTIMPL;
  379. }
  380. hr = TriggerProperties.InitFromActual(spTrigger);
  381. BREAK_ON_FAILURE(hr);
  382. g_Log.Write(LOG_TEXT, "");
  383. g_Log.Write(LOG_TEXT, " Trigger %u:", usTrigger);
  384. TriggerProperties.Dump();
  385. }
  386. while (0);
  387. return hr;
  388. }
  389. //+---------------------------------------------------------------------------
  390. //
  391. // Function: GetInterfaceString
  392. //
  393. // Synopsis: Return string in the form IID_* or "unrecognized interface"
  394. //
  395. // Arguments: [iidToBind] - interface
  396. //
  397. // History: 04-25-95 DavidMun Created
  398. // 09-11-95 DavidMun New interfaces
  399. //
  400. //----------------------------------------------------------------------------
  401. LPCSTR GetInterfaceString(REFIID iid)
  402. {
  403. CHAR *szInterface;
  404. if (&iid == &IID_IUnknown)
  405. {
  406. szInterface = "IID_IUnknown";
  407. }
  408. else if (&iid == &IID_ITask)
  409. {
  410. szInterface = "IID_ITask";
  411. }
  412. else if (&iid == &IID_ITaskTrigger)
  413. {
  414. szInterface = "IID_ITaskTrigger";
  415. }
  416. else
  417. {
  418. szInterface = "unrecognized interface";
  419. }
  420. return szInterface;
  421. }
  422. //+---------------------------------------------------------------------------
  423. //
  424. // Function: GetTriggerTypeString
  425. //
  426. // Synopsis: Return a static human-readable string describing
  427. // [TriggerType].
  428. //
  429. // Arguments: [TriggerType] - TASK_TRIGGER_TYPE
  430. //
  431. // Returns: static string
  432. //
  433. // History: 01-04-96 DavidMun Created
  434. // 06-13-96 DavidMun Logon trigger
  435. //
  436. //----------------------------------------------------------------------------
  437. LPCSTR GetTriggerTypeString(TASK_TRIGGER_TYPE TriggerType)
  438. {
  439. switch (TriggerType)
  440. {
  441. case TASK_TIME_TRIGGER_ONCE:
  442. return "Once";
  443. case TASK_TIME_TRIGGER_DAILY:
  444. return "Daily";
  445. case TASK_TIME_TRIGGER_WEEKLY:
  446. return "Weekly";
  447. case TASK_TIME_TRIGGER_MONTHLYDATE:
  448. return "MonthlyDate";
  449. case TASK_TIME_TRIGGER_MONTHLYDOW:
  450. return "MonthlyDOW";
  451. case TASK_EVENT_TRIGGER_ON_IDLE:
  452. return "OnIdle";
  453. case TASK_EVENT_TRIGGER_AT_SYSTEMSTART:
  454. return "AtStartup";
  455. case TASK_EVENT_TRIGGER_AT_LOGON:
  456. return "AtLogon";
  457. }
  458. return "INVALID TRIGGER TYPE";
  459. }
  460. //+---------------------------------------------------------------------------
  461. //
  462. // Function: GetDaysString
  463. //
  464. // Synopsis: Returns static string representing day bits in
  465. // [rgfDays].
  466. //
  467. // Arguments: [rgfDays] - each of the 32 bits corresponds to a day of the
  468. // month.
  469. //
  470. // Returns: static string
  471. //
  472. // History: 03-07-96 DavidMun Created
  473. //
  474. // Notes: This routine supports "day 32" because if the job scheduler
  475. // erroneously turns on that bit we want to make it visible.
  476. //
  477. //----------------------------------------------------------------------------
  478. LPCSTR GetDaysString(DWORD rgfDays)
  479. {
  480. static CHAR s_szDaysList[] =
  481. "1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,32";
  482. ULONG i;
  483. ULONG j;
  484. ULONG ulRunStart = 0;
  485. BOOL fInRun = FALSE;
  486. //
  487. // Note s_szDaysList is initialized to worst case to get adequately long
  488. // string. The most significant bit may be set and we want to display
  489. // that, so it includes space for 32.
  490. //
  491. s_szDaysList[0] = '\0';
  492. for (i = 0; i <= 32; i++, rgfDays >>= 1)
  493. {
  494. if (rgfDays & 1)
  495. {
  496. //
  497. // Day 'i' should be included in the string. If we're in a run of
  498. // days that are on, simply continue. When the run ends we'll add
  499. // it to the string.
  500. //
  501. // If we're not in a run of days, consider this day the start of
  502. // a new run (which may turn out to be only one day long).
  503. //
  504. if (!fInRun)
  505. {
  506. fInRun = TRUE;
  507. ulRunStart = i;
  508. }
  509. }
  510. else if (fInRun)
  511. {
  512. //
  513. // Bit i is a zero, so obviously we're not in a run of ones
  514. // anymore. Turn off that flag.
  515. //
  516. fInRun = FALSE;
  517. //
  518. // The bits from ulRunStart to i-1 were all on. Find out if the
  519. // run was just one or two bits long, if that's the case then
  520. // we don't want to use the m-n list form, the day number(s) should
  521. // simply be appended to the string.
  522. //
  523. // Note that at this point i must be >= 1.
  524. //
  525. if (i == 1)
  526. {
  527. // ulRunStart == 0. bit 0 was on, which corresponds to day 1.
  528. strcpy(s_szDaysList, "1");
  529. }
  530. else if (i == 2)
  531. {
  532. //
  533. // ulRunStart == 0 or 1, so the run is 1 or 2 bits long. So
  534. // we don't want to use a dash.
  535. //
  536. if (ulRunStart == 0)
  537. {
  538. strcpy(s_szDaysList, "1,2");
  539. }
  540. else
  541. {
  542. strcpy(s_szDaysList, "2");
  543. }
  544. }
  545. else if (ulRunStart <= i - 3) // i >= 3 at this point
  546. {
  547. // There's a run of > 2 bits, which means we want a dash
  548. if (s_szDaysList[0])
  549. {
  550. strcat(s_szDaysList, ",");
  551. }
  552. //
  553. // Remember we're converting from a bit position, which is 0
  554. // based, to a day number, which is 1 based.
  555. //
  556. CHAR *pszNext;
  557. pszNext = s_szDaysList + strlen(s_szDaysList);
  558. pszNext += wsprintfA(pszNext, "%u", ulRunStart + 1);
  559. *pszNext++ = '-';
  560. wsprintfA(pszNext, "%u", i);
  561. }
  562. else
  563. {
  564. // There's a run of 1 or 2 bits
  565. CHAR *pszNext = s_szDaysList + strlen(s_szDaysList);
  566. for (j = ulRunStart; j < i; j++)
  567. {
  568. if (s_szDaysList[0])
  569. {
  570. *pszNext++ = ',';
  571. }
  572. pszNext += wsprintfA(pszNext, "%u", j+1);
  573. }
  574. }
  575. }
  576. }
  577. return s_szDaysList;
  578. }
  579. //+---------------------------------------------------------------------------
  580. //
  581. // Function: GetDaysOfWeekString
  582. //
  583. // Synopsis: Returns static string representing day bits in
  584. // [flDaysOfTheWeek].
  585. //
  586. // Arguments: [flDaysOfTheWeek] - TASK_*DAY bits
  587. //
  588. // Returns: static string
  589. //
  590. // History: 01-04-96 DavidMun Created
  591. //
  592. //----------------------------------------------------------------------------
  593. LPCSTR GetDaysOfWeekString(WORD flDaysOfTheWeek)
  594. {
  595. static CHAR s_szDOW[] = "UMTWRFA"; // init to get max size
  596. sprintf(s_szDOW, ".......");
  597. if (flDaysOfTheWeek & TASK_SUNDAY)
  598. {
  599. s_szDOW[0] = 'U';
  600. }
  601. if (flDaysOfTheWeek & TASK_MONDAY)
  602. {
  603. s_szDOW[1] = 'M';
  604. }
  605. if (flDaysOfTheWeek & TASK_TUESDAY)
  606. {
  607. s_szDOW[2] = 'T';
  608. }
  609. if (flDaysOfTheWeek & TASK_WEDNESDAY)
  610. {
  611. s_szDOW[3] = 'W';
  612. }
  613. if (flDaysOfTheWeek & TASK_THURSDAY)
  614. {
  615. s_szDOW[4] = 'R';
  616. }
  617. if (flDaysOfTheWeek & TASK_FRIDAY)
  618. {
  619. s_szDOW[5] = 'F';
  620. }
  621. if (flDaysOfTheWeek & TASK_SATURDAY)
  622. {
  623. s_szDOW[6] = 'A';
  624. }
  625. return s_szDOW;
  626. }
  627. //+---------------------------------------------------------------------------
  628. //
  629. // Function: GetStatusString
  630. //
  631. // Synopsis: Return a string describing job status.
  632. //
  633. // Arguments: [hrJobStatus] - SCHED_* hresult
  634. //
  635. // Returns: static string
  636. //
  637. // History: 01-08-96 DavidMun Created
  638. //
  639. //----------------------------------------------------------------------------
  640. LPCSTR GetStatusString(HRESULT hrJobStatus)
  641. {
  642. static CHAR s_szStatus[11]; // big enough for 0x00000000
  643. switch (hrJobStatus)
  644. {
  645. case S_OK:
  646. return "S_OK";
  647. case SCHED_S_TASK_READY:
  648. return "SCHED_S_TASK_READY";
  649. case SCHED_S_TASK_RUNNING:
  650. return "SCHED_S_TASK_RUNNING";
  651. case SCHED_S_TASK_DISABLED:
  652. return "SCHED_S_TASK_DISABLED";
  653. case SCHED_S_TASK_TERMINATED:
  654. return "SCHED_S_TASK_TERMINATED";
  655. case SCHED_S_TASK_HAS_NOT_RUN:
  656. return "SCHED_S_TASK_HAS_NOT_RUN";
  657. case SCHED_S_TASK_NO_VALID_TRIGGERS:
  658. return "SCHED_S_TASK_NO_VALID_TRIGGERS";
  659. case SCHED_S_TASK_NO_MORE_RUNS:
  660. return "SCHED_S_TASK_NO_MORE_RUNS";
  661. case SCHED_S_TASK_NOT_SCHEDULED:
  662. return "SCHED_S_TASK_NOT_SCHEDULED";
  663. case SCHED_E_TASK_NOT_RUNNING:
  664. return "SCHED_E_TASK_NOT_RUNNING";
  665. case SCHED_E_SERVICE_NOT_INSTALLED:
  666. return "SCHED_E_SERVICE_NOT_INSTALLED";
  667. case SCHED_E_ACCOUNT_INFORMATION_NOT_SET:
  668. return "SCHED_E_ACCOUNT_INFORMATION_NOT_SET";
  669. #ifdef DELETED
  670. case SCHED_E_NOT_AN_AT_JOB:
  671. return "SCHED_E_NOT_AN_AT_JOB";
  672. #endif // DELETED
  673. default:
  674. sprintf(s_szStatus, "%#x", hrJobStatus);
  675. return s_szStatus;
  676. }
  677. }
  678. //+---------------------------------------------------------------------------
  679. //
  680. // Function: Bind
  681. //
  682. // Synopsis: Bind to [wszFilename] for [iidToBind].
  683. //
  684. // Arguments: [wszFilename] - file to bind to
  685. // [iidToBind] - interface to request
  686. // [ppitf] - resulting interface
  687. //
  688. // Returns: S_OK - *[ppitf] valid
  689. // E_* - error logged
  690. //
  691. // Modifies: *[ppitf]
  692. //
  693. // History: 04-20-95 DavidMun Created
  694. // 04-25-95 DavidMun Add performance output
  695. //
  696. //----------------------------------------------------------------------------
  697. HRESULT Bind(WCHAR *wszFilename, REFIID iidToBind, VOID **ppitf)
  698. {
  699. HRESULT hr = S_OK;
  700. SpIMoniker spmk;
  701. ULONG ulTicks;
  702. do
  703. {
  704. g_Log.Write(
  705. LOG_DEBUG,
  706. "Binding to %S for %s",
  707. wszFilename,
  708. GetInterfaceString(iidToBind));
  709. hr = GetMoniker(wszFilename, &spmk);
  710. BREAK_ON_FAILURE(hr);
  711. ulTicks = GetTickCount();
  712. hr = BindMoniker(spmk, 0, iidToBind, ppitf);
  713. ulTicks = GetTickCount() - ulTicks;
  714. g_Log.Write(
  715. LOG_PERF,
  716. "Bind to %S for %s %u ms",
  717. wszFilename,
  718. GetInterfaceString(iidToBind),
  719. ulTicks);
  720. if (FAILED(hr))
  721. {
  722. g_Log.Write(
  723. LOG_FAIL,
  724. "BindMoniker to \"%S\" hr=%#010x",
  725. wszFilename,
  726. hr);
  727. }
  728. }
  729. while (0);
  730. return hr;
  731. }
  732. //+---------------------------------------------------------------------------
  733. //
  734. // Function: GetMoniker
  735. //
  736. // Synopsis: Return a filemoniker to [wszFilename].
  737. //
  738. // Arguments: [wszFilename] - file to get moniker for
  739. // [ppmk] - resulting moniker
  740. //
  741. // Returns: S_OK - *[ppmk] valid
  742. // E_* - error logged
  743. //
  744. // Modifies: *[ppmk]
  745. //
  746. // History: 04-20-95 DavidMun Created
  747. //
  748. //----------------------------------------------------------------------------
  749. HRESULT GetMoniker(WCHAR *wszFilename, IMoniker **ppmk)
  750. {
  751. HRESULT hr = S_OK;
  752. do
  753. {
  754. g_Log.Write(LOG_DEBUG, "Creating file moniker to %S", wszFilename);
  755. hr = CreateFileMoniker(wszFilename, ppmk);
  756. if (FAILED(hr))
  757. {
  758. g_Log.Write(
  759. LOG_FAIL,
  760. "CreateFileMoniker(\"%S\") hr=%#010x",
  761. wszFilename,
  762. hr);
  763. break;
  764. }
  765. }
  766. while (0);
  767. return hr;
  768. }
  769. //+---------------------------------------------------------------------------
  770. //
  771. // Function: DupString
  772. //
  773. // Synopsis: Fill *[ppwszDest] with a buffer containing a copy of
  774. // [wszSource].
  775. //
  776. // Arguments: [wszSource] - string to copy
  777. // [ppwszDest] - filled with buffer containing copy
  778. //
  779. // Returns: S_OK
  780. // E_OUTOFMEMORY;
  781. //
  782. // Modifies: *[ppwszDest]
  783. //
  784. // History: 04-20-95 DavidMun Created
  785. //
  786. // Notes: Caller must use delete to free *[ppwszDest].
  787. //
  788. //----------------------------------------------------------------------------
  789. HRESULT DupString(const WCHAR *wszSource, WCHAR **ppwszDest)
  790. {
  791. HRESULT hr = S_OK;
  792. *ppwszDest = (LPWSTR)CoTaskMemAlloc(sizeof(WCHAR) * (1 + wcslen(wszSource)));
  793. if (!*ppwszDest)
  794. {
  795. hr = E_OUTOFMEMORY;
  796. g_Log.Write(LOG_ERROR, "DupString: out of memory");
  797. }
  798. else
  799. {
  800. wcscpy(*ppwszDest, wszSource);
  801. }
  802. return hr;
  803. }
  804. //+---------------------------------------------------------------------------
  805. //
  806. // Function: HasFilename
  807. //
  808. // Synopsis: Return S_OK if object has filename, S_FALSE if not.
  809. //
  810. // Arguments: [pPersistFile] - IPFile itf on object
  811. //
  812. // Returns: S_OK - object has filename
  813. // S_FALSE - object does not have filename
  814. // E_* - error logged
  815. //
  816. // History: 01-10-96 DavidMun Created
  817. //
  818. //----------------------------------------------------------------------------
  819. HRESULT HasFilename(IPersistFile *pPersistFile)
  820. {
  821. HRESULT hr = S_OK;
  822. LPOLESTR pstrFile;
  823. do
  824. {
  825. hr = pPersistFile->GetCurFile(&pstrFile);
  826. LOG_AND_BREAK_ON_FAIL(hr, "IPersistFile::GetCurFile");
  827. CoTaskMemFree(pstrFile);
  828. }
  829. while (0);
  830. return hr;
  831. }
  832. //+---------------------------------------------------------------------------
  833. //
  834. // Function: SaveIfDirty
  835. //
  836. // Synopsis: Save given job object if it's dirty.
  837. //
  838. // Arguments: [pJob] - job to save
  839. //
  840. // Returns: S_OK - not dirty or successfully saved
  841. // E_* - error logged
  842. //
  843. // History: 01-10-96 DavidMun Created
  844. //
  845. //----------------------------------------------------------------------------
  846. HRESULT SaveIfDirty(ITask *pJob)
  847. {
  848. HRESULT hr = S_OK;
  849. SpIPersistFile spPersistFile;
  850. do
  851. {
  852. hr = pJob->QueryInterface(IID_IPersistFile, (void **)&spPersistFile);
  853. LOG_AND_BREAK_ON_FAIL(hr, "ITask::QI(IPersistFile)");
  854. hr = _SaveIfDirty(spPersistFile);
  855. }
  856. while (0);
  857. return hr;
  858. }
  859. //+---------------------------------------------------------------------------
  860. //
  861. // Function: SaveIfDirty
  862. //
  863. // Synopsis: Save queue object if it's dirty. See job object version.
  864. //
  865. // History: 01-10-96 DavidMun Created
  866. //
  867. //----------------------------------------------------------------------------
  868. HRESULT SaveIfDirty(IUnknown *pJobQueue)
  869. {
  870. HRESULT hr = S_OK;
  871. SpIPersistFile spPersistFile;
  872. do
  873. {
  874. hr = pJobQueue->QueryInterface(
  875. IID_IPersistFile,
  876. (void **)&spPersistFile);
  877. LOG_AND_BREAK_ON_FAIL(hr, "ITaskQueue::QI(IPersistFile)");
  878. hr = _SaveIfDirty(spPersistFile);
  879. }
  880. while (0);
  881. return hr;
  882. }
  883. //+---------------------------------------------------------------------------
  884. //
  885. // Function: _SaveIfDirty
  886. //
  887. // Synopsis: Save persisted object if it reports it's dirty.
  888. //
  889. // Arguments: [pPersistFile] - IPFile on job or queue
  890. //
  891. // Returns: S_OK - saved or not dirty
  892. // E_* - error logged
  893. //
  894. // History: 01-10-96 DavidMun Created
  895. //
  896. //----------------------------------------------------------------------------
  897. HRESULT _SaveIfDirty(IPersistFile *pPersistFile)
  898. {
  899. HRESULT hr = S_OK;
  900. do
  901. {
  902. hr = HasFilename(pPersistFile);
  903. BREAK_ON_FAILURE(hr);
  904. //
  905. // If the object doesn't have a filename then it can't be persisted.
  906. //
  907. if (hr == S_FALSE)
  908. {
  909. break;
  910. }
  911. //
  912. // If the object isn't dirty, there's nothing to do
  913. //
  914. hr = pPersistFile->IsDirty();
  915. LOG_AND_BREAK_ON_FAIL(hr, "IPersistFile::IsDirty");
  916. if (hr == S_FALSE)
  917. {
  918. break;
  919. }
  920. //
  921. // Save the object.
  922. //
  923. hr = pPersistFile->Save(NULL, TRUE);
  924. LOG_AND_BREAK_ON_FAIL(hr, "IPersistFile::Save");
  925. }
  926. while (0);
  927. return hr;
  928. }
  929. //+---------------------------------------------------------------------------
  930. //
  931. // Function: Activate
  932. //
  933. // Synopsis: Perform the Activate command
  934. //
  935. // Arguments: [wszFileName] - name of job or queue to activate
  936. // [ppJob] - filled if file is job
  937. // [ppQueue] - filled if file is queue
  938. // [pfJob] - set TRUE if [wszFileName] is a job, FALSE
  939. // otherwise.
  940. //
  941. // Returns: S_OK - *[pfJob] and either *[ppJob] or *[ppQueue] valid
  942. // E_* - error logged
  943. //
  944. // Modifies: *[pfJob], and either *[ppJob] or *[ppQueue]
  945. //
  946. // History: 01-30-96 DavidMun Created
  947. //
  948. //----------------------------------------------------------------------------
  949. HRESULT Activate(
  950. WCHAR *wszFileName,
  951. ITask **ppJob,
  952. IUnknown **ppQueue,
  953. BOOL *pfJob)
  954. {
  955. HRESULT hr = S_OK;
  956. SpIJob spJob;
  957. SpIUnknown spQueue;
  958. do
  959. {
  960. *pfJob = TRUE;
  961. //
  962. // BUGBUG remove this ifdef when ITaskScheduler::IsTask() and
  963. // ITaskScheduler::IsQueue() are implemented.
  964. //
  965. #ifdef IS_JOB_IMPLEMENTED
  966. hr = g_pJobScheduler->IsJob(wszFileName);
  967. LOG_AND_BREAK_ON_FAIL(hr, "ITaskScheduler::IsTask");
  968. if (hr == S_FALSE)
  969. {
  970. hr = g_pJobScheduler->IsQueue(wszFileName);
  971. if (hr == S_OK)
  972. {
  973. *pfJob = FALSE;
  974. }
  975. else
  976. {
  977. g_Log.Write(
  978. LOG_FAIL,
  979. "File '%S' is neither a job nor a queue, IsJob hr=S_FALSE, IsQueue hr=%#010x",
  980. wszFilename,
  981. hr);
  982. hr = E_FAIL;
  983. break;
  984. }
  985. }
  986. else if (hr != S_OK)
  987. {
  988. g_pLog->Write(
  989. LOG_FAIL,
  990. "Unexpected hr from IsJob: %#010x", hr);
  991. hr = E_FAIL;
  992. break;
  993. }
  994. #endif // IS_JOB_IMPLEMENTED
  995. //
  996. // Activate the job or queue and ask for the appropriate interface.
  997. //
  998. g_Log.Write(
  999. LOG_TRACE,
  1000. "Activating %s '%S'",
  1001. *pfJob ? "job" : "queue",
  1002. wszFileName);
  1003. if (*pfJob)
  1004. {
  1005. hr = g_pJobScheduler->Activate(
  1006. wszFileName,
  1007. IID_ITask,
  1008. (IUnknown**)(ITask**)&spJob);
  1009. }
  1010. else
  1011. {
  1012. hr = g_pJobScheduler->Activate(
  1013. wszFileName,
  1014. IID_IUnknown,
  1015. (IUnknown**)&spQueue);
  1016. }
  1017. //
  1018. // Bail if the activate failed
  1019. //
  1020. if (FAILED(hr))
  1021. {
  1022. g_Log.Write(
  1023. LOG_FAIL,
  1024. "ITaskScheduler::Activate(%S, IID_ITask%s) hr=%#010x",
  1025. wszFileName,
  1026. *pfJob ? "" : "Queue",
  1027. hr);
  1028. break;
  1029. }
  1030. //
  1031. // Replace the passed in job or queue object with the new one.
  1032. //
  1033. if (*pfJob)
  1034. {
  1035. if (*ppJob)
  1036. {
  1037. hr = SaveIfDirty(*ppJob);
  1038. (*ppJob)->Release();
  1039. }
  1040. spJob.Transfer(ppJob);
  1041. }
  1042. else
  1043. {
  1044. if (*ppQueue)
  1045. {
  1046. hr = SaveIfDirty(*ppQueue);
  1047. (*ppQueue)->Release();
  1048. }
  1049. #ifdef NOT_YET
  1050. spQueue.Transfer(ppQueue);
  1051. #endif // NOT_YET
  1052. hr = E_NOTIMPL;
  1053. }
  1054. }
  1055. while (0);
  1056. return hr;
  1057. }
  1058. //+---------------------------------------------------------------------------
  1059. //
  1060. // Function: GetAndPrepareEnumeratorSlot
  1061. //
  1062. // Synopsis: Get an enumerator slot number from the command line.
  1063. //
  1064. // Arguments: [ppwsz] - command line
  1065. // [pidxSlot] - filled with slot number 0..NUM_ENUMERATOR_SLOTS-1
  1066. //
  1067. // Returns: S_OK - *[pidxSlot] is valid
  1068. // E_INVALIDARG - command line specified bad slot number
  1069. //
  1070. // Modifies: *pidxSlot
  1071. //
  1072. // History: 01-30-96 DavidMun Created
  1073. //
  1074. //----------------------------------------------------------------------------
  1075. HRESULT GetEnumeratorSlot(WCHAR **ppwsz, ULONG *pidxSlot)
  1076. {
  1077. HRESULT hr = S_OK;
  1078. do
  1079. {
  1080. hr = Expect(TKN_NUMBER, ppwsz, L"enumerator slot number");
  1081. BREAK_ON_FAILURE(hr);
  1082. if (g_ulLastNumberToken >= NUM_ENUMERATOR_SLOTS)
  1083. {
  1084. hr = E_INVALIDARG;
  1085. g_Log.Write(
  1086. LOG_ERROR,
  1087. "got %u for enumerator slot, but value must be in 0..%u",
  1088. g_ulLastNumberToken,
  1089. NUM_ENUMERATOR_SLOTS - 1);
  1090. break;
  1091. }
  1092. *pidxSlot = g_ulLastNumberToken;
  1093. }
  1094. while (0);
  1095. return hr;
  1096. }
  1097. //+---------------------------------------------------------------------------
  1098. //
  1099. // Function: GetAndPrepareEnumeratorSlot
  1100. //
  1101. // Synopsis: Get an enumerator slot number from the command line, and
  1102. // release any existing enumerator at that slot.
  1103. //
  1104. // Arguments: [ppwsz] - command line
  1105. // [pidxSlot] - filled with slot number 0..NUM_ENUMERATOR_SLOTS-1
  1106. //
  1107. // Returns: S_OK - *[pidxSlot] is valid
  1108. // E_INVALIDARG - command line specified bad slot number
  1109. //
  1110. // Modifies: *pidxSlot, g_apEnumJob[*pidxSlot]
  1111. //
  1112. // History: 01-30-96 DavidMun Created
  1113. //
  1114. //----------------------------------------------------------------------------
  1115. HRESULT GetAndPrepareEnumeratorSlot(WCHAR **ppwsz, ULONG *pidxSlot)
  1116. {
  1117. HRESULT hr = S_OK;
  1118. do
  1119. {
  1120. hr = GetEnumeratorSlot(ppwsz, pidxSlot);
  1121. BREAK_ON_FAILURE(hr);
  1122. //
  1123. // If there's an existing enumerator, get rid of it.
  1124. //
  1125. if (g_apEnumJobs[*pidxSlot])
  1126. {
  1127. g_Log.Write(
  1128. LOG_TRACE,
  1129. "Releasing existing enumerator in slot %u",
  1130. *pidxSlot);
  1131. g_apEnumJobs[*pidxSlot]->Release();
  1132. g_apEnumJobs[*pidxSlot] = NULL;
  1133. }
  1134. }
  1135. while (0);
  1136. return hr;
  1137. }
  1138. //+---------------------------------------------------------------------------
  1139. //
  1140. // Function: VerifySlotFilled
  1141. //
  1142. // Synopsis: Return S_OK if g_apEnumJob[idxSlot] contains a non-NULL
  1143. // pointer, E_INVALIDARG otherwise.
  1144. //
  1145. // History: 01-30-96 DavidMun Created
  1146. //
  1147. //----------------------------------------------------------------------------
  1148. HRESULT VerifySlotFilled(ULONG idxSlot)
  1149. {
  1150. if (!g_apEnumJobs[idxSlot])
  1151. {
  1152. g_Log.Write(
  1153. LOG_ERROR,
  1154. "Slot %u does not contain an enumerator",
  1155. idxSlot);
  1156. return E_INVALIDARG;
  1157. }
  1158. return S_OK;
  1159. }
  1160. //+---------------------------------------------------------------------------
  1161. //
  1162. // Function: AddSeconds
  1163. //
  1164. // Synopsis: Add [ulSeconds] to [pst].
  1165. //
  1166. // Arguments: [pst] - valid systemtime
  1167. // [ulSeconds] - seconds to add
  1168. //
  1169. // Modifies: *[pst]
  1170. //
  1171. // History: 04-11-96 DavidMun Created
  1172. //
  1173. //----------------------------------------------------------------------------
  1174. VOID AddSeconds(SYSTEMTIME *pst, ULONG ulSeconds)
  1175. {
  1176. FILETIME ft;
  1177. LONGLONG llTime;
  1178. LONGLONG llIncrement;
  1179. //
  1180. // Convert caller's SYSTEMTIME to a FILETIME, which is easy to do math on.
  1181. //
  1182. SystemTimeToFileTime(pst, &ft);
  1183. //
  1184. // Convert the ulSeconds increment from seconds to 100 ns intervals, which
  1185. // is the unit used in the FILETIME struct.
  1186. //
  1187. llIncrement = ulSeconds;
  1188. llIncrement *= 10000000UL;
  1189. //
  1190. // Convert the FILETIME equivalent of pst into a LONGLONG, then add the
  1191. // increment.
  1192. //
  1193. llTime = ft.dwHighDateTime;
  1194. llTime <<= 32;
  1195. llTime |= ft.dwLowDateTime;
  1196. llTime += llIncrement;
  1197. //
  1198. // Convert the incremented LONGLONG back to a filetime, then convert that
  1199. // back to a SYSTEMTIME
  1200. //
  1201. ft.dwLowDateTime = (DWORD) llTime;
  1202. ft.dwHighDateTime = (DWORD) (llTime >> 32);
  1203. FileTimeToSystemTime(&ft, pst);
  1204. }