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.

714 lines
19 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Job Scheduler Service
  4. //
  5. // Microsoft Windows
  6. // Copyright (C) Microsoft Corporation, 1992 - 1996.
  7. //
  8. // File: job_enum.cxx
  9. //
  10. // Contents: job object enumerator implementation
  11. //
  12. // Classes: CEnumJobs
  13. //
  14. // Interfaces: IEnumWorkItems
  15. //
  16. // History: 13-Sep-95 EricB created
  17. //
  18. //-----------------------------------------------------------------------------
  19. #include "..\pch\headers.hxx"
  20. #pragma hdrstop
  21. #include "Sched.hxx"
  22. void FreeStrings(LPWSTR * rgpwszNames, int n);
  23. //+----------------------------------------------------------------------------
  24. //
  25. // Member: CEnumJobs::IEnumWorkItems::Next, public
  26. //
  27. // Synopsis: Returns the indicated number of job object monikers
  28. //
  29. // Arguments: [cJobs] - the number of jobs to return
  30. // [rgpwszNames] - the array of returned job names
  31. // [pcJobsFetched] - the actual number of jobs returned; can be
  32. // less than or equal to cJobs. Can be NULL if
  33. // cJobs is equal to one.
  34. //
  35. // Returns: S_OK - returned requested number of job names
  36. // S_FALSE - returned less than requested number of names because
  37. // the end of the enumeration sequence was reached.
  38. // E_INVALIDARG or E_OUTOFMEMORY - s.b. obvious
  39. //
  40. // Notes: Each LPWSTR in the array must be caller freed using
  41. // CoTaskMemFree and then the array itself must be freed
  42. // CoTaskMemFree.
  43. //
  44. //-----------------------------------------------------------------------------
  45. STDMETHODIMP
  46. CEnumJobs::Next(ULONG cJobs, LPWSTR ** rgpwszNames, ULONG * pcJobsFetched)
  47. {
  48. HRESULT hr = S_OK;
  49. if (cJobs == 0)
  50. {
  51. return E_INVALIDARG;
  52. }
  53. if (cJobs > 1 && pcJobsFetched == NULL)
  54. {
  55. // as required by IEnumX spec.
  56. //
  57. return E_INVALIDARG;
  58. }
  59. if (!rgpwszNames)
  60. {
  61. return E_INVALIDARG;
  62. }
  63. *rgpwszNames = NULL;
  64. if (m_fFindOverrun)
  65. {
  66. if (pcJobsFetched != NULL)
  67. {
  68. *pcJobsFetched = 0;
  69. }
  70. return S_FALSE;
  71. }
  72. TCHAR * ptszName;
  73. WCHAR * pwszName;
  74. //
  75. // find the first requested
  76. //
  77. hr = GetNext(&ptszName);
  78. if (hr != S_OK)
  79. {
  80. if (pcJobsFetched != NULL)
  81. {
  82. *pcJobsFetched = 0;
  83. }
  84. *rgpwszNames = NULL;
  85. return hr;
  86. }
  87. //
  88. // allocate the first job object name string and the pointer to it
  89. //
  90. *rgpwszNames = (LPWSTR *)CoTaskMemAlloc(sizeof(LPWSTR *));
  91. if (*rgpwszNames == NULL)
  92. {
  93. if (pcJobsFetched != NULL)
  94. {
  95. *pcJobsFetched = 0;
  96. }
  97. return E_OUTOFMEMORY;
  98. }
  99. pwszName = ptszName;
  100. size_t cch = wcslen(pwszName) + 1;
  101. **rgpwszNames = (LPWSTR)CoTaskMemAlloc(cch * sizeof(WCHAR));
  102. if (**rgpwszNames == NULL)
  103. {
  104. if (pcJobsFetched != NULL)
  105. {
  106. *pcJobsFetched = 0;
  107. }
  108. CoTaskMemFree(*rgpwszNames);
  109. *rgpwszNames = NULL;
  110. return E_OUTOFMEMORY;
  111. }
  112. StringCchCopy(**rgpwszNames, cch, pwszName);
  113. delete ptszName;
  114. if (cJobs == 1)
  115. {
  116. if (pcJobsFetched != NULL)
  117. {
  118. *pcJobsFetched = 1;
  119. }
  120. return S_OK;
  121. }
  122. //
  123. // Note a check at entry guarantees that at this point pcJobsFetched !=
  124. // NULL.
  125. //
  126. ULONG i = 1;
  127. //
  128. // find the rest requested
  129. //
  130. while (++i <= cJobs)
  131. {
  132. hr = GetNext(&ptszName);
  133. if (hr != S_OK)
  134. {
  135. //
  136. // Either hr == S_FALSE and we've completed successfully because
  137. // there are no more jobs to enumerate, or else hr is a
  138. // failure code and we must bail.
  139. //
  140. break;
  141. }
  142. LPWSTR * rgpwszTmp = *rgpwszNames;
  143. *rgpwszNames = (LPWSTR *)CoTaskMemAlloc(sizeof(LPWSTR *) * i);
  144. if (*rgpwszNames == NULL)
  145. {
  146. *rgpwszNames = rgpwszTmp; // so cleanup will free strings
  147. hr = E_OUTOFMEMORY;
  148. break;
  149. }
  150. memcpy(*rgpwszNames, rgpwszTmp, sizeof(LPWSTR *) * (i - 1));
  151. CoTaskMemFree(rgpwszTmp);
  152. pwszName = ptszName;
  153. cch = wcslen(pwszName) + 1;
  154. (*rgpwszNames)[i - 1] = (LPWSTR)CoTaskMemAlloc(cch * sizeof(WCHAR));
  155. if ((*rgpwszNames)[i - 1] == NULL)
  156. {
  157. hr = E_OUTOFMEMORY;
  158. break;
  159. }
  160. StringCchCopy((*rgpwszNames)[i - 1], cch, pwszName);
  161. delete ptszName;
  162. ptszName = NULL;
  163. }
  164. if (FAILED(hr))
  165. {
  166. FreeStrings(*rgpwszNames, i - 1);
  167. delete ptszName;
  168. *pcJobsFetched = 0;
  169. *rgpwszNames = NULL;
  170. }
  171. else
  172. {
  173. *pcJobsFetched = --i;
  174. }
  175. return hr;
  176. }
  177. //+----------------------------------------------------------------------------
  178. //
  179. // Member: CEnumJobs::GetNext, private
  180. //
  181. // Synopsis: enumeration helper
  182. //
  183. // Arguments: [pptszName] - the job/queue name, relative to the jobs folder
  184. //
  185. // Returns: S_OK - found next file
  186. // S_FALSE - the end of the enumeration sequence was reached.
  187. // other code - file system or memory error
  188. //
  189. //-----------------------------------------------------------------------------
  190. HRESULT
  191. CEnumJobs::GetNext(LPTSTR * pptszName)
  192. {
  193. HRESULT hr = S_OK;
  194. DWORD dwRet = NO_ERROR;
  195. WIN32_FIND_DATA FindData;
  196. //
  197. // loop until either a matching file is found or the search is done
  198. //
  199. do
  200. {
  201. //
  202. // if the find handle is invalid, then we need to start a find in the
  203. // next directory (which may in fact be the first directory)
  204. //
  205. if (m_hFind == INVALID_HANDLE_VALUE)
  206. {
  207. //
  208. // Note that, unless ENUM_SUBDIRS is defined, PopDir returns the
  209. // string "." the first time it is called and returns S_FALSE the
  210. // second time to stop the enumeration.
  211. //
  212. hr = PopDir(m_tszCurDir, MAX_PATH + 1);
  213. if (hr == S_FALSE)
  214. {
  215. // we're done
  216. //
  217. m_fFindOverrun = TRUE;
  218. return S_FALSE;
  219. }
  220. TCHAR tszFullDirPath[MAX_PATH + 1];
  221. StringCchCopy(tszFullDirPath, MAX_PATH + 1, m_ptszFolderPath);
  222. StringCchCat(tszFullDirPath, MAX_PATH + 1, TEXT("\\*"));
  223. m_hFind = FindFirstFile(tszFullDirPath, &FindData);
  224. if (m_hFind == INVALID_HANDLE_VALUE)
  225. {
  226. dwRet = GetLastError();
  227. if (dwRet == ERROR_FILE_NOT_FOUND)
  228. { // no files in the current dir, check the next dir.
  229. continue;
  230. }
  231. else
  232. {
  233. return HRESULT_FROM_WIN32(dwRet);
  234. }
  235. }
  236. hr = CheckFound(&FindData);
  237. if (hr == S_OK)
  238. { // match found
  239. break;
  240. }
  241. if (hr != S_FALSE)
  242. { // an error condition
  243. return hr;
  244. }
  245. }
  246. //
  247. // Continue looking at files in the current dir until a job/queue has
  248. // been found or the dir has been scanned. If the former, break out of
  249. // both loops. If the latter, break out of the inner loop and then
  250. // restart the search on the next dir.
  251. //
  252. do
  253. {
  254. if (!FindNextFile(m_hFind, &FindData))
  255. {
  256. dwRet = GetLastError();
  257. if (dwRet == ERROR_NO_MORE_FILES)
  258. {
  259. FindClose(m_hFind);
  260. m_hFind = INVALID_HANDLE_VALUE;
  261. hr = S_FALSE;
  262. break;
  263. }
  264. else
  265. {
  266. return HRESULT_FROM_WIN32(dwRet);
  267. }
  268. }
  269. hr = CheckFound(&FindData);
  270. if (hr == S_OK)
  271. { // match found
  272. break;
  273. }
  274. if (hr != S_FALSE)
  275. { // an error condition
  276. return hr;
  277. }
  278. } while (hr != S_OK);
  279. } while (hr != S_OK);
  280. if (pptszName != NULL && dwRet == NO_ERROR)
  281. {
  282. int cch = lstrlen(FindData.cFileName);
  283. *pptszName = new TCHAR[cch + 1];
  284. if (*pptszName == NULL)
  285. {
  286. return E_OUTOFMEMORY;
  287. }
  288. StringCchCopy(*pptszName, cch + 1, FindData.cFileName);
  289. }
  290. m_cFound++;
  291. return S_OK;
  292. }
  293. //+----------------------------------------------------------------------------
  294. //
  295. // Member: CEnumJobs::CheckFound, private
  296. //
  297. // Synopsis: Checks if the found file is a job or queue. If it is a
  298. // directory, push it onto the dir stack.
  299. //
  300. // Returns: S_OK if a job or queue, S_FALSE if not.
  301. //
  302. // Notes: The file find functions match on both long and short versions
  303. // of file names, so all names of the form *.job* will match
  304. // (a file like foo.jobber will have a short name of foo~1.job).
  305. // Thus, the returned file names must be checked for an exact
  306. // extension match.
  307. //-----------------------------------------------------------------------------
  308. HRESULT
  309. CEnumJobs::CheckFound(LPWIN32_FIND_DATA pFindData)
  310. {
  311. HRESULT hr;
  312. TCHAR * ptszExt = _tcsrchr(pFindData->cFileName, TEXT('.'));
  313. if (ptszExt)
  314. {
  315. if (lstrcmpi(ptszExt, m_tszJobExt) == 0)
  316. // || lstrcmpi(ptszExt, m_tszQueExt) == 0
  317. {
  318. return S_OK;
  319. }
  320. }
  321. return S_FALSE;
  322. }
  323. //+----------------------------------------------------------------------------
  324. //
  325. // Member: CEnumJobs::IEnumWorkItems::Skip, public
  326. //
  327. // Synopsis: Skips the indicated number of jobs in the enumeration
  328. //
  329. // Arguments: [cJobs] - the number of jobs to skip
  330. //
  331. // Returns: S_OK - skipped requested number of job names
  332. // S_FALSE - skipped less than requested number of names because
  333. // the end of the enumeration sequence was reached.
  334. // E_INVALIDARG - if cJobs == 0
  335. //
  336. //-----------------------------------------------------------------------------
  337. STDMETHODIMP
  338. CEnumJobs::Skip(ULONG cJobs)
  339. {
  340. if (cJobs == 0)
  341. {
  342. return E_INVALIDARG;
  343. }
  344. if (m_fFindOverrun)
  345. {
  346. return S_FALSE;
  347. }
  348. HRESULT hr = S_OK;
  349. //
  350. // skip the requested number
  351. //
  352. for (ULONG i = 1; i <= cJobs; i++)
  353. {
  354. hr = GetNext(NULL);
  355. if (hr != S_OK)
  356. {
  357. return hr;
  358. }
  359. }
  360. return S_OK;
  361. }
  362. //+----------------------------------------------------------------------------
  363. //
  364. // Member: CEnumJobs::IEnumWorkItems::Reset, public
  365. //
  366. // Synopsis: Sets the enumerator back to its original state
  367. //
  368. // Returns: hresults
  369. //
  370. //-----------------------------------------------------------------------------
  371. STDMETHODIMP
  372. CEnumJobs::Reset(void)
  373. {
  374. if (m_hFind != INVALID_HANDLE_VALUE)
  375. {
  376. FindClose(m_hFind);
  377. m_hFind = INVALID_HANDLE_VALUE;
  378. }
  379. m_fFindOverrun = FALSE;
  380. m_cFound = 0;
  381. ClearDirStack();
  382. m_pdsHead = new DIRSTACK;
  383. if (m_pdsHead == NULL)
  384. {
  385. return E_OUTOFMEMORY;
  386. }
  387. StringCchCopy(m_pdsHead->tszDir, MAX_PATH + 1, TEXT("."));
  388. return S_OK;
  389. }
  390. //+----------------------------------------------------------------------------
  391. //
  392. // Member: CEnumJobs::IEnumWorkItems::Clone, public
  393. //
  394. // Synopsis: Creates a copy of the enumerator object with the same state
  395. //
  396. // Arguments: [ppEnumJobs] - a place to return a pointer to the enum object
  397. //
  398. // Returns: hresults
  399. //
  400. //-----------------------------------------------------------------------------
  401. STDMETHODIMP
  402. CEnumJobs::Clone(IEnumWorkItems ** ppEnumJobs)
  403. {
  404. TRACE(CEnumJobs, Clone);
  405. if (!ppEnumJobs)
  406. {
  407. return E_INVALIDARG;
  408. }
  409. HRESULT hr;
  410. CEnumJobs * pEnumJobs = new CEnumJobs;
  411. if (pEnumJobs == NULL)
  412. {
  413. hr = E_OUTOFMEMORY;
  414. goto ErrCleanup;
  415. }
  416. hr = pEnumJobs->Init(m_ptszFolderPath);
  417. if (FAILED(hr))
  418. {
  419. goto ErrCleanup;
  420. }
  421. if (m_cFound > 0)
  422. {
  423. hr = pEnumJobs->Skip(m_cFound);
  424. if (FAILED(hr))
  425. {
  426. goto ErrCleanup;
  427. }
  428. }
  429. *ppEnumJobs = pEnumJobs;
  430. return S_OK;
  431. ErrCleanup:
  432. delete pEnumJobs;
  433. *ppEnumJobs = NULL;
  434. return hr;
  435. }
  436. //+----------------------------------------------------------------------------
  437. //
  438. // Member: CEnumJobs::Init, protected
  439. //
  440. // Synopsis: Initializes the enumeration
  441. //
  442. // Returns: hresults
  443. //
  444. // Notes: Initialization is not done during construction since the only
  445. // way to return ctor errors is to throw an exception.
  446. //-----------------------------------------------------------------------------
  447. HRESULT
  448. CEnumJobs::Init(TCHAR * ptszFolderPath)
  449. {
  450. TRACE(CEnumJobs, Init);
  451. if (ptszFolderPath == NULL)
  452. {
  453. return E_FAIL;
  454. }
  455. size_t cch = lstrlen(ptszFolderPath) + 1;
  456. m_ptszFolderPath = new TCHAR[cch];
  457. if (!m_ptszFolderPath)
  458. {
  459. return E_OUTOFMEMORY;
  460. }
  461. StringCchCopy(m_ptszFolderPath, cch, ptszFolderPath);
  462. m_pdsHead = new DIRSTACK;
  463. if (m_pdsHead == NULL)
  464. {
  465. return E_OUTOFMEMORY;
  466. }
  467. StringCchCopy(m_pdsHead->tszDir, MAX_PATH + 1, TEXT("."));
  468. StringCchCopy(m_tszJobExt, SCH_SMBUF_LEN, TEXT(".") TSZ_JOB);
  469. m_fInitialized = TRUE;
  470. return S_OK;
  471. }
  472. //+----------------------------------------------------------------------------
  473. //
  474. // Member: CEnumJobs::CEnumJobs
  475. //
  476. // Synopsis: constructor
  477. //
  478. //-----------------------------------------------------------------------------
  479. CEnumJobs::CEnumJobs(void) :
  480. m_hFind(INVALID_HANDLE_VALUE),
  481. m_pdsHead(NULL),
  482. m_ptszFolderPath(NULL),
  483. m_cFound(0),
  484. m_fInitialized(FALSE),
  485. m_fFindOverrun(FALSE),
  486. m_uRefs(1)
  487. {
  488. m_tszCurDir[0] = TEXT('\0');
  489. }
  490. //+----------------------------------------------------------------------------
  491. //
  492. // Member: CEnumJobs::~CEnumJobs
  493. //
  494. // Synopsis: destructor
  495. //
  496. //-----------------------------------------------------------------------------
  497. CEnumJobs::~CEnumJobs(void)
  498. {
  499. if (m_hFind != INVALID_HANDLE_VALUE)
  500. {
  501. FindClose(m_hFind);
  502. }
  503. ClearDirStack();
  504. if (m_ptszFolderPath)
  505. {
  506. delete m_ptszFolderPath;
  507. }
  508. }
  509. //+----------------------------------------------------------------------------
  510. //
  511. // Member: CEnumJobs::PopDir, private
  512. //
  513. // Synopsis: Pops the head element off of the dir stack.
  514. //
  515. //-----------------------------------------------------------------------------
  516. HRESULT
  517. CEnumJobs::PopDir(LPTSTR ptszDir, size_t cchBuff)
  518. {
  519. if (m_pdsHead == NULL)
  520. {
  521. return S_FALSE;
  522. }
  523. StringCchCopy(ptszDir, cchBuff, m_pdsHead->tszDir);
  524. PDIRSTACK pdsNode = m_pdsHead->pdsNext;
  525. delete m_pdsHead;
  526. m_pdsHead = pdsNode;
  527. return S_OK;
  528. }
  529. //+----------------------------------------------------------------------------
  530. //
  531. // Member: CEnumJobs::ClearDirStack, private
  532. //
  533. // Synopsis: free the stack element memory
  534. //
  535. //-----------------------------------------------------------------------------
  536. void
  537. CEnumJobs::ClearDirStack(void)
  538. {
  539. if (m_pdsHead != NULL)
  540. {
  541. PDIRSTACK pdsNode, pdsNextNode;
  542. pdsNode = m_pdsHead;
  543. do
  544. {
  545. pdsNextNode = pdsNode->pdsNext;
  546. delete pdsNode;
  547. pdsNode = pdsNextNode;
  548. } while (pdsNode);
  549. m_pdsHead = NULL;
  550. }
  551. }
  552. //+----------------------------------------------------------------------------
  553. //
  554. // Function: FreeStrings
  555. //
  556. // Synopsis: Frees the strings contained in the array and then the array
  557. // itself.
  558. //
  559. // Arguments: [rgpwszNames] - the array of strings.
  560. // [n] - the array size.
  561. //
  562. //-----------------------------------------------------------------------------
  563. void
  564. FreeStrings(LPWSTR * rgpwszNames, int n)
  565. {
  566. for (int i = 0; i < n; i++)
  567. {
  568. CoTaskMemFree(rgpwszNames[i]);
  569. }
  570. CoTaskMemFree(rgpwszNames);
  571. }
  572. //+----------------------------------------------------------------------------
  573. //
  574. // CEnumJobs IUnknown methods
  575. //
  576. //-----------------------------------------------------------------------------
  577. //+----------------------------------------------------------------------------
  578. //
  579. // Member: CEnumJobs::IUnknown::QueryInterface
  580. //
  581. // Synopsis: Returns requested interface pointer
  582. //
  583. //-----------------------------------------------------------------------------
  584. STDMETHODIMP
  585. CEnumJobs::QueryInterface(REFIID riid, void ** ppvObject)
  586. {
  587. if (!ppvObject)
  588. {
  589. return E_INVALIDARG;
  590. }
  591. if (IID_IUnknown == riid)
  592. {
  593. *ppvObject = (IUnknown *)(IEnumWorkItems *)this;
  594. }
  595. else if (IID_IEnumWorkItems == riid)
  596. {
  597. *ppvObject = (IUnknown *)(IEnumWorkItems *)this;
  598. }
  599. else
  600. {
  601. *ppvObject = NULL;
  602. return E_NOINTERFACE;
  603. }
  604. AddRef();
  605. return S_OK;
  606. }
  607. //+----------------------------------------------------------------------------
  608. //
  609. // Member: CEnumJobs::IUnknown::AddRef
  610. //
  611. // Synopsis: increments reference count
  612. //
  613. // Returns: the reference count
  614. //
  615. //-----------------------------------------------------------------------------
  616. STDMETHODIMP_(ULONG)
  617. CEnumJobs::AddRef(void)
  618. {
  619. return InterlockedIncrement((long *)&m_uRefs);
  620. }
  621. //+----------------------------------------------------------------------------
  622. //
  623. // Member: CEnumJobs::IUnknown::Release
  624. //
  625. // Synopsis: Decrements the object's reference count and frees it when
  626. // no longer referenced.
  627. //
  628. // Returns: zero if the reference count is zero or non-zero otherwise
  629. //
  630. //-----------------------------------------------------------------------------
  631. STDMETHODIMP_(ULONG)
  632. CEnumJobs::Release(void)
  633. {
  634. unsigned long uTmp;
  635. if ((uTmp = InterlockedDecrement((long *)&m_uRefs)) == 0)
  636. {
  637. delete this;
  638. }
  639. return uTmp;
  640. }
  641. // BUGBUG: need a class factory if the interface is going to be exposed to OA