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.

644 lines
17 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Job Scheduler service
  4. //
  5. // Microsoft Windows
  6. // Copyright (C) Microsoft Corporation, 1992 - 1996.
  7. //
  8. // File: sch_util.cxx
  9. //
  10. // Contents: scheduler object IUnknown methods, class factory,
  11. // plus misc private class methods
  12. //
  13. // Classes: CSchedule, CScheduleCF
  14. //
  15. // Interfaces: IUnknown, IClassFactory
  16. //
  17. // History: 09-Sep-95 EricB created
  18. //
  19. //-----------------------------------------------------------------------------
  20. #include "..\pch\headers.hxx"
  21. #pragma hdrstop
  22. #include "Sched.hxx"
  23. //+----------------------------------------------------------------------------
  24. //
  25. // Member: CSchedule::ActivateJob, private
  26. //
  27. // Synopsis: Given a valid name, returns a pointer to the activated job
  28. // object
  29. //
  30. // Arguments: [pwszName] - the folder-relative name of the job to activate
  31. // [ppJob] - a pointer to the job class object; on entry,
  32. // must either be NULL or point to a CJob object.
  33. // [fAllData] - load all job data from disk.
  34. //
  35. // Returns: hresults
  36. //
  37. //-----------------------------------------------------------------------------
  38. HRESULT
  39. CSchedule::ActivateJob(LPCTSTR ptszName, CJob ** ppJob, BOOL fAllData)
  40. {
  41. TCHAR tszFullName[MAX_PATH + MAX_PATH];
  42. lstrcpy(tszFullName, g_TasksFolderInfo.ptszPath);
  43. lstrcat(tszFullName, TEXT("\\"));
  44. lstrcat(tszFullName, ptszName);
  45. //
  46. // If *ppJob is NULL, allocate a new job object.
  47. //
  48. if (*ppJob == NULL)
  49. {
  50. //
  51. // CJob is a single-use, in-proc handler, so no need to get OLE in the
  52. // loop here. Use new (called by CJob::Create) instead of CoCreateInstance.
  53. //
  54. *ppJob = CJob::Create();
  55. if (*ppJob == NULL)
  56. {
  57. return E_OUTOFMEMORY;
  58. }
  59. }
  60. HRESULT hr = (*ppJob)->LoadP(tszFullName, 0, TRUE, fAllData);
  61. if (FAILED(hr))
  62. {
  63. schDebugOut((DEB_ERROR, "CSchedule::ActivateJob: pJob->Load failed"
  64. " with error 0x%x\n", hr));
  65. }
  66. return hr;
  67. }
  68. //+----------------------------------------------------------------------------
  69. //
  70. // Member: CSchedule::CheckJobName
  71. //
  72. // Synopsis: Checks for a valid job object file name and returns the full
  73. // path name. Takes an UNICODE input name and returns a TCHAR.
  74. //
  75. // Arguments: [pwszJobName] - the job name as specified by the client
  76. // [pptszFullPathName] - the name including the job folder path
  77. //
  78. // Returns: HRESULTS
  79. //
  80. // Notes: The job name can be an absolute or UNC path. If not,it is
  81. // assumed to be relative to the job schedule folder.
  82. // If there is an extension on the last element (the actual file
  83. // name), then it must be .job. If there is no extension, then
  84. // the the correct one will be added.
  85. //-----------------------------------------------------------------------------
  86. HRESULT
  87. CSchedule::CheckJobName(LPCWSTR pwszJobName, LPTSTR * pptszFullPathName)
  88. {
  89. //
  90. // Make sure that the string doesn't end in a slash character.
  91. //
  92. ULONG cchJobName = wcslen(pwszJobName);
  93. ULONG cchNameParam = cchJobName;
  94. if (!cchNameParam)
  95. {
  96. schDebugOut((DEB_ERROR,
  97. "CSchedule::CheckJobName: pwszJobName is a 0 length string\n"));
  98. return E_INVALIDARG;
  99. }
  100. if (cchNameParam > 1 &&
  101. (pwszJobName[cchNameParam - 1] == L'\\' ||
  102. pwszJobName[cchNameParam - 1] == L'/'))
  103. {
  104. schDebugOut((DEB_ERROR,
  105. "CSchedule::CheckJobName: pwszJobName ends in illegal char %c\n",
  106. pwszJobName[cchNameParam - 1]));
  107. return E_INVALIDARG;
  108. }
  109. BOOL fNeedsPath = TRUE;
  110. //
  111. // Is it a full or relative path?
  112. //
  113. if ((cchNameParam > 2 &&
  114. (pwszJobName[1] == TEXT(':') ||
  115. ((pwszJobName[0] == TEXT('\\') || pwszJobName[0] == TEXT('/')) &&
  116. (pwszJobName[1] == TEXT('\\') || pwszJobName[1] == TEXT('/'))))))
  117. {
  118. fNeedsPath = FALSE;
  119. }
  120. //
  121. // Check extension
  122. //
  123. #if defined(UNICODE)
  124. WCHAR * pwszJobExt = TSZ_JOB;
  125. #else
  126. WCHAR * pwszJobExt = WSZ_JOB;
  127. #endif // defined(UNICODE)
  128. ULONG cJobExt = ARRAY_LEN(TSZ_JOB); // add one for the period
  129. BOOL fNeedExt = FALSE;
  130. const WCHAR * pwszLastDot = wcsrchr(pwszJobName, L'.');
  131. if (pwszLastDot != NULL)
  132. {
  133. // check if the period is within cJobExt chars of the end
  134. //
  135. if ((size_t)(cchNameParam - (pwszLastDot - pwszJobName)) <= (size_t)cJobExt)
  136. {
  137. if (_wcsicmp(pwszLastDot + 1, pwszJobExt) != 0)
  138. {
  139. // Its extension does not match TSZ_JOB, so it is invalid.
  140. //
  141. schDebugOut((DEB_ERROR,
  142. "CSchedule::CheckJobName: expected '%S', got '%S'",
  143. pwszJobExt,
  144. pwszLastDot + 1));
  145. return E_INVALIDARG;
  146. }
  147. }
  148. else // append the extension.
  149. {
  150. fNeedExt = TRUE;
  151. cchNameParam += cJobExt; // add the length of the extension
  152. }
  153. }
  154. else // append the extension.
  155. {
  156. fNeedExt = TRUE;
  157. cchNameParam += cJobExt; // add the length of the extension
  158. }
  159. //
  160. // Allocate the string to return the result.
  161. //
  162. if (fNeedsPath)
  163. {
  164. // add one for the '\'
  165. cchNameParam += lstrlen(m_ptszFolderPath) + 1;
  166. }
  167. //
  168. // If we're about to convert to multibyte, make sure that we allocate
  169. // enough to hold the job name, even if all of its chars become double
  170. // byte. Note that everything else that's been added to cchNameParam has
  171. // been computed from TCHAR strings.
  172. //
  173. #if !defined(UNICODE)
  174. cchNameParam += cchJobName;
  175. #endif
  176. // add 1 to the array length for the null
  177. TCHAR * ptszPath = new TCHAR[cchNameParam + 1];
  178. if (ptszPath == NULL)
  179. {
  180. return E_OUTOFMEMORY;
  181. }
  182. if (fNeedsPath)
  183. {
  184. lstrcpy(ptszPath, m_ptszFolderPath);
  185. lstrcat(ptszPath, TEXT("\\"));
  186. #if defined(UNICODE)
  187. lstrcat(ptszPath, pwszJobName);
  188. #else
  189. HRESULT hr = UnicodeToAnsi(ptszPath + lstrlen(ptszPath),
  190. pwszJobName,
  191. 2 * cchJobName + 1);
  192. if (FAILED(hr))
  193. {
  194. delete [] ptszPath;
  195. CHECK_HRESULT(hr);
  196. return hr;
  197. }
  198. #endif // defined(UNICODE)
  199. }
  200. else
  201. {
  202. #if defined(UNICODE)
  203. lstrcpy(ptszPath, pwszJobName);
  204. #else
  205. HRESULT hr = UnicodeToAnsi(ptszPath,
  206. pwszJobName,
  207. 2 * cchJobName + 1);
  208. if (FAILED(hr))
  209. {
  210. delete [] ptszPath;
  211. CHECK_HRESULT(hr);
  212. return hr;
  213. }
  214. #endif // defined(UNICODE)
  215. }
  216. if (fNeedExt)
  217. {
  218. lstrcat(ptszPath, TEXT(".") TSZ_JOB);
  219. }
  220. *pptszFullPathName = ptszPath;
  221. return S_OK;
  222. }
  223. //+----------------------------------------------------------------------------
  224. //
  225. // Member: CSchedule::CSchedule
  226. //
  227. // Synopsis: constructor
  228. //
  229. //-----------------------------------------------------------------------------
  230. CSchedule::CSchedule(void) :
  231. m_ptszTargetMachine(NULL),
  232. m_ptszFolderPath(NULL),
  233. m_dwNextID(1),
  234. m_uRefs(1)
  235. {
  236. InitializeCriticalSection(&m_CriticalSection);
  237. }
  238. //+----------------------------------------------------------------------------
  239. //
  240. // Member: CSchedule::~CSchedule
  241. //
  242. // Synopsis: destructor
  243. //
  244. //-----------------------------------------------------------------------------
  245. CSchedule::~CSchedule(void)
  246. {
  247. DeleteCriticalSection(&m_CriticalSection);
  248. if (m_ptszTargetMachine)
  249. {
  250. delete m_ptszTargetMachine;
  251. }
  252. if (m_ptszFolderPath)
  253. {
  254. delete m_ptszFolderPath;
  255. }
  256. }
  257. //+----------------------------------------------------------------------------
  258. //
  259. // Member: CSchedule::Init
  260. //
  261. // Synopsis: Two phase construction - can't do operations that could fail
  262. // in the ctor since there is no way to return errors without
  263. // throwing exceptions.
  264. //
  265. //-----------------------------------------------------------------------------
  266. HRESULT
  267. CSchedule::Init(void)
  268. {
  269. if (g_TasksFolderInfo.ptszPath == NULL)
  270. {
  271. ERR_OUT("CSchedule::Init, folder path not set", E_FAIL);
  272. return E_FAIL;
  273. }
  274. HRESULT hr;
  275. //
  276. // Get the jobs folder location. These values will be replaced when a
  277. // call is made to SetTargetMachine
  278. //
  279. m_ptszFolderPath = new TCHAR[lstrlen(g_TasksFolderInfo.ptszPath) + 1];
  280. if (!m_ptszFolderPath)
  281. {
  282. ERR_OUT("CSchedule::Init", E_OUTOFMEMORY);
  283. return E_OUTOFMEMORY;
  284. }
  285. lstrcpy(m_ptszFolderPath, g_TasksFolderInfo.ptszPath);
  286. return S_OK;
  287. }
  288. #if !defined(_CHICAGO_) // don't need AT support on chicago
  289. //+----------------------------------------------------------------------------
  290. //
  291. // Function: GetNextAtID
  292. //
  293. // Synopsis: Examine the AT jobs to find the highest ID.
  294. //
  295. //-----------------------------------------------------------------------------
  296. void
  297. GetNextAtID(LPDWORD pdwAtID)
  298. {
  299. WCHAR wszAtJobSearchPath[MAX_PATH];
  300. wcscpy(wszAtJobSearchPath, g_TasksFolderInfo.ptszPath);
  301. wcscat(wszAtJobSearchPath, L"\\" TSZ_AT_JOB_PREFIX L"*." TSZ_JOB);
  302. DWORD cchNamePrefixLen = ARRAY_LEN(TSZ_AT_JOB_PREFIX) - 1;
  303. WIN32_FIND_DATA fd;
  304. HANDLE hFileFind = FindFirstFile(wszAtJobSearchPath, &fd);
  305. if (hFileFind == INVALID_HANDLE_VALUE)
  306. {
  307. //
  308. // If no at jobs, set the initial job ID to be 1, since zero is
  309. // reserved for an error flag.
  310. //
  311. *pdwAtID = 1;
  312. return;
  313. }
  314. DWORD dwMaxID = 1;
  315. do
  316. {
  317. WCHAR * pDot = wcschr(fd.cFileName, L'.');
  318. if (pDot == NULL)
  319. {
  320. continue;
  321. }
  322. *pDot = L'\0';
  323. DWORD dwCurID = (DWORD)_wtol(fd.cFileName + cchNamePrefixLen);
  324. schDebugOut((DEB_ITRACE, "GetNextAtID: found %S, with ID %d\n",
  325. fd.cFileName, dwCurID));
  326. if (dwCurID > dwMaxID)
  327. {
  328. dwMaxID = dwCurID;
  329. }
  330. } while (FindNextFile(hFileFind, &fd));
  331. FindClose(hFileFind);
  332. //
  333. // The next available AT ID will be one greater than the current max.
  334. //
  335. *pdwAtID = dwMaxID + 1;
  336. return;
  337. }
  338. #endif // !defined(_CHICAGO_)
  339. //+----------------------------------------------------------------------------
  340. //
  341. // CSchedule IUnknown methods
  342. //
  343. //-----------------------------------------------------------------------------
  344. //+----------------------------------------------------------------------------
  345. //
  346. // Member: CSchedule::IUnknown::QueryInterface
  347. //
  348. // Synopsis: Returns requested interface pointer
  349. //
  350. //-----------------------------------------------------------------------------
  351. STDMETHODIMP
  352. CSchedule::QueryInterface(REFIID riid, void ** ppvObject)
  353. {
  354. //schDebugOut((DEB_ITRACE, "CSchedule::QueryInterface"));
  355. if (IID_IUnknown == riid)
  356. {
  357. *ppvObject = (IUnknown *)this;
  358. }
  359. else if (IID_ITaskScheduler == riid)
  360. {
  361. *ppvObject = (IUnknown *)(ITaskScheduler *)this;
  362. }
  363. //else if (IID_IDispatch == riid)
  364. //{
  365. // *ppvObject = (IUnknown *)(IDispatch *)this;
  366. //}
  367. else
  368. {
  369. #if DBG == 1
  370. //TCHAR * pwsz;
  371. //StringFromIID(riid, &pwsz);
  372. //schDebugOut((DEB_NOPREFIX, "%S, refused\n", pwsz));
  373. //CoTaskMemFree(pwsz);
  374. #endif
  375. *ppvObject = NULL;
  376. return E_NOINTERFACE;
  377. }
  378. AddRef();
  379. return S_OK;
  380. }
  381. //+----------------------------------------------------------------------------
  382. //
  383. // Member: CSchedule::IUnknown::AddRef
  384. //
  385. // Synopsis: increments reference count
  386. //
  387. // Returns: the reference count
  388. //
  389. //-----------------------------------------------------------------------------
  390. STDMETHODIMP_(ULONG)
  391. CSchedule::AddRef(void)
  392. {
  393. //schDebugOut((DEB_ITRACE, "CSchedule::AddRef refcount going in %d\n", m_uRefs));
  394. return InterlockedIncrement((long *)&m_uRefs);
  395. }
  396. //+----------------------------------------------------------------------------
  397. //
  398. // Member: CSchedule::IUnknown::Release
  399. //
  400. // Synopsis: Decrements the object's reference count and frees it when
  401. // no longer referenced.
  402. //
  403. // Returns: zero if the reference count is zero or non-zero otherwise
  404. //
  405. //-----------------------------------------------------------------------------
  406. STDMETHODIMP_(ULONG)
  407. CSchedule::Release(void)
  408. {
  409. //schDebugOut((DEB_ITRACE, "CSchedule::Release ref count going in %d\n", m_uRefs));
  410. unsigned long uTmp;
  411. if ((uTmp = InterlockedDecrement((long *)&m_uRefs)) == 0)
  412. {
  413. delete this;
  414. }
  415. return uTmp;
  416. }
  417. //+----------------------------------------------------------------------------
  418. //
  419. // CScheduleCF - class factory for the Schedule Service object
  420. //
  421. //-----------------------------------------------------------------------------
  422. //+----------------------------------------------------------------------------
  423. //
  424. // Member: CScheduleCF::Create
  425. //
  426. // Synopsis: creates a new class factory object
  427. //
  428. //-----------------------------------------------------------------------------
  429. IClassFactory *
  430. CScheduleCF::Create(void)
  431. {
  432. return new CScheduleCF;
  433. }
  434. //+----------------------------------------------------------------------------
  435. //
  436. // Member: CScheduleCF::CScheduleCF
  437. //
  438. // Synopsis: ctor
  439. //
  440. //-----------------------------------------------------------------------------
  441. CScheduleCF::CScheduleCF(void)
  442. {
  443. m_uRefs = 1;
  444. }
  445. //+----------------------------------------------------------------------------
  446. //
  447. // Member: CScheduleCF::~CScheduleCF
  448. //
  449. // Synopsis: dtor
  450. //
  451. //-----------------------------------------------------------------------------
  452. CScheduleCF::~CScheduleCF(void)
  453. {
  454. ;
  455. }
  456. //+----------------------------------------------------------------------------
  457. //
  458. // Member: CScheduleCF::IUnknown::QueryInterface
  459. //
  460. // Synopsis: Returns requested interface pointer
  461. //
  462. //-----------------------------------------------------------------------------
  463. STDMETHODIMP
  464. CScheduleCF::QueryInterface(REFIID riid, void ** ppvObject)
  465. {
  466. //schDebugOut((DEB_ITRACE, "CScheduleCF::QueryInterface"));
  467. if (IID_IUnknown == riid)
  468. {
  469. *ppvObject = (IUnknown *)this;
  470. }
  471. else if (IsEqualIID(IID_IClassFactory, riid))
  472. {
  473. *ppvObject = (IClassFactory *)this;
  474. }
  475. else
  476. {
  477. #if DBG == 1
  478. //TCHAR * pwsz;
  479. //StringFromIID(riid, &pwsz);
  480. //schDebugOut((DEB_NOPREFIX, "%S, refused\n", pwsz));
  481. //CoTaskMemFree(pwsz);
  482. #endif
  483. *ppvObject = NULL;
  484. return E_NOINTERFACE;
  485. }
  486. AddRef();
  487. return S_OK;
  488. }
  489. //+----------------------------------------------------------------------------
  490. //
  491. // Member: CScheduleCF::IUnknown::AddRef
  492. //
  493. // Synopsis: increments reference count
  494. //
  495. // Returns: the new reference count
  496. //
  497. //-----------------------------------------------------------------------------
  498. STDMETHODIMP_(ULONG)
  499. CScheduleCF::AddRef(void)
  500. {
  501. return InterlockedIncrement((long *)&m_uRefs);
  502. }
  503. //+----------------------------------------------------------------------------
  504. //
  505. // Member: CScheduleCF::IUnknown::Release
  506. //
  507. // Synopsis: noop, since this is a static object
  508. //
  509. // Returns: the new reference count
  510. //
  511. //-----------------------------------------------------------------------------
  512. STDMETHODIMP_(ULONG)
  513. CScheduleCF::Release(void)
  514. {
  515. unsigned long uTmp;
  516. if ((uTmp = InterlockedDecrement((long *)&m_uRefs)) == 0)
  517. {
  518. delete this;
  519. }
  520. return uTmp;
  521. }
  522. //+----------------------------------------------------------------------------
  523. //
  524. // Member: CScheduleCF::IClassFactory::CreateInstance
  525. //
  526. // Synopsis: create an incore instance of the job class object
  527. //
  528. // Arguments: [pUnkOuter] - aggregator
  529. // [riid] - requested interface
  530. // [ppvObject] - receptor for itf ptr
  531. //
  532. // Returns: HRESULTS
  533. //
  534. //-----------------------------------------------------------------------------
  535. STDMETHODIMP
  536. CScheduleCF::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject)
  537. {
  538. //schDebugOut((DEB_ITRACE, "CScheduleCF::CreateInstance\n"));
  539. HRESULT hr = S_OK;
  540. *ppvObject = NULL;
  541. CSchedule * pSched = new CSchedule;
  542. if (pSched == NULL)
  543. {
  544. return E_OUTOFMEMORY;
  545. }
  546. hr = pSched->Init();
  547. if (FAILED(hr))
  548. {
  549. ERR_OUT("CScheduleCF::CreateInstance, pSched->Init", hr);
  550. pSched->Release();
  551. return hr;
  552. }
  553. hr = pSched->QueryInterface(riid, ppvObject);
  554. if (FAILED(hr))
  555. {
  556. ERR_OUT("CScheduleCF::CreateInstance, pSched->QueryInterface", hr);
  557. pSched->Release();
  558. return hr;
  559. }
  560. //
  561. // We got a refcount of one when launched, and the above QI increments it
  562. // to 2, so call release to take it back to 1.
  563. //
  564. pSched->Release();
  565. return hr;
  566. }
  567. //+----------------------------------------------------------------------------
  568. //
  569. // Member: CScheduleCF::IClassFactory::LockServer
  570. //
  571. // Synopsis: Called with fLock set to TRUE to indicate that the server
  572. // should continue to run even if none of its objects are active
  573. //
  574. // Arguments: [fLock] - increment/decrement the instance count
  575. //
  576. // Returns: HRESULTS
  577. //
  578. // Notes: This is a no-op since the handler runs in-proc.
  579. //
  580. //-----------------------------------------------------------------------------
  581. STDMETHODIMP
  582. CScheduleCF::LockServer(BOOL fLock)
  583. {
  584. return S_OK;
  585. }