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.

1038 lines
32 KiB

  1. #pragma once
  2. // Extensions to ATL to enable things it doesn't natively support
  3. template <const CLSID* pcoclsid, const IID* psrcid, class tihclass = CMarsTypeInfoHolder>
  4. class MarsIProvideClassInfo2Impl : public IProvideClassInfo2Impl<pcoclsid, psrcid, NULL, 0, 0, tihclass>
  5. {
  6. };
  7. template <class T, const IID* piid, class tihclass = CMarsTypeInfoHolder>
  8. class MarsIDispatchImpl : public IDispatchImpl<T, piid, NULL, 0, 0, tihclass>
  9. {
  10. public:
  11. STDMETHOD(Invoke)(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags,
  12. DISPPARAMS *pdispparams, VARIANT *pvarResult,
  13. EXCEPINFO *pexcepinfo, UINT *puArgErr)
  14. {
  15. HRESULT hr = IDispatchImpl<T, piid, NULL, 0, 0, tihclass>::Invoke(dispidMember,
  16. riid,
  17. lcid,
  18. wFlags,
  19. pdispparams,
  20. pvarResult,
  21. pexcepinfo,
  22. puArgErr);
  23. hr = SanitizeResult(hr);
  24. if (DISP_E_EXCEPTION == hr)
  25. {
  26. // We're getting DISP_E_EXCEPTION returns which are not generated by Mars
  27. // whenever invalid parameter types are passed. They're probably coming
  28. // from oleaut itself.
  29. // ASSERT(NULL != m_pwszException);
  30. if ((NULL != m_pwszException) && (NULL != pexcepinfo))
  31. {
  32. memset(pexcepinfo, 0, sizeof(EXCEPINFO));
  33. pexcepinfo->wCode = (WORD)dispidMember;
  34. pexcepinfo->bstrSource = SysAllocString(L"OM Exception");
  35. pexcepinfo->bstrDescription = SysAllocString(m_pwszException);
  36. }
  37. }
  38. return hr;
  39. }
  40. protected:
  41. LPWSTR m_pwszException;
  42. };
  43. // each module implements this themselves
  44. HRESULT GetMarsTypeLib(ITypeLib **ppTypeLib);
  45. //==================================================================
  46. // Begin CComTypeInfoHolder override
  47. //
  48. // By providing our own CComTypeInfoHolder, we can load the type
  49. // library ourselves, rather than requiring it to be loaded from
  50. // the registry as ATL does. Only "GetTI" is changed from
  51. // ATL source. Since GetTI isn't virtual we need to duplicate
  52. // the entire class.
  53. // CMarsTypeInfoHolder accepts an ITypeLib * (with reference)
  54. // instead of a LIBID in m_plibid
  55. //
  56. //==================================================================
  57. // ATL doesn't support multiple LCID's at the same time
  58. // Whatever LCID is queried for first is the one that is used.
  59. class CMarsTypeInfoHolder
  60. {
  61. // Should be 'protected' but can cause compiler to generate fat code.
  62. public:
  63. const GUID* m_pguid;
  64. const GUID* m_plibid;
  65. WORD m_wMajor;
  66. WORD m_wMinor;
  67. ITypeInfo* m_pInfo;
  68. long m_dwRef;
  69. struct stringdispid
  70. {
  71. CComBSTR bstr;
  72. int nLen;
  73. DISPID id;
  74. };
  75. stringdispid* m_pMap;
  76. int m_nCount;
  77. public:
  78. HRESULT GetTI(LCID lcid, ITypeInfo** ppInfo)
  79. {
  80. HRESULT hr = S_OK;
  81. if (m_pInfo == NULL)
  82. hr = GetTI(lcid);
  83. *ppInfo = m_pInfo;
  84. if (m_pInfo != NULL)
  85. {
  86. m_pInfo->AddRef();
  87. hr = S_OK;
  88. }
  89. return hr;
  90. }
  91. HRESULT GetTI(LCID lcid);
  92. HRESULT EnsureTI(LCID lcid)
  93. {
  94. HRESULT hr = S_OK;
  95. if (m_pInfo == NULL)
  96. hr = GetTI(lcid);
  97. return hr;
  98. }
  99. // This function is called by the module on exit
  100. // It is registered through _Module.AddTermFunc()
  101. static void __stdcall Cleanup2(DWORD_PTR dw)
  102. {
  103. CMarsTypeInfoHolder* p = (CMarsTypeInfoHolder*) dw;
  104. if (p->m_pInfo != NULL)
  105. p->m_pInfo->Release();
  106. p->m_pInfo = NULL;
  107. delete [] p->m_pMap;
  108. p->m_pMap = NULL;
  109. }
  110. HRESULT GetTypeInfo(UINT /* itinfo */, LCID lcid, ITypeInfo** pptinfo)
  111. {
  112. HRESULT hRes = E_POINTER;
  113. if (pptinfo != NULL)
  114. hRes = GetTI(lcid, pptinfo);
  115. return hRes;
  116. }
  117. HRESULT GetIDsOfNames(REFIID /* riid */, LPOLESTR* rgszNames, UINT cNames,
  118. LCID lcid, DISPID* rgdispid)
  119. {
  120. HRESULT hRes = EnsureTI(lcid);
  121. if (m_pInfo != NULL)
  122. {
  123. for (int i=0; i<(int)cNames; i++)
  124. {
  125. int n = ocslen(rgszNames[i]);
  126. for (int j=m_nCount-1; j>=0; j--)
  127. {
  128. if ((n == m_pMap[j].nLen) &&
  129. (memcmp(m_pMap[j].bstr, rgszNames[i], m_pMap[j].nLen * sizeof(OLECHAR)) == 0))
  130. {
  131. rgdispid[i] = m_pMap[j].id;
  132. break;
  133. }
  134. // Give debug warning if we differ only in case
  135. //DEBUG_ONLY(StrEql(m_pMap[j].bstr, rgszNames[i]));
  136. }
  137. if (j < 0)
  138. {
  139. // Not a warning. Common for behaviors as Trident passes all calls to
  140. // our IDispatch for the first shot. We should possibly just return
  141. // failure in this case instead of delegating to oleaut.
  142. hRes = m_pInfo->GetIDsOfNames(rgszNames + i, 1, &rgdispid[i]);
  143. if (FAILED(hRes))
  144. break;
  145. }
  146. }
  147. }
  148. return hRes;
  149. }
  150. HRESULT Invoke(IDispatch* p, DISPID dispidMember, REFIID /* riid */,
  151. LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
  152. EXCEPINFO* pexcepinfo, UINT* puArgErr)
  153. {
  154. HRESULT hRes = EnsureTI(lcid);
  155. if (m_pInfo != NULL)
  156. hRes = m_pInfo->Invoke(p, dispidMember, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
  157. return hRes;
  158. }
  159. HRESULT LoadNameCache(ITypeInfo* pTypeInfo)
  160. {
  161. TYPEATTR* pta;
  162. HRESULT hr = pTypeInfo->GetTypeAttr(&pta);
  163. if (SUCCEEDED(hr))
  164. {
  165. m_nCount = pta->cFuncs;
  166. m_pMap = m_nCount == 0 ? 0 : new stringdispid[m_nCount];
  167. for (int i=0; i<m_nCount; i++)
  168. {
  169. FUNCDESC* pfd;
  170. if (SUCCEEDED(pTypeInfo->GetFuncDesc(i, &pfd)))
  171. {
  172. CComBSTR bstrName;
  173. if (SUCCEEDED(pTypeInfo->GetDocumentation(pfd->memid, &bstrName, NULL, NULL, NULL)))
  174. {
  175. m_pMap[i].bstr.Attach(bstrName.Detach());
  176. m_pMap[i].nLen = SysStringLen(m_pMap[i].bstr);
  177. m_pMap[i].id = pfd->memid;
  178. }
  179. pTypeInfo->ReleaseFuncDesc(pfd);
  180. }
  181. }
  182. pTypeInfo->ReleaseTypeAttr(pta);
  183. }
  184. return S_OK;
  185. }
  186. };
  187. inline HRESULT CMarsTypeInfoHolder::GetTI(LCID lcid)
  188. {
  189. UNREFERENCED_PARAMETER(lcid);
  190. // Change: removed asserts
  191. if (m_pInfo != NULL)
  192. return S_OK;
  193. HRESULT hRes = E_FAIL;
  194. EnterCriticalSection(&_Module.m_csTypeInfoHolder);
  195. if (m_pInfo == NULL)
  196. {
  197. ITypeLib* pTypeLib;
  198. // Here's a change
  199. // hRes = LoadRegTypeLib(*m_plibid, m_wMajor, m_wMinor, lcid, &pTypeLib);
  200. hRes = GetMarsTypeLib(&pTypeLib);
  201. // End change
  202. if (SUCCEEDED(hRes))
  203. {
  204. CComPtr<ITypeInfo> spTypeInfo;
  205. hRes = pTypeLib->GetTypeInfoOfGuid(*m_pguid, &spTypeInfo);
  206. if (SUCCEEDED(hRes))
  207. {
  208. CComPtr<ITypeInfo> spInfo(spTypeInfo);
  209. CComPtr<ITypeInfo2> spTypeInfo2;
  210. if (SUCCEEDED(spTypeInfo->QueryInterface(&spTypeInfo2)))
  211. spInfo = spTypeInfo2;
  212. LoadNameCache(spInfo);
  213. m_pInfo = spInfo.Detach();
  214. }
  215. pTypeLib->Release();
  216. }
  217. }
  218. LeaveCriticalSection(&_Module.m_csTypeInfoHolder);
  219. _Module.AddTermFunc(Cleanup2, (DWORD_PTR)this);
  220. return hRes;
  221. }
  222. //==================================================================
  223. // End CComTypeInfoHolder override
  224. //==================================================================
  225. // CComClassPtr is like CComPtr but it works with C++ classes, by not
  226. // assuming that we can cast to IUnknown unambiguously.
  227. // Use caution when initializing within your constructor. You can't
  228. // AddRef an object which hasn't finished constructing yet, so you can
  229. // only initialize smart pointers to object which don't contain you.
  230. template <class T>
  231. class _NoAddRefReleaseOnCComClassPtr : public T
  232. {
  233. public:
  234. // If you get a compile error here, make sure that the destructors
  235. // for any CComClassPtr<> classes are protected instead of private
  236. ~_NoAddRefReleaseOnCComClassPtr() {}
  237. private:
  238. STDMETHOD_(ULONG, AddRef)()=0;
  239. STDMETHOD_(ULONG, Release)()=0;
  240. };
  241. template <class T>
  242. class CComClassPtr
  243. {
  244. public:
  245. typedef T _PtrClass;
  246. CComClassPtr()
  247. {
  248. p=NULL;
  249. }
  250. CComClassPtr(T* lp)
  251. {
  252. if ((p = lp) != NULL)
  253. p->AddRef();
  254. }
  255. CComClassPtr(const CComClassPtr<T>& lp)
  256. {
  257. if ((p = lp.p) != NULL)
  258. p->AddRef();
  259. }
  260. ~CComClassPtr()
  261. {
  262. if (p)
  263. p->Release();
  264. }
  265. void Release()
  266. {
  267. T* pTemp = p;
  268. if (pTemp)
  269. {
  270. p = NULL;
  271. pTemp->Release();
  272. }
  273. }
  274. operator T*() const
  275. {
  276. return p;
  277. }
  278. T& operator*() const
  279. {
  280. ATLASSERT(p!=NULL);
  281. return *p;
  282. }
  283. //The assert on operator& usually indicates a bug. If this is really
  284. //what is needed, however, take the address of the p member explicitly.
  285. T** operator&()
  286. {
  287. ATLASSERT(p==NULL);
  288. return &p;
  289. }
  290. HRESULT PassivateAndRelease()
  291. {
  292. if (p)
  293. {
  294. HRESULT hr = p->Passivate();
  295. Release();
  296. return hr;
  297. }
  298. return S_FALSE;
  299. }
  300. _NoAddRefReleaseOnCComClassPtr<T>* operator->() const
  301. {
  302. ATLASSERT(p!=NULL);
  303. return (_NoAddRefReleaseOnCComClassPtr<T>*)p;
  304. }
  305. T* AtlComClassPtrAssign(T** pp, T* lp)
  306. {
  307. if (lp != NULL)
  308. lp->AddRef();
  309. if (*pp)
  310. (*pp)->Release();
  311. *pp = lp;
  312. return lp;
  313. }
  314. T* operator=(T* lp)
  315. {
  316. return AtlComClassPtrAssign(&p, lp);
  317. }
  318. T* operator=(const CComClassPtr<T>& lp)
  319. {
  320. return AtlComClassPtrAssign(&p, lp.p);
  321. }
  322. bool operator!() const
  323. {
  324. return (p == NULL);
  325. }
  326. bool operator<(T* pT) const
  327. {
  328. return p < pT;
  329. }
  330. bool operator==(T* pT) const
  331. {
  332. return p == pT;
  333. }
  334. // Compare two objects for equivalence
  335. bool IsEqualObject(T* pOther)
  336. {
  337. return (p == pOther);
  338. }
  339. void Attach(T* p2)
  340. {
  341. if (p)
  342. p->Release();
  343. p = p2;
  344. }
  345. T* Detach()
  346. {
  347. T* pt = p;
  348. p = NULL;
  349. return pt;
  350. }
  351. HRESULT CopyTo(T** ppT)
  352. {
  353. ATLASSERT(ppT != NULL);
  354. if (ppT == NULL)
  355. return E_POINTER;
  356. *ppT = p;
  357. if (p)
  358. p->AddRef();
  359. return S_OK;
  360. }
  361. template <class Q>
  362. HRESULT QueryInterface(Q** pp) const
  363. {
  364. ATLASSERT(pp != NULL && *pp == NULL);
  365. return p->QueryInterface(__uuidof(Q), (void**)pp);
  366. }
  367. T* p;
  368. };
  369. //////////////////////////////////////////////////////////////////////////////
  370. // CMarsComDispatchDriver / Specialization of CComQIPtr<IDispatch, IID_IDispatch>
  371. //
  372. // This is better than CComDispatchDriver for these reasons:
  373. // - CComDispatchDriver in atl30 doesn't define an assignment/copy constructor
  374. // - CcomDispatchDriver doesn't use _NoAddRefReleaseOnCComPtr
  375. // - Added "const" to methods which are const
  376. //
  377. class CMarsComDispatchDriver
  378. {
  379. public:
  380. CMarsComDispatchDriver()
  381. {
  382. p = NULL;
  383. }
  384. CMarsComDispatchDriver(IDispatch* lp)
  385. {
  386. if ((p = lp) != NULL)
  387. p->AddRef();
  388. }
  389. CMarsComDispatchDriver(IUnknown* lp)
  390. {
  391. p=NULL;
  392. if (lp != NULL)
  393. lp->QueryInterface(IID_IDispatch, (void **)&p);
  394. }
  395. CMarsComDispatchDriver(const CMarsComDispatchDriver& lp)
  396. {
  397. if ((p = lp.p) != NULL)
  398. p->AddRef();
  399. }
  400. ~CMarsComDispatchDriver() { if (p) p->Release(); }
  401. void Release() {if (p) p->Release(); p=NULL;}
  402. operator IDispatch*() const {return p;}
  403. IDispatch& operator*() const {ATLASSERT(p!=NULL); return *p; }
  404. IDispatch** operator&() {ATLASSERT(p==NULL); return &p; }
  405. _NoAddRefReleaseOnCComPtr<IDispatch>* operator->() const
  406. {
  407. ATLASSERT(p!=NULL);
  408. return (_NoAddRefReleaseOnCComPtr<IDispatch>*)p;
  409. }
  410. //IDispatch* operator->() {ATLASSERT(p!=NULL); return p; }
  411. IDispatch* operator=(IDispatch* lp){return (IDispatch*)AtlComPtrAssign((IUnknown**)&p, lp);}
  412. IDispatch* operator=(IUnknown* lp)
  413. {
  414. return (IDispatch*)AtlComQIPtrAssign((IUnknown**)&p, lp, IID_IDispatch);
  415. }
  416. IDispatch* operator=(const CMarsComDispatchDriver& lp)
  417. {
  418. return (IDispatch*)AtlComPtrAssign((IUnknown**)&p, lp.p);
  419. }
  420. BOOL operator!() const {return (p == NULL) ? TRUE : FALSE;}
  421. HRESULT GetPropertyByName(LPCOLESTR lpsz, VARIANT* pVar)
  422. {
  423. ATLASSERT(p);
  424. ATLASSERT(pVar);
  425. DISPID dwDispID;
  426. HRESULT hr = GetIDOfName(lpsz, &dwDispID);
  427. if (SUCCEEDED(hr))
  428. hr = GetProperty(p, dwDispID, pVar);
  429. return hr;
  430. }
  431. HRESULT GetProperty(DISPID dwDispID, VARIANT* pVar)
  432. {
  433. ATLASSERT(p);
  434. return GetProperty(p, dwDispID, pVar);
  435. }
  436. HRESULT PutPropertyByName(LPCOLESTR lpsz, VARIANT* pVar)
  437. {
  438. ATLASSERT(p);
  439. ATLASSERT(pVar);
  440. DISPID dwDispID;
  441. HRESULT hr = GetIDOfName(lpsz, &dwDispID);
  442. if (SUCCEEDED(hr))
  443. hr = PutProperty(p, dwDispID, pVar);
  444. return hr;
  445. }
  446. HRESULT PutProperty(DISPID dwDispID, VARIANT* pVar)
  447. {
  448. ATLASSERT(p);
  449. return PutProperty(p, dwDispID, pVar);
  450. }
  451. HRESULT GetIDOfName(LPCOLESTR lpsz, DISPID* pdispid)
  452. {
  453. return p->GetIDsOfNames(IID_NULL, (LPOLESTR*)&lpsz, 1, LOCALE_USER_DEFAULT, pdispid);
  454. }
  455. // Invoke a method by DISPID with no parameters
  456. HRESULT Invoke0(DISPID dispid, VARIANT* pvarRet = NULL)
  457. {
  458. DISPPARAMS dispparams = { NULL, NULL, 0, 0};
  459. return p->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, pvarRet, NULL, NULL);
  460. }
  461. // Invoke a method by name with no parameters
  462. HRESULT Invoke0(LPCOLESTR lpszName, VARIANT* pvarRet = NULL)
  463. {
  464. HRESULT hr;
  465. DISPID dispid;
  466. hr = GetIDOfName(lpszName, &dispid);
  467. if (SUCCEEDED(hr))
  468. hr = Invoke0(dispid, pvarRet);
  469. return hr;
  470. }
  471. // Invoke a method by DISPID with a single parameter
  472. HRESULT Invoke1(DISPID dispid, VARIANT* pvarParam1, VARIANT* pvarRet = NULL)
  473. {
  474. DISPPARAMS dispparams = { pvarParam1, NULL, 1, 0};
  475. return p->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, pvarRet, NULL, NULL);
  476. }
  477. // Invoke a method by name with a single parameter
  478. HRESULT Invoke1(LPCOLESTR lpszName, VARIANT* pvarParam1, VARIANT* pvarRet = NULL)
  479. {
  480. HRESULT hr;
  481. DISPID dispid;
  482. hr = GetIDOfName(lpszName, &dispid);
  483. if (SUCCEEDED(hr))
  484. hr = Invoke1(dispid, pvarParam1, pvarRet);
  485. return hr;
  486. }
  487. // Invoke a method by DISPID with two parameters
  488. HRESULT Invoke2(DISPID dispid, VARIANT* pvarParam1, VARIANT* pvarParam2, VARIANT* pvarRet = NULL)
  489. {
  490. CComVariant varArgs[2] = { *pvarParam2, *pvarParam1 };
  491. DISPPARAMS dispparams = { &varArgs[0], NULL, 2, 0};
  492. return p->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, pvarRet, NULL, NULL);
  493. }
  494. // Invoke a method by name with two parameters
  495. HRESULT Invoke2(LPCOLESTR lpszName, VARIANT* pvarParam1, VARIANT* pvarParam2, VARIANT* pvarRet = NULL)
  496. {
  497. HRESULT hr;
  498. DISPID dispid;
  499. hr = GetIDOfName(lpszName, &dispid);
  500. if (SUCCEEDED(hr))
  501. hr = Invoke2(dispid, pvarParam1, pvarParam2, pvarRet);
  502. return hr;
  503. }
  504. // Invoke a method by DISPID with N parameters
  505. HRESULT InvokeN(DISPID dispid, VARIANT* pvarParams, int nParams, VARIANT* pvarRet = NULL)
  506. {
  507. DISPPARAMS dispparams = { pvarParams, NULL, nParams, 0};
  508. return p->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, pvarRet, NULL, NULL);
  509. }
  510. // Invoke a method by name with Nparameters
  511. HRESULT InvokeN(LPCOLESTR lpszName, VARIANT* pvarParams, int nParams, VARIANT* pvarRet = NULL)
  512. {
  513. HRESULT hr;
  514. DISPID dispid;
  515. hr = GetIDOfName(lpszName, &dispid);
  516. if (SUCCEEDED(hr))
  517. hr = InvokeN(dispid, pvarParams, nParams, pvarRet);
  518. return hr;
  519. }
  520. static HRESULT GetProperty(IDispatch* pDisp, DISPID dwDispID,
  521. VARIANT* pVar)
  522. {
  523. ATLTRACE2(atlTraceCOM, 0, _T("CPropertyHelper::GetProperty\n"));
  524. DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
  525. return pDisp->Invoke(dwDispID, IID_NULL,
  526. LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET,
  527. &dispparamsNoArgs, pVar, NULL, NULL);
  528. }
  529. static HRESULT PutProperty(IDispatch* pDisp, DISPID dwDispID,
  530. VARIANT* pVar)
  531. {
  532. ATLTRACE2(atlTraceCOM, 0, _T("CPropertyHelper::PutProperty\n"));
  533. DISPPARAMS dispparams = {NULL, NULL, 1, 1};
  534. dispparams.rgvarg = pVar;
  535. DISPID dispidPut = DISPID_PROPERTYPUT;
  536. dispparams.rgdispidNamedArgs = &dispidPut;
  537. if (pVar->vt == VT_UNKNOWN || pVar->vt == VT_DISPATCH ||
  538. (pVar->vt & VT_ARRAY) || (pVar->vt & VT_BYREF))
  539. {
  540. HRESULT hr = pDisp->Invoke(dwDispID, IID_NULL,
  541. LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUTREF,
  542. &dispparams, NULL, NULL, NULL);
  543. if (SUCCEEDED(hr))
  544. return hr;
  545. }
  546. return pDisp->Invoke(dwDispID, IID_NULL,
  547. LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT,
  548. &dispparams, NULL, NULL, NULL);
  549. }
  550. IDispatch* p;
  551. };
  552. #define CComDispatchDriver _DONT_USE_CComDispatchDriver_USE_CMarsComDispatchDriver
  553. //////////////////////////////////////////////////////////////////////////////
  554. // CMarsSimpleArray / Specialization of CSimpleArray
  555. //
  556. // This is better than CSimpleArray for these reasons:
  557. // overloaded the operator=() and defined a copy constructor.
  558. // Fixed various pointer math to use + instead of & because the operator&()
  559. // on contained smart types (like CComPtr) gets called accidentally if you
  560. // do this: &m_aT[i] instead of (m_aT + i).
  561. //
  562. /////////////////////////////////////////////////////////////////////////////
  563. // Collection helpers - CMarsSimpleArray
  564. #ifdef new
  565. #pragma push_macro("new")
  566. #define _ATL_REDEF_NEW
  567. #undef new
  568. #endif
  569. template <class T>
  570. class CMarsSimpleArray
  571. {
  572. public:
  573. T* m_aT;
  574. int m_nSize;
  575. int m_nAllocSize;
  576. // Construction/destruction
  577. CMarsSimpleArray() : m_aT(NULL), m_nSize(0), m_nAllocSize(0)
  578. { }
  579. ~CMarsSimpleArray()
  580. {
  581. RemoveAll();
  582. }
  583. CMarsSimpleArray(const CMarsSimpleArray<T> &current) : m_aT(NULL), m_nSize(0), m_nAllocSize(0)
  584. {
  585. *this = current;
  586. }
  587. CMarsSimpleArray &operator=(const CMarsSimpleArray<T> &right)
  588. {
  589. if (&right != this)
  590. {
  591. // BUGBUG (tnoonan) -- this code is going to potentially leak
  592. // if the new size is smaller than the old.
  593. T *aT = NULL;
  594. aT = (T *)realloc(m_aT, right.m_nAllocSize * sizeof(T));
  595. // Did the realloc succeed?
  596. if (aT)
  597. {
  598. m_aT = aT;
  599. m_nSize = right.m_nSize;
  600. m_nAllocSize = right.m_nAllocSize;
  601. // WARNING: This is not a simple mempcy() for a very specific reason!
  602. // Each element must be copied with = in case the T class has an
  603. // overloaded operator=(). (i.e. in the case of smart ptrs).
  604. //
  605. for (int idx = 0; idx < m_nSize; ++idx)
  606. {
  607. m_aT[idx] = right.m_aT[idx];
  608. }
  609. }
  610. }
  611. return *this;
  612. }
  613. // Operations
  614. int GetSize() const
  615. {
  616. return m_nSize;
  617. }
  618. BOOL Add(T& t)
  619. {
  620. if(m_nSize == m_nAllocSize)
  621. {
  622. T* aT;
  623. int nNewAllocSize = (m_nAllocSize == 0) ? 1 : (m_nSize * 2);
  624. aT = (T*)realloc(m_aT, nNewAllocSize * sizeof(T));
  625. if(aT == NULL)
  626. return FALSE;
  627. m_nAllocSize = nNewAllocSize;
  628. m_aT = aT;
  629. }
  630. m_nSize++;
  631. SetAtIndex(m_nSize - 1, t);
  632. return TRUE;
  633. }
  634. BOOL Remove(T& t)
  635. {
  636. int nIndex = Find(t);
  637. if(nIndex == -1)
  638. return FALSE;
  639. return RemoveAt(nIndex);
  640. }
  641. BOOL RemoveAt(int nIndex)
  642. {
  643. ATLASSERT(nIndex >= 0 && nIndex < m_nSize);
  644. m_aT[nIndex].~T();
  645. if(nIndex != (m_nSize - 1))
  646. {
  647. //
  648. // BUGFIX: Use m_aT + nIndex instead of &m_aT[nIndex] to avoid calling type's operator &()
  649. //
  650. memmove((void*)(m_aT + nIndex), (void*)(m_aT + nIndex + 1), (m_nSize - (nIndex + 1)) * sizeof(T));
  651. ZeroMemory((void*)(m_aT + (m_nSize-1)), sizeof(m_aT[0]));
  652. }
  653. m_nSize--;
  654. return TRUE;
  655. }
  656. BOOL InsertAt(int nIndex, T& t)
  657. {
  658. // Index equal to size means to insert at the end
  659. ATLASSERT(nIndex >= 0 && nIndex <= m_nSize);
  660. // First check if we have room...
  661. if(m_nSize == m_nAllocSize)
  662. {
  663. T* aT;
  664. int nNewAllocSize = (m_nAllocSize == 0) ? 1 : (m_nSize * 2);
  665. aT = (T*)realloc(m_aT, nNewAllocSize * sizeof(T));
  666. if(aT == NULL)
  667. return FALSE;
  668. m_nAllocSize = nNewAllocSize;
  669. m_aT = aT;
  670. }
  671. // If we're not adding to the end, then we need to shift elements past the insertion point
  672. // down one.
  673. if (nIndex < m_nSize)
  674. {
  675. memmove( (void*)(m_aT + (nIndex + 1)), (void*)(m_aT + (nIndex)), sizeof(T) * (m_nSize - nIndex));
  676. // TRICKY: This memmove is a HACK -- it doesn't call the ctors and dtors of the elements.
  677. // However below, we're going to make an assignment, and that assignment is going to
  678. // cause the operator=() to fire on user types, which might mess up any
  679. // internal pointers. Ouch. We need to avoid that by wiping out the memory
  680. // destructively first.
  681. //
  682. // The reason this is bad is because the memmove has caused the nIndex and nIndex + 1
  683. // entries to both share the same data, including pointers, so we have danglers. :-(
  684. //
  685. ZeroMemory((void*)(m_aT + nIndex), sizeof(T));
  686. }
  687. m_nSize++;
  688. SetAtIndex(nIndex, t);
  689. return TRUE;
  690. }
  691. void RemoveAll()
  692. {
  693. if(m_aT != NULL)
  694. {
  695. for(int i = 0; i < m_nSize; i++)
  696. m_aT[i].~T();
  697. free(m_aT);
  698. m_aT = NULL;
  699. }
  700. m_nSize = 0;
  701. m_nAllocSize = 0;
  702. }
  703. T& operator[] (int nIndex) const
  704. {
  705. ATLASSERT(nIndex >= 0 && nIndex < m_nSize);
  706. return m_aT[nIndex];
  707. }
  708. T* GetData() const
  709. {
  710. return m_aT;
  711. }
  712. // Implementation
  713. class Wrapper
  714. {
  715. public:
  716. Wrapper(T& _t) : t(_t)
  717. {
  718. }
  719. template <class _Ty>
  720. void *operator new(size_t, _Ty* p)
  721. {
  722. return p;
  723. }
  724. T t;
  725. };
  726. void SetAtIndex(int nIndex, T& t)
  727. {
  728. ATLASSERT(nIndex >= 0 && nIndex < m_nSize);
  729. //
  730. // BUGFIX: Use m_aT + nIndex instead of &m_aT[nIndex] to avoid calling type's operator &()
  731. //
  732. new(m_aT + nIndex) Wrapper(t);
  733. }
  734. int Find(T& t) const
  735. {
  736. for(int i = 0; i < m_nSize; i++)
  737. {
  738. if(m_aT[i] == t)
  739. return i;
  740. }
  741. return -1; // not found
  742. }
  743. }; // CMarsSimpleArray
  744. // for arrays of simple types
  745. template <class T>
  746. class CMarsSimpleValArray : public CMarsSimpleArray< T >
  747. {
  748. public:
  749. BOOL Add(T t)
  750. {
  751. return CMarsSimpleArray< T >::Add(t);
  752. }
  753. BOOL Remove(T t)
  754. {
  755. return CMarsSimpleArray< T >::Remove(t);
  756. }
  757. T operator[] (int nIndex) const
  758. {
  759. return CMarsSimpleArray< T >::operator[](nIndex);
  760. }
  761. CMarsSimpleValArray &operator=(const CMarsSimpleValArray<T> &right)
  762. {
  763. if (&right != this)
  764. {
  765. T *aT = NULL;
  766. aT = (T *)realloc(m_aT, right.m_nAllocSize * sizeof(T));
  767. // Did the realloc succeed?
  768. if (aT)
  769. {
  770. m_aT = aT;
  771. m_nSize = right.m_nSize;
  772. m_nAllocSize = right.m_nAllocSize;
  773. CopyMemory(m_aT, right.m_aT, sizeof(T) * m_nSize);
  774. }
  775. }
  776. return *this;
  777. }
  778. };
  779. #ifdef _ATL_REDEF_NEW
  780. #pragma pop_macro("new")
  781. #undef _ATL_REDEF_NEW
  782. #endif
  783. //-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  784. // class CComTableMarshalPtr
  785. //-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  786. template <class I>
  787. class CComTableMarshalPtr : public CComPtr<I>
  788. {
  789. public:
  790. CComTableMarshalPtr(DWORD dwGITKey);
  791. virtual ~CComTableMarshalPtr();
  792. static HRESULT RegisterInterface(IUnknown *pUnk, DWORD *pdwKey);
  793. static HRESULT RevokeInterface(DWORD dwKey);
  794. private:
  795. CComTableMarshalPtr(); // Protect access to default ctor
  796. }; // CComTableMarshalPtr
  797. //============================================================================
  798. // class CComTableMarshalPtr
  799. //============================================================================
  800. template <class I>
  801. CComTableMarshalPtr<I>::CComTableMarshalPtr(DWORD dwKey)
  802. {
  803. CComPtr<IGlobalInterfaceTable> spGIT(CMarsGlobalsManager::GIT());
  804. if (spGIT)
  805. {
  806. I *pInt = NULL;
  807. HRESULT hr = spGIT->GetInterfaceFromGlobal(dwKey, __uuidof(I), (void **)&pInt);
  808. if (SUCCEEDED(hr))
  809. Attach(pInt);
  810. }
  811. } // CComTableMarshalPtr
  812. template <class I>
  813. CComTableMarshalPtr<I>::~CComTableMarshalPtr()
  814. {
  815. } // ~CComTableMarshalPtr
  816. //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  817. //
  818. //
  819. //
  820. //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  821. template <class I>
  822. HRESULT CComTableMarshalPtr<I>::RegisterInterface(IUnknown *pInt, DWORD *pdwKey)
  823. {
  824. HRESULT hr = E_INVALIDARG;
  825. if (IsValidInterfacePtr(pInt) && IsValidWritePtr(pdwKey))
  826. {
  827. CComPtr<IGlobalInterfaceTable> spGIT(CMarsGlobalsManager::GIT());
  828. ATLASSERT(spGIT);
  829. if (spGIT)
  830. {
  831. hr = spGIT->RegisterInterfaceInGlobal(pInt, __uuidof(I), pdwKey);
  832. }
  833. }
  834. return hr;
  835. } // RegisterInterface
  836. //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  837. //
  838. // CComTableMarshalPtr::RevokeInterface()
  839. //
  840. //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  841. template <class I>
  842. HRESULT CComTableMarshalPtr<I>::RevokeInterface(DWORD dwKey)
  843. {
  844. HRESULT hr = E_FAIL;
  845. CComPtr<IGlobalInterfaceTable> spGIT(CMarsGlobalsManager::GIT());
  846. ATLASSERT(spGIT);
  847. if (spGIT)
  848. {
  849. hr = spGIT->RevokeInterfaceFromGlobal(dwKey);
  850. }
  851. return hr;
  852. } // RevokeInterface
  853. typedef CComEnum<IEnumVARIANT, &IID_IEnumVARIANT, VARIANT, _Copy<VARIANT> > CComVariantEnum;
  854. //////////////////////////////////////////////////////////////////////////////
  855. // CMarsComEnumVariant - Simple derivation for convenience. This is the standard
  856. // type of a CComEnum for use in a collection that returns IEnumVARIANT.
  857. //
  858. // Our helper class has some luxury features that completely handle the common
  859. // case of take a CMarsSimpleArray full of "stuff," stuffing those things into
  860. // an array of CComVariant's (so we can be type-agnostic about what the
  861. // "things" are), and then creates a CComEnum and puts it in an out-param.
  862. //
  863. template <class I>
  864. class CMarsComEnumVariant :
  865. public CComEnum<IEnumVARIANT, &IID_IEnumVARIANT, VARIANT, _Copy<VARIANT> >
  866. {
  867. public:
  868. static HRESULT CreateFromMarsSimpleArray(CMarsSimpleArray<CComClassPtr< I > > &arr, IUnknown **ppUnk)
  869. {
  870. // Internal API, so rip if the out param is bad
  871. ATLASSERT(NULL != ppUnk);
  872. HRESULT hr = E_FAIL;
  873. // Create one of ourselves...
  874. CComObject<CMarsComEnumVariant<CMarsSimpleArray< CComClassPtr< I > > > > *pEnum = NULL;
  875. hr = CComObject<CMarsComEnumVariant<CMarsSimpleArray< CComClassPtr< I > > > >::CreateInstance(&pEnum);
  876. if (SUCCEEDED(hr))
  877. {
  878. // Allocation must have succeeded if no error HRESULT
  879. ATLASSERT(pEnum);
  880. pEnum->AddRef();
  881. VARIANT *rgVar = new VARIANT[arr.GetSize()];
  882. LONG idxEntry;
  883. if (rgVar)
  884. {
  885. HRESULT hrTestForDispatch = E_FAIL;
  886. for (idxEntry = 0; idxEntry < arr.GetSize(); idxEntry++)
  887. {
  888. CComClassPtr<I> spElt;
  889. spElt = arr.operator[](idxEntry);
  890. hrTestForDispatch = spElt->QueryInterface(IID_IDispatch, (void **)&V_DISPATCH(&rgVar[idxEntry]));
  891. //
  892. // This had better succeed: the type I must be a dispatch interface, because otherwise,
  893. // you can't pass this object to script anyway, so what's the point of the collection???
  894. // If you really want an IEnumXXXX for your non-automation interfaces, use ATL's CComEnum
  895. // directly with appropriate template parameters.
  896. //
  897. ATLASSERT(SUCCEEDED(hrTestForDispatch));
  898. V_VT(&rgVar[idxEntry]) = VT_DISPATCH;
  899. }
  900. // If this succeeds, then ATL will have taken care of freeing our array for
  901. // us. How nice of it.
  902. //
  903. hr = pEnum->Init(&rgVar[0], &rgVar[arr.GetSize()], NULL, AtlFlagTakeOwnership);
  904. if (SUCCEEDED(hr))
  905. {
  906. hr = pEnum->QueryInterface(IID_IUnknown, (void **)ppUnk);
  907. }
  908. else
  909. {
  910. for(idxEntry = 0; idxEntry < arr.GetSize(); idxEntry++)
  911. {
  912. VariantClear(&rgVar[idxEntry]);
  913. }
  914. delete[] rgVar;
  915. }
  916. }
  917. else
  918. {
  919. hr = E_OUTOFMEMORY;
  920. }
  921. pEnum->Release();
  922. } // If CreateInstance SUCCEEDED
  923. return hr;
  924. }
  925. };