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.

370 lines
9.2 KiB

  1. //=--------------------------------------------------------------------------=
  2. // StandardEnum.Cpp
  3. //=--------------------------------------------------------------------------=
  4. // Copyright 1995 Microsoft Corporation. All Rights Reserved.
  5. //
  6. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  7. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  8. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  9. // PARTICULAR PURPOSE.
  10. //=--------------------------------------------------------------------------=
  11. //
  12. // implementation of a generic enumerator object.
  13. //
  14. #include "stock.h"
  15. #pragma hdrstop
  16. #include "stdenum.h"
  17. // Used by creators of CStandardEnum
  18. //
  19. void WINAPI CopyAndAddRefObject
  20. (
  21. void *pDest, // dest
  22. const void *pSource, // src
  23. DWORD dwSize // size, ignored, since it's always 4
  24. )
  25. {
  26. IUnknown *pUnk = *((IUnknown **)pSource);
  27. *((IUnknown **)pDest) = pUnk;
  28. pUnk->AddRef();
  29. }
  30. void* CStandardEnum_CreateInstance(REFIID riid, BOOL fMembersAreInterfaces, int cElement, int cbElement, void *rgElements,
  31. void (WINAPI * pfnCopyElement)(void *, const void *, DWORD))
  32. {
  33. return (LPVOID)new CStandardEnum(riid, fMembersAreInterfaces, cElement, cbElement, rgElements, pfnCopyElement);
  34. }
  35. //=--------------------------------------------------------------------------=
  36. // CStandardEnum::CStandardEnum
  37. //=--------------------------------------------------------------------------=
  38. // create the object and initialize the refcount
  39. //
  40. // Parameters:
  41. // REFCLSID - [in] type of enumerator that we are
  42. // int - [in] number of elements in the enumeration
  43. // int - [in] size of each element
  44. // void * - [in] pointer to element data
  45. // void (WINAPI *pfnCopyElement)(void *, const void *, DWORD)
  46. // - [in] copying function
  47. //
  48. // Notes:
  49. //
  50. #pragma warning(disable:4355) // using 'this' in constructor
  51. CStandardEnum::CStandardEnum
  52. (
  53. REFCLSID rclsid,
  54. BOOL fMembersAreInterfaces,
  55. int cElements,
  56. int cbElementSize,
  57. void *rgElements,
  58. void (WINAPI *pfnCopyElement)(void *, const void *, DWORD)
  59. )
  60. : m_cRef(1),
  61. m_iid(rclsid),
  62. m_cElements(cElements),
  63. m_cbElementSize(cbElementSize),
  64. m_iCurrent(0),
  65. m_rgElements(rgElements),
  66. m_pfnCopyElement(pfnCopyElement),
  67. m_fMembersAreInterfaces(fMembersAreInterfaces)
  68. {
  69. m_pEnumClonedFrom = NULL;
  70. if(m_fMembersAreInterfaces)
  71. {
  72. if(m_rgElements)
  73. {
  74. int i;
  75. for(i=0; i<m_cElements; i++)
  76. {
  77. LPUNKNOWN *ppunk = (IUnknown **)GetNthElement(i);
  78. (*ppunk)->AddRef();
  79. }
  80. }
  81. }
  82. }
  83. #pragma warning(default:4355) // using 'this' in constructor
  84. //=--------------------------------------------------------------------------=
  85. // CStandardEnum::CStandardEnum
  86. //=--------------------------------------------------------------------------=
  87. // "it is not death, but dying, which is terrible."
  88. // - Henry Fielding (1707-54)
  89. //
  90. // Notes:
  91. //
  92. CStandardEnum::~CStandardEnum ()
  93. {
  94. // if we're a cloned object, then just release our parent object and
  95. // we're done. otherwise, free up the allocated memory we were given
  96. //
  97. if (m_pEnumClonedFrom)
  98. {
  99. m_pEnumClonedFrom->Release();
  100. }
  101. else
  102. {
  103. if (m_rgElements)
  104. {
  105. if(m_fMembersAreInterfaces)
  106. {
  107. int i;
  108. for(i=0; i<m_cElements; i++)
  109. {
  110. LPUNKNOWN *ppunk = (IUnknown **)GetNthElement(i);
  111. (*ppunk)->Release();
  112. }
  113. }
  114. GlobalFree(m_rgElements);
  115. }
  116. }
  117. }
  118. //=--------------------------------------------------------------------------=
  119. // CStandardEnum::InternalQueryInterface
  120. //=--------------------------------------------------------------------------=
  121. // we support our internal iid, and that's all
  122. //
  123. // Parameters:
  124. // REFIID - [in] interface they want
  125. // void ** - [out] where they want to put the resulting object ptr.
  126. //
  127. // Output:
  128. // HRESULT - S_OK, E_NOINTERFACE
  129. //
  130. // Notes:
  131. //
  132. HRESULT CStandardEnum::QueryInterface
  133. (
  134. REFIID riid,
  135. void **ppvObjOut
  136. )
  137. {
  138. *ppvObjOut = NULL;
  139. if (IsEqualIID(riid, m_iid))
  140. {
  141. *ppvObjOut = (IEnumGeneric *)this;
  142. }
  143. else if (IsEqualIID(riid, IID_IUnknown))
  144. {
  145. *ppvObjOut = (IUnknown *)this;
  146. }
  147. if (*ppvObjOut)
  148. {
  149. AddRef();
  150. return S_OK;
  151. }
  152. else
  153. {
  154. return E_NOINTERFACE;
  155. }
  156. }
  157. ULONG CStandardEnum::AddRef(void)
  158. {
  159. return ++m_cRef;
  160. }
  161. ULONG CStandardEnum::Release(void)
  162. {
  163. int n = --m_cRef;
  164. if (n == 0)
  165. delete this;
  166. return(n);
  167. }
  168. //=--------------------------------------------------------------------------=
  169. // CStandardEnum::Next
  170. //=--------------------------------------------------------------------------=
  171. // returns the next dude in our iteration
  172. //
  173. // Parameters:
  174. // unsigned long - [in] count of elements requested
  175. // void * - [out] array of slots to put values in.
  176. // unsigned long * - [out] actual number fetched
  177. //
  178. // Output:
  179. // HRESULT - S_OK, E_INVALIDARG, S_FALSE
  180. //
  181. // Notes:
  182. //
  183. STDMETHODIMP CStandardEnum::Next
  184. (
  185. unsigned long cElm,
  186. void *rgDest,
  187. unsigned long *pcElmOut
  188. )
  189. {
  190. unsigned long cElementsFetched = 0;
  191. void *pElementDest = rgDest;
  192. const void *pElementSrc = GetNthElement(m_iCurrent);
  193. while (cElementsFetched < cElm) {
  194. // if we hit EOF, break out
  195. //
  196. if (m_iCurrent >= m_cElements)
  197. break;
  198. // copy the element out for them
  199. //
  200. m_pfnCopyElement(pElementDest, pElementSrc, m_cbElementSize);
  201. // increase the counters
  202. //
  203. pElementDest = (LPBYTE)pElementDest + m_cbElementSize;
  204. pElementSrc = (const BYTE *)pElementSrc + m_cbElementSize;
  205. m_iCurrent++;
  206. cElementsFetched++;
  207. }
  208. if (pcElmOut)
  209. *pcElmOut = cElementsFetched;
  210. return (cElementsFetched < cElm)? S_FALSE : S_OK;
  211. }
  212. //=--------------------------------------------------------------------------=
  213. // CStandardEnum::Skip
  214. //=--------------------------------------------------------------------------=
  215. // skips the requested number of rows.
  216. //
  217. // Parameters:
  218. // unsigned long - [in] number to skip
  219. //
  220. // Output:
  221. // HRESULT - S_OK, S_FALSE
  222. //
  223. // Notes:
  224. //
  225. STDMETHODIMP CStandardEnum::Skip
  226. (
  227. unsigned long cSkip
  228. )
  229. {
  230. // handle running off the end
  231. //
  232. if (m_iCurrent + (int)cSkip > m_cElements) {
  233. m_iCurrent = m_cElements;
  234. return S_FALSE;
  235. }
  236. m_iCurrent += cSkip;
  237. return S_OK;
  238. }
  239. //=--------------------------------------------------------------------------=
  240. // CStandardEnum::Reset
  241. //=--------------------------------------------------------------------------=
  242. // reset the counter.
  243. //
  244. // Output:
  245. // HRESULT - S_OK
  246. //
  247. // Notes:
  248. //
  249. STDMETHODIMP CStandardEnum::Reset
  250. (
  251. void
  252. )
  253. {
  254. m_iCurrent = 0;
  255. return S_OK;
  256. }
  257. //=--------------------------------------------------------------------------=
  258. // CStandardEnum::Clone
  259. //=--------------------------------------------------------------------------=
  260. // clones the object and gives the new one the same position
  261. //
  262. // Parameters:
  263. // IEnumVARIANT ** - [out] where to put the new object.
  264. //
  265. // Output;
  266. // HRESULT - S_OK, E_OUTOFMEMORY
  267. //
  268. // Notes:
  269. //
  270. STDMETHODIMP CStandardEnum::Clone
  271. (
  272. IEnumGeneric **ppEnumClone
  273. )
  274. {
  275. CStandardEnum *pNewEnum = new CStandardEnum(m_iid, m_fMembersAreInterfaces, m_cElements,
  276. m_cbElementSize, m_rgElements, m_pfnCopyElement);
  277. if (NULL == pNewEnum)
  278. return E_OUTOFMEMORY;
  279. // The clone has the same current position as we do
  280. pNewEnum->m_iCurrent = m_iCurrent;
  281. // hold on to who we were cloned from so m_rgElements stays alive, and we don't
  282. // have to copy it.
  283. //
  284. pNewEnum->m_pEnumClonedFrom = this;
  285. // AddRef() ourselves on their behalf.
  286. //
  287. AddRef();
  288. return S_OK;
  289. }
  290. // Helper function for creating IConnectionPoint enumerators
  291. //
  292. HRESULT CreateInstance_IEnumConnectionPoints(LPENUMCONNECTIONPOINTS * ppEnum, DWORD count, ...)
  293. {
  294. DWORD countTemp;
  295. IConnectionPoint **rgCPs;
  296. if (NULL == ppEnum)
  297. return E_POINTER;
  298. ASSERT(count > 0);
  299. // GlobalAlloc an array of connection points [since our standard enum
  300. // assumes this and GlobalFree's it later]
  301. //
  302. rgCPs = (LPCONNECTIONPOINT*)GlobalAlloc(GPTR, SIZEOF(LPCONNECTIONPOINT) * count);
  303. if (NULL == rgCPs)
  304. return E_OUTOFMEMORY;
  305. va_list ArgList;
  306. va_start(ArgList, count);
  307. IConnectionPoint **prgCPs = rgCPs;
  308. countTemp = count;
  309. while (countTemp)
  310. {
  311. IConnectionPoint *pArg = va_arg(ArgList, IConnectionPoint*);
  312. *prgCPs = pArg;
  313. prgCPs++;
  314. countTemp--;
  315. }
  316. va_end(ArgList);
  317. *ppEnum = (IEnumConnectionPoints *)(IEnumGeneric *) new CStandardEnum(IID_IEnumConnectionPoints,
  318. TRUE, count, SIZEOF(LPCONNECTIONPOINT), (LPVOID)rgCPs,
  319. CopyAndAddRefObject);
  320. if (!*ppEnum)
  321. {
  322. GlobalFree(rgCPs);
  323. return E_OUTOFMEMORY;
  324. }
  325. return S_OK;
  326. }