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.

483 lines
13 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 2000
  5. //
  6. // File: enumerator.inl
  7. //
  8. // Contents: Supports enumeration for collections of com objects
  9. //
  10. // History: 08-Mar-2000 AudriusZ Created
  11. //
  12. //--------------------------------------------------------------------------
  13. #ifndef ENUMERATOR_INL_INCLUDED
  14. #define ENUMERATOR_INL_INCLUDED
  15. #pragma once
  16. /*+-------------------------------------------------------------------------*
  17. *
  18. * CMMCNewEnumImpl<BaseClass, _Position, EnumImplementor>::get__NewEnum
  19. *
  20. * PURPOSE: Returns new enumerator for collection
  21. * in the array rgvar
  22. *
  23. * PARAMETERS:
  24. * IUnknown** ppUnk : [out] - new enumerator
  25. *
  26. * RETURNS:
  27. * HRESULT
  28. *
  29. *+-------------------------------------------------------------------------*/
  30. template <class BaseClass, class _Position, class EnumImplementor>
  31. STDMETHODIMP CMMCNewEnumImpl<BaseClass, _Position, EnumImplementor>::get__NewEnum(IUnknown** ppUnk)
  32. {
  33. MMC_COM_MANAGE_STATE();
  34. SC sc;
  35. EnumImplementor *pEnumImpl = NULL; //get enum implementor
  36. // validate the parameter
  37. sc = ScCheckPointers (ppUnk);
  38. if (sc)
  39. return (sc.ToHr());
  40. *ppUnk = NULL;
  41. sc = ScGetEnumImplementor(pEnumImpl);
  42. if(sc)
  43. return (sc.ToHr());
  44. // typedef the enumerator
  45. typedef CComObject<CMMCEnumerator<EnumImplementor, _Position> > CEnumerator;
  46. // create an instance of the enumerator
  47. CEnumerator *pEnum = NULL;
  48. sc = CEnumerator::CreateInstance(&pEnum);
  49. if (sc)
  50. return (sc.ToHr());
  51. if(!pEnum)
  52. return ((sc = E_UNEXPECTED).ToHr());
  53. // create a connection between the enumerator and the tied object.
  54. sc = ScCreateConnection(*pEnum, *pEnumImpl);
  55. if(sc)
  56. return (sc.ToHr());
  57. // initialize the position using the Reset function
  58. sc = pEnumImpl->ScEnumReset(pEnum->m_position);
  59. if(sc)
  60. return (sc.ToHr());
  61. // get the IUnknown from which IEnumVARIANT can be queried
  62. sc = pEnum->QueryInterface (IID_IUnknown, (void**) ppUnk);
  63. if (sc)
  64. return (sc.ToHr());
  65. return (sc.ToHr());
  66. }
  67. /*+-------------------------------------------------------------------------*
  68. *
  69. * CMMCEnumerator<TiedObj,_Position>::Next
  70. *
  71. * PURPOSE: Returns the next celt items starting from the current position
  72. * in the array rgvar
  73. *
  74. * PARAMETERS:
  75. * unsigned long :
  76. * PVARIANT rgvar :
  77. * unsigned long : The number of elements actually fetched
  78. *
  79. * RETURNS:
  80. * STDMETHODIMP
  81. *
  82. *+-------------------------------------------------------------------------*/
  83. template<class TiedObj, class _Position>
  84. STDMETHODIMP CMMCEnumerator<TiedObj,_Position>::Next(unsigned long celt, PVARIANT rgvar,
  85. unsigned long * pceltFetched)
  86. {
  87. MMC_COM_MANAGE_STATE();
  88. DECLARE_SC(sc, TEXT("CMMCEnumerator::Next"));
  89. CMyTiedObject *pTiedObj = NULL;
  90. PVARIANT pVar = rgvar;
  91. unsigned long celtFetched = 0;
  92. _Position posTemp = m_position;
  93. int i = 0;
  94. sc = ScGetTiedObject(pTiedObj);
  95. if(sc)
  96. goto Error;
  97. // initialize the variables.
  98. if(pceltFetched != NULL)
  99. *pceltFetched = 0;
  100. // initialize the array
  101. for(i = 0; i<celt; i++)
  102. VariantInit(&rgvar[i]);
  103. for(celtFetched = 0; celtFetched < celt; celtFetched++, pVar++)
  104. {
  105. // at this point, we have a valid position.
  106. IDispatchPtr spDispatch;
  107. // Get the next element from the tied object.
  108. // The returned IDispatch* _must_ have been AddRef'd for us!
  109. sc = pTiedObj->ScEnumNext(m_position, *(&spDispatch));
  110. if(sc)
  111. goto Error;
  112. if(sc == SC(S_FALSE) )
  113. goto Cleanup; // return just the elements so far.
  114. if(spDispatch == NULL)
  115. {
  116. sc = E_UNEXPECTED;
  117. goto Error;
  118. }
  119. // set the dispatch member of the input array to the interface returned
  120. V_VT (pVar) = VT_DISPATCH;
  121. V_DISPATCH (pVar) = spDispatch.Detach();
  122. }
  123. Cleanup:
  124. // return the count fetched, if the caller wants it
  125. if (pceltFetched != NULL)
  126. *pceltFetched = celtFetched;
  127. return sc.ToHr();
  128. Error:
  129. // clear the array.
  130. for (i=0; i<celt; i++)
  131. VariantClear(&rgvar[i]);
  132. //restore the position and set the count to zero.
  133. m_position = posTemp;
  134. celtFetched = 0;
  135. goto Cleanup;
  136. }
  137. /*+-------------------------------------------------------------------------*
  138. *
  139. * CMMCEnumerator<TiedObj,_Position>::Skip
  140. *
  141. * PURPOSE: Skips over the next celt elements in the enumeration sequence.
  142. *
  143. * PARAMETERS:
  144. * unsigned long :
  145. *
  146. * RETURNS:
  147. * STDMETHODIMP
  148. *
  149. *+-------------------------------------------------------------------------*/
  150. template<class TiedObj, class _Position>
  151. STDMETHODIMP CMMCEnumerator<TiedObj,_Position>::Skip(unsigned long celt)
  152. {
  153. MMC_COM_MANAGE_STATE();
  154. DECLARE_SC(sc, TEXT("CMMCEnumerator::Skip"));
  155. CMyTiedObject *pTiedObj = NULL;
  156. sc = ScGetTiedObject(pTiedObj);
  157. if(sc)
  158. return (sc.ToHr());
  159. /*
  160. * It's too easy for implementers of ScEnumSkip to forget to
  161. * return S_FALSE if the count fetched is less than the count
  162. * requested. We'll take care of that here.
  163. */
  164. unsigned long celtSkipped = celt + 1;
  165. /*
  166. * It's also easy for implementers of ScEnumNext to forget
  167. * that if the enumeration fails, the position needs to
  168. * remain unaffected.
  169. */
  170. _Position posT = m_position;
  171. // call the tied object with the position.
  172. sc = pTiedObj->ScEnumSkip(celt, celtSkipped, posT);
  173. if (sc)
  174. return (sc.ToHr());
  175. /*
  176. * success, so update the enumeration position
  177. */
  178. m_position = posT;
  179. /*
  180. * if this assert fails, the implementation of ScEnumSkip either
  181. * didn't initialize or didn't update celtSkipped
  182. */
  183. ASSERT (celtSkipped <= celt);
  184. if (celtSkipped < celt)
  185. sc = S_FALSE;
  186. if (celtSkipped > celt)
  187. celtSkipped = celt; // sanity
  188. return sc.ToHr();
  189. }
  190. /*+-------------------------------------------------------------------------*
  191. *
  192. * CMMCEnumerator<TiedObj,_Position>::Reset
  193. *
  194. * PURPOSE: Resets the enumeration sequence to the beginning
  195. *
  196. * RETURNS:
  197. * STDMETHODIMP
  198. *
  199. *+-------------------------------------------------------------------------*/
  200. template<class TiedObj, class _Position>
  201. STDMETHODIMP CMMCEnumerator<TiedObj,_Position>::Reset()
  202. {
  203. MMC_COM_MANAGE_STATE();
  204. DECLARE_SC(sc, TEXT("CMMCEnumerator::Reset"));
  205. CMyTiedObject *pTiedObj = NULL;
  206. sc = ScGetTiedObject(pTiedObj);
  207. if(sc)
  208. return (sc.ToHr());
  209. // call the tied object with the position.
  210. sc = pTiedObj->ScEnumReset(m_position);
  211. return sc.ToHr();
  212. }
  213. /*+-------------------------------------------------------------------------*
  214. *
  215. * CMMCEnumerator<TiedObj,_Position>::Clone
  216. *
  217. * PURPOSE: Creates a copy of the current state of enumeration
  218. *
  219. * PARAMETERS:
  220. * PPENUMVARIANT ppenum :
  221. *
  222. * RETURNS:
  223. * STDMETHODIMP
  224. *
  225. *+-------------------------------------------------------------------------*/
  226. template<class TiedObj, class _Position>
  227. STDMETHODIMP CMMCEnumerator<TiedObj,_Position>::Clone(PPENUMVARIANT ppenum)
  228. {
  229. MMC_COM_MANAGE_STATE();
  230. DECLARE_SC(sc, TEXT("CMMCEnumerator::Clone"));
  231. if(!ppenum)
  232. {
  233. sc = E_INVALIDARG;
  234. return sc.ToHr();
  235. }
  236. CMyTiedObject *pTiedObj = NULL;
  237. sc = ScGetTiedObject(pTiedObj);
  238. if(sc)
  239. return (sc.ToHr());
  240. typedef CComObject<ThisClass> CNewComObject;
  241. CNewComObject *pNewComObj = NULL;
  242. // create an instance of the new enumerator.
  243. sc = CNewComObject::CreateInstance(&pNewComObj);
  244. if (sc)
  245. return (sc.ToHr());
  246. if(!pNewComObj)
  247. return ((sc = E_UNEXPECTED).ToHr());
  248. // at this point the new object has been created.
  249. // Set the position directly from the present state.
  250. pNewComObj->m_position = m_position;
  251. // connect the COM object to the tied object
  252. sc = ScCreateConnection(*pNewComObj, *pTiedObj);
  253. if(sc)
  254. return sc.ToHr();
  255. // addref the new object for the client.
  256. *ppenum = pNewComObj;
  257. (*ppenum)->AddRef();
  258. return sc.ToHr();
  259. }
  260. /***************************************************************************\
  261. *
  262. * CMMCArrayEnumBase<_CollectionInterface, _ItemInterface>::get_Count
  263. *
  264. * PURPOSE: Returns count of items in the collection
  265. *
  266. * RETURNS:
  267. * HRESULT
  268. *
  269. \***************************************************************************/
  270. template <class _CollectionInterface, class _ItemInterface>
  271. STDMETHODIMP CMMCArrayEnumBase<_CollectionInterface, _ItemInterface>::get_Count( PLONG pCount )
  272. {
  273. MMC_COM_MANAGE_STATE();
  274. DECLARE_SC(sc, TEXT("CMMCArrayEnumBase::get_Count"));
  275. // parameter check
  276. sc = ScCheckPointers(pCount);
  277. if (sc)
  278. return sc.ToHr();
  279. // return the count
  280. *pCount = m_array.size();
  281. return sc.ToHr();
  282. }
  283. /***************************************************************************\
  284. *
  285. * CMMCArrayEnumBase<_CollectionInterface, _ItemInterface>::Item
  286. *
  287. * PURPOSE: Returns specified item from collection
  288. *
  289. * RETURNS:
  290. * HRESULT
  291. *
  292. \***************************************************************************/
  293. template <class _CollectionInterface, class _ItemInterface>
  294. STDMETHODIMP CMMCArrayEnumBase<_CollectionInterface, _ItemInterface>::Item( long Index, _ItemInterface ** ppItem )
  295. {
  296. MMC_COM_MANAGE_STATE();
  297. DECLARE_SC(sc, TEXT("CMMCArrayEnumBase::Item"));
  298. // parameter check
  299. sc = ScCheckPointers(ppItem);
  300. if (sc)
  301. return sc.ToHr();
  302. // initialization
  303. *ppItem = NULL;
  304. // remember - we are 1 based!
  305. if (Index < 1 || Index > m_array.size())
  306. return (sc = E_INVALIDARG).ToHr();
  307. *ppItem = m_array[Index - 1];
  308. // recheck the pointer
  309. sc = ScCheckPointers(*ppItem, E_NOINTERFACE);
  310. if (sc)
  311. return sc.ToHr();
  312. (*ppItem)->AddRef();
  313. return sc.ToHr();
  314. }
  315. /***************************************************************************\
  316. *
  317. * CMMCArrayEnumBase<_CollectionInterface, _ItemInterface>::ScEnumReset
  318. *
  319. * PURPOSE: Resets position to the first item in the collection
  320. *
  321. * RETURNS:
  322. * HRESULT
  323. *
  324. \***************************************************************************/
  325. template <class _CollectionInterface, class _ItemInterface>
  326. ::SC CMMCArrayEnumBase<_CollectionInterface, _ItemInterface>::ScEnumReset (unsigned &pos)
  327. {
  328. MMC_COM_MANAGE_STATE();
  329. DECLARE_SC(sc, TEXT("CMMCArrayEnumBase::ScEnumReset"));
  330. pos = 0;
  331. return sc;
  332. }
  333. /***************************************************************************\
  334. *
  335. * CMMCArrayEnumBase<_CollectionInterface, _ItemInterface>::ScEnumNext
  336. *
  337. * PURPOSE: Returns item from the collection, advances position
  338. *
  339. * RETURNS:
  340. * HRESULT
  341. *
  342. \***************************************************************************/
  343. template <class _CollectionInterface, class _ItemInterface>
  344. ::SC CMMCArrayEnumBase<_CollectionInterface, _ItemInterface>::ScEnumNext(unsigned &pos, PDISPATCH & pDispatch)
  345. {
  346. MMC_COM_MANAGE_STATE();
  347. DECLARE_SC(sc, TEXT("CMMCArrayEnumBase::ScEnumNext"));
  348. // initialize;
  349. pDispatch = NULL;
  350. // check the ranges
  351. if (pos >= m_array.size())
  352. return sc = S_FALSE;
  353. // get element
  354. pDispatch = m_array[pos];
  355. // recheck the pointer
  356. sc = ScCheckPointers(pDispatch, E_NOINTERFACE);
  357. if (sc)
  358. return sc;
  359. pDispatch->AddRef();
  360. ++pos;
  361. return sc;
  362. }
  363. /***************************************************************************\
  364. *
  365. * CMMCArrayEnumBase<_CollectionInterface, _ItemInterface>::ScEnumSkip
  366. *
  367. * PURPOSE: Skips the amount of items in enumeration
  368. *
  369. * RETURNS:
  370. * HRESULT
  371. *
  372. \***************************************************************************/
  373. template <class _CollectionInterface, class _ItemInterface>
  374. ::SC CMMCArrayEnumBase<_CollectionInterface, _ItemInterface>::ScEnumSkip (unsigned long celt, unsigned long& celtSkipped, unsigned &pos)
  375. {
  376. MMC_COM_MANAGE_STATE();
  377. DECLARE_SC(sc, TEXT("CMMCArrayEnumBase::ScEnumSkip"));
  378. // no skipped at start
  379. celtSkipped = 0;
  380. // check if it's a void task
  381. if (!celt)
  382. return sc;
  383. // are we behind the last item?
  384. if (pos >= m_array.size())
  385. return sc = S_FALSE;
  386. // how far can we go?
  387. celtSkipped = m_array.size() - pos;
  388. // but go no more than requested
  389. if (celtSkipped > celt)
  390. celtSkipped = celt;
  391. // advance
  392. pos += celtSkipped;
  393. // check if we could do as much as requested
  394. if (celtSkipped < celt)
  395. return sc = S_FALSE;
  396. return sc;
  397. }
  398. #endif // ENUMERATOR_INL_INCLUDED