Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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