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.

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