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.

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