home *** CD-ROM | disk | FTP | other *** search
/ Inter.Net 55-1 / Inter.Net 55-1.iso / CBuilder / Setup / BCB / data.z / atlcom.h < prev    next >
Encoding:
C/C++ Source or Header  |  1998-02-09  |  56.7 KB  |  2,134 lines

  1. // This is a part of the Active Template Library.
  2. // Copyright (C) 1996-1997 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Active Template Library Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Active Template Library product.
  10.  
  11. #ifndef __ATLCOM_H__
  12. #define __ATLCOM_H__
  13.  
  14. #ifndef __cplusplus
  15.     #error ATL requires C++ compilation (use a .cpp suffix)
  16. #endif
  17.  
  18. #ifndef __ATLBASE_H__
  19.     #error atlcom.h requires atlbase.h to be included first
  20. #endif
  21.  
  22. #pragma pack(push, _ATL_PACKING)
  23.  
  24. #ifndef ATL_NO_NAMESPACE
  25. namespace ATL
  26. {
  27. #endif
  28.  
  29. #define CComConnectionPointContainerImpl IConnectionPointContainerImpl
  30. #define CComISupportErrorInfoImpl ISupportErrorInfoImpl
  31. #define CComProvideClassInfo2Impl IProvideClassInfoImpl
  32. #define CComDualImpl IDispatchImpl
  33.  
  34. #ifdef _ATL_DEBUG_QI
  35. HRESULT WINAPI AtlDumpIID(REFIID iid, LPCTSTR pszClassName, HRESULT hr);
  36. #define _ATLDUMPIID(iid, name, hr) AtlDumpIID(iid, name, hr)
  37. #else
  38. #define _ATLDUMPIID(iid, name, hr) hr
  39. #endif
  40.  
  41. #ifdef _ATL_DEBUG_REFCOUNT
  42. //////////////////////////////////////////////////////////////////////////////
  43. // CComDebugRefCount for interface level ref counting
  44. class CComDebugRefCount
  45. {
  46. public:
  47.     CComDebugRefCount()
  48.     {
  49.         m_nRef = 0;
  50.     }
  51.     ~CComDebugRefCount()
  52.     {
  53.         _ASSERTE(m_nRef == 0);
  54.     }
  55.     long m_nRef;
  56. };
  57. #define _ATL_DEBUG_ADDREF_RELEASE_IMPL(className) \
  58. public:\
  59.     CComDebugRefCount _ref;\
  60.     virtual ULONG STDMETHODCALLTYPE _DebugAddRef(void) \
  61.     {return ((T*)this)->DebugAddRef(_ref.m_nRef, _T(#className));} \
  62.     virtual ULONG STDMETHODCALLTYPE _DebugRelease(void) \
  63.     {return ((T*)this)->DebugRelease(_ref.m_nRef, _T(#className));}
  64. #else
  65. #define _ATL_DEBUG_ADDREF_RELEASE_IMPL(className)\
  66.     virtual ULONG STDMETHODCALLTYPE AddRef(void) = 0;\
  67.     virtual ULONG STDMETHODCALLTYPE Release(void) = 0;
  68. #endif // _ATL_DEBUG_REFCOUNT
  69.  
  70.  
  71. HRESULT WINAPI AtlReportError(const CLSID& clsid, LPCOLESTR lpszDesc,
  72.     const IID& iid = GUID_NULL, HRESULT hRes = 0);
  73.  
  74. HRESULT WINAPI AtlReportError(const CLSID& clsid, LPCOLESTR lpszDesc,
  75.     DWORD dwHelpID, LPCOLESTR lpszHelpFile, const IID& iid = GUID_NULL,
  76.     HRESULT hRes = 0);
  77.  
  78. HRESULT WINAPI AtlReportError(const CLSID& clsid, UINT nID,
  79.     const IID& iid = GUID_NULL, HRESULT hRes = 0,
  80.     HINSTANCE hInst = _Module.GetResourceInstance());
  81.  
  82. HRESULT WINAPI AtlReportError(const CLSID& clsid, UINT nID,
  83.     DWORD dwHelpID, LPCOLESTR lpszHelpFile, const IID& iid = GUID_NULL,
  84.     HRESULT hRes = 0, HINSTANCE hInst = _Module.GetResourceInstance());
  85.  
  86. #ifndef OLE2ANSI
  87. HRESULT WINAPI AtlReportError(const CLSID& clsid, LPCSTR lpszDesc,
  88.     const IID& iid = GUID_NULL, HRESULT hRes = 0);
  89.  
  90. HRESULT WINAPI AtlReportError(const CLSID& clsid, LPCSTR lpszDesc,
  91.     DWORD dwHelpID, LPCSTR lpszHelpFile, const IID& iid = GUID_NULL,
  92.     HRESULT hRes = 0);
  93. #endif
  94.  
  95. #ifndef _ATL_NO_SECURITY
  96.  
  97. /////////////////////////////////////////////////////////////////////////////
  98. // CSecurityDescriptor
  99.  
  100. class CSecurityDescriptor
  101. {
  102. public:
  103.     CSecurityDescriptor();
  104.     ~CSecurityDescriptor();
  105.  
  106. public:
  107.     HRESULT Attach(PSECURITY_DESCRIPTOR pSelfRelativeSD);
  108.     HRESULT AttachObject(HANDLE hObject);
  109.     HRESULT Initialize();
  110.     HRESULT InitializeFromProcessToken(BOOL bDefaulted = FALSE);
  111.     HRESULT InitializeFromThreadToken(BOOL bDefaulted = FALSE, BOOL bRevertToProcessToken = TRUE);
  112.     HRESULT SetOwner(PSID pOwnerSid, BOOL bDefaulted = FALSE);
  113.     HRESULT SetGroup(PSID pGroupSid, BOOL bDefaulted = FALSE);
  114.     HRESULT Allow(LPCTSTR pszPrincipal, DWORD dwAccessMask);
  115.     HRESULT Deny(LPCTSTR pszPrincipal, DWORD dwAccessMask);
  116.     HRESULT Revoke(LPCTSTR pszPrincipal);
  117.  
  118.     // utility functions
  119.     // Any PSID you get from these functions should be free()ed
  120.     static HRESULT SetPrivilege(LPCTSTR Privilege, BOOL bEnable = TRUE, HANDLE hToken = NULL);
  121.     static HRESULT GetTokenSids(HANDLE hToken, PSID* ppUserSid, PSID* ppGroupSid);
  122.     static HRESULT GetProcessSids(PSID* ppUserSid, PSID* ppGroupSid = NULL);
  123.     static HRESULT GetThreadSids(PSID* ppUserSid, PSID* ppGroupSid = NULL, BOOL bOpenAsSelf = FALSE);
  124.     static HRESULT CopyACL(PACL pDest, PACL pSrc);
  125.     static HRESULT GetCurrentUserSID(PSID *ppSid);
  126.     static HRESULT GetPrincipalSID(LPCTSTR pszPrincipal, PSID *ppSid);
  127.     static HRESULT AddAccessAllowedACEToACL(PACL *Acl, LPCTSTR pszPrincipal, DWORD dwAccessMask);
  128.     static HRESULT AddAccessDeniedACEToACL(PACL *Acl, LPCTSTR pszPrincipal, DWORD dwAccessMask);
  129.     static HRESULT RemovePrincipalFromACL(PACL Acl, LPCTSTR pszPrincipal);
  130.  
  131.     operator PSECURITY_DESCRIPTOR()
  132.     {
  133.         return m_pSD;
  134.     }
  135.  
  136. public:
  137.     PSECURITY_DESCRIPTOR m_pSD;
  138.     PSID m_pOwner;
  139.     PSID m_pGroup;
  140.     PACL m_pDACL;
  141.     PACL m_pSACL;
  142. };
  143.  
  144. #endif // _ATL_NO_SECURITY
  145.  
  146. /////////////////////////////////////////////////////////////////////////////
  147. // COM Objects
  148.  
  149. #define DECLARE_PROTECT_FINAL_CONSTRUCT()\
  150.     void InternalFinalConstructAddRef() {InternalAddRef();}\
  151.     void InternalFinalConstructRelease() {InternalRelease();}
  152.  
  153. template <class T1>
  154. class CComCreator
  155. {
  156. public:
  157.     static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv)
  158.     {
  159.         _ASSERTE(*ppv == NULL);
  160.         HRESULT hRes = E_OUTOFMEMORY;
  161.         T1* p = NULL;
  162.         ATLTRY(p = new T1(pv))
  163.         if (p != NULL)
  164.         {
  165.             p->SetVoid(pv);
  166.             p->InternalFinalConstructAddRef();
  167.             hRes = p->FinalConstruct();
  168.             p->InternalFinalConstructRelease();
  169.             if (hRes == S_OK)
  170.                 hRes = p->QueryInterface(riid, ppv);
  171.             if (hRes != S_OK)
  172.                 delete p;
  173.         }
  174.         return hRes;
  175.     }
  176. };
  177.  
  178. template <class T1>
  179. class CComInternalCreator
  180. {
  181. public:
  182.     static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv)
  183.     {
  184.         _ASSERTE(*ppv == NULL);
  185.         HRESULT hRes = E_OUTOFMEMORY;
  186.         T1* p = NULL;
  187.         ATLTRY(p = new T1(pv))
  188.         if (p != NULL)
  189.         {
  190.             p->SetVoid(pv);
  191.             p->InternalFinalConstructAddRef();
  192.             hRes = p->FinalConstruct();
  193.             p->InternalFinalConstructRelease();
  194.             if (hRes == S_OK)
  195.                 hRes = p->_InternalQueryInterface(riid, ppv);
  196.             if (hRes != S_OK)
  197.                 delete p;
  198.         }
  199.         return hRes;
  200.     }
  201. };
  202.  
  203. template <HRESULT hr>
  204. class CComFailCreator
  205. {
  206. public:
  207.     static HRESULT WINAPI CreateInstance(void*, REFIID, LPVOID*)
  208.     {
  209.         return hr;
  210.     }
  211. };
  212.  
  213. template <class T1, class T2>
  214. class CComCreator2
  215. {
  216. public:
  217.     static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv)
  218.     {
  219.         _ASSERTE(*ppv == NULL);
  220.         HRESULT hRes = E_OUTOFMEMORY;
  221.         if (pv == NULL)
  222.             hRes = T1::CreateInstance(NULL, riid, ppv);
  223.         else
  224.             hRes = T2::CreateInstance(pv, riid, ppv);
  225.         return hRes;
  226.     }
  227. };
  228.  
  229. #define DECLARE_NOT_AGGREGATABLE(x) public:\
  230.     typedef CComCreator2< CComCreator< CComObject< x > >, CComFailCreator<CLASS_E_NOAGGREGATION> > _CreatorClass;
  231. #define DECLARE_AGGREGATABLE(x) public:\
  232.     typedef CComCreator2< CComCreator< CComObject< x > >, CComCreator< CComAggObject< x > > > _CreatorClass;
  233. #define DECLARE_ONLY_AGGREGATABLE(x) public:\
  234.     typedef CComCreator2< CComFailCreator<E_FAIL>, CComCreator< CComAggObject< x > > > _CreatorClass;
  235. #define DECLARE_POLY_AGGREGATABLE(x) public:\
  236.     typedef CComCreator< CComPolyObject< x > > _CreatorClass;
  237.  
  238. struct _ATL_CREATORDATA
  239. {
  240.     _ATL_CREATORFUNC* pFunc;
  241. };
  242.  
  243. template <class Creator>
  244. class _CComCreatorData
  245. {
  246. public:
  247.     static _ATL_CREATORDATA data;
  248. };
  249.  
  250. template <class Creator>
  251. _ATL_CREATORDATA _CComCreatorData<Creator>::data = {Creator::CreateInstance};
  252.  
  253. struct _ATL_CACHEDATA
  254. {
  255.     DWORD dwOffsetVar;
  256.     _ATL_CREATORFUNC* pFunc;
  257. };
  258.  
  259. template <class Creator, DWORD dwVar>
  260. class _CComCacheData
  261. {
  262. public:
  263.     static _ATL_CACHEDATA data;
  264. };
  265.  
  266. template <class Creator, DWORD dwVar>
  267. _ATL_CACHEDATA _CComCacheData<Creator, dwVar>::data = {dwVar, Creator::CreateInstance};
  268.  
  269. struct _ATL_CHAINDATA
  270. {
  271.     DWORD dwOffset;
  272.     const _ATL_INTMAP_ENTRY* (WINAPI *pFunc)();
  273. };
  274.  
  275. template <class base, class derived>
  276. class _CComChainData
  277. {
  278. public:
  279.     static _ATL_CHAINDATA data;
  280. };
  281.  
  282. template <class base, class derived>
  283. _ATL_CHAINDATA _CComChainData<base, derived>::data =
  284.     {offsetofclass(base, derived), base::_GetEntries};
  285.  
  286. template <class T, const CLSID* pclsid>
  287. class CComAggregateCreator
  288. {
  289. public:
  290.     static HRESULT WINAPI CreateInstance(void* pv, REFIID/*riid*/, LPVOID* ppv)
  291.     {
  292.         _ASSERTE(*ppv == NULL);
  293.         _ASSERTE(pv != NULL);
  294.         T* p = (T*) pv;
  295.         // Add the following line to your object if you get a message about
  296.         // GetControllingUnknown() being undefined
  297.         // DECLARE_GET_CONTROLLING_UNKNOWN()
  298.         return CoCreateInstance(*pclsid, p->GetControllingUnknown(), CLSCTX_INPROC, IID_IUnknown, ppv);
  299.     }
  300. };
  301.  
  302. #ifdef _ATL_DEBUG_QI
  303. #define DEBUG_QI_ENTRY(x) \
  304.         {NULL, \
  305.         (DWORD)_T(#x), \
  306.         (_ATL_CREATORARGFUNC*)0},
  307. #else
  308. #define DEBUG_QI_ENTRY(x)
  309. #endif //_ATL_DEBUG_QI
  310.  
  311. //If you get a message that FinalConstruct is ambiguous then you need to
  312. // override it in your class and call each base class' version of this
  313. #define BEGIN_COM_MAP(x) public: \
  314.     typedef x _ComMapClass; \
  315.     static HRESULT WINAPI _Cache(void* pv, REFIID iid, void** ppvObject, DWORD dw)\
  316.     {\
  317.         _ComMapClass* p = (_ComMapClass*)pv;\
  318.         p->Lock();\
  319.         HRESULT hRes = CComObjectRootBase::_Cache(pv, iid, ppvObject, dw);\
  320.         p->Unlock();\
  321.         return hRes;\
  322.     }\
  323.     IUnknown* GetUnknown() \
  324.     { _ASSERTE(_GetEntries()[0].pFunc == _ATL_SIMPLEMAPENTRY); return (IUnknown*)((int)this+_GetEntries()->dw); } \
  325.     HRESULT _InternalQueryInterface(REFIID iid, void** ppvObject) \
  326.     { return InternalQueryInterface(this, _GetEntries(), iid, ppvObject); } \
  327.     const static _ATL_INTMAP_ENTRY* WINAPI _GetEntries() { \
  328.     static const _ATL_INTMAP_ENTRY _entries[] = { DEBUG_QI_ENTRY(x)
  329.  
  330. #define DECLARE_GET_CONTROLLING_UNKNOWN() public:\
  331.     virtual IUnknown* GetControllingUnknown() {return GetUnknown();}
  332.  
  333. #define COM_INTERFACE_ENTRY_BREAK(x)\
  334.     {&IID_##x, \
  335.     NULL, \
  336.     _Break},
  337.  
  338. #define COM_INTERFACE_ENTRY_NOINTERFACE(x)\
  339.     {&IID_##x, \
  340.     NULL, \
  341.     _NoInterface},
  342.  
  343. #define COM_INTERFACE_ENTRY(x)\
  344.     {&IID_##x, \
  345.     offsetofclass(x, _ComMapClass), \
  346.     _ATL_SIMPLEMAPENTRY},
  347.  
  348. #define COM_INTERFACE_ENTRY_IID(iid, x)\
  349.     {&iid,\
  350.     offsetofclass(x, _ComMapClass),\
  351.     _ATL_SIMPLEMAPENTRY},
  352.  
  353. #define COM_INTERFACE_ENTRY_IMPL(x)\
  354.     COM_INTERFACE_ENTRY_IID(IID_##x, x##Impl<_ComMapClass>)
  355.  
  356. #define COM_INTERFACE_ENTRY_IMPL_IID(iid, x)\
  357.     COM_INTERFACE_ENTRY_IID(iid, x##Impl<_ComMapClass>)
  358.  
  359. #define COM_INTERFACE_ENTRY2(x, x2)\
  360.     {&IID_##x,\
  361.     (DWORD)((x*)(x2*)((_ComMapClass*)8))-8,\
  362.     _ATL_SIMPLEMAPENTRY},
  363.  
  364. #define COM_INTERFACE_ENTRY2_IID(iid, x, x2)\
  365.     {&iid,\
  366.     (DWORD)((x*)(x2*)((_ComMapClass*)8))-8,\
  367.     _ATL_SIMPLEMAPENTRY},
  368.  
  369. #define COM_INTERFACE_ENTRY_FUNC(iid, dw, func)\
  370.     {&iid, \
  371.     dw, \
  372.     func},
  373.  
  374. #define COM_INTERFACE_ENTRY_FUNC_BLIND(dw, func)\
  375.     {NULL, \
  376.     dw, \
  377.     func},
  378.  
  379. #define COM_INTERFACE_ENTRY_TEAR_OFF(iid, x)\
  380.     {&iid,\
  381.     (DWORD)&_CComCreatorData<\
  382.         CComInternalCreator< CComTearOffObject< x > >\
  383.         >::data,\
  384.     _Creator},
  385.  
  386. #define COM_INTERFACE_ENTRY_CACHED_TEAR_OFF(iid, x, punk)\
  387.     {&iid,\
  388.     (DWORD)&_CComCacheData<\
  389.         CComCreator< CComCachedTearOffObject< x > >,\
  390.         (DWORD)offsetof(_ComMapClass, punk)\
  391.         >::data,\
  392.     _Cache},
  393.  
  394. #define COM_INTERFACE_ENTRY_AGGREGATE(iid, punk)\
  395.     {&iid,\
  396.     (DWORD)offsetof(_ComMapClass, punk),\
  397.     _Delegate},
  398.  
  399. #define COM_INTERFACE_ENTRY_AGGREGATE_BLIND(punk)\
  400.     {NULL,\
  401.     (DWORD)offsetof(_ComMapClass, punk),\
  402.     _Delegate},
  403.  
  404. #define COM_INTERFACE_ENTRY_AUTOAGGREGATE(iid, punk, clsid)\
  405.     {&iid,\
  406.     (DWORD)&_CComCacheData<\
  407.         CComAggregateCreator<_ComMapClass, &clsid>,\
  408.         (DWORD)offsetof(_ComMapClass, punk)\
  409.         >::data,\
  410.     _Cache},
  411.  
  412. #define COM_INTERFACE_ENTRY_AUTOAGGREGATE_BLIND(punk, clsid)\
  413.     {NULL,\
  414.     (DWORD)&_CComCacheData<\
  415.         CComAggregateCreator<_ComMapClass, &clsid>,\
  416.         (DWORD)offsetof(_ComMapClass, punk)\
  417.         >::data,\
  418.     _Cache},
  419.  
  420. #define COM_INTERFACE_ENTRY_CHAIN(classname)\
  421.     {NULL,\
  422.     (DWORD)&_CComChainData<classname, _ComMapClass>::data,\
  423.     _Chain},
  424.  
  425. #ifdef _ATL_DEBUG_QI
  426. #define END_COM_MAP()   {NULL, 0, 0}};\
  427.     return &_entries[1];}
  428. #else
  429. #define END_COM_MAP()   {NULL, 0, 0}};\
  430.     return _entries;}
  431. #endif // _ATL_DEBUG_QI
  432.  
  433. #define BEGIN_OBJECT_MAP(x) static _ATL_OBJMAP_ENTRY x[] = {
  434. #define END_OBJECT_MAP()   {NULL, NULL, NULL, NULL}};
  435. #define OBJECT_ENTRY(clsid, class) {&clsid, &class::UpdateRegistry, &class::_ClassFactoryCreatorClass::CreateInstance, &class::_CreatorClass::CreateInstance, NULL, 0, &class::GetObjectDescription },
  436.  
  437. #ifdef _ATL_DEBUG_QI
  438. extern HRESULT WINAPI AtlDumpIID(REFIID iid, LPCTSTR pszClassName, HRESULT hr);
  439. #endif // _ATL_DEBUG_QI
  440.  
  441.  
  442. // the functions in this class don't need to be virtual because
  443. // they are called from CComObject
  444. class CComObjectRootBase
  445. {
  446. public:
  447.     CComObjectRootBase()
  448.     {
  449.         m_dwRef = 0L;
  450.     }
  451.     HRESULT FinalConstruct()
  452.     {
  453.         return S_OK;
  454.     }
  455.     void FinalRelease() {}
  456.  
  457.     static HRESULT WINAPI InternalQueryInterface(void* pThis,
  458.         const _ATL_INTMAP_ENTRY* pEntries, REFIID iid, void** ppvObject)
  459.     {
  460.         _ASSERTE(pThis != NULL);
  461.         // First entry in the com map should be a simple map entry
  462.         _ASSERTE(pEntries->pFunc == _ATL_SIMPLEMAPENTRY);
  463.     #ifdef _ATL_DEBUG_QI
  464.         LPCTSTR pszClassName = (LPCTSTR) pEntries[-1].dw;
  465.     #endif // _ATL_DEBUG_QI
  466.         HRESULT hRes = AtlInternalQueryInterface(pThis, pEntries, iid, ppvObject);
  467.         return _ATLDUMPIID(iid, pszClassName, hRes);
  468.     }
  469.  
  470. //Outer funcs
  471.     ULONG OuterAddRef()
  472.     {
  473.         return m_pOuterUnknown->AddRef();
  474.     }
  475.     ULONG OuterRelease()
  476.     {
  477.         return m_pOuterUnknown->Release();
  478.     }
  479.     HRESULT OuterQueryInterface(REFIID iid, void ** ppvObject)
  480.     {
  481.         return m_pOuterUnknown->QueryInterface(iid, ppvObject);
  482.     }
  483.  
  484.     void SetVoid(void*) {}
  485.     void InternalFinalConstructAddRef() {}
  486.     void InternalFinalConstructRelease()
  487.     {
  488.         _ASSERTE(m_dwRef == 0);
  489.     }
  490.     // If this assert occurs, your object has probably been deleted
  491.     // Try using DECLARE_PROTECT_FINAL_CONSTRUCT()
  492.  
  493.  
  494.     static HRESULT WINAPI _Break(void* pv, REFIID iid, void** ppvObject, DWORD dw);
  495.     static HRESULT WINAPI _NoInterface(void* pv, REFIID iid, void** ppvObject, DWORD dw);
  496.     static HRESULT WINAPI _Creator(void* pv, REFIID iid, void** ppvObject, DWORD dw);
  497.     static HRESULT WINAPI _Delegate(void* pv, REFIID iid, void** ppvObject, DWORD dw);
  498.     static HRESULT WINAPI _Chain(void* pv, REFIID iid, void** ppvObject, DWORD dw);
  499.     static HRESULT WINAPI _Cache(void* pv, REFIID iid, void** ppvObject, DWORD dw);
  500.  
  501.     union
  502.     {
  503.         long m_dwRef;
  504.         IUnknown* m_pOuterUnknown;
  505.     };
  506. };
  507.  
  508. template <class ThreadModel>
  509. class CComObjectRootEx : public CComObjectRootBase
  510. {
  511. public:
  512.     typedef ThreadModel _ThreadModel;
  513.     typedef _ThreadModel::AutoCriticalSection _CritSec;
  514.  
  515.     ULONG InternalAddRef()
  516.     {
  517.         _ASSERTE(m_dwRef != -1L);
  518.         return _ThreadModel::Increment(&m_dwRef);
  519.     }
  520.     ULONG InternalRelease()
  521.     {
  522.         return _ThreadModel::Decrement(&m_dwRef);
  523.     }
  524.  
  525. #ifdef _ATL_DEBUG_REFCOUNT
  526.     ULONG DebugAddRef(long& dw, LPCTSTR lpszClassName)
  527.     {
  528.         _ThreadModel::Increment(&dw);
  529.         ATLTRACE(_T("%s %d>\n"), lpszClassName, dw);
  530.         return AddRef();
  531.     }
  532.     ULONG DebugRelease(long& dw, LPCTSTR lpszClassName)
  533.     {
  534.         _ThreadModel::Decrement(&dw);
  535.         ATLTRACE(_T("%s %d<\n"), lpszClassName, dw);
  536.         return Release();
  537.     }
  538.     virtual ULONG STDMETHODCALLTYPE AddRef( void) = 0;
  539.     virtual ULONG STDMETHODCALLTYPE Release( void) = 0;
  540. #endif // _ATL_DEBUG_REFCOUNT
  541.  
  542.     void Lock() {m_critsec.Lock();}
  543.     void Unlock() {m_critsec.Unlock();}
  544. private:
  545.     _CritSec m_critsec;
  546. };
  547.  
  548. #if _MSC_VER>1020
  549. template <>
  550. #endif
  551. class CComObjectRootEx<CComSingleThreadModel> : public CComObjectRootBase
  552. {
  553. public:
  554.     typedef CComSingleThreadModel _ThreadModel;
  555.     typedef _ThreadModel::AutoCriticalSection _CritSec;
  556.  
  557.     ULONG InternalAddRef()
  558.     {
  559.         _ASSERTE(m_dwRef != -1L);
  560.         return _ThreadModel::Increment(&m_dwRef);
  561.     }
  562.     ULONG InternalRelease()
  563.     {
  564.         return _ThreadModel::Decrement(&m_dwRef);
  565.     }
  566.  
  567. #ifdef _ATL_DEBUG_REFCOUNT
  568.     ULONG DebugAddRef(long& dw, LPCTSTR lpszClassName)
  569.     {
  570.         _ThreadModel::Increment(&dw);
  571.         ATLTRACE(_T("%s %d>\n"), lpszClassName, dw);
  572.         return AddRef();
  573.     }
  574.     ULONG DebugRelease(long& dw, LPCTSTR lpszClassName)
  575.     {
  576.         _ThreadModel::Decrement(&dw);
  577.         ATLTRACE(_T("%s %d<\n"), lpszClassName, dw);
  578.         return Release();
  579.     }
  580.     virtual ULONG STDMETHODCALLTYPE AddRef( void) = 0;
  581.     virtual ULONG STDMETHODCALLTYPE Release( void) = 0;
  582. #endif // _ATL_DEBUG_REFCOUNT
  583.  
  584.     void Lock() {}
  585.     void Unlock() {}
  586. };
  587.  
  588. typedef CComObjectRootEx<CComObjectThreadModel> CComObjectRoot;
  589.  
  590. #if defined(_WINDLL) | defined(_USRDLL)
  591. #define DECLARE_CLASSFACTORY_EX(cf) typedef CComCreator< CComObjectCached< cf > > _ClassFactoryCreatorClass;
  592. #else
  593. // don't let class factory refcount influence lock count
  594. #define DECLARE_CLASSFACTORY_EX(cf) typedef CComCreator< CComObjectNoLock< cf > > _ClassFactoryCreatorClass;
  595. #endif
  596. #define DECLARE_CLASSFACTORY() DECLARE_CLASSFACTORY_EX(CComClassFactory)
  597. #define DECLARE_CLASSFACTORY2(lic) DECLARE_CLASSFACTORY_EX(CComClassFactory2<lic>)
  598. #define DECLARE_CLASSFACTORY_AUTO_THREAD() DECLARE_CLASSFACTORY_EX(CComClassFactoryAutoThread)
  599. #define DECLARE_CLASSFACTORY_SINGLETON(obj) DECLARE_CLASSFACTORY_EX(CComClassFactorySingleton<obj>)
  600.  
  601. #define DECLARE_OBJECT_DESCRIPTION(x)\
  602.     static LPCTSTR WINAPI GetObjectDescription()\
  603.     {\
  604.         return _T(x);\
  605.     }
  606.  
  607. #define DECLARE_NO_REGISTRY()\
  608.     static HRESULT WINAPI UpdateRegistry(BOOL /*bRegister*/)\
  609.     {return S_OK;}
  610.  
  611. #define DECLARE_REGISTRY(class, pid, vpid, nid, flags)\
  612.     static HRESULT WINAPI UpdateRegistry(BOOL bRegister)\
  613.     {\
  614.         return _Module.UpdateRegistryClass(GetObjectCLSID(), pid, vpid, nid,\
  615.             flags, bRegister);\
  616.     }
  617.  
  618. #define DECLARE_REGISTRY_RESOURCE(x)\
  619.     static HRESULT WINAPI UpdateRegistry(BOOL bRegister)\
  620.     {\
  621.     return _Module.UpdateRegistryFromResource(_T(#x), bRegister);\
  622.     }
  623.  
  624. #define DECLARE_REGISTRY_RESOURCEID(x)\
  625.     static HRESULT WINAPI UpdateRegistry(BOOL bRegister)\
  626.     {\
  627.     return _Module.UpdateRegistryFromResource(x, bRegister);\
  628.     }
  629.  
  630. //DECLARE_STATIC_* provided for backward compatibility
  631. #ifdef _ATL_STATIC_REGISTRY
  632. #define DECLARE_STATIC_REGISTRY_RESOURCE(x) DECLARE_REGISTRY_RESOURCE(x)
  633. #define DECLARE_STATIC_REGISTRY_RESOURCEID(x) DECLARE_REGISTRY_RESOURCEID(x)
  634. #endif //_ATL_STATIC_REGISTRY
  635.  
  636. template<class Base> class CComObject; // fwd decl
  637.  
  638. template <class Owner, class ThreadModel = CComObjectThreadModel>
  639. class CComTearOffObjectBase : public CComObjectRootEx<ThreadModel>
  640. {
  641. public:
  642.     typedef Owner _OwnerClass;
  643.     CComObject<Owner>* m_pOwner;
  644.     CComTearOffObjectBase() {m_pOwner = NULL;}
  645. };
  646.  
  647. //Base is the user's class that derives from CComObjectRoot and whatever
  648. //interfaces the user wants to support on the object
  649. template <class Base>
  650. class CComObject : public Base
  651. {
  652. public:
  653.     typedef Base _BaseClass;
  654.     CComObject(void* = NULL)
  655.     {
  656.         _Module.Lock();
  657.     }
  658.     // Set refcount to 1 to protect destruction
  659.     ~CComObject()
  660.     {
  661.         m_dwRef = 1L;
  662.         FinalRelease();
  663.         _Module.Unlock();
  664.     }
  665.     //If InternalAddRef or InteralRelease is undefined then your class
  666.     //doesn't derive from CComObjectRoot
  667.     STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();}
  668.     STDMETHOD_(ULONG, Release)()
  669.     {
  670.         ULONG l = InternalRelease();
  671.         if (l == 0)
  672.             delete this;
  673.         return l;
  674.     }
  675.     //if _InternalQueryInterface is undefined then you forgot BEGIN_COM_MAP
  676.     STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  677.     {return _InternalQueryInterface(iid, ppvObject);}
  678.     static HRESULT WINAPI CreateInstance(CComObject<Base>** pp);
  679. };
  680.  
  681. template <class Base>
  682. HRESULT WINAPI CComObject<Base>::CreateInstance(CComObject<Base>** pp)
  683. {
  684.     _ASSERTE(pp != NULL);
  685.     HRESULT hRes = E_OUTOFMEMORY;
  686.     CComObject<Base>* p = NULL;
  687.     ATLTRY(p = new CComObject<Base>())
  688.     if (p != NULL)
  689.     {
  690.         p->SetVoid(NULL);
  691.         p->InternalFinalConstructAddRef();
  692.         hRes = p->FinalConstruct();
  693.         p->InternalFinalConstructRelease();
  694.         if (hRes != S_OK)
  695.         {
  696.             delete p;
  697.             p = NULL;
  698.         }
  699.     }
  700.     *pp = p;
  701.     return hRes;
  702. }
  703.  
  704. //Base is the user's class that derives from CComObjectRoot and whatever
  705. //interfaces the user wants to support on the object
  706. // CComObjectCached is used primarily for class factories in DLL's
  707. // but it is useful anytime you want to cache an object
  708. template <class Base>
  709. class CComObjectCached : public Base
  710. {
  711. public:
  712.     typedef Base _BaseClass;
  713.     CComObjectCached(void* = NULL){}
  714.     // Set refcount to 1 to protect destruction
  715.     ~CComObjectCached(){m_dwRef = 1L; FinalRelease();}
  716.     //If InternalAddRef or InteralRelease is undefined then your class
  717.     //doesn't derive from CComObjectRoot
  718.     STDMETHOD_(ULONG, AddRef)()
  719.     {
  720.         m_csCached.Lock();
  721.         ULONG l = InternalAddRef();
  722.         if (m_dwRef == 2)
  723.             _Module.Lock();
  724.         m_csCached.Unlock();
  725.         return l;
  726.     }
  727.     STDMETHOD_(ULONG, Release)()
  728.     {
  729.         m_csCached.Lock();
  730.         InternalRelease();
  731.         ULONG l = m_dwRef;
  732.         m_csCached.Unlock();
  733.         if (l == 0)
  734.             delete this;
  735.         else if (l == 1)
  736.             _Module.Unlock();
  737.         return l;
  738.     }
  739.     //if _InternalQueryInterface is undefined then you forgot BEGIN_COM_MAP
  740.     STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  741.     {return _InternalQueryInterface(iid, ppvObject);}
  742.     CComGlobalsThreadModel::AutoCriticalSection m_csCached;
  743. };
  744.  
  745. //Base is the user's class that derives from CComObjectRoot and whatever
  746. //interfaces the user wants to support on the object
  747. template <class Base>
  748. class CComObjectNoLock : public Base
  749. {
  750. public:
  751.     typedef Base _BaseClass;
  752.     CComObjectNoLock(void* = NULL){}
  753.     // Set refcount to 1 to protect destruction
  754.     ~CComObjectNoLock() {m_dwRef = 1L; FinalRelease();}
  755.  
  756.     //If InternalAddRef or InteralRelease is undefined then your class
  757.     //doesn't derive from CComObjectRoot
  758.     STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();}
  759.     STDMETHOD_(ULONG, Release)()
  760.     {
  761.         ULONG l = InternalRelease();
  762.         if (l == 0)
  763.             delete this;
  764.         return l;
  765.     }
  766.     //if _InternalQueryInterface is undefined then you forgot BEGIN_COM_MAP
  767.     STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  768.     {return _InternalQueryInterface(iid, ppvObject);}
  769. };
  770.  
  771. // It is possible for Base not to derive from CComObjectRoot
  772. // However, you will need to provide FinalConstruct and InternalQueryInterface
  773. template <class Base>
  774. class CComObjectGlobal : public Base
  775. {
  776. public:
  777.     typedef Base _BaseClass;
  778.     CComObjectGlobal(void* = NULL){m_hResFinalConstruct = FinalConstruct();}
  779.     ~CComObjectGlobal() {FinalRelease();}
  780.  
  781.     STDMETHOD_(ULONG, AddRef)() {return _Module.Lock();}
  782.     STDMETHOD_(ULONG, Release)(){return _Module.Unlock();}
  783.     STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  784.     {return _InternalQueryInterface(iid, ppvObject);}
  785.     HRESULT m_hResFinalConstruct;
  786. };
  787.  
  788. // It is possible for Base not to derive from CComObjectRoot
  789. // However, you will need to provide FinalConstruct and InternalQueryInterface
  790. template <class Base>
  791. class CComObjectStack : public Base
  792. {
  793. public:
  794.     typedef Base _BaseClass;
  795.     CComObjectStack(void* = NULL){m_hResFinalConstruct = FinalConstruct();}
  796.     ~CComObjectStack() {FinalRelease();}
  797.  
  798.     STDMETHOD_(ULONG, AddRef)() {_ASSERTE(FALSE);return 0;}
  799.     STDMETHOD_(ULONG, Release)(){_ASSERTE(FALSE);return 0;}
  800.     STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  801.     {_ASSERTE(FALSE);return E_NOINTERFACE;}
  802.     HRESULT m_hResFinalConstruct;
  803. };
  804.  
  805. template <class Base> //Base must be derived from CComObjectRoot
  806. class CComContainedObject : public Base
  807. {
  808. public:
  809.     typedef Base _BaseClass;
  810.     CComContainedObject(void* pv) {m_pOuterUnknown = (IUnknown*)pv;}
  811.  
  812.     STDMETHOD_(ULONG, AddRef)() {return OuterAddRef();}
  813.     STDMETHOD_(ULONG, Release)() {return OuterRelease();}
  814.     STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  815.     {return OuterQueryInterface(iid, ppvObject);}
  816.     //GetControllingUnknown may be virtual if the Base class has declared
  817.     //DECLARE_GET_CONTROLLING_UNKNOWN()
  818.     IUnknown* GetControllingUnknown() {return m_pOuterUnknown;}
  819. };
  820.  
  821. //contained is the user's class that derives from CComObjectRoot and whatever
  822. //interfaces the user wants to support on the object
  823. template <class contained>
  824. class CComAggObject :
  825.     public IUnknown,
  826.         public CComObjectRootEx< contained::_ThreadModel::ThreadModelNoCS >
  827. {
  828. public:
  829.     typedef contained _BaseClass;
  830.     CComAggObject(void* pv) : m_contained(pv)
  831.     {
  832.         _Module.Lock();
  833.     }
  834.     //If you get a message that this call is ambiguous then you need to
  835.     // override it in your class and call each base class' version of this
  836.     HRESULT FinalConstruct()
  837.     {
  838.         CComObjectRootEx<contained::_ThreadModel::ThreadModelNoCS>::FinalConstruct();
  839.         return m_contained.FinalConstruct();
  840.     }
  841.     void FinalRelease()
  842.     {
  843.         CComObjectRootEx<contained::_ThreadModel::ThreadModelNoCS>::FinalRelease();
  844.         m_contained.FinalRelease();
  845.     }
  846.     // Set refcount to 1 to protect destruction
  847.     ~CComAggObject()
  848.     {
  849.         m_dwRef = 1L;
  850.         FinalRelease();
  851.         _Module.Unlock();
  852.     }
  853.  
  854.     STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();}
  855.     STDMETHOD_(ULONG, Release)()
  856.     {
  857.         ULONG l = InternalRelease();
  858.         if (l == 0)
  859.             delete this;
  860.         return l;
  861.     }
  862.     STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  863.     {
  864.         HRESULT hRes = S_OK;
  865.         if (InlineIsEqualUnknown(iid))
  866.         {
  867.             *ppvObject = (void*)(IUnknown*)this;
  868.             AddRef();
  869.         }
  870.         else
  871.             hRes = m_contained._InternalQueryInterface(iid, ppvObject);
  872.         return hRes;
  873.     }
  874.     CComContainedObject<contained> m_contained;
  875. };
  876.  
  877. ///////////////////////////////////////////////////////////////////////////////
  878. // CComPolyObject can be either aggregated or not aggregated
  879.  
  880. template <class contained>
  881. class CComPolyObject :
  882.     public IUnknown,
  883.         public CComObjectRootEx< contained::_ThreadModel::ThreadModelNoCS >
  884. {
  885. public:
  886.     typedef contained _BaseClass;
  887.     CComPolyObject(void* pv) : m_contained(pv ? pv : this)
  888.     {
  889.         _Module.Lock();
  890.     }
  891.     //If you get a message that this call is ambiguous then you need to
  892.     // override it in your class and call each base class' version of this
  893.     HRESULT FinalConstruct()
  894.     {
  895.         CComObjectRootEx<contained::_ThreadModel::ThreadModelNoCS>::FinalConstruct();
  896.         return m_contained.FinalConstruct();
  897.     }
  898.     void FinalRelease()
  899.     {
  900.         CComObjectRootEx<contained::_ThreadModel::ThreadModelNoCS>::FinalRelease();
  901.         m_contained.FinalRelease();
  902.     }
  903.     // Set refcount to 1 to protect destruction
  904.     ~CComPolyObject()
  905.     {
  906.         m_dwRef = 1L;
  907.         FinalRelease();
  908.         _Module.Unlock();
  909.     }
  910.  
  911.     STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();}
  912.     STDMETHOD_(ULONG, Release)()
  913.     {
  914.         ULONG l = InternalRelease();
  915.         if (l == 0)
  916.             delete this;
  917.         return l;
  918.     }
  919.     STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  920.     {
  921.         HRESULT hRes = S_OK;
  922.         if (InlineIsEqualUnknown(iid))
  923.         {
  924.             *ppvObject = (void*)(IUnknown*)this;
  925.             AddRef();
  926.         }
  927.         else
  928.             hRes = m_contained._InternalQueryInterface(iid, ppvObject);
  929.         return hRes;
  930.     }
  931.     CComContainedObject<contained> m_contained;
  932. };
  933.  
  934. template <class Base>
  935. class CComTearOffObject : public Base
  936. {
  937. public:
  938.     CComTearOffObject(void* pv)
  939.     {
  940.         _ASSERTE(m_pOwner == NULL);
  941.         m_pOwner = reinterpret_cast<CComObject<Base::_OwnerClass>*>(pv);
  942.         m_pOwner->AddRef();
  943.     }
  944.     // Set refcount to 1 to protect destruction
  945.     ~CComTearOffObject()
  946.     {
  947.         m_dwRef = 1L;
  948.         FinalRelease();
  949.         m_pOwner->Release();
  950.     }
  951.  
  952.     STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();}
  953.     STDMETHOD_(ULONG, Release)()
  954.     {
  955.         ULONG l = InternalRelease();
  956.         if (l == 0)
  957.             delete this;
  958.         return l;
  959.     }
  960.     STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  961.     {
  962.         return m_pOwner->QueryInterface(iid, ppvObject);
  963.     }
  964. };
  965.  
  966. template <class contained>
  967. class CComCachedTearOffObject :
  968.     public IUnknown,
  969.     public CComObjectRootEx<contained::_ThreadModel::ThreadModelNoCS>
  970. {
  971. public:
  972.     typedef contained _BaseClass;
  973.     CComCachedTearOffObject(void* pv) :
  974.         m_contained(((contained::_OwnerClass*)pv)->GetControllingUnknown())
  975.     {
  976.         _ASSERTE(m_contained.m_pOwner == NULL);
  977.         m_contained.m_pOwner = reinterpret_cast<CComObject<contained::_OwnerClass>*>(pv);
  978.     }
  979.     //If you get a message that this call is ambiguous then you need to
  980.     // override it in your class and call each base class' version of this
  981.     HRESULT FinalConstruct()
  982.     {
  983.         CComObjectRootEx<contained::_ThreadModel::ThreadModelNoCS>::FinalConstruct();
  984.         return m_contained.FinalConstruct();
  985.     }
  986.     void FinalRelease()
  987.     {
  988.         CComObjectRootEx<contained::_ThreadModel::ThreadModelNoCS>::FinalRelease();
  989.         m_contained.FinalRelease();
  990.     }
  991.     // Set refcount to 1 to protect destruction
  992.     ~CComCachedTearOffObject(){m_dwRef = 1L; FinalRelease();}
  993.  
  994.     STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();}
  995.     STDMETHOD_(ULONG, Release)()
  996.     {
  997.         ULONG l = InternalRelease();
  998.         if (l == 0)
  999.             delete this;
  1000.         return l;
  1001.     }
  1002.     STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  1003.     {
  1004.         HRESULT hRes = S_OK;
  1005.         if (InlineIsEqualUnknown(iid))
  1006.         {
  1007.             *ppvObject = (void*)(IUnknown*)this;
  1008.             AddRef();
  1009.         }
  1010.         else
  1011.             hRes = m_contained._InternalQueryInterface(iid, ppvObject);
  1012.         return hRes;
  1013.     }
  1014.     CComContainedObject<contained> m_contained;
  1015. };
  1016.  
  1017. class CComClassFactory :
  1018.     public IClassFactory,
  1019.     public CComObjectRootEx<CComGlobalsThreadModel>
  1020. {
  1021. public:
  1022.     BEGIN_COM_MAP(CComClassFactory)
  1023.         COM_INTERFACE_ENTRY(IClassFactory)
  1024.     END_COM_MAP()
  1025.  
  1026.     // IClassFactory
  1027.     STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void** ppvObj);
  1028.     STDMETHOD(LockServer)(BOOL fLock);
  1029.     // helper
  1030.     void SetVoid(void* pv)
  1031.     {
  1032.         m_pfnCreateInstance = (_ATL_CREATORFUNC*)pv;
  1033.     }
  1034.     _ATL_CREATORFUNC* m_pfnCreateInstance;
  1035. };
  1036.  
  1037. class CComClassFactory2Base :
  1038.     public IClassFactory2,
  1039.     public CComObjectRootEx<CComGlobalsThreadModel>
  1040. {
  1041. public:
  1042. BEGIN_COM_MAP(CComClassFactory2Base)
  1043.     COM_INTERFACE_ENTRY(IClassFactory)
  1044.     COM_INTERFACE_ENTRY(IClassFactory2)
  1045. END_COM_MAP()
  1046.     // IClassFactory
  1047.     STDMETHOD(LockServer)(BOOL fLock);
  1048.     // helper
  1049.     void SetVoid(void* pv)
  1050.     {
  1051.         m_pfnCreateInstance = (_ATL_CREATORFUNC*)pv;
  1052.     }
  1053.     _ATL_CREATORFUNC* m_pfnCreateInstance;
  1054. };
  1055.  
  1056. template <class license>
  1057. class CComClassFactory2 : public CComClassFactory2Base, license
  1058. {
  1059. public:
  1060.     typedef license _LicenseClass;
  1061.     typedef CComClassFactory2<license> _ComMapClass;
  1062.     // IClassFactory
  1063.     STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter,
  1064.         REFIID riid, void** ppvObj)
  1065.     {
  1066.         _ASSERTE(m_pfnCreateInstance != NULL);
  1067.         if (ppvObj == NULL)
  1068.             return E_POINTER;
  1069.         *ppvObj = NULL;
  1070.         if (!IsLicenseValid())
  1071.             return CLASS_E_NOTLICENSED;
  1072.  
  1073.         if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid))
  1074.             return CLASS_E_NOAGGREGATION;
  1075.         else
  1076.             return m_pfnCreateInstance(pUnkOuter, riid, ppvObj);
  1077.     }
  1078.     // IClassFactory2
  1079.     STDMETHOD(CreateInstanceLic)(IUnknown* pUnkOuter, IUnknown* pUnkReserved,
  1080.                 REFIID riid, BSTR bstrKey, void** ppvObject)
  1081.     {
  1082.         _ASSERTE(m_pfnCreateInstance != NULL);
  1083.         if (ppvObject == NULL)
  1084.             return E_POINTER;
  1085.         *ppvObject = NULL;
  1086.         if ( ((bstrKey != NULL) && !VerifyLicenseKey(bstrKey)) ||
  1087.              ((bstrKey == NULL) && !IsLicenseValid()) )
  1088.             return CLASS_E_NOTLICENSED;
  1089.         return m_pfnCreateInstance(pUnkOuter, riid, ppvObject);
  1090.     }
  1091.     STDMETHOD(RequestLicKey)(DWORD dwReserved, BSTR* pbstrKey)
  1092.     {
  1093.         if (pbstrKey == NULL)
  1094.             return E_POINTER;
  1095.         *pbstrKey = NULL;
  1096.  
  1097.         if (!IsLicenseValid())
  1098.             return CLASS_E_NOTLICENSED;
  1099.         return GetLicenseKey(dwReserved,pbstrKey) ? S_OK : E_FAIL;
  1100.     }
  1101.     STDMETHOD(GetLicInfo)(LICINFO* pLicInfo)
  1102.     {
  1103.         if (pLicInfo == NULL)
  1104.             return E_POINTER;
  1105.         pLicInfo->cbLicInfo = sizeof(LICINFO);
  1106.         pLicInfo->fLicVerified = IsLicenseValid();
  1107.         BSTR bstr = NULL;
  1108.         pLicInfo->fRuntimeKeyAvail = GetLicenseKey(0,&bstr);
  1109.         ::SysFreeString(bstr);
  1110.         return S_OK;
  1111.     }
  1112. };
  1113.  
  1114. /////////////////////////////////////////////////////////////////////////////////////////////
  1115. // Thread Pooling class factory
  1116.  
  1117. class CComClassFactoryAutoThread :
  1118.     public IClassFactory,
  1119.     public CComObjectRootEx<CComGlobalsThreadModel>
  1120. {
  1121. public:
  1122.     BEGIN_COM_MAP(CComClassFactoryAutoThread)
  1123.         COM_INTERFACE_ENTRY(IClassFactory)
  1124.     END_COM_MAP()
  1125.  
  1126.     // helper
  1127.     void SetVoid(void* pv)
  1128.     {
  1129.         m_pfnCreateInstance = (_ATL_CREATORFUNC*)pv;
  1130.     }
  1131.     STDMETHODIMP CComClassFactoryAutoThread::CreateInstance(LPUNKNOWN pUnkOuter,
  1132.         REFIID riid, void** ppvObj)
  1133.     {
  1134.         _ASSERTE(m_pfnCreateInstance != NULL);
  1135.         HRESULT hRes = E_POINTER;
  1136.         if (ppvObj != NULL)
  1137.         {
  1138.             *ppvObj = NULL;
  1139.             // cannot aggregate across apartments
  1140.             _ASSERTE(pUnkOuter == NULL);
  1141.             if (pUnkOuter != NULL)
  1142.                 hRes = CLASS_E_NOAGGREGATION;
  1143.             else
  1144.                 hRes = _Module.CreateInstance(m_pfnCreateInstance, riid, ppvObj);
  1145.         }
  1146.         return hRes;
  1147.     }
  1148.     STDMETHODIMP CComClassFactoryAutoThread::LockServer(BOOL fLock)
  1149.     {
  1150.         if (fLock)
  1151.             _Module.Lock();
  1152.         else
  1153.             _Module.Unlock();
  1154.         return S_OK;
  1155.     }
  1156.     _ATL_CREATORFUNC* m_pfnCreateInstance;
  1157. };
  1158.  
  1159. /////////////////////////////////////////////////////////////////////////////////////////////
  1160. // Singleton Class Factory
  1161. template <class T>
  1162. class CComClassFactorySingleton : public CComClassFactory
  1163. {
  1164. public:
  1165.     // IClassFactory
  1166.     STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void** ppvObj)
  1167.     {
  1168.         HRESULT hRes = E_POINTER;
  1169.         if (ppvObj != NULL)
  1170.         {
  1171.             // can't ask for anything other than IUnknown when aggregating
  1172.             _ASSERTE((pUnkOuter == NULL) || InlineIsEqualUnknown(riid));
  1173.             if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid))
  1174.                 hRes = CLASS_E_NOAGGREGATION;
  1175.             else
  1176.                 hRes = m_Obj.QueryInterface(riid, ppvObj);
  1177.         }
  1178.         return hRes;
  1179.     }
  1180.     CComObjectGlobal<T> m_Obj;
  1181. };
  1182.  
  1183.  
  1184. template <class T, const CLSID* pclsid>
  1185. class CComCoClass
  1186. {
  1187. public:
  1188.     DECLARE_CLASSFACTORY()
  1189.     DECLARE_AGGREGATABLE(T)
  1190.     typedef T _CoClass;
  1191.     static const CLSID& WINAPI GetObjectCLSID() {return *pclsid;}
  1192.     static LPCTSTR WINAPI GetObjectDescription() {return NULL;}
  1193.     static HRESULT WINAPI Error(LPCOLESTR lpszDesc,
  1194.         const IID& iid = GUID_NULL, HRESULT hRes = 0)
  1195.     {
  1196.         return AtlReportError(GetObjectCLSID(), lpszDesc, iid, hRes);
  1197.     }
  1198.     static HRESULT WINAPI Error(LPCOLESTR lpszDesc, DWORD dwHelpID,
  1199.         LPCOLESTR lpszHelpFile, const IID& iid = GUID_NULL, HRESULT hRes = 0)
  1200.     {
  1201.         return AtlReportError(GetObjectCLSID(), lpszDesc, dwHelpID, lpszHelpFile,
  1202.             iid, hRes);
  1203.     }
  1204.     static HRESULT WINAPI Error(UINT nID, const IID& iid = GUID_NULL,
  1205.         HRESULT hRes = 0, HINSTANCE hInst = _Module.GetResourceInstance())
  1206.     {
  1207.         return AtlReportError(GetObjectCLSID(), nID, iid, hRes, hInst);
  1208.     }
  1209.     static HRESULT WINAPI Error(UINT nID, DWORD dwHelpID,
  1210.         LPCOLESTR lpszHelpFile, const IID& iid = GUID_NULL,
  1211.         HRESULT hRes = 0, HINSTANCE hInst = _Module.GetResourceInstance())
  1212.     {
  1213.         return AtlReportError(GetObjectCLSID(), nID, dwHelpID, lpszHelpFile,
  1214.             iid, hRes, hInst);
  1215.     }
  1216. #ifndef OLE2ANSI
  1217.     static HRESULT WINAPI Error(LPCSTR lpszDesc,
  1218.         const IID& iid = GUID_NULL, HRESULT hRes = 0)
  1219.     {
  1220.         return AtlReportError(GetObjectCLSID(), lpszDesc, iid, hRes);
  1221.     }
  1222.     static HRESULT WINAPI Error(LPCSTR lpszDesc, DWORD dwHelpID,
  1223.         LPCSTR lpszHelpFile, const IID& iid = GUID_NULL, HRESULT hRes = 0)
  1224.     {
  1225.         return AtlReportError(GetObjectCLSID(), lpszDesc, dwHelpID,
  1226.             lpszHelpFile, iid, hRes);
  1227.     }
  1228. #endif
  1229. };
  1230.  
  1231. // ATL doesn't support multiple LCID's at the same time
  1232. // Whatever LCID is queried for first is the one that is used.
  1233. class CComTypeInfoHolder
  1234. {
  1235. // Should be 'protected' but can cause compiler to generate fat code.
  1236. public:
  1237.     const GUID* m_pguid;
  1238.     const GUID* m_plibid;
  1239.     WORD m_wMajor;
  1240.     WORD m_wMinor;
  1241.  
  1242.     ITypeInfo* m_pInfo;
  1243.     long m_dwRef;
  1244.  
  1245. public:
  1246.     HRESULT GetTI(LCID lcid, ITypeInfo** ppInfo);
  1247.  
  1248.     void AddRef();
  1249.     void Release();
  1250.     HRESULT GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo);
  1251.     HRESULT GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames,
  1252.         LCID lcid, DISPID* rgdispid);
  1253.     HRESULT Invoke(IDispatch* p, DISPID dispidMember, REFIID riid,
  1254.         LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
  1255.         EXCEPINFO* pexcepinfo, UINT* puArgErr);
  1256. };
  1257.  
  1258. //////////////////////////////////////////////////////////////////////////////
  1259. // IObjectWithSite
  1260. //
  1261. template <class T>
  1262. class ATL_NO_VTABLE IObjectWithSiteImpl
  1263. {
  1264. public:
  1265.     // IUnknown
  1266.     //
  1267.     STDMETHOD(QueryInterface)(REFIID riid, void ** ppvObject) = 0;
  1268.     _ATL_DEBUG_ADDREF_RELEASE_IMPL(IObjectWithSiteImpl)
  1269.  
  1270.     // IObjectWithSite
  1271.     //
  1272.     STDMETHOD(SetSite)(IUnknown *pUnkSite)
  1273.     {
  1274.         ATLTRACE(_T("IObjectWithSiteImpl::SetSite\n"));
  1275.         T* pT = static_cast<T*>(this);
  1276.         pT->m_spUnkSite = pUnkSite;
  1277.         return S_OK;
  1278.     }
  1279.     STDMETHOD(GetSite)(REFIID riid, void **ppvSite)
  1280.     {
  1281.         ATLTRACE(_T("IObjectWithSiteImpl::GetSite\n"));
  1282.         T* pT = static_cast<T*>(this);
  1283.         _ASSERTE(ppvSite);
  1284.         HRESULT hRes = E_POINTER;
  1285.         if (ppvSite != NULL)
  1286.         {
  1287.             if (pT->m_spUnkSite)
  1288.                 hRes = pT->m_spUnkSite->QueryInterface(riid, ppvSite);
  1289.             else
  1290.             {
  1291.                 *ppvSite = NULL;
  1292.                 hRes = E_FAIL;
  1293.             }
  1294.         }
  1295.         return hRes;
  1296.     }
  1297.  
  1298.     CComPtr<IUnknown> m_spUnkSite;
  1299. };
  1300.  
  1301. /////////////////////////////////////////////////////////////////////////////
  1302. // IDispatchImpl
  1303.  
  1304. template <class T, const IID* piid, const GUID* plibid, WORD wMajor = 1,
  1305. WORD wMinor = 0, class tihclass = CComTypeInfoHolder>
  1306. class ATL_NO_VTABLE IDispatchImpl : public T
  1307. {
  1308. public:
  1309.     typedef tihclass _tihclass;
  1310.     IDispatchImpl() {_tih.AddRef();}
  1311.     ~IDispatchImpl() {_tih.Release();}
  1312.  
  1313.     STDMETHOD(GetTypeInfoCount)(UINT* pctinfo)
  1314.     {*pctinfo = 1; return S_OK;}
  1315.  
  1316.     STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
  1317.     {return _tih.GetTypeInfo(itinfo, lcid, pptinfo);}
  1318.  
  1319.     STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR* rgszNames, UINT cNames,
  1320.         LCID lcid, DISPID* rgdispid)
  1321.     {return _tih.GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);}
  1322.  
  1323.     STDMETHOD(Invoke)(DISPID dispidMember, REFIID riid,
  1324.         LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
  1325.         EXCEPINFO* pexcepinfo, UINT* puArgErr)
  1326.     {return _tih.Invoke((IDispatch*)this, dispidMember, riid, lcid,
  1327.         wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);}
  1328. protected:
  1329.     static _tihclass _tih;
  1330.     static HRESULT GetTI(LCID lcid, ITypeInfo** ppInfo)
  1331.     {return _tih.GetTI(lcid, ppInfo);}
  1332. };
  1333.  
  1334. template <class T, const IID* piid, const GUID* plibid, WORD wMajor = 1,
  1335. WORD wMinor = 0, class tihclass = CComTypeInfoHolder>
  1336. IDispatchImpl<T, piid, plibid, wMajor, wMinor, tihclass>::_tihclass
  1337. IDispatchImpl<T, piid, plibid, wMajor, wMinor, tihclass>::_tih =
  1338. {piid, plibid, wMajor, wMinor, NULL, 0};
  1339.  
  1340.  
  1341. /////////////////////////////////////////////////////////////////////////////
  1342. // IProvideClassInfoImpl
  1343.  
  1344. template <const CLSID* pcoclsid, const IID* psrcid, const GUID* plibid,
  1345. WORD wMajor = 1, WORD wMinor = 0, class tihclass = CComTypeInfoHolder>
  1346. class ATL_NO_VTABLE IProvideClassInfo2Impl : public IProvideClassInfo2
  1347. {
  1348. public:
  1349.     typedef tihclass _tihclass;
  1350.     IProvideClassInfo2Impl() {_tih.AddRef();}
  1351.     ~IProvideClassInfo2Impl() {_tih.Release();}
  1352.  
  1353.     STDMETHOD(GetClassInfo)(ITypeInfo** pptinfo)
  1354.     {
  1355.         return _tih.GetTypeInfo(0, LANG_NEUTRAL, pptinfo);
  1356.     }
  1357.     STDMETHOD(GetGUID)(DWORD dwGuidKind, GUID* pGUID)
  1358.     {
  1359.         if (pGUID == NULL)
  1360.             return E_POINTER;
  1361.  
  1362.         if (dwGuidKind == GUIDKIND_DEFAULT_SOURCE_DISP_IID && psrcid)
  1363.         {
  1364.             *pGUID = *psrcid;
  1365.             return S_OK;
  1366.         }
  1367.         *pGUID = GUID_NULL;
  1368.         return E_FAIL;
  1369.     }
  1370.  
  1371. protected:
  1372.     static _tihclass _tih;
  1373. };
  1374.  
  1375.  
  1376. template <const CLSID* pcoclsid, const IID* psrcid, const GUID* plibid,
  1377. WORD wMajor = 1, WORD wMinor = 0, class tihclass = CComTypeInfoHolder>
  1378. IProvideClassInfo2Impl<pcoclsid, psrcid, plibid, wMajor, wMinor, tihclass>::_tihclass
  1379. IProvideClassInfo2Impl<pcoclsid, psrcid, plibid, wMajor, wMinor, tihclass>::_tih =
  1380. {pcoclsid,plibid, wMajor, wMinor, NULL, 0};
  1381.  
  1382.  
  1383. /////////////////////////////////////////////////////////////////////////////
  1384. // ISupportErrorInfoImpl
  1385.  
  1386. template <const IID* piid>
  1387. class ATL_NO_VTABLE ISupportErrorInfoImpl : public ISupportErrorInfo
  1388. {
  1389. public:
  1390.     STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid)\
  1391.     {return (InlineIsEqualGUID(riid,*piid)) ? S_OK : S_FALSE;}
  1392. };
  1393.  
  1394.  
  1395. /////////////////////////////////////////////////////////////////////////////
  1396. // CComEnumImpl
  1397.  
  1398. // These _CopyXXX classes are used with enumerators in order to control
  1399. // how enumerated items are initialized, copied, and deleted
  1400.  
  1401. // Default is shallow copy with no special init or cleanup
  1402. template <class T>
  1403. class _Copy
  1404. {
  1405. public:
  1406.     static void copy(T* p1, T* p2) {memcpy(p1, p2, sizeof(T));}
  1407.     static void init(T*) {}
  1408.     static void destroy(T*) {}
  1409. };
  1410.  
  1411. #if _MSC_VER>1020
  1412. template<>
  1413. #endif
  1414. class _Copy<VARIANT>
  1415. {
  1416. public:
  1417.     static void copy(VARIANT* p1, VARIANT* p2) {VariantCopy(p1, p2);}
  1418.     static void init(VARIANT* p) {VariantInit(p);}
  1419.     static void destroy(VARIANT* p) {VariantClear(p);}
  1420. };
  1421.  
  1422. #if _MSC_VER>1020
  1423. template<>
  1424. #endif
  1425. class _Copy<LPOLESTR>
  1426. {
  1427. public:
  1428.     static void copy(LPOLESTR* p1, LPOLESTR* p2)
  1429.     {
  1430.         (*p1) = (LPOLESTR)CoTaskMemAlloc(sizeof(OLECHAR)*(ocslen(*p2)+1));
  1431.         ocscpy(*p1,*p2);
  1432.     }
  1433.     static void init(LPOLESTR* p) {*p = NULL;}
  1434.     static void destroy(LPOLESTR* p) { CoTaskMemFree(*p);}
  1435. };
  1436.  
  1437. #if _MSC_VER>1020
  1438. template<>
  1439. #endif
  1440. class _Copy<OLEVERB>
  1441. {
  1442. public:
  1443.     static void copy(OLEVERB* p1, OLEVERB* p2)
  1444.     {
  1445.         *p1 = *p2;
  1446.         if (p1->lpszVerbName == NULL)
  1447.             return;
  1448.         p1->lpszVerbName = (LPOLESTR)CoTaskMemAlloc(sizeof(OLECHAR)*(ocslen(p2->lpszVerbName)+1));
  1449.         ocscpy(p1->lpszVerbName,p2->lpszVerbName);
  1450.     }
  1451.     static void init(OLEVERB* p) { p->lpszVerbName = NULL;}
  1452.     static void destroy(OLEVERB* p) { if (p->lpszVerbName) CoTaskMemFree(p->lpszVerbName);}
  1453. };
  1454.  
  1455. #if _MSC_VER>1020
  1456. template<>
  1457. #endif
  1458. class _Copy<CONNECTDATA>
  1459. {
  1460. public:
  1461.     static void copy(CONNECTDATA* p1, CONNECTDATA* p2)
  1462.     {
  1463.         *p1 = *p2;
  1464.         if (p1->pUnk)
  1465.             p1->pUnk->AddRef();
  1466.     }
  1467.     static void init(CONNECTDATA* ) {}
  1468.     static void destroy(CONNECTDATA* p) {if (p->pUnk) p->pUnk->Release();}
  1469. };
  1470.  
  1471. template <class T>
  1472. class _CopyInterface
  1473. {
  1474. public:
  1475.     static void copy(T** p1, T** p2)
  1476.     {*p1 = *p2;if (*p1) (*p1)->AddRef();}
  1477.     static void init(T** ) {}
  1478.     static void destroy(T** p) {if (*p) (*p)->Release();}
  1479. };
  1480.  
  1481. template<class T>
  1482. class ATL_NO_VTABLE CComIEnum : public IUnknown
  1483. {
  1484. public:
  1485.     STDMETHOD(Next)(ULONG celt, T* rgelt, ULONG* pceltFetched) = 0;
  1486.     STDMETHOD(Skip)(ULONG celt) = 0;
  1487.     STDMETHOD(Reset)(void) = 0;
  1488.     STDMETHOD(Clone)(CComIEnum<T>** ppEnum) = 0;
  1489. };
  1490.  
  1491.  
  1492. enum CComEnumFlags
  1493. {
  1494.     //see FlagBits in CComEnumImpl
  1495.     AtlFlagNoCopy = 0,
  1496.     AtlFlagTakeOwnership = 2,
  1497.     AtlFlagCopy = 3 // copy implies ownership
  1498. };
  1499.  
  1500. template <class Base, const IID* piid, class T, class Copy>
  1501. class ATL_NO_VTABLE CComEnumImpl : public Base
  1502. {
  1503. public:
  1504.     CComEnumImpl() {m_begin = m_end = m_iter = NULL; m_dwFlags = 0; m_pUnk = NULL;}
  1505.     ~CComEnumImpl();
  1506.     STDMETHOD(Next)(ULONG celt, T* rgelt, ULONG* pceltFetched);
  1507.     STDMETHOD(Skip)(ULONG celt);
  1508.     STDMETHOD(Reset)(void){m_iter = m_begin;return S_OK;}
  1509.     STDMETHOD(Clone)(Base** ppEnum);
  1510.     HRESULT Init(T* begin, T* end, IUnknown* pUnk,
  1511.         CComEnumFlags flags = AtlFlagNoCopy);
  1512.     IUnknown* m_pUnk;
  1513.     T* m_begin;
  1514.     T* m_end;
  1515.     T* m_iter;
  1516.     DWORD m_dwFlags;
  1517. protected:
  1518.     enum FlagBits
  1519.     {
  1520.         BitCopy=1,
  1521.         BitOwn=2
  1522.     };
  1523. };
  1524.  
  1525. template <class Base, const IID* piid, class T, class Copy>
  1526. CComEnumImpl<Base, piid, T, Copy>::~CComEnumImpl()
  1527. {
  1528.     if (m_dwFlags & BitOwn)
  1529.     {
  1530.         for (T* p = m_begin; p != m_end; p++)
  1531.             Copy::destroy(p);
  1532.         delete [] m_begin;
  1533.     }
  1534.     if (m_pUnk)
  1535.         m_pUnk->Release();
  1536. }
  1537.  
  1538. template <class Base, const IID* piid, class T, class Copy>
  1539. STDMETHODIMP CComEnumImpl<Base, piid, T, Copy>::Next(ULONG celt, T* rgelt,
  1540.     ULONG* pceltFetched)
  1541. {
  1542.     if (rgelt == NULL || (celt != 1 && pceltFetched == NULL))
  1543.         return E_POINTER;
  1544.     if (m_begin == NULL || m_end == NULL || m_iter == NULL)
  1545.         return E_FAIL;
  1546.     ULONG nRem = (ULONG)(m_end - m_iter);
  1547.     HRESULT hRes = S_OK;
  1548.     if (nRem < celt)
  1549.         hRes = S_FALSE;
  1550.     ULONG nMin = min(celt, nRem);
  1551.     if (pceltFetched != NULL)
  1552.         *pceltFetched = nMin;
  1553.     while(nMin--)
  1554.         Copy::copy(rgelt++, m_iter++);
  1555.     return hRes;
  1556. }
  1557.  
  1558. template <class Base, const IID* piid, class T, class Copy>
  1559. STDMETHODIMP CComEnumImpl<Base, piid, T, Copy>::Skip(ULONG celt)
  1560. {
  1561.     m_iter += celt;
  1562.     if (m_iter < m_end)
  1563.         return S_OK;
  1564.     m_iter = m_end;
  1565.     return S_FALSE;
  1566. }
  1567.  
  1568. template <class Base, const IID* piid, class T, class Copy>
  1569. STDMETHODIMP CComEnumImpl<Base, piid, T, Copy>::Clone(Base** ppEnum)
  1570. {
  1571.     typedef CComObject<CComEnum<Base, piid, T, Copy> > _class;
  1572.     HRESULT hRes = E_POINTER;
  1573.     if (ppEnum != NULL)
  1574.     {
  1575.         _class* p = NULL;
  1576.         ATLTRY(p = new _class)
  1577.         if (p == NULL)
  1578.         {
  1579.             *ppEnum = NULL;
  1580.             hRes = E_OUTOFMEMORY;
  1581.         }
  1582.         else
  1583.         {
  1584.             // If the data is a copy then we need to keep "this" object around
  1585.             hRes = p->Init(m_begin, m_end, (m_dwFlags & BitCopy) ? this : m_pUnk);
  1586.             if (FAILED(hRes))
  1587.                 delete p;
  1588.             else
  1589.             {
  1590.                 p->m_iter = m_iter;
  1591.                 hRes = p->_InternalQueryInterface(*piid, (void**)ppEnum);
  1592.                 if (FAILED(hRes))
  1593.                     delete p;
  1594.             }
  1595.         }
  1596.     }
  1597.     return hRes;
  1598. }
  1599.  
  1600. template <class Base, const IID* piid, class T, class Copy>
  1601. HRESULT CComEnumImpl<Base, piid, T, Copy>::Init(T* begin, T* end, IUnknown* pUnk,
  1602.     CComEnumFlags flags)
  1603. {
  1604.     if (flags == AtlFlagCopy)
  1605.     {
  1606.         _ASSERTE(m_begin == NULL); //Init called twice?
  1607.         ATLTRY(m_begin = new T[end-begin])
  1608.         m_iter = m_begin;
  1609.         if (m_begin == NULL)
  1610.             return E_OUTOFMEMORY;
  1611.         for (T* i=begin; i != end; i++)
  1612.         {
  1613.             Copy::init(m_iter);
  1614.             Copy::copy(m_iter++, i);
  1615.         }
  1616.         m_end = m_begin + (end-begin);
  1617.     }
  1618.     else
  1619.     {
  1620.         m_begin = begin;
  1621.         m_end = end;
  1622.     }
  1623.     m_pUnk = pUnk;
  1624.     if (m_pUnk)
  1625.         m_pUnk->AddRef();
  1626.     m_iter = m_begin;
  1627.     m_dwFlags = flags;
  1628.     return S_OK;
  1629. }
  1630.  
  1631. template <class Base, const IID* piid, class T, class Copy, class ThreadModel = CComObjectThreadModel>
  1632. class ATL_NO_VTABLE CComEnum :
  1633.     public CComEnumImpl<Base, piid, T, Copy>,
  1634.     public CComObjectRootEx< ThreadModel >
  1635. {
  1636. public:
  1637.     typedef CComEnum<Base, piid, T, Copy > _CComEnum;
  1638.     typedef CComEnumImpl<Base, piid, T, Copy > _CComEnumBase;
  1639.     BEGIN_COM_MAP(_CComEnum)
  1640.         COM_INTERFACE_ENTRY_IID(*piid, _CComEnumBase)
  1641.     END_COM_MAP()
  1642. };
  1643.  
  1644. #ifndef _ATL_NO_CONNECTION_POINTS
  1645. /////////////////////////////////////////////////////////////////////////////
  1646. // Connection Points
  1647.  
  1648. struct _ATL_CONNMAP_ENTRY
  1649. {
  1650.     DWORD dwOffset;
  1651. };
  1652.  
  1653.  
  1654. // We want the offset of the connection point relative to the connection
  1655. // point container base class
  1656. #define BEGIN_CONNECTION_POINT_MAP(x)\
  1657.     typedef x _atl_conn_classtype;\
  1658.     static const _ATL_CONNMAP_ENTRY* GetConnMap(int* pnEntries) {\
  1659.     static const _ATL_CONNMAP_ENTRY _entries[] = {
  1660. // CONNECTION_POINT_ENTRY computes the offset of the connection point to the
  1661. // IConnectionPointContainer interface
  1662. #define CONNECTION_POINT_ENTRY(iid){offsetofclass(_ICPLocator<&iid>, _atl_conn_classtype)-\
  1663.     offsetofclass(IConnectionPointContainerImpl<_atl_conn_classtype>, _atl_conn_classtype)},
  1664. #define END_CONNECTION_POINT_MAP() {(DWORD)-1} }; \
  1665.     if (pnEntries) *pnEntries = sizeof(_entries)/sizeof(_ATL_CONNMAP_ENTRY) - 1; \
  1666.     return _entries;}
  1667.  
  1668.  
  1669. #ifndef _DEFAULT_VECTORLENGTH
  1670. #define _DEFAULT_VECTORLENGTH 4
  1671. #endif
  1672.  
  1673. template <unsigned int nMaxSize>
  1674. class CComUnkArray
  1675. {
  1676. public:
  1677.     CComUnkArray()
  1678.     {
  1679.         memset(m_arr, 0, sizeof(IUnknown*)*nMaxSize);
  1680.     }
  1681.     DWORD Add(IUnknown* pUnk);
  1682.     BOOL Remove(DWORD dwCookie);
  1683.     static DWORD WINAPI GetCookie(IUnknown** pp)
  1684.     {
  1685.         return (DWORD)pp;
  1686.     }
  1687.     static IUnknown* WINAPI GetUnknown(DWORD dwCookie)
  1688.     {
  1689.         return dwCookie ? *(IUnknown**)dwCookie : 0;
  1690.     }
  1691.     IUnknown** begin()
  1692.     {
  1693.         return &m_arr[0];
  1694.     }
  1695.     IUnknown** end()
  1696.     {
  1697.         return &m_arr[nMaxSize];
  1698.     }
  1699. protected:
  1700.     IUnknown* m_arr[nMaxSize];
  1701. };
  1702.  
  1703. template <unsigned int nMaxSize>
  1704. inline DWORD CComUnkArray<nMaxSize>::Add(IUnknown* pUnk)
  1705. {
  1706.     for (IUnknown** pp = begin();pp<end();pp++)
  1707.     {
  1708.         if (*pp == NULL)
  1709.         {
  1710.             *pp = pUnk;
  1711.             return (DWORD)pp; // return cookie
  1712.         }
  1713.     }
  1714.     // If this fires then you need a larger array
  1715.     _ASSERTE(0);
  1716.     return 0;
  1717. }
  1718.  
  1719. template <unsigned int nMaxSize>
  1720. inline BOOL CComUnkArray<nMaxSize>::Remove(DWORD dwCookie)
  1721. {
  1722.     IUnknown** pp = (IUnknown**)dwCookie;
  1723.     BOOL b = ((pp >= begin()) && (pp < end()));
  1724.     if (b)
  1725.         *pp = NULL;
  1726.     return b;
  1727. }
  1728.  
  1729. #if _MSC_VER>1020
  1730. template<>
  1731. #endif
  1732. class CComUnkArray<1>
  1733. {
  1734. public:
  1735.     CComUnkArray()
  1736.     {
  1737.         m_arr[0] = NULL;
  1738.     }
  1739.     DWORD Add(IUnknown* pUnk)
  1740.     {
  1741.         if (m_arr[0] != NULL)
  1742.         {
  1743.             // If this fires then you need a larger array
  1744.             _ASSERTE(0);
  1745.             return 0;
  1746.         }
  1747.         m_arr[0] = pUnk;
  1748.         return (DWORD)&m_arr[0];
  1749.     }
  1750.     BOOL Remove(DWORD dwCookie)
  1751.     {
  1752.         if (dwCookie != (DWORD)&m_arr[0])
  1753.             return FALSE;
  1754.         m_arr[0] = NULL;
  1755.         return TRUE;
  1756.     }
  1757.     static DWORD WINAPI GetCookie(IUnknown** pp)
  1758.     {
  1759.         return (DWORD)pp;
  1760.     }
  1761.     static IUnknown* WINAPI GetUnknown(DWORD dwCookie)
  1762.     {
  1763.         return dwCookie ? *(IUnknown**)dwCookie : 0;
  1764.     }
  1765.     IUnknown** begin()
  1766.     {
  1767.         return &m_arr[0];
  1768.     }
  1769.     IUnknown** end()
  1770.     {
  1771.         return (&m_arr[0])+1;
  1772.     }
  1773. protected:
  1774.     IUnknown* m_arr[1];
  1775. };
  1776.  
  1777. class CComDynamicUnkArray
  1778. {
  1779. public:
  1780.     CComDynamicUnkArray()
  1781.     {
  1782.         m_nSize = 0;
  1783.         m_ppUnk = NULL;
  1784.     }
  1785.  
  1786.     ~CComDynamicUnkArray()
  1787.     {
  1788.         if (m_nSize > 1)
  1789.             free(m_ppUnk);
  1790.     }
  1791.     DWORD Add(IUnknown* pUnk);
  1792.     BOOL Remove(DWORD dwCookie);
  1793.     static DWORD WINAPI GetCookie(IUnknown** pp)
  1794.     {
  1795.         return (DWORD)*pp;
  1796.     }
  1797.     static IUnknown* WINAPI GetUnknown(DWORD dwCookie)
  1798.     {
  1799.         return (IUnknown*)dwCookie;
  1800.     }
  1801.     IUnknown** begin()
  1802.     {
  1803.         return (m_nSize < 2) ? &m_pUnk : m_ppUnk;
  1804.     }
  1805.     IUnknown** end()
  1806.     {
  1807.         return (m_nSize < 2) ? (&m_pUnk)+m_nSize : &m_ppUnk[m_nSize];
  1808.     }
  1809. protected:
  1810.     union
  1811.     {
  1812.         IUnknown** m_ppUnk;
  1813.         IUnknown* m_pUnk;
  1814.     };
  1815.     int m_nSize;
  1816. };
  1817.  
  1818. template <const IID* piid>
  1819. class ATL_NO_VTABLE _ICPLocator
  1820. {
  1821.     //this method needs a different name than QueryInterface
  1822.     STDMETHOD(_LocCPQueryInterface)(REFIID riid, void ** ppvObject) = 0;
  1823. };
  1824.  
  1825. template <class T, const IID* piid, class CDV = CComDynamicUnkArray >
  1826. class ATL_NO_VTABLE IConnectionPointImpl : public _ICPLocator<piid>
  1827. {
  1828.     typedef CComEnum<IEnumConnections, &IID_IEnumConnections, CONNECTDATA,
  1829.         _Copy<CONNECTDATA> > CComEnumConnections;
  1830.     typedef CDV _CDV;
  1831. public:
  1832.     ~IConnectionPointImpl();
  1833.     STDMETHOD(_LocCPQueryInterface)(REFIID riid, void ** ppvObject)
  1834.     {
  1835.         if (InlineIsEqualGUID(riid, IID_IConnectionPoint) || InlineIsEqualGUID(riid, IID_IUnknown))
  1836.         {
  1837.             *ppvObject = this;
  1838. #ifdef _ATL_DEBUG_REFCOUNT
  1839.             _DebugAddRef();
  1840. #else
  1841.             AddRef();
  1842. #endif
  1843.             return S_OK;
  1844.         }
  1845.         else
  1846.             return E_NOINTERFACE;
  1847.     }
  1848.     _ATL_DEBUG_ADDREF_RELEASE_IMPL(IConnectionPointImpl)
  1849.  
  1850.     STDMETHOD(GetConnectionInterface)(IID* piid2)
  1851.     {
  1852.         if (piid2 == NULL)
  1853.             return E_POINTER;
  1854.         *piid2 = *piid;
  1855.         return S_OK;
  1856.     }
  1857.     STDMETHOD(GetConnectionPointContainer)(IConnectionPointContainer** ppCPC)
  1858.     {
  1859.         if (ppCPC == NULL)
  1860.             return E_POINTER;
  1861.         *ppCPC = reinterpret_cast<IConnectionPointContainer*>(
  1862.             (IConnectionPointContainerImpl<T>*)(T*)this);
  1863.         return S_OK;
  1864.     }
  1865.     STDMETHOD(Advise)(IUnknown* pUnkSink, DWORD* pdwCookie);
  1866.     STDMETHOD(Unadvise)(DWORD dwCookie);
  1867.     STDMETHOD(EnumConnections)(IEnumConnections** ppEnum);
  1868.     CDV m_vec;
  1869. };
  1870.  
  1871. template <class T, const IID* piid, class CDV>
  1872. IConnectionPointImpl<T, piid, CDV>::~IConnectionPointImpl()
  1873. {
  1874.     IUnknown** pp = m_vec.begin();
  1875.     while (pp < m_vec.end())
  1876.     {
  1877.         if (*pp != NULL)
  1878.             (*pp)->Release();
  1879.         pp++;
  1880.     }
  1881. }
  1882.  
  1883. template <class T, const IID* piid, class CDV>
  1884. STDMETHODIMP IConnectionPointImpl<T, piid, CDV>::Advise(IUnknown* pUnkSink,
  1885.     DWORD* pdwCookie)
  1886. {
  1887.     T* pT = (T*)this;
  1888.     IUnknown* p;
  1889.     HRESULT hRes = S_OK;
  1890.     if (pUnkSink == NULL || pdwCookie == NULL)
  1891.         return E_POINTER;
  1892.     IID iid;
  1893.     GetConnectionInterface(&iid);
  1894.     hRes = pUnkSink->QueryInterface(iid, (void**)&p);
  1895.     if (SUCCEEDED(hRes))
  1896.     {
  1897.         pT->Lock();
  1898.         *pdwCookie = m_vec.Add(p);
  1899.         hRes = (*pdwCookie != NULL) ? S_OK : CONNECT_E_ADVISELIMIT;
  1900.         pT->Unlock();
  1901.         if (hRes != S_OK)
  1902.         {
  1903.             *pdwCookie = 0;
  1904.             p->Release();
  1905.         }
  1906.     }
  1907.     else if (hRes == E_NOINTERFACE)
  1908.         hRes = CONNECT_E_CANNOTCONNECT;
  1909.     return hRes;
  1910. }
  1911.  
  1912. template <class T, const IID* piid, class CDV>
  1913. STDMETHODIMP IConnectionPointImpl<T, piid, CDV>::Unadvise(DWORD dwCookie)
  1914. {
  1915.     T* pT = (T*)this;
  1916.     pT->Lock();
  1917.     IUnknown* p = _CDV::GetUnknown(dwCookie);
  1918.     HRESULT hRes = m_vec.Remove(dwCookie) ? S_OK : CONNECT_E_NOCONNECTION;
  1919.     pT->Unlock();
  1920.     if (hRes == S_OK && p != NULL)
  1921.         p->Release();
  1922.     return hRes;
  1923. }
  1924.  
  1925. template <class T, const IID* piid, class CDV>
  1926. STDMETHODIMP IConnectionPointImpl<T, piid, CDV>::EnumConnections(
  1927.     IEnumConnections** ppEnum)
  1928. {
  1929.     if (ppEnum == NULL)
  1930.         return E_POINTER;
  1931.     *ppEnum = NULL;
  1932.     CComObject<CComEnumConnections>* pEnum = NULL;
  1933.     ATLTRY(pEnum = new CComObject<CComEnumConnections>)
  1934.     if (pEnum == NULL)
  1935.         return E_OUTOFMEMORY;
  1936.     T* pT = (T*)this;
  1937.     pT->Lock();
  1938.     CONNECTDATA* pcd = NULL;
  1939.     ATLTRY(pcd = new CONNECTDATA[m_vec.end()-m_vec.begin()])
  1940.     if (pcd == NULL)
  1941.     {
  1942.         delete pEnum;
  1943.         pT->Unlock();
  1944.         return E_OUTOFMEMORY;
  1945.     }
  1946.     CONNECTDATA* pend = pcd;
  1947.     // Copy the valid CONNECTDATA's
  1948.     for (IUnknown** pp = m_vec.begin();pp<m_vec.end();pp++)
  1949.     {
  1950.         if (*pp != NULL)
  1951.         {
  1952.             (*pp)->AddRef();
  1953.             pend->pUnk = *pp;
  1954.             pend->dwCookie = _CDV::GetCookie(pp);
  1955.             pend++;
  1956.         }
  1957.     }
  1958.     // don't copy the data, but transfer ownership to it
  1959.     pEnum->Init(pcd, pend, NULL, AtlFlagTakeOwnership);
  1960.     pT->Unlock();
  1961.     HRESULT hRes = pEnum->_InternalQueryInterface(IID_IEnumConnections, (void**)ppEnum);
  1962.     if (FAILED(hRes))
  1963.         delete pEnum;
  1964.     return hRes;
  1965. }
  1966.  
  1967. /////////////////////////////////////////////////////////////////////////////
  1968. // IConnectionPointContainerImpl
  1969.  
  1970. template <class T>
  1971. class ATL_NO_VTABLE IConnectionPointContainerImpl
  1972. {
  1973.     typedef CComEnum<IEnumConnectionPoints,
  1974.         &IID_IEnumConnectionPoints, IConnectionPoint*,
  1975.         _CopyInterface<IConnectionPoint> >
  1976.         CComEnumConnectionPoints;
  1977. public:
  1978.     // IUnknown
  1979.     //
  1980.     STDMETHOD(QueryInterface)(REFIID riid, void ** ppvObject) = 0;
  1981.     _ATL_DEBUG_ADDREF_RELEASE_IMPL(IConnectionPointContainerImpl)
  1982.  
  1983.     STDMETHOD(EnumConnectionPoints)(IEnumConnectionPoints** ppEnum)
  1984.     {
  1985.         if (ppEnum == NULL)
  1986.             return E_POINTER;
  1987.         *ppEnum = NULL;
  1988.         CComEnumConnectionPoints* pEnum = NULL;
  1989.         ATLTRY(pEnum = new CComObject<CComEnumConnectionPoints>)
  1990.         if (pEnum == NULL)
  1991.             return E_OUTOFMEMORY;
  1992.  
  1993.         int nCPCount;
  1994.         const _ATL_CONNMAP_ENTRY* pEntry = T::GetConnMap(&nCPCount);
  1995.  
  1996.         // allocate an initialize a vector of connection point object pointers
  1997.         IConnectionPoint** ppCP = (IConnectionPoint**)alloca(sizeof(IConnectionPoint*)*nCPCount);
  1998.  
  1999.         int i = 0;
  2000.         while (pEntry->dwOffset != (DWORD)-1)
  2001.         {
  2002.             ppCP[i++] = (IConnectionPoint*)((int)this+pEntry->dwOffset);
  2003.             pEntry++;
  2004.         }
  2005.  
  2006.         // copy the pointers: they will AddRef this object
  2007.         HRESULT hRes = pEnum->Init((IConnectionPoint**)&ppCP[0],
  2008.             (IConnectionPoint**)&ppCP[nCPCount],
  2009.             reinterpret_cast<IConnectionPointContainer*>(this), AtlFlagCopy);
  2010.         if (FAILED(hRes))
  2011.         {
  2012.             delete pEnum;
  2013.             return hRes;
  2014.         }
  2015.         hRes = pEnum->QueryInterface(IID_IEnumConnectionPoints, (void**)ppEnum);
  2016.         if (FAILED(hRes))
  2017.             delete pEnum;
  2018.         return hRes;
  2019.     }
  2020.     STDMETHOD(FindConnectionPoint)(REFIID riid, IConnectionPoint** ppCP)
  2021.     {
  2022.         if (ppCP == NULL)
  2023.             return E_POINTER;
  2024.         *ppCP = NULL;
  2025.         HRESULT hRes = CONNECT_E_NOCONNECTION;
  2026.         const _ATL_CONNMAP_ENTRY* pEntry = T::GetConnMap(NULL);
  2027.         IID iid;
  2028.         while (pEntry->dwOffset != (DWORD)-1)
  2029.         {
  2030.             IConnectionPoint* pCP =
  2031.                 (IConnectionPoint*)((int)this+pEntry->dwOffset);
  2032.             if (SUCCEEDED(pCP->GetConnectionInterface(&iid)) &&
  2033.                 InlineIsEqualGUID(riid, iid))
  2034.             {
  2035.                 *ppCP = pCP;
  2036.                 pCP->AddRef();
  2037.                 hRes = S_OK;
  2038.                 break;
  2039.             }
  2040.             pEntry++;
  2041.         }
  2042.         return hRes;
  2043.     }
  2044. };
  2045.  
  2046.  
  2047. #endif //!_ATL_NO_CONNECTION_POINTS
  2048.  
  2049. #pragma pack(pop)
  2050.  
  2051. /////////////////////////////////////////////////////////////////////////////
  2052. // CComAutoThreadModule
  2053.  
  2054. template <class ThreadAllocator>
  2055. inline void CComAutoThreadModule<ThreadAllocator>::Init(_ATL_OBJMAP_ENTRY* p, HINSTANCE h, int nThreads)
  2056. {
  2057.     m_nThreads = nThreads;
  2058.     m_pApartments = new CComApartment[m_nThreads];
  2059.     for (int i = 0; i < nThreads; i++)
  2060.         m_pApartments[i].m_hThread = CreateThread(NULL, 0, CComApartment::_Apartment, (void*)&m_pApartments[i], 0, &m_pApartments[i].m_dwThreadID);
  2061.     CComApartment::ATL_CREATE_OBJECT = RegisterWindowMessage(_T("ATL_CREATE_OBJECT"));
  2062.     CComModule::Init(p, h);
  2063. }
  2064.  
  2065. template <class ThreadAllocator>
  2066. inline LONG CComAutoThreadModule<ThreadAllocator>::Lock()
  2067. {
  2068.     LONG l = CComModule::Lock();
  2069.     DWORD dwThreadID = GetCurrentThreadId();
  2070.     for (int i=0; i < m_nThreads; i++)
  2071.     {
  2072.         if (m_pApartments[i].m_dwThreadID == dwThreadID)
  2073.         {
  2074.             m_pApartments[i].Lock();
  2075.             break;
  2076.         }
  2077.     }
  2078.     return l;
  2079. }
  2080.  
  2081. template <class ThreadAllocator>
  2082. inline LONG CComAutoThreadModule<ThreadAllocator>::Unlock()
  2083. {
  2084.     LONG l = CComModule::Unlock();
  2085.     DWORD dwThreadID = GetCurrentThreadId();
  2086.     for (int i=0; i < m_nThreads; i++)
  2087.     {
  2088.         if (m_pApartments[i].m_dwThreadID == dwThreadID)
  2089.         {
  2090.             m_pApartments[i].Unlock();
  2091.             break;
  2092.         }
  2093.     }
  2094.     return l;
  2095. }
  2096.  
  2097. template <class ThreadAllocator>
  2098. HRESULT CComAutoThreadModule<ThreadAllocator>::CreateInstance(void* pfnCreateInstance, REFIID riid, void** ppvObj)
  2099. {
  2100.     _ATL_CREATORFUNC* pFunc = (_ATL_CREATORFUNC*) pfnCreateInstance;
  2101.     _AtlAptCreateObjData data;
  2102.     data.pfnCreateInstance = pFunc;
  2103.     data.piid = &riid;
  2104.     data.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  2105.     data.hRes = S_OK;
  2106.     int nThread = m_Allocator.GetThread(m_pApartments, m_nThreads);
  2107.     ::PostThreadMessage(m_pApartments[nThread].m_dwThreadID, CComApartment::ATL_CREATE_OBJECT, 0, (LPARAM)&data);
  2108.     AtlWaitWithMessageLoop(data.hEvent);
  2109.     CloseHandle(data.hEvent);
  2110.     if (SUCCEEDED(data.hRes))
  2111.         data.hRes = CoGetInterfaceAndReleaseStream(data.pStream, riid, ppvObj);
  2112.     return data.hRes;
  2113. }
  2114.  
  2115. template <class ThreadAllocator>
  2116. CComAutoThreadModule<ThreadAllocator>::~CComAutoThreadModule()
  2117. {
  2118.     for (int i=0; i < m_nThreads; i++)
  2119.     {
  2120.         ::PostThreadMessage(m_pApartments[i].m_dwThreadID, WM_QUIT, 0, 0);
  2121.         ::WaitForSingleObject(m_pApartments[i].m_hThread, INFINITE);
  2122.     }
  2123.     delete[] m_pApartments;
  2124. }
  2125.  
  2126.  
  2127. #ifndef ATL_NO_NAMESPACE
  2128. }; //namespace ATL
  2129. #endif
  2130.  
  2131. #endif // __ATLCOM_H__
  2132.  
  2133. /////////////////////////////////////////////////////////////////////////////
  2134.