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.

743 lines
16 KiB

  1. /*
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. Module Name:
  4. blbcoen.h
  5. Abstract:
  6. Author:
  7. */
  8. #ifndef __BLB_COLLECTION_ENUMERATION_IMPL__
  9. #define __BLB_COLLECTION_ENUMERATION_IMPL__
  10. #include "resource.h"
  11. #include <afxtempl.h>
  12. #include "blberr.h"
  13. #include "blbgen.h"
  14. #include "sdp.h"
  15. // forward declaration
  16. class CSdpConferenceBlob;
  17. template <class T>
  18. class ENUM_ELEMENT
  19. {
  20. public:
  21. inline ENUM_ELEMENT();
  22. inline void SuccessInit(
  23. IN T &Element,
  24. IN BOOL DestroyElementOnDestruction = FALSE
  25. );
  26. inline T &GetElement();
  27. inline T &GetContent();
  28. inline void SetDestroyElementFlag();
  29. virtual ~ENUM_ELEMENT();
  30. protected:
  31. T *m_Element;
  32. BOOL m_DestroyElementOnDestruction;
  33. };
  34. template <class T>
  35. inline
  36. ENUM_ELEMENT<T>::ENUM_ELEMENT(
  37. )
  38. : m_Element(NULL),
  39. m_DestroyElementOnDestruction(FALSE)
  40. {
  41. }
  42. template <class T>
  43. inline void
  44. ENUM_ELEMENT<T>::SuccessInit(
  45. IN T &Element,
  46. IN BOOL DestroyElementOnDestruction /* = FALSE */
  47. )
  48. {
  49. ASSERT(NULL == m_Element);
  50. m_Element = &Element;
  51. m_DestroyElementOnDestruction = DestroyElementOnDestruction;
  52. }
  53. template <class T>
  54. inline T &
  55. ENUM_ELEMENT<T>::GetElement(
  56. )
  57. {
  58. ASSERT(NULL != m_Element);
  59. return *m_Element;
  60. }
  61. template <class T>
  62. inline void
  63. ENUM_ELEMENT<T>::SetDestroyElementFlag(
  64. )
  65. {
  66. ASSERT(NULL != m_Element);
  67. m_DestroyElementOnDestruction = TRUE;
  68. }
  69. template <class T>
  70. inline T &
  71. ENUM_ELEMENT<T>::GetContent(
  72. )
  73. {
  74. ASSERT(NULL != m_Element);
  75. return *m_Element;
  76. }
  77. template <class T>
  78. /* virtual */
  79. ENUM_ELEMENT<T>::~ENUM_ELEMENT(
  80. )
  81. {
  82. if ( m_DestroyElementOnDestruction )
  83. {
  84. ASSERT(NULL != m_Element);
  85. delete m_Element;
  86. }
  87. }
  88. template <class T>
  89. class IF_ARRAY : public CArray<VARIANT, VARIANT &>
  90. {
  91. protected:
  92. typedef typename T::SDP_LIST SDP_LIST;
  93. typedef typename T::ELEM_IF ELEM_IF;
  94. typedef CArray<VARIANT, VARIANT &> BASE;
  95. public:
  96. inline IF_ARRAY();
  97. HRESULT Init(
  98. IN CSdpConferenceBlob &ConfBlob,
  99. IN SDP_LIST &SdpList
  100. );
  101. inline ELEM_IF *GetAt(
  102. IN UINT Index
  103. );
  104. HRESULT Add(
  105. IN UINT Index,
  106. IN ELEM_IF *ElemIf
  107. );
  108. inline void Delete(
  109. IN UINT Index
  110. );
  111. inline UINT GetSize();
  112. inline SDP_LIST *GetSdpList();
  113. inline VARIANT *GetData();
  114. inline ELEM_IF **GetElemIfArrayData();
  115. inline CSdpConferenceBlob *GetSdpBlob();
  116. inline void ClearSdpBlobRefs();
  117. ~IF_ARRAY();
  118. protected:
  119. CSdpConferenceBlob *m_ConfBlob;
  120. SDP_LIST *m_SdpList;
  121. CArray<ELEM_IF *, ELEM_IF *> m_ElemIfArray;
  122. };
  123. template <class T>
  124. inline
  125. IF_ARRAY<T>::IF_ARRAY(
  126. )
  127. : m_ConfBlob(NULL),
  128. m_SdpList(NULL)
  129. {
  130. }
  131. template <class T>
  132. HRESULT
  133. IF_ARRAY<T>::Init(
  134. IN CSdpConferenceBlob &ConfBlob,
  135. IN SDP_LIST &SdpList
  136. )
  137. {
  138. ASSERT(NULL == m_ConfBlob);
  139. ASSERT(NULL == m_SdpList);
  140. // create the array in 3 steps -
  141. // i) create each of the instances and insert into the list
  142. // ii) set the sdp list destroy members flag to FALSE
  143. // iii) set the destroy element flag to TRUE for each of the created instances
  144. // this order is needed to ensure that only one of (sdp list, T instance) is responsible
  145. // for deleting the sdp instance
  146. // for each sdp specific data structure, create and initialize a COM component,
  147. // set the corresponding element in the interface array to the queried interface ptr
  148. for (UINT i=0; (int)i < SdpList.GetSize(); i++)
  149. {
  150. // create an instance of the component supporting the elem if
  151. CComObject<T> *CompInstance;
  152. HRESULT HResult = CComObject<T>::CreateInstance(&CompInstance);
  153. BAIL_ON_FAILURE(HResult);
  154. // initialize the instance with the sdp specific data structure
  155. CompInstance->SuccessInit(ConfBlob, *((T::SDP_TYPE *)SdpList.GetAt(i)));
  156. // query for the elem interface
  157. T::ELEM_IF *ElemIf;
  158. // query for the element interface and return it
  159. HResult = CompInstance->_InternalQueryInterface(T::ELEM_IF_ID, (void**)&ElemIf);
  160. if ( FAILED(HResult) )
  161. {
  162. delete CompInstance;
  163. return HResult;
  164. }
  165. // initialize the variant wrapper
  166. VARIANT ElemVariant;
  167. V_VT(&ElemVariant) = VT_DISPATCH;
  168. V_DISPATCH(&ElemVariant) = ElemIf;
  169. // the ElemIf is stored twice (although it was incremented once in _InternalQueryInterface
  170. // need to keep this in mind when releasing the interfaces
  171. INT_PTR Index;
  172. try
  173. {
  174. Index = m_ElemIfArray.Add(ElemIf);
  175. }
  176. catch(...)
  177. {
  178. delete CompInstance;
  179. return E_OUTOFMEMORY;
  180. }
  181. try
  182. {
  183. BASE::Add(ElemVariant);
  184. }
  185. catch(...)
  186. {
  187. m_ElemIfArray.RemoveAt(Index);
  188. delete CompInstance;
  189. return E_OUTOFMEMORY;
  190. }
  191. }
  192. // inform the sdp list that there is no need to destroy the members on destruction
  193. SdpList.ClearDestroyMembersFlag();
  194. // for each of the inserted instances, set the destroy element flag to true
  195. for (i=0; (int)i < BASE::GetSize(); i++)
  196. {
  197. ((T *)m_ElemIfArray.GetAt(i))->SetDestroyElementFlag();
  198. }
  199. m_ConfBlob = &ConfBlob;
  200. m_SdpList = &SdpList;
  201. return S_OK;
  202. }
  203. template <class T>
  204. inline typename IF_ARRAY<T>::ELEM_IF *
  205. IF_ARRAY<T>::GetAt(
  206. IN UINT Index
  207. )
  208. {
  209. ASSERT(Index < (UINT)BASE::GetSize());
  210. return m_ElemIfArray.GetAt(Index);
  211. }
  212. template <class T>
  213. HRESULT
  214. IF_ARRAY<T>::Add(
  215. IN UINT Index,
  216. IN ELEM_IF *ElemIf
  217. )
  218. {
  219. ASSERT(NULL != m_SdpList);
  220. ASSERT(BASE::GetSize() == m_SdpList->GetSize());
  221. ASSERT(Index <= (UINT)BASE::GetSize());
  222. ASSERT(NULL != ElemIf);
  223. // shift elements with equal or higher indices forwards
  224. // cheat COM here, and get the sdp specific class instance for the elem if
  225. // initialize the variant wrapper
  226. VARIANT ElemVariant;
  227. V_VT(&ElemVariant) = VT_DISPATCH;
  228. V_DISPATCH(&ElemVariant) = ElemIf;
  229. // insert into the arrays
  230. try
  231. {
  232. m_ElemIfArray.InsertAt(Index, ElemIf);
  233. }
  234. catch(...)
  235. {
  236. return E_OUTOFMEMORY;
  237. }
  238. try
  239. {
  240. BASE::InsertAt(Index, ElemVariant);
  241. }
  242. catch(...)
  243. {
  244. m_ElemIfArray.RemoveAt(Index);
  245. return E_OUTOFMEMORY;
  246. }
  247. try
  248. {
  249. m_SdpList->InsertAt(Index, &(((T *)ElemIf)->GetContent()));
  250. }
  251. catch(...)
  252. {
  253. BASE::RemoveAt(Index);
  254. m_ElemIfArray.RemoveAt(Index);
  255. return E_OUTOFMEMORY;
  256. }
  257. return S_OK;
  258. }
  259. template <class T>
  260. inline void
  261. IF_ARRAY<T>::Delete(
  262. IN UINT Index
  263. )
  264. {
  265. ASSERT(NULL != m_SdpList);
  266. ASSERT(BASE::GetSize() == m_SdpList->GetSize());
  267. ASSERT(Index < (UINT)BASE::GetSize());
  268. // inform the instance that a reference to the blob is no longer needed
  269. ((T *)m_ElemIfArray.GetAt(Index))->ClearSdpBlobRefs();
  270. m_ElemIfArray.GetAt(Index)->Release();
  271. // move other members backwards
  272. m_ElemIfArray.RemoveAt(Index);
  273. BASE::RemoveAt(Index);
  274. m_SdpList->RemoveAt(Index);
  275. }
  276. template <class T>
  277. inline UINT
  278. IF_ARRAY<T>::GetSize(
  279. )
  280. {
  281. ASSERT(0 <= BASE::GetSize());
  282. return (UINT)BASE::GetSize();
  283. }
  284. template <class T>
  285. inline VARIANT *
  286. IF_ARRAY<T>::GetData(
  287. )
  288. {
  289. return BASE::GetData();
  290. }
  291. template <class T>
  292. inline typename IF_ARRAY<T>::ELEM_IF **
  293. IF_ARRAY<T>::GetElemIfArrayData(
  294. )
  295. {
  296. return m_ElemIfArray.GetData();
  297. }
  298. template <class T>
  299. inline CSdpConferenceBlob *
  300. IF_ARRAY<T>::GetSdpBlob(
  301. )
  302. {
  303. return m_ConfBlob;
  304. }
  305. template <class T>
  306. inline void
  307. IF_ARRAY<T>::ClearSdpBlobRefs(
  308. )
  309. {
  310. m_ConfBlob = NULL;
  311. // clear sdp blob references in each of the inserted instances
  312. for(UINT i=0; (int)i < BASE::GetSize(); i++)
  313. {
  314. // inform the inserted instance that a reference to the blob is no longer needed
  315. ((T *)m_ElemIfArray.GetAt(i))->ClearSdpBlobRefs();
  316. }
  317. // keep the list (m_SdpList) around, it is already disassociated from the conf blob instance
  318. }
  319. template <class T>
  320. inline typename IF_ARRAY<T>::SDP_LIST *
  321. IF_ARRAY<T>::GetSdpList(
  322. )
  323. {
  324. return m_SdpList;
  325. }
  326. template <class T>
  327. IF_ARRAY<T>::~IF_ARRAY(
  328. )
  329. {
  330. for(UINT i=0; (int)i < BASE::GetSize(); i++)
  331. {
  332. if ( NULL != m_ElemIfArray.GetAt(i) )
  333. {
  334. // inform the instance that a reference to the blob is no longer needed
  335. // NOTE: the Remove... call may already have been made, but since it is an
  336. // inline fn, no need to check that before calling
  337. ((T *)m_ElemIfArray.GetAt(i))->ClearSdpBlobRefs();
  338. // NOTE: since the interface is stored twice - in the elem if array as well
  339. // as the base variant array but AddRef is only done once (by _InternalQuery..)
  340. // Release is also done only once
  341. m_ElemIfArray.GetAt(i)->Release();
  342. }
  343. }
  344. }
  345. template <class T>
  346. class ATL_NO_VTABLE MY_COLL_IMPL :
  347. public T::COLL_IF
  348. {
  349. protected:
  350. typedef typename T::SDP_LIST SDP_LIST;
  351. typedef typename T::ELEM_IF ELEM_IF;
  352. typedef CComObject<CSafeComEnum<IEnumVARIANT, &IID_IEnumVARIANT, VARIANT, _Copy<VARIANT> > > ENUM_VARIANT;
  353. typedef typename T::ENUM_IF ENUM_IF;
  354. typedef _CopyInterface<typename T::ELEM_IF> COPY_ELEM_IF;
  355. public:
  356. inline MY_COLL_IMPL();
  357. inline HRESULT Init(
  358. IN CSdpConferenceBlob &ConfBlob,
  359. IN SDP_LIST &SdpList
  360. );
  361. STDMETHOD(Create)(/*[in]*/ LONG Index, /*[out, retval]*/ ELEM_IF **Interface);
  362. STDMETHOD(Delete)(/*[in]*/ LONG Index);
  363. STDMETHOD(get__NewEnum)(/*[out, retval]*/ IUnknown * *pVal);
  364. STDMETHOD(get_EnumerationIf)(/*[out, retval]*/ ENUM_IF **pVal) = 0;
  365. STDMETHOD(get_Item)(/*[in]*/ LONG Index, /*[out, retval]*/ ELEM_IF **pVal);
  366. STDMETHOD(get_Count)(/*[out, retval]*/ LONG *pVal);
  367. inline void ClearSdpBlobRefs();
  368. virtual ~MY_COLL_IMPL();
  369. protected:
  370. IF_ARRAY<T> *m_IfArray;
  371. };
  372. template <class T>
  373. inline
  374. MY_COLL_IMPL<T>::MY_COLL_IMPL(
  375. )
  376. : m_IfArray(NULL)
  377. {
  378. }
  379. template <class T>
  380. inline HRESULT
  381. MY_COLL_IMPL<T>::Init(
  382. IN CSdpConferenceBlob &ConfBlob,
  383. IN SDP_LIST &SdpList
  384. )
  385. {
  386. if ( NULL != m_IfArray )
  387. {
  388. delete m_IfArray;
  389. }
  390. // create an interface array
  391. try
  392. {
  393. m_IfArray = new IF_ARRAY<T>;
  394. }
  395. catch(...)
  396. {
  397. m_IfArray = NULL;
  398. }
  399. BAIL_IF_NULL(m_IfArray, E_OUTOFMEMORY);
  400. // initialize the interface array
  401. HRESULT HResult = m_IfArray->Init(ConfBlob, SdpList);
  402. BAIL_ON_FAILURE(HResult);
  403. // successful
  404. return S_OK;
  405. }
  406. template <class T>
  407. STDMETHODIMP MY_COLL_IMPL<T>::Create(
  408. /*[in]*/ LONG Index,
  409. /*[out, retval]*/ ELEM_IF **Interface
  410. )
  411. {
  412. CLock Lock(g_DllLock);
  413. ASSERT(NULL != m_IfArray);
  414. BAIL_IF_NULL(m_IfArray, E_FAIL);
  415. // use 1-based index, VB like
  416. // can add at atmost 1 beyond the last element
  417. if ((Index < (LONG)1) || (Index > (LONG)(m_IfArray->GetSize()+1)))
  418. {
  419. return E_INVALIDARG;
  420. }
  421. BAIL_IF_NULL(Interface, E_INVALIDARG);
  422. // if the sdp blob doesn't exist, creation is not allowed
  423. if ( NULL == m_IfArray->GetSdpBlob() )
  424. {
  425. return HRESULT_FROM_ERROR_CODE(SDPBLB_CONF_BLOB_DESTROYED);
  426. }
  427. CComObject<T> *TComObject;
  428. HRESULT HResult = CComObject<T>::CreateInstance(&TComObject);
  429. BAIL_ON_FAILURE(HResult);
  430. HResult = TComObject->Init(*(m_IfArray->GetSdpBlob()));
  431. if ( FAILED(HResult) )
  432. {
  433. delete TComObject;
  434. return HResult;
  435. }
  436. HResult = TComObject->_InternalQueryInterface(T::ELEM_IF_ID, (void**)Interface);
  437. if (FAILED(HResult))
  438. {
  439. delete TComObject;
  440. return HResult;
  441. }
  442. // adjust index to c like index value
  443. HResult = m_IfArray->Add(Index-1, *Interface);
  444. if (FAILED(HResult))
  445. {
  446. delete TComObject;
  447. return HResult;
  448. }
  449. // add another reference count for the interface being returned
  450. (*Interface)->AddRef();
  451. return S_OK;
  452. }
  453. template <class T>
  454. STDMETHODIMP MY_COLL_IMPL<T>::Delete(
  455. /*[in]*/ LONG Index
  456. )
  457. {
  458. CLock Lock(g_DllLock);
  459. ASSERT(NULL != m_IfArray);
  460. BAIL_IF_NULL(m_IfArray, E_FAIL);
  461. // use 1-based index, VB like
  462. if ((Index < (LONG)1) || (Index > (LONG)m_IfArray->GetSize()))
  463. {
  464. return E_INVALIDARG;
  465. }
  466. // if the sdp blob doesn't exist, deletion is not allowed
  467. if ( NULL == m_IfArray->GetSdpBlob() )
  468. {
  469. return HRESULT_FROM_ERROR_CODE(SDPBLB_CONF_BLOB_DESTROYED);
  470. }
  471. // adjust index to c like index value, delete the instance
  472. m_IfArray->Delete(Index-1);
  473. return S_OK;
  474. }
  475. template <class T>
  476. STDMETHODIMP MY_COLL_IMPL<T>::get__NewEnum(
  477. /*[out, retval]*/ IUnknown **pVal
  478. )
  479. {
  480. CLock Lock(g_DllLock);
  481. ASSERT(NULL != m_IfArray);
  482. BAIL_IF_NULL(m_IfArray, E_FAIL);
  483. BAIL_IF_NULL(pVal, E_INVALIDARG);
  484. ENUM_VARIANT *EnumComObject;
  485. HRESULT HResult = ENUM_VARIANT::CreateInstance(&EnumComObject);
  486. BAIL_ON_FAILURE(HResult);
  487. HResult = EnumComObject->Init(
  488. m_IfArray->GetData(),
  489. m_IfArray->GetData() + m_IfArray->GetSize(),
  490. NULL, // no owner pUnk
  491. AtlFlagCopy // copy the array data
  492. );
  493. if ( FAILED(HResult) )
  494. {
  495. delete EnumComObject;
  496. return HResult;
  497. }
  498. // query for the IUnknown interface and return it
  499. HResult = EnumComObject->_InternalQueryInterface(IID_IUnknown, (void**)pVal);
  500. if ( FAILED(HResult) )
  501. {
  502. delete EnumComObject;
  503. return HResult;
  504. }
  505. return S_OK;
  506. }
  507. template <class T>
  508. STDMETHODIMP MY_COLL_IMPL<T>::get_Item(
  509. /*[in]*/ LONG Index,
  510. /*[out, retval]*/ ELEM_IF **pVal
  511. )
  512. {
  513. CLock Lock(g_DllLock);
  514. ASSERT(NULL != m_IfArray);
  515. BAIL_IF_NULL(m_IfArray, E_FAIL);
  516. BAIL_IF_NULL(pVal, E_INVALIDARG);
  517. // use 1-based index, VB like
  518. if ((Index < (LONG)1) || (Index > (LONG)m_IfArray->GetSize()))
  519. {
  520. return E_INVALIDARG;
  521. }
  522. *pVal = m_IfArray->GetAt(Index-1);
  523. (*pVal)->AddRef();
  524. return S_OK;
  525. }
  526. template <class T>
  527. STDMETHODIMP MY_COLL_IMPL<T>::get_Count(
  528. /*[out, retval]*/ LONG *pVal
  529. )
  530. {
  531. CLock Lock(g_DllLock);
  532. ASSERT(NULL != m_IfArray);
  533. BAIL_IF_NULL(m_IfArray, E_FAIL);
  534. BAIL_IF_NULL(pVal, E_INVALIDARG);
  535. *pVal = m_IfArray->GetSize();
  536. return S_OK;
  537. }
  538. template <class T>
  539. inline void
  540. MY_COLL_IMPL<T>::ClearSdpBlobRefs(
  541. )
  542. {
  543. m_IfArray->ClearSdpBlobRefs();
  544. }
  545. template <class T>
  546. /* virtual */
  547. MY_COLL_IMPL<T>::~MY_COLL_IMPL(
  548. )
  549. {
  550. // if an interface array exists, destroy it
  551. if ( NULL != m_IfArray )
  552. {
  553. if ( NULL != m_IfArray->GetSdpList() )
  554. {
  555. delete m_IfArray->GetSdpList();
  556. }
  557. delete m_IfArray;
  558. }
  559. }
  560. #endif // __BLB_COLLECTION_ENUMERATION_IMPL__