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.

353 lines
11 KiB

  1. /*-----------------------------------------------------------------------------
  2. *
  3. * File: collect.cpp
  4. * Author: Samuel Clement (samclem)
  5. * Date: Fri Aug 13 14:40:17 1999
  6. * Description:
  7. * Implementation of the CCollection object helper class.
  8. *
  9. * History:
  10. * 13 Aug 1999: Created.
  11. *----------------------------------------------------------------------------*/
  12. #include "stdafx.h"
  13. /*-----------------------------------------------------------------------------
  14. * CCollection::CCollection
  15. *
  16. * Create a new CCollection object. this initializes the collection to be
  17. * an empty collection, a collection with no elements.
  18. *---------------------------------------------------------------------------*/
  19. CCollection::CCollection()
  20. : m_lLength( 0 ), m_rgpDispatch( NULL ), m_lCursor( 0 )
  21. {
  22. TRACK_OBJECT( "CCollection" );
  23. }
  24. STDMETHODIMP_(void)
  25. CCollection::FinalRelease()
  26. {
  27. // free our dispatch array, release our referance
  28. // back to our owner
  29. FreeDispatchArray();
  30. }
  31. /*-----------------------------------------------------------------------------
  32. * CCollection::FreeDispatchArray()
  33. *
  34. * This handles freeing the array of IDispatch pointers we have. this
  35. * will free all the pointers, then delete the array.
  36. *---------------------------------------------------------------------------*/
  37. void CCollection::FreeDispatchArray()
  38. {
  39. // step 1, call release on all the pointers
  40. for ( unsigned long i = 0; i < m_lLength; i++ )
  41. {
  42. m_rgpDispatch[i]->Release();
  43. }
  44. // step 2, free the array
  45. {
  46. CoTaskMemFree( m_rgpDispatch );
  47. m_rgpDispatch = NULL;
  48. m_lLength = 0;
  49. }
  50. }
  51. /*-----------------------------------------------------------------------------
  52. * CCollection:SetDispatchArray
  53. *
  54. * This handles setting the dispatch array for this collection. You cannot
  55. * call this unless you don't have an array yet. The array must be allocated
  56. * with CoTaskMemAlloc.
  57. *
  58. * rgpDispatch: the array of IDispatch pointers
  59. * lSize: the number of elements within the array.
  60. *---------------------------------------------------------------------------*/
  61. bool CCollection::SetDispatchArray( IDispatch** rgpDispatch, unsigned long lSize )
  62. {
  63. Assert( m_rgpDispatch == NULL );
  64. if ( NULL == rgpDispatch )
  65. {
  66. TraceTag((tagError, "Invalid argument passed to SetDispatchArray"));
  67. return false;
  68. }
  69. // assign the pointers. It is assumed that the caller has
  70. // already addref'd the pointers
  71. m_rgpDispatch = rgpDispatch;
  72. m_lLength = lSize;
  73. return true;
  74. }
  75. /*-----------------------------------------------------------------------------
  76. * Collection::AllocateDispatchArray
  77. *
  78. * This handles the allocation of the Dispatch array. This will allocate
  79. * an array with lSize elements and initialize it to NULL, This cannot be
  80. * called after the array has been set.
  81. *
  82. * lSize: the size of the array to allocate.
  83. *---------------------------------------------------------------------------*/
  84. HRESULT CCollection::AllocateDispatchArray( unsigned long lSize )
  85. {
  86. Assert( m_rgpDispatch == NULL );
  87. // if the array is zero in length we are done.
  88. if ( lSize == 0 )
  89. return S_OK;
  90. ULONG cb = sizeof( IDispatch* ) * lSize;
  91. m_rgpDispatch = static_cast<IDispatch**>(CoTaskMemAlloc( cb ));
  92. if ( !m_rgpDispatch )
  93. return E_OUTOFMEMORY;
  94. // clear the memory, set the length
  95. ZeroMemory( m_rgpDispatch, cb );
  96. m_lLength = lSize;
  97. return S_OK;
  98. }
  99. /*-----------------------------------------------------------------------------
  100. * CCollection::CopyFrom
  101. *
  102. * This handles creating this collection from an existing collection, this
  103. * copies the members from pCollection, and then sets punkToRelease so that
  104. * the owner will live.
  105. *
  106. * pCollection: the collection to copy from
  107. *---------------------------------------------------------------------------*/
  108. HRESULT CCollection::CopyFrom( CCollection* pCollection )
  109. {
  110. Assert( m_rgpDispatch == NULL );
  111. Assert( pCollection != NULL );
  112. HRESULT hr;
  113. // Allocate the array
  114. hr = AllocateDispatchArray( pCollection->m_lLength );
  115. if ( FAILED(hr) ) {
  116. return hr;
  117. }
  118. // copy the fields
  119. m_lLength = pCollection->m_lLength;
  120. m_lCursor = pCollection->m_lCursor;
  121. // Copy and AddRef the elements in the collection
  122. for ( int i = 0; i < m_lLength; i++ ) {
  123. m_rgpDispatch[i] = pCollection->m_rgpDispatch[i];
  124. m_rgpDispatch[i]->AddRef();
  125. }
  126. return S_OK;
  127. }
  128. /*-----------------------------------------------------------------------------
  129. * CCollection::get_Count() [ICollection]
  130. *
  131. * This returns the length of the collection.
  132. *
  133. * plLength: our param, to recieve the length of the collection
  134. *---------------------------------------------------------------------------*/
  135. STDMETHODIMP
  136. CCollection::get_Count( /*out*/ long* plLength )
  137. {
  138. if ( NULL == plLength )
  139. return E_POINTER;
  140. *plLength = m_lLength;
  141. return S_OK;
  142. }
  143. /*-----------------------------------------------------------------------------
  144. * CCollection::get_Length() [ICollection]
  145. *
  146. * This returns the length of the collection.
  147. *
  148. * plLength: our param, to recieve the length of the collection
  149. *---------------------------------------------------------------------------*/
  150. STDMETHODIMP
  151. CCollection::get_Length( /*out*/ unsigned long* plLength )
  152. {
  153. if ( NULL == plLength )
  154. return E_POINTER;
  155. *plLength = m_lLength;
  156. return S_OK;
  157. }
  158. /*-----------------------------------------------------------------------------
  159. * CCollection::get_Item() [ICollection]
  160. *
  161. * This returns the desired item from our dispatch array. If the index
  162. * is invalid then will put NULl into the out param.
  163. *
  164. * lItem: the item that we want to retrieve
  165. * ppDispItem: Out param to recieve the item's IDispatch
  166. *---------------------------------------------------------------------------*/
  167. STDMETHODIMP
  168. CCollection::get_Item( long Index, /*out*/ IDispatch** ppDispItem )
  169. {
  170. if ( NULL == ppDispItem )
  171. return E_POINTER;
  172. // initialize the out param
  173. *ppDispItem = NULL;
  174. if ( Index >= m_lLength || Index < 0)
  175. {
  176. TraceTag((tagError, "CCollection: access item %ld, only %ld items", Index, m_lLength ));
  177. return S_OK;
  178. }
  179. *ppDispItem = m_rgpDispatch[Index];
  180. Assert( *ppDispItem );
  181. (*ppDispItem)->AddRef();
  182. return S_OK;
  183. }
  184. /*-----------------------------------------------------------------------------
  185. * CCollection::get_NewEnum() [ICollection]
  186. *
  187. * This create a new enumeration which is a copy of this one. this creates
  188. * an exact copy of this enumeration and returns it.
  189. *---------------------------------------------------------------------------*/
  190. STDMETHODIMP
  191. CCollection::get__NewEnum( /*out*/ IUnknown** ppEnum )
  192. {
  193. HRESULT hr;
  194. CComObject<CCollection>* pCollection = NULL;
  195. if ( NULL == ppEnum )
  196. return E_POINTER;
  197. // initialize the out param
  198. *ppEnum = NULL;
  199. // attempt to create a new collection object
  200. hr = THR( CComObject<CCollection>::CreateInstance( &pCollection ) );
  201. if ( FAILED( hr ) )
  202. goto Cleanup;
  203. // attempt to copy this collection
  204. hr = THR( pCollection->CopyFrom( this ) );
  205. if ( FAILED( hr ) )
  206. goto Cleanup;
  207. // fill the our param
  208. hr = THR( pCollection->QueryInterface( IID_IUnknown,
  209. reinterpret_cast<void**>(ppEnum) ) );
  210. Cleanup:
  211. if ( FAILED( hr ) )
  212. delete pCollection;
  213. return hr;
  214. }
  215. /*-----------------------------------------------------------------------------
  216. * CCollection::Next() [IEnumVARIANT]
  217. *
  218. * Copies celt elements int the rgvar array. returns the number of elements
  219. * retrieved.
  220. *
  221. * celt: the number of elements the caller wants
  222. * rgvar: a place to put these elements
  223. * pceltFetched: How many elements we actually we able to get.
  224. *---------------------------------------------------------------------------*/
  225. STDMETHODIMP
  226. CCollection::Next( unsigned long celt, VARIANT* rgvar, unsigned long* pceltFetched )
  227. {
  228. unsigned long celtFetched = 0;
  229. // verify the argments
  230. if ( NULL == rgvar && celt )
  231. return E_POINTER;
  232. // figure out how many we can return
  233. celtFetched = celt;
  234. if ( m_lCursor + celtFetched >= m_lLength )
  235. celtFetched = m_lLength - m_lCursor;
  236. // Init, and copy the results
  237. for ( unsigned long i = 0; i < celt; i++ )
  238. VariantInit( &rgvar[i] );
  239. for ( i = 0; i < celtFetched; i++ )
  240. {
  241. rgvar[i].vt = VT_DISPATCH;
  242. rgvar[i].pdispVal = m_rgpDispatch[m_lCursor+i];
  243. rgvar[i].pdispVal->AddRef();
  244. }
  245. // Return the number of elements fetched, if required
  246. if ( pceltFetched ) {
  247. *pceltFetched = celtFetched;
  248. }
  249. m_lCursor += celtFetched;
  250. return( celt == celtFetched ? S_OK : S_FALSE );
  251. }
  252. /*-----------------------------------------------------------------------------
  253. * CCollection::Skip() [IEnumVARIANT]
  254. *
  255. * Skips celt elements in the array.
  256. *
  257. * celt: the number of elements that we want to skip.
  258. *---------------------------------------------------------------------------*/
  259. STDMETHODIMP
  260. CCollection::Skip( unsigned long celt )
  261. {
  262. m_lCursor += celt;
  263. if ( m_lCursor >= m_lLength )
  264. {
  265. m_lCursor = m_lLength;
  266. return S_FALSE; // no more left
  267. }
  268. return S_OK;
  269. }
  270. /*-----------------------------------------------------------------------------
  271. * CCollection::Reset() [IEnumVARIANT]
  272. *
  273. * Resets the cursor to the start of the collection
  274. *---------------------------------------------------------------------------*/
  275. STDMETHODIMP
  276. CCollection::Reset()
  277. {
  278. // simply point to element 0, I don't know how this can fail.
  279. m_lCursor = 0;
  280. return S_OK;
  281. }
  282. /*-----------------------------------------------------------------------------
  283. * CCollection::Clone() [IEnumVARIANT]
  284. *
  285. * Copies this collection including its current position
  286. *
  287. * ppEnum: Out, recieves a pointer to the new enumeration
  288. *---------------------------------------------------------------------------*/
  289. STDMETHODIMP
  290. CCollection::Clone( /*out*/ IEnumVARIANT** ppEnum )
  291. {
  292. // delegate the work to get_NewEnum()
  293. IUnknown* pUnk = NULL;
  294. HRESULT hr;
  295. if ( NULL == ppEnum )
  296. return E_POINTER;
  297. *ppEnum = NULL;
  298. hr = THR( get__NewEnum( &pUnk ) );
  299. if ( FAILED( hr ) )
  300. return hr;
  301. hr = THR( pUnk->QueryInterface( IID_IEnumVARIANT,
  302. reinterpret_cast<void**>(ppEnum) ) );
  303. // release the temporary pointer
  304. pUnk->Release();
  305. return hr;
  306. }