home *** CD-ROM | disk | FTP | other *** search
/ Team Palmtops 7 / Palmtops_numero07.iso / WinCE / SDKWindowsCE / HandHeldPCPro30 / sdk.exe / Jupiter SDK / data1.cab / ATL / include / Atlcom.h < prev    next >
Encoding:
C/C++ Source or Header  |  1999-02-19  |  151.0 KB  |  5,749 lines

  1. // This is a part of the Active Template Library.
  2. // Copyright (C) 1996-1998 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. #if defined(_WIN32_WCE)
  23. #include "wcedisp.h"
  24. #endif // _WIN32_WCE
  25. #pragma pack(push, _ATL_PACKING)
  26.  
  27. EXTERN_C const IID IID_ITargetFrame;
  28.  
  29. namespace ATL
  30. {
  31.  
  32. #define CComConnectionPointContainerImpl IConnectionPointContainerImpl
  33. #define CComISupportErrorInfoImpl ISupportErrorInfoImpl
  34. #define CComProvideClassInfo2Impl IProvideClassInfoImpl
  35. #define CComDualImpl IDispatchImpl
  36.  
  37. #ifdef _ATL_DEBUG_QI
  38. #ifndef _ATL_DEBUG
  39. #define _ATL_DEBUG
  40. #endif // _ATL_DEBUG
  41. #endif // _ATL_DEBUG_QI
  42.  
  43. #ifdef _ATL_DEBUG_QI
  44. #define _ATLDUMPIID(iid, name, hr) AtlDumpIID(iid, name, hr)
  45. #else
  46. #define _ATLDUMPIID(iid, name, hr) hr
  47. #endif
  48.  
  49. #define _ATL_DEBUG_ADDREF_RELEASE_IMPL(className)\
  50.     virtual ULONG STDMETHODCALLTYPE AddRef(void) = 0;\
  51.     virtual ULONG STDMETHODCALLTYPE Release(void) = 0;
  52.  
  53. /////////////////////////////////////////////////////////////////////////////
  54. // AtlReportError
  55.  
  56. inline HRESULT WINAPI AtlReportError(const CLSID& clsid, UINT nID, const IID& iid,
  57.     HRESULT hRes, HINSTANCE hInst)
  58. {
  59.     return AtlSetErrorInfo(clsid, (LPCOLESTR)MAKEINTRESOURCE(nID), 0, NULL, iid, hRes, hInst);
  60. }
  61.  
  62. inline HRESULT WINAPI AtlReportError(const CLSID& clsid, UINT nID, DWORD dwHelpID,
  63.     LPCOLESTR lpszHelpFile, const IID& iid, HRESULT hRes, HINSTANCE hInst)
  64. {
  65.     return AtlSetErrorInfo(clsid, (LPCOLESTR)MAKEINTRESOURCE(nID), dwHelpID,
  66.         lpszHelpFile, iid, hRes, hInst);
  67. }
  68.  
  69. #ifndef OLE2ANSI
  70. inline HRESULT WINAPI AtlReportError(const CLSID& clsid, LPCSTR lpszDesc,
  71.     DWORD dwHelpID, LPCSTR lpszHelpFile, const IID& iid, HRESULT hRes)
  72. {
  73.     ATLASSERT(lpszDesc != NULL);
  74.     USES_CONVERSION;
  75.     return AtlSetErrorInfo(clsid, A2COLE(lpszDesc), dwHelpID, A2CW(lpszHelpFile),
  76.         iid, hRes, NULL);
  77. }
  78.  
  79. inline HRESULT WINAPI AtlReportError(const CLSID& clsid, LPCSTR lpszDesc,
  80.     const IID& iid, HRESULT hRes)
  81. {
  82.     ATLASSERT(lpszDesc != NULL);
  83.     USES_CONVERSION;
  84.     return AtlSetErrorInfo(clsid, A2COLE(lpszDesc), 0, NULL, iid, hRes, NULL);
  85. }
  86. #endif
  87.  
  88. inline HRESULT WINAPI AtlReportError(const CLSID& clsid, LPCOLESTR lpszDesc,
  89.     const IID& iid, HRESULT hRes)
  90. {
  91.     return AtlSetErrorInfo(clsid, lpszDesc, 0, NULL, iid, hRes, NULL);
  92. }
  93.  
  94. inline HRESULT WINAPI AtlReportError(const CLSID& clsid, LPCOLESTR lpszDesc, DWORD dwHelpID,
  95.     LPCOLESTR lpszHelpFile, const IID& iid, HRESULT hRes)
  96. {
  97.     return AtlSetErrorInfo(clsid, lpszDesc, dwHelpID, lpszHelpFile, iid, hRes, NULL);
  98. }
  99.  
  100. //////////////////////////////////////////////////////////////////////////////
  101. // IPersistImpl
  102. template <class T>
  103. class ATL_NO_VTABLE IPersistImpl : public IPersist
  104. {
  105. public:
  106.     STDMETHOD(GetClassID)(CLSID *pClassID)
  107.     {
  108.         ATLTRACE2(atlTraceCOM, 0, _T("IPersistImpl::GetClassID\n"));
  109.         if (pClassID == NULL)
  110.             return E_FAIL;
  111.         *pClassID = T::GetObjectCLSID();
  112.         return S_OK;
  113.     }
  114. };
  115.  
  116.  
  117. //////////////////////////////////////////////////////////////////////////////
  118. // CComDispatchDriver / Specialization of CComQIPtr<IDispatch, IID_IDispatch>
  119. class CComDispatchDriver
  120. {
  121. public:
  122.     CComDispatchDriver()
  123.     {
  124.         p = NULL;
  125.     }
  126.     CComDispatchDriver(IDispatch* lp)
  127.     {
  128.         if ((p = lp) != NULL)
  129.             p->AddRef();
  130.     }
  131.     CComDispatchDriver(IUnknown* lp)
  132.     {
  133.         p=NULL;
  134.         if (lp != NULL)
  135.             lp->QueryInterface(IID_IDispatch, (void **)&p);
  136.     }
  137.     ~CComDispatchDriver() { if (p) p->Release(); }
  138.     void Release() {if (p) p->Release(); p=NULL;}
  139.     operator IDispatch*() {return p;}
  140.     IDispatch& operator*() {ATLASSERT(p!=NULL); return *p; }
  141.     IDispatch** operator&() {ATLASSERT(p==NULL); return &p; }
  142.     IDispatch* operator->() {ATLASSERT(p!=NULL); return p; }
  143.     IDispatch* operator=(IDispatch* lp){return (IDispatch*)AtlComPtrAssign((IUnknown**)&p, lp);}
  144.     IDispatch* operator=(IUnknown* lp)
  145.     {
  146.         return (IDispatch*)AtlComQIPtrAssign((IUnknown**)&p, lp, IID_IDispatch);
  147.     }
  148.     BOOL operator!(){return (p == NULL) ? TRUE : FALSE;}
  149.  
  150.     HRESULT GetPropertyByName(LPCOLESTR lpsz, VARIANT* pVar)
  151.     {
  152.         ATLASSERT(p);
  153.         ATLASSERT(pVar);
  154.         DISPID dwDispID;
  155.         HRESULT hr = GetIDOfName(lpsz, &dwDispID);
  156.         if (SUCCEEDED(hr))
  157.             hr = GetProperty(p, dwDispID, pVar);
  158.         return hr;
  159.     }
  160.     HRESULT GetProperty(DISPID dwDispID, VARIANT* pVar)
  161.     {
  162.         ATLASSERT(p);
  163.         return GetProperty(p, dwDispID, pVar);
  164.     }
  165.     HRESULT PutPropertyByName(LPCOLESTR lpsz, VARIANT* pVar)
  166.     {
  167.         ATLASSERT(p);
  168.         ATLASSERT(pVar);
  169.         DISPID dwDispID;
  170.         HRESULT hr = GetIDOfName(lpsz, &dwDispID);
  171.         if (SUCCEEDED(hr))
  172.             hr = PutProperty(p, dwDispID, pVar);
  173.         return hr;
  174.     }
  175.     HRESULT PutProperty(DISPID dwDispID, VARIANT* pVar)
  176.     {
  177.         ATLASSERT(p);
  178.         return PutProperty(p, dwDispID, pVar);
  179.     }
  180.     HRESULT GetIDOfName(LPCOLESTR lpsz, DISPID* pdispid)
  181.     {
  182.         return p->GetIDsOfNames(IID_NULL, (LPOLESTR*)&lpsz, 1, LOCALE_USER_DEFAULT, pdispid);
  183.     }
  184.     // Invoke a method by DISPID with no parameters
  185.     HRESULT Invoke0(DISPID dispid, VARIANT* pvarRet = NULL)
  186.     {
  187.         DISPPARAMS dispparams = { NULL, NULL, 0, 0};
  188.         return p->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, pvarRet, NULL, NULL);
  189.     }
  190.     // Invoke a method by name with no parameters
  191.     HRESULT Invoke0(LPCOLESTR lpszName, VARIANT* pvarRet = NULL)
  192.     {
  193.         HRESULT hr;
  194.         DISPID dispid;
  195.         hr = GetIDOfName(lpszName, &dispid);
  196.         if (SUCCEEDED(hr))
  197.             hr = Invoke0(dispid, pvarRet);
  198.         return hr;
  199.     }
  200.     // Invoke a method by DISPID with a single parameter
  201.     HRESULT Invoke1(DISPID dispid, VARIANT* pvarParam1, VARIANT* pvarRet = NULL)
  202.     {
  203.         DISPPARAMS dispparams = { pvarParam1, NULL, 1, 0};
  204.         return p->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, pvarRet, NULL, NULL);
  205.     }
  206.     // Invoke a method by name with a single parameter
  207.     HRESULT Invoke1(LPCOLESTR lpszName, VARIANT* pvarParam1, VARIANT* pvarRet = NULL)
  208.     {
  209.         HRESULT hr;
  210.         DISPID dispid;
  211.         hr = GetIDOfName(lpszName, &dispid);
  212.         if (SUCCEEDED(hr))
  213.             hr = Invoke1(dispid, pvarParam1, pvarRet);
  214.         return hr;
  215.     }
  216.     // Invoke a method by DISPID with two parameters
  217.     HRESULT Invoke2(DISPID dispid, VARIANT* pvarParam1, VARIANT* pvarParam2, VARIANT* pvarRet = NULL)
  218.     {
  219.         CComVariant varArgs[2] = { *pvarParam2, *pvarParam1 };
  220.         DISPPARAMS dispparams = { &varArgs[0], NULL, 2, 0};
  221.         return p->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, pvarRet, NULL, NULL);
  222.     }
  223.     // Invoke a method by name with two parameters
  224.     HRESULT Invoke2(LPCOLESTR lpszName, VARIANT* pvarParam1, VARIANT* pvarParam2, VARIANT* pvarRet = NULL)
  225.     {
  226.         HRESULT hr;
  227.         DISPID dispid;
  228.         hr = GetIDOfName(lpszName, &dispid);
  229.         if (SUCCEEDED(hr))
  230.             hr = Invoke2(dispid, pvarParam1, pvarParam2, pvarRet);
  231.         return hr;
  232.     }
  233.     // Invoke a method by DISPID with N parameters
  234.     HRESULT InvokeN(DISPID dispid, VARIANT* pvarParams, int nParams, VARIANT* pvarRet = NULL)
  235.     {
  236.         DISPPARAMS dispparams = { pvarParams, NULL, nParams, 0};
  237.         return p->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, pvarRet, NULL, NULL);
  238.     }
  239.     // Invoke a method by name with Nparameters
  240.     HRESULT InvokeN(LPCOLESTR lpszName, VARIANT* pvarParams, int nParams, VARIANT* pvarRet = NULL)
  241.     {
  242.         HRESULT hr;
  243.         DISPID dispid;
  244.         hr = GetIDOfName(lpszName, &dispid);
  245.         if (SUCCEEDED(hr))
  246.             hr = InvokeN(dispid, pvarParams, nParams, pvarRet);
  247.         return hr;
  248.     }
  249.     static HRESULT GetProperty(IDispatch* pDisp, DISPID dwDispID,
  250.         VARIANT* pVar)
  251.     {
  252.         ATLTRACE2(atlTraceCOM, 0, _T("CPropertyHelper::GetProperty\n"));
  253.         DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
  254.         return pDisp->Invoke(dwDispID, IID_NULL,
  255.                 LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET,
  256.                 &dispparamsNoArgs, pVar, NULL, NULL);
  257.     }
  258.  
  259.     static HRESULT PutProperty(IDispatch* pDisp, DISPID dwDispID,
  260.         VARIANT* pVar)
  261.     {
  262.         ATLTRACE2(atlTraceCOM, 0, _T("CPropertyHelper::PutProperty\n"));
  263.         DISPPARAMS dispparams = {NULL, NULL, 1, 1};
  264.         dispparams.rgvarg = pVar;
  265.         DISPID dispidPut = DISPID_PROPERTYPUT;
  266.         dispparams.rgdispidNamedArgs = &dispidPut;
  267.  
  268.         if (pVar->vt == VT_UNKNOWN || pVar->vt == VT_DISPATCH || 
  269.             (pVar->vt & VT_ARRAY) || (pVar->vt & VT_BYREF))
  270.         {
  271.             HRESULT hr = pDisp->Invoke(dwDispID, IID_NULL,
  272.                 LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUTREF,
  273.                 &dispparams, NULL, NULL, NULL);
  274.             if (SUCCEEDED(hr))
  275.                 return hr;
  276.         }
  277.  
  278.         return pDisp->Invoke(dwDispID, IID_NULL,
  279.                 LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT,
  280.                 &dispparams, NULL, NULL, NULL);
  281.     }
  282.  
  283.     IDispatch* p;
  284. };
  285.  
  286. //////////////////////////////////////////////////////////////////////////////
  287. // CFakeFirePropNotifyEvent
  288. class CFakeFirePropNotifyEvent
  289. {
  290. public:
  291.     static HRESULT FireOnRequestEdit(IUnknown* /*pUnk*/, DISPID /*dispID*/)
  292.     {
  293.         return S_OK;
  294.     }
  295.     static HRESULT FireOnChanged(IUnknown* /*pUnk*/, DISPID /*dispID*/)
  296.     {
  297.         return S_OK;
  298.     }
  299. };
  300. typedef CFakeFirePropNotifyEvent _ATL_PROP_NOTIFY_EVENT_CLASS;
  301.  
  302. //////////////////////////////////////////////////////////////////////////////
  303. // ATL Persistence
  304.  
  305. struct ATL_PROPMAP_ENTRY
  306. {
  307.     LPCOLESTR szDesc;
  308.     DISPID dispid;
  309.     const CLSID* pclsidPropPage;
  310.     const IID* piidDispatch;
  311.     DWORD dwOffsetData;
  312.     DWORD dwSizeData;
  313.     VARTYPE vt;
  314. };
  315.  
  316. // This one is DEPRECATED and is used for ATL 2.X controls
  317. // it includes an implicit m_sizeExtent
  318. #define BEGIN_PROPERTY_MAP(theClass) \
  319.     typedef _ATL_PROP_NOTIFY_EVENT_CLASS __ATL_PROP_NOTIFY_EVENT_CLASS; \
  320.     typedef theClass _PropMapClass; \
  321.     static ATL_PROPMAP_ENTRY* GetPropertyMap()\
  322.     {\
  323.         static ATL_PROPMAP_ENTRY pPropMap[] = \
  324.         { \
  325.             {OLESTR("_cx"), 0, &CLSID_NULL, NULL, offsetof(_PropMapClass, m_sizeExtent.cx), sizeof(long), VT_UI4}, \
  326.             {OLESTR("_cy"), 0, &CLSID_NULL, NULL, offsetof(_PropMapClass, m_sizeExtent.cy), sizeof(long), VT_UI4},
  327.  
  328. // This one can be used on any type of object, but does not
  329. // include the implicit m_sizeExtent
  330. #define BEGIN_PROP_MAP(theClass) \
  331.     typedef _ATL_PROP_NOTIFY_EVENT_CLASS __ATL_PROP_NOTIFY_EVENT_CLASS; \
  332.     typedef theClass _PropMapClass; \
  333.     static ATL_PROPMAP_ENTRY* GetPropertyMap()\
  334.     {\
  335.         static ATL_PROPMAP_ENTRY pPropMap[] = \
  336.         {
  337.  
  338. #define PROP_ENTRY(szDesc, dispid, clsid) \
  339.         {OLESTR(szDesc), dispid, &clsid, &IID_IDispatch, 0, 0, 0},
  340.  
  341. #define PROP_ENTRY_EX(szDesc, dispid, clsid, iidDispatch) \
  342.         {OLESTR(szDesc), dispid, &clsid, &iidDispatch, 0, 0, 0},
  343.  
  344. #define PROP_PAGE(clsid) \
  345.         {NULL, NULL, &clsid, &IID_NULL, 0, 0, 0},
  346.  
  347. #define PROP_DATA_ENTRY(szDesc, member, vt) \
  348.         {OLESTR(szDesc), 0, &CLSID_NULL, NULL, offsetof(_PropMapClass, member), sizeof(((_PropMapClass*)0)->member), vt},
  349.  
  350. #define END_PROPERTY_MAP() \
  351.             {NULL, 0, NULL, &IID_NULL, 0, 0, 0} \
  352.         }; \
  353.         return pPropMap; \
  354.     }
  355.  
  356. #define END_PROP_MAP() \
  357.             {NULL, 0, NULL, &IID_NULL, 0, 0, 0} \
  358.         }; \
  359.         return pPropMap; \
  360.     }
  361.  
  362.  
  363. #ifdef _ATL_DLL
  364. ATLAPI AtlIPersistStreamInit_Load(LPSTREAM pStm, ATL_PROPMAP_ENTRY* pMap, void* pThis, IUnknown* pUnk);
  365. #else
  366. #if defined(_WIN32_WCE)
  367. ATLAPI AtlIPersistStreamInit_Load(LPSTREAM pStm, ATL_PROPMAP_ENTRY* pMap, void* pThis, IUnknown* pUnk);
  368. #else // _WIN32_WCE
  369. ATLINLINE ATLAPI AtlIPersistStreamInit_Load(LPSTREAM pStm, ATL_PROPMAP_ENTRY* pMap, void* pThis, IUnknown* pUnk)
  370. {
  371.     ATLASSERT(pMap != NULL);
  372.     HRESULT hr = S_OK;
  373.     DWORD dwVer;
  374.     hr = pStm->Read(&dwVer, sizeof(DWORD), NULL);
  375.     if (FAILED(hr))
  376.         return hr;
  377.     if (dwVer > _ATL_VER)
  378.         return E_FAIL;
  379.  
  380.     CComPtr<IDispatch> pDispatch;
  381.     const IID* piidOld = NULL;
  382.     for (int i = 0; pMap[i].pclsidPropPage != NULL; i++)
  383.     {
  384.         if (pMap[i].szDesc == NULL)
  385.             continue;
  386.  
  387.         // check if raw data entry
  388.         if (pMap[i].dwSizeData != 0)
  389.         {
  390.             void* pData = (void*) (pMap[i].dwOffsetData + (DWORD)pThis);
  391.             hr = pStm->Read(pData, pMap[i].dwSizeData, NULL);
  392.             if (FAILED(hr))
  393.                 return hr;
  394.             continue;
  395.         }
  396.  
  397.         CComVariant var;
  398.  
  399.         hr = var.ReadFromStream(pStm);
  400.         if (FAILED(hr))
  401.             break;
  402.  
  403.         if (pMap[i].piidDispatch != piidOld)
  404.         {
  405.             pDispatch.Release();
  406.             if (FAILED(pUnk->QueryInterface(*pMap[i].piidDispatch, (void**)&pDispatch)))
  407.             {
  408.                 ATLTRACE2(atlTraceCOM, 0, _T("Failed to get a dispatch pointer for property #%i\n"), i);
  409.                 hr = E_FAIL;
  410.                 break;
  411.             }
  412.             piidOld = pMap[i].piidDispatch;
  413.         }
  414.  
  415.         if (FAILED(CComDispatchDriver::PutProperty(pDispatch, pMap[i].dispid, &var)))
  416.         {
  417.             ATLTRACE2(atlTraceCOM, 0, _T("Invoked failed on DISPID %x\n"), pMap[i].dispid);
  418.             hr = E_FAIL;
  419.             break;
  420.         }
  421.     }
  422.     return hr;
  423. }
  424. #endif // _WIN32_WCE
  425. #endif //_ATL_DLL
  426.  
  427. #ifdef _ATL_DLL
  428. ATLAPI AtlIPersistStreamInit_Save(LPSTREAM pStm, BOOL fClearDirty, ATL_PROPMAP_ENTRY* pMap, void* pThis, IUnknown* pUnk);
  429. #else
  430. #if defined(_WIN32_WCE)
  431. ATLAPI AtlIPersistStreamInit_Save(LPSTREAM pStm,
  432.     BOOL /* fClearDirty */, ATL_PROPMAP_ENTRY* pMap,
  433.     void* pThis, IUnknown* pUnk);
  434. #else
  435. ATLINLINE ATLAPI AtlIPersistStreamInit_Save(LPSTREAM pStm,
  436.     BOOL /* fClearDirty */, ATL_PROPMAP_ENTRY* pMap,
  437.     void* pThis, IUnknown* pUnk)
  438. {
  439.     ATLASSERT(pMap != NULL);
  440.     DWORD dw = _ATL_VER;
  441.     HRESULT hr = pStm->Write(&dw, sizeof(DWORD), NULL);
  442.     if (FAILED(hr))
  443.         return hr;
  444.  
  445.     CComPtr<IDispatch> pDispatch;
  446.     const IID* piidOld = NULL;
  447.     for (int i = 0; pMap[i].pclsidPropPage != NULL; i++)
  448.     {
  449.         if (pMap[i].szDesc == NULL)
  450.             continue;
  451.  
  452.         // check if raw data entry
  453.         if (pMap[i].dwSizeData != 0)
  454.         {
  455.             void* pData = (void*) (pMap[i].dwOffsetData + (DWORD)pThis);
  456.             hr = pStm->Write(pData, pMap[i].dwSizeData, NULL);
  457.             if (FAILED(hr))
  458.                 return hr;
  459.             continue;
  460.         }
  461.  
  462.         CComVariant var;
  463.         if (pMap[i].piidDispatch != piidOld)
  464.         {
  465.             pDispatch.Release();
  466.             if (FAILED(pUnk->QueryInterface(*pMap[i].piidDispatch, (void**)&pDispatch)))
  467.             {
  468.                 ATLTRACE2(atlTraceCOM, 0, _T("Failed to get a dispatch pointer for property #%i\n"), i);
  469.                 hr = E_FAIL;
  470.                 break;
  471.             }
  472.             piidOld = pMap[i].piidDispatch;
  473.         }
  474.  
  475.         if (FAILED(CComDispatchDriver::GetProperty(pDispatch, pMap[i].dispid, &var)))
  476.         {
  477.             ATLTRACE2(atlTraceCOM, 0, _T("Invoked failed on DISPID %x\n"), pMap[i].dispid);
  478.             hr = E_FAIL;
  479.             break;
  480.         }
  481.  
  482.         hr = var.WriteToStream(pStm);
  483.         if (FAILED(hr))
  484.             break;
  485.     }
  486.     return hr;
  487. }
  488. #endif // _WIN32_WCE
  489. #endif //_ATL_DLL
  490.  
  491.  
  492. #ifdef _ATL_DLL
  493. ATLAPI AtlIPersistPropertyBag_Load(LPPROPERTYBAG pPropBag, LPERRORLOG pErrorLog, ATL_PROPMAP_ENTRY* pMap, void* pThis, IUnknown* pUnk);
  494. #else
  495. #if defined(_WIN32_WCE)
  496. ATLAPI AtlIPersistPropertyBag_Load(LPPROPERTYBAG pPropBag, LPERRORLOG pErrorLog, ATL_PROPMAP_ENTRY* pMap, void* pThis, IUnknown* pUnk);
  497. #else // _WIN32_WCE
  498. ATLINLINE ATLAPI AtlIPersistPropertyBag_Load(LPPROPERTYBAG pPropBag, LPERRORLOG pErrorLog, ATL_PROPMAP_ENTRY* pMap, void* pThis, IUnknown* pUnk)
  499. {
  500.     USES_CONVERSION;
  501.     CComPtr<IDispatch> pDispatch;
  502.     const IID* piidOld = NULL;
  503.     for (int i = 0; pMap[i].pclsidPropPage != NULL; i++)
  504.     {
  505.         if (pMap[i].szDesc == NULL)
  506.             continue;
  507.  
  508.         CComVariant var;
  509.  
  510.         // If raw entry skip it - we don't handle it for property bags just yet
  511.         if (pMap[i].dwSizeData != 0)
  512.         {
  513.             void* pData = (void*) (pMap[i].dwOffsetData + (DWORD)pThis);
  514.             HRESULT hr = pPropBag->Read(pMap[i].szDesc, &var, pErrorLog);
  515.             if (SUCCEEDED(hr))
  516.             {
  517.                 // check the type - we only deal with limited set
  518.                 switch (pMap[i].vt)
  519.                 {
  520.                 case VT_UI1:
  521.                 case VT_I1:
  522.                     *((BYTE*)pData) = var.bVal;
  523.                     break;
  524.                 case VT_BOOL:
  525.                     *((VARIANT_BOOL*)pData) = var.boolVal;
  526.                     break;
  527.                 case VT_UI2:
  528.                     *((short*)pData) = var.iVal;
  529.                     break;
  530.                 case VT_UI4:
  531.                 case VT_INT:
  532.                 case VT_UINT:
  533.                     *((long*)pData) = var.lVal;
  534.                     break;
  535.                 }
  536.             }
  537.             continue;
  538.         }
  539.  
  540.         if (pMap[i].piidDispatch != piidOld)
  541.         {
  542.             pDispatch.Release();
  543.             if (FAILED(pUnk->QueryInterface(*pMap[i].piidDispatch, (void**)&pDispatch)))
  544.             {
  545.                 ATLTRACE2(atlTraceCOM, 0, _T("Failed to get a dispatch pointer for property #%i\n"), i);
  546.                 return E_FAIL;
  547.             }
  548.             piidOld = pMap[i].piidDispatch;
  549.         }
  550.  
  551.         if (FAILED(CComDispatchDriver::GetProperty(pDispatch, pMap[i].dispid, &var)))
  552.         {
  553.             ATLTRACE2(atlTraceCOM, 0, _T("Invoked failed on DISPID %x\n"), pMap[i].dispid);
  554.             return E_FAIL;
  555.         }
  556.  
  557.         HRESULT hr = pPropBag->Read(pMap[i].szDesc, &var, pErrorLog);
  558.         if (FAILED(hr))
  559.         {
  560.             if (hr == E_INVALIDARG)
  561.             {
  562.                 ATLTRACE2(atlTraceCOM, 0, _T("Property %s not in Bag\n"), OLE2CT(pMap[i].szDesc));
  563.             }
  564.             else
  565.             {
  566.                 // Many containers return different ERROR values for Member not found
  567.                 ATLTRACE2(atlTraceCOM, 0, _T("Error attempting to read Property %s from PropertyBag \n"), OLE2CT(pMap[i].szDesc));
  568.             }
  569.             continue;
  570.         }
  571.  
  572.         if (FAILED(CComDispatchDriver::PutProperty(pDispatch, pMap[i].dispid, &var)))
  573.         {
  574.             ATLTRACE2(atlTraceCOM, 0, _T("Invoked failed on DISPID %x\n"), pMap[i].dispid);
  575.             return E_FAIL;
  576.         }
  577.     }
  578.     return S_OK;
  579. }
  580. #endif // _WIN32_WCE
  581. #endif //_ATL_DLL
  582.  
  583. #ifdef _ATL_DLL
  584. ATLAPI AtlIPersistPropertyBag_Save(LPPROPERTYBAG pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties, ATL_PROPMAP_ENTRY* pMap, void* pThis, IUnknown* pUnk);
  585. #else
  586. #if defined(_WIN32_WCE)
  587. ATLAPI AtlIPersistPropertyBag_Save(LPPROPERTYBAG pPropBag,
  588.     BOOL /* fClearDirty */, BOOL /* fSaveAllProperties */,
  589.     ATL_PROPMAP_ENTRY* pMap, void* pThis, IUnknown* pUnk);
  590. #else // _WIN32_WCE
  591. ATLINLINE ATLAPI AtlIPersistPropertyBag_Save(LPPROPERTYBAG pPropBag,
  592.     BOOL /* fClearDirty */, BOOL /* fSaveAllProperties */,
  593.     ATL_PROPMAP_ENTRY* pMap, void* pThis, IUnknown* pUnk)
  594. {
  595.     if (pPropBag == NULL)
  596.     {
  597.         ATLTRACE2(atlTraceCOM, 0, _T("PropBag pointer passed in was invalid\n"));
  598.         return E_POINTER;
  599.     }
  600.  
  601.     CComPtr<IDispatch> pDispatch;
  602.     const IID* piidOld = NULL;
  603.     for (int i = 0; pMap[i].pclsidPropPage != NULL; i++)
  604.     {
  605.         if (pMap[i].szDesc == NULL)
  606.             continue;
  607.  
  608.         CComVariant var;
  609.  
  610.         // If raw entry skip it - we don't handle it for property bags just yet
  611.         if (pMap[i].dwSizeData != 0)
  612.         {
  613.             void* pData = (void*) (pMap[i].dwOffsetData + (DWORD)pThis);
  614.             // check the type - we only deal with limited set
  615.             bool bTypeOK = false;
  616.             switch (pMap[i].vt)
  617.             {
  618.             case VT_UI1:
  619.             case VT_I1:
  620.                 var.bVal = *((BYTE*)pData);
  621.                 bTypeOK = true;
  622.                 break;
  623.             case VT_BOOL:
  624.                 var.boolVal = *((VARIANT_BOOL*)pData);
  625.                 bTypeOK = true;
  626.                 break;
  627.             case VT_UI2:
  628.                 var.iVal = *((short*)pData);
  629.                 bTypeOK = true;
  630.                 break;
  631.             case VT_UI4:
  632.             case VT_INT:
  633.             case VT_UINT:
  634.                 var.lVal = *((long*)pData);
  635.                 bTypeOK = true;
  636.                 break;
  637.             }
  638.             if (bTypeOK)
  639.             {
  640.                 var.vt = pMap[i].vt;
  641.                 HRESULT hr = pPropBag->Write(pMap[i].szDesc, &var);
  642.                 if (FAILED(hr))
  643.                     return hr;
  644.             }
  645.             continue;
  646.         }
  647.  
  648.         if (pMap[i].piidDispatch != piidOld)
  649.         {
  650.             pDispatch.Release();
  651.             if (FAILED(pUnk->QueryInterface(*pMap[i].piidDispatch, (void**)&pDispatch)))
  652.             {
  653.                 ATLTRACE2(atlTraceCOM, 0, _T("Failed to get a dispatch pointer for property #%i\n"), i);
  654.                 return E_FAIL;
  655.             }
  656.             piidOld = pMap[i].piidDispatch;
  657.         }
  658.  
  659.         if (FAILED(CComDispatchDriver::GetProperty(pDispatch, pMap[i].dispid, &var)))
  660.         {
  661.             ATLTRACE2(atlTraceCOM, 0, _T("Invoked failed on DISPID %x\n"), pMap[i].dispid);
  662.             return E_FAIL;
  663.         }
  664.  
  665.         if (var.vt == VT_UNKNOWN || var.vt == VT_DISPATCH)
  666.         {
  667.             if (var.punkVal == NULL)
  668.             {
  669.                 ATLTRACE2(atlTraceCOM, 0, _T("Warning skipping empty IUnknown in Save\n"));
  670.                 continue;
  671.             }
  672.         }
  673.  
  674.         HRESULT hr = pPropBag->Write(pMap[i].szDesc, &var);
  675.         if (FAILED(hr))
  676.             return hr;
  677.     }
  678.     return S_OK;
  679. }
  680. #endif // _WIN32_WCE
  681. #endif //_ATL_DLL
  682.  
  683.  
  684. //////////////////////////////////////////////////////////////////////////////
  685. // IPersistStreamInitImpl
  686. template <class T>
  687. class ATL_NO_VTABLE IPersistStreamInitImpl : public IPersistStreamInit
  688. {
  689. public:
  690.     // IPersist
  691.     STDMETHOD(GetClassID)(CLSID *pClassID)
  692.     {
  693.         ATLTRACE2(atlTraceCOM, 0, _T("IPersistStreamInitImpl::GetClassID\n"));
  694.         *pClassID = T::GetObjectCLSID();
  695.         return S_OK;
  696.     }
  697.  
  698.     // IPersistStream
  699.     STDMETHOD(IsDirty)()
  700.     {
  701.         ATLTRACE2(atlTraceCOM, 0, _T("IPersistStreamInitImpl::IsDirty\n"));
  702.         T* pT = static_cast<T*>(this);
  703.         return (pT->m_bRequiresSave) ? S_OK : S_FALSE;
  704.     }
  705.     STDMETHOD(Load)(LPSTREAM pStm)
  706.     {
  707. #if defined(_WIN32_WCE)
  708. // WinCE:  there is a stack-related problem with wce_OleLoadFromStream 
  709.         memset(alloca(128), 0, 128);
  710. #endif // _WIN32_WCE
  711.         ATLTRACE2(atlTraceCOM, 0, _T("IPersistStreamInitImpl::Load\n"));
  712.         T* pT = static_cast<T*>(this);
  713.         return pT->IPersistStreamInit_Load(pStm, T::GetPropertyMap());
  714.     }
  715.     STDMETHOD(Save)(LPSTREAM pStm, BOOL fClearDirty)
  716.     {
  717.         T* pT = static_cast<T*>(this);
  718.         ATLTRACE2(atlTraceCOM, 0, _T("IPersistStreamInitImpl::Save\n"));
  719.         return pT->IPersistStreamInit_Save(pStm, fClearDirty, T::GetPropertyMap());
  720.     }
  721.     STDMETHOD(GetSizeMax)(ULARGE_INTEGER FAR* /* pcbSize */)
  722.     {
  723.         ATLTRACENOTIMPL(_T("IPersistStreamInitImpl::GetSizeMax"));
  724.     }
  725.  
  726.     // IPersistStreamInit
  727.     STDMETHOD(InitNew)()
  728.     {
  729.         ATLTRACE2(atlTraceCOM, 0, _T("IPersistStreamInitImpl::InitNew\n"));
  730.         return S_OK;
  731.     }
  732.  
  733.     HRESULT IPersistStreamInit_Load(LPSTREAM pStm, ATL_PROPMAP_ENTRY* pMap)
  734.     {
  735.         T* pT = static_cast<T*>(this);
  736.         HRESULT hr = AtlIPersistStreamInit_Load(pStm, pMap, pT, pT->GetUnknown());
  737.         if (SUCCEEDED(hr))
  738.             pT->m_bRequiresSave = FALSE;
  739.         return hr;
  740.  
  741.     }
  742.     HRESULT IPersistStreamInit_Save(LPSTREAM pStm, BOOL fClearDirty, ATL_PROPMAP_ENTRY* pMap)
  743.     {
  744.         T* pT = static_cast<T*>(this);
  745.         return AtlIPersistStreamInit_Save(pStm, fClearDirty, pMap, pT, pT->GetUnknown());
  746.     }
  747. };
  748.  
  749. //////////////////////////////////////////////////////////////////////////////
  750. // IPersistStorageImpl
  751. template <class T>
  752. class ATL_NO_VTABLE IPersistStorageImpl : public IPersistStorage
  753. {
  754. public:
  755.     // IPersist
  756.     STDMETHOD(GetClassID)(CLSID *pClassID)
  757.     {
  758.         ATLTRACE2(atlTraceCOM, 0, _T("IPersistStorageImpl::GetClassID\n"));
  759.         *pClassID = T::GetObjectCLSID();
  760.         return S_OK;
  761.     }
  762.  
  763.     // IPersistStorage
  764.     STDMETHOD(IsDirty)(void)
  765.     {
  766.         ATLTRACE2(atlTraceCOM, 0, _T("IPersistStorageImpl::IsDirty\n"));
  767.         CComPtr<IPersistStreamInit> p;
  768.         p.p = IPSI_GetIPersistStreamInit();
  769.         return (p != NULL) ? p->IsDirty() : E_FAIL;
  770.     }
  771.     STDMETHOD(InitNew)(IStorage*)
  772.     {
  773.         ATLTRACE2(atlTraceCOM, 0, _T("IPersistStorageImpl::InitNew\n"));
  774.         CComPtr<IPersistStreamInit> p;
  775.         p.p = IPSI_GetIPersistStreamInit();
  776.         return (p != NULL) ? p->InitNew() : E_FAIL;
  777.     }
  778.     STDMETHOD(Load)(IStorage* pStorage)
  779.     {
  780.         ATLTRACE2(atlTraceCOM, 0, _T("IPersistStorageImpl::Load\n"));
  781.         CComPtr<IPersistStreamInit> p;
  782.         p.p = IPSI_GetIPersistStreamInit();
  783.         HRESULT hr = E_FAIL;
  784.         if (p != NULL)
  785.         {
  786.             CComPtr<IStream> spStream;
  787.             hr = pStorage->OpenStream(OLESTR("Contents"), NULL,
  788.                 STGM_DIRECT | STGM_SHARE_EXCLUSIVE, 0, &spStream);
  789.             if (SUCCEEDED(hr))
  790.                 hr = p->Load(spStream);
  791.         }
  792.         return hr;
  793.     }
  794.     STDMETHOD(Save)(IStorage* pStorage, BOOL fSameAsLoad)
  795.     {
  796.         ATLTRACE2(atlTraceCOM, 0, _T("IPersistStorageImpl::Save\n"));
  797.         CComPtr<IPersistStreamInit> p;
  798.         p.p = IPSI_GetIPersistStreamInit();
  799.         HRESULT hr = E_FAIL;
  800.         if (p != NULL)
  801.         {
  802.             CComPtr<IStream> spStream;
  803.             static LPCOLESTR vszContents = OLESTR("Contents");
  804.             hr = pStorage->CreateStream(vszContents,
  805.                 STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
  806.                 0, 0, &spStream);
  807.             if (SUCCEEDED(hr))
  808.                 hr = p->Save(spStream, fSameAsLoad);
  809.         }
  810.         return hr;
  811.     }
  812.     STDMETHOD(SaveCompleted)(IStorage* /* pStorage */)
  813.     {
  814.         ATLTRACE2(atlTraceCOM, 0, _T("IPersistStorageImpl::SaveCompleted\n"));
  815.         return S_OK;
  816.     }
  817.     STDMETHOD(HandsOffStorage)(void)
  818.     {
  819.         ATLTRACE2(atlTraceCOM, 0, _T("IPersistStorageImpl::HandsOffStorage\n"));
  820.         return S_OK;
  821.     }
  822. private:
  823.     IPersistStreamInit* IPSI_GetIPersistStreamInit();
  824. };
  825.  
  826. template <class T>
  827. IPersistStreamInit* IPersistStorageImpl<T>::IPSI_GetIPersistStreamInit()
  828. {
  829.     T* pT = static_cast<T*>(this);
  830.     IPersistStreamInit* p;
  831.     if (FAILED(pT->GetUnknown()->QueryInterface(IID_IPersistStreamInit, (void**)&p)))
  832.         pT->_InternalQueryInterface(IID_IPersistStreamInit, (void**)&p);
  833.     return p;
  834. }
  835.  
  836.  
  837. //////////////////////////////////////////////////////////////////////////////
  838. // IPersistPropertyBagImpl
  839. template <class T>
  840. class ATL_NO_VTABLE IPersistPropertyBagImpl : public IPersistPropertyBag
  841. {
  842. public:
  843.     // IPersist
  844.     STDMETHOD(GetClassID)(CLSID *pClassID)
  845.     {
  846.         ATLTRACE2(atlTraceCOM, 0, _T("IPersistPropertyBagImpl::GetClassID\n"));
  847.         *pClassID = T::GetObjectCLSID();
  848.         return S_OK;
  849.     }
  850.  
  851.     // IPersistPropertyBag
  852.     //
  853.     STDMETHOD(InitNew)()
  854.     {
  855.         ATLTRACE2(atlTraceCOM, 0, _T("IPersistPropertyBagImpl::InitNew\n"));
  856.         return S_OK;
  857.     }
  858.     STDMETHOD(Load)(LPPROPERTYBAG pPropBag, LPERRORLOG pErrorLog)
  859.     {
  860.         ATLTRACE2(atlTraceCOM, 0, _T("IPersistPropertyBagImpl::Load\n"));
  861.         T* pT = static_cast<T*>(this);
  862.         ATL_PROPMAP_ENTRY* pMap = T::GetPropertyMap();
  863.         ATLASSERT(pMap != NULL);
  864.         return pT->IPersistPropertyBag_Load(pPropBag, pErrorLog, pMap);
  865.     }
  866.     STDMETHOD(Save)(LPPROPERTYBAG pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties)
  867.     {
  868.         ATLTRACE2(atlTraceCOM, 0, _T("IPersistPropertyBagImpl::Save\n"));
  869.         T* pT = static_cast<T*>(this);
  870.         ATL_PROPMAP_ENTRY* pMap = T::GetPropertyMap();
  871.         ATLASSERT(pMap != NULL);
  872.         return pT->IPersistPropertyBag_Save(pPropBag, fClearDirty, fSaveAllProperties, pMap);
  873.     }
  874.     HRESULT IPersistPropertyBag_Load(LPPROPERTYBAG pPropBag, LPERRORLOG pErrorLog, ATL_PROPMAP_ENTRY* pMap)
  875.     {
  876.         T* pT = static_cast<T*>(this);
  877.         HRESULT hr = AtlIPersistPropertyBag_Load(pPropBag, pErrorLog, pMap, pT, pT->GetUnknown());
  878.         if (SUCCEEDED(hr))
  879.             pT->m_bRequiresSave = FALSE;
  880.         return hr;
  881.     }
  882.     HRESULT IPersistPropertyBag_Save(LPPROPERTYBAG pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties, ATL_PROPMAP_ENTRY* pMap)
  883.     {
  884.         T* pT = static_cast<T*>(this);
  885.         return AtlIPersistPropertyBag_Save(pPropBag, fClearDirty, fSaveAllProperties, pMap, pT, pT->GetUnknown());
  886.     }
  887. };
  888.  
  889. #if !defined(_WIN32_WCE)
  890. //////////////////////////////////////////////////////////////////////////////
  891. // CSecurityDescriptor
  892. class CSecurityDescriptor
  893. {
  894. public:
  895.     CSecurityDescriptor();
  896.     ~CSecurityDescriptor();
  897.  
  898. public:
  899.     HRESULT Attach(PSECURITY_DESCRIPTOR pSelfRelativeSD);
  900.     HRESULT AttachObject(HANDLE hObject);
  901.     HRESULT Initialize();
  902.     HRESULT InitializeFromProcessToken(BOOL bDefaulted = FALSE);
  903.     HRESULT InitializeFromThreadToken(BOOL bDefaulted = FALSE, BOOL bRevertToProcessToken = TRUE);
  904.     HRESULT SetOwner(PSID pOwnerSid, BOOL bDefaulted = FALSE);
  905.     HRESULT SetGroup(PSID pGroupSid, BOOL bDefaulted = FALSE);
  906.     HRESULT Allow(LPCTSTR pszPrincipal, DWORD dwAccessMask);
  907.     HRESULT Deny(LPCTSTR pszPrincipal, DWORD dwAccessMask);
  908.     HRESULT Revoke(LPCTSTR pszPrincipal);
  909.  
  910.     // utility functions
  911.     // Any PSID you get from these functions should be free()ed
  912.     static HRESULT SetPrivilege(LPCTSTR Privilege, BOOL bEnable = TRUE, HANDLE hToken = NULL);
  913.     static HRESULT GetTokenSids(HANDLE hToken, PSID* ppUserSid, PSID* ppGroupSid);
  914.     static HRESULT GetProcessSids(PSID* ppUserSid, PSID* ppGroupSid = NULL);
  915.     static HRESULT GetThreadSids(PSID* ppUserSid, PSID* ppGroupSid = NULL, BOOL bOpenAsSelf = FALSE);
  916.     static HRESULT CopyACL(PACL pDest, PACL pSrc);
  917.     static HRESULT GetCurrentUserSID(PSID *ppSid);
  918.     static HRESULT GetPrincipalSID(LPCTSTR pszPrincipal, PSID *ppSid);
  919.     static HRESULT AddAccessAllowedACEToACL(PACL *Acl, LPCTSTR pszPrincipal, DWORD dwAccessMask);
  920.     static HRESULT AddAccessDeniedACEToACL(PACL *Acl, LPCTSTR pszPrincipal, DWORD dwAccessMask);
  921.     static HRESULT RemovePrincipalFromACL(PACL Acl, LPCTSTR pszPrincipal);
  922.  
  923.     operator PSECURITY_DESCRIPTOR()
  924.     {
  925.         return m_pSD;
  926.     }
  927.  
  928. public:
  929.     PSECURITY_DESCRIPTOR m_pSD;
  930.     PSID m_pOwner;
  931.     PSID m_pGroup;
  932.     PACL m_pDACL;
  933.     PACL m_pSACL;
  934. };
  935.  
  936. inline CSecurityDescriptor::CSecurityDescriptor()
  937. {
  938.     m_pSD = NULL;
  939.     m_pOwner = NULL;
  940.     m_pGroup = NULL;
  941.     m_pDACL = NULL;
  942.     m_pSACL= NULL;
  943. }
  944.  
  945. inline CSecurityDescriptor::~CSecurityDescriptor()
  946. {
  947.     if (m_pSD)
  948.         delete m_pSD;
  949.     if (m_pOwner)
  950.         free(m_pOwner);
  951.     if (m_pGroup)
  952.         free(m_pGroup);
  953.     if (m_pDACL)
  954.         free(m_pDACL);
  955.     if (m_pSACL)
  956.         free(m_pSACL);
  957. }
  958.  
  959. inline HRESULT CSecurityDescriptor::Initialize()
  960. {
  961.     if (m_pSD)
  962.     {
  963.         delete m_pSD;
  964.         m_pSD = NULL;
  965.     }
  966.     if (m_pOwner)
  967.     {
  968.         free(m_pOwner);
  969.         m_pOwner = NULL;
  970.     }
  971.     if (m_pGroup)
  972.     {
  973.         free(m_pGroup);
  974.         m_pGroup = NULL;
  975.     }
  976.     if (m_pDACL)
  977.     {
  978.         free(m_pDACL);
  979.         m_pDACL = NULL;
  980.     }
  981.     if (m_pSACL)
  982.     {
  983.         free(m_pSACL);
  984.         m_pSACL = NULL;
  985.     }
  986.  
  987.     ATLTRY(m_pSD = new SECURITY_DESCRIPTOR);
  988.     if (m_pSD == NULL)
  989.         return E_OUTOFMEMORY;
  990.  
  991.     if (!InitializeSecurityDescriptor(m_pSD, SECURITY_DESCRIPTOR_REVISION))
  992.     {
  993.         HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
  994.         delete m_pSD;
  995.         m_pSD = NULL;
  996.         ATLASSERT(FALSE);
  997.         return hr;
  998.     }
  999.     // Set the DACL to allow EVERYONE
  1000.     SetSecurityDescriptorDacl(m_pSD, TRUE, NULL, FALSE);
  1001.     return S_OK;
  1002. }
  1003.  
  1004. inline HRESULT CSecurityDescriptor::InitializeFromProcessToken(BOOL bDefaulted)
  1005. {
  1006.     PSID pUserSid = NULL;
  1007.     PSID pGroupSid = NULL;
  1008.     HRESULT hr;
  1009.  
  1010.     Initialize();
  1011.     hr = GetProcessSids(&pUserSid, &pGroupSid);
  1012.     if (SUCCEEDED(hr))
  1013.     {
  1014.         hr = SetOwner(pUserSid, bDefaulted);
  1015.         if (SUCCEEDED(hr))
  1016.             hr = SetGroup(pGroupSid, bDefaulted);
  1017.     }
  1018.     if (pUserSid != NULL)
  1019.         free(pUserSid);
  1020.     if (pGroupSid != NULL)
  1021.         free(pGroupSid);
  1022.     return hr;
  1023. }
  1024.  
  1025. inline HRESULT CSecurityDescriptor::InitializeFromThreadToken(BOOL bDefaulted, BOOL bRevertToProcessToken)
  1026. {
  1027.     PSID pUserSid = NULL;
  1028.     PSID pGroupSid = NULL;
  1029.     HRESULT hr;
  1030.  
  1031.     Initialize();
  1032.     hr = GetThreadSids(&pUserSid, &pGroupSid);
  1033.     if (HRESULT_CODE(hr) == ERROR_NO_TOKEN && bRevertToProcessToken)
  1034.         hr = GetProcessSids(&pUserSid, &pGroupSid);
  1035.     if (SUCCEEDED(hr))
  1036.     {
  1037.         hr = SetOwner(pUserSid, bDefaulted);
  1038.         if (SUCCEEDED(hr))
  1039.             hr = SetGroup(pGroupSid, bDefaulted);
  1040.     }
  1041.     if (pUserSid != NULL)
  1042.         free(pUserSid);
  1043.     if (pGroupSid != NULL)
  1044.         free(pGroupSid);
  1045.     return hr;
  1046. }
  1047.  
  1048. inline HRESULT CSecurityDescriptor::SetOwner(PSID pOwnerSid, BOOL bDefaulted)
  1049. {
  1050.     ATLASSERT(m_pSD);
  1051.  
  1052.     // Mark the SD as having no owner
  1053.     if (!SetSecurityDescriptorOwner(m_pSD, NULL, bDefaulted))
  1054.     {
  1055.         HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
  1056.         ATLASSERT(FALSE);
  1057.         return hr;
  1058.     }
  1059.  
  1060.     if (m_pOwner)
  1061.     {
  1062.         free(m_pOwner);
  1063.         m_pOwner = NULL;
  1064.     }
  1065.  
  1066.     // If they asked for no owner don't do the copy
  1067.     if (pOwnerSid == NULL)
  1068.         return S_OK;
  1069.  
  1070.     // Make a copy of the Sid for the return value
  1071.     DWORD dwSize = GetLengthSid(pOwnerSid);
  1072.  
  1073.     m_pOwner = (PSID) malloc(dwSize);
  1074.     if (m_pOwner == NULL)
  1075.         return E_OUTOFMEMORY;
  1076.     if (!CopySid(dwSize, m_pOwner, pOwnerSid))
  1077.     {
  1078.         HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
  1079.         ATLASSERT(FALSE);
  1080.         free(m_pOwner);
  1081.         m_pOwner = NULL;
  1082.         return hr;
  1083.     }
  1084.  
  1085.     ATLASSERT(IsValidSid(m_pOwner));
  1086.  
  1087.     if (!SetSecurityDescriptorOwner(m_pSD, m_pOwner, bDefaulted))
  1088.     {
  1089.         HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
  1090.         ATLASSERT(FALSE);
  1091.         free(m_pOwner);
  1092.         m_pOwner = NULL;
  1093.         return hr;
  1094.     }
  1095.  
  1096.     return S_OK;
  1097. }
  1098.  
  1099. inline HRESULT CSecurityDescriptor::SetGroup(PSID pGroupSid, BOOL bDefaulted)
  1100. {
  1101.     ATLASSERT(m_pSD);
  1102.  
  1103.     // Mark the SD as having no Group
  1104.     if (!SetSecurityDescriptorGroup(m_pSD, NULL, bDefaulted))
  1105.     {
  1106.         HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
  1107.         ATLASSERT(FALSE);
  1108.         return hr;
  1109.     }
  1110.  
  1111.     if (m_pGroup)
  1112.     {
  1113.         free(m_pGroup);
  1114.         m_pGroup = NULL;
  1115.     }
  1116.  
  1117.     // If they asked for no Group don't do the copy
  1118.     if (pGroupSid == NULL)
  1119.         return S_OK;
  1120.  
  1121.     // Make a copy of the Sid for the return value
  1122.     DWORD dwSize = GetLengthSid(pGroupSid);
  1123.  
  1124.     m_pGroup = (PSID) malloc(dwSize);
  1125.     if (m_pGroup == NULL)
  1126.         return E_OUTOFMEMORY;
  1127.     if (!CopySid(dwSize, m_pGroup, pGroupSid))
  1128.     {
  1129.         HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
  1130.         ATLASSERT(FALSE);
  1131.         free(m_pGroup);
  1132.         m_pGroup = NULL;
  1133.         return hr;
  1134.     }
  1135.  
  1136.     ATLASSERT(IsValidSid(m_pGroup));
  1137.  
  1138.     if (!SetSecurityDescriptorGroup(m_pSD, m_pGroup, bDefaulted))
  1139.     {
  1140.         HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
  1141.         ATLASSERT(FALSE);
  1142.         free(m_pGroup);
  1143.         m_pGroup = NULL;
  1144.         return hr;
  1145.     }
  1146.  
  1147.     return S_OK;
  1148. }
  1149.  
  1150. inline HRESULT CSecurityDescriptor::Allow(LPCTSTR pszPrincipal, DWORD dwAccessMask)
  1151. {
  1152.     HRESULT hr = AddAccessAllowedACEToACL(&m_pDACL, pszPrincipal, dwAccessMask);
  1153.     if (SUCCEEDED(hr))
  1154.         SetSecurityDescriptorDacl(m_pSD, TRUE, m_pDACL, FALSE);
  1155.     return hr;
  1156. }
  1157.  
  1158. inline HRESULT CSecurityDescriptor::Deny(LPCTSTR pszPrincipal, DWORD dwAccessMask)
  1159. {
  1160.     HRESULT hr = AddAccessDeniedACEToACL(&m_pDACL, pszPrincipal, dwAccessMask);
  1161.     if (SUCCEEDED(hr))
  1162.         SetSecurityDescriptorDacl(m_pSD, TRUE, m_pDACL, FALSE);
  1163.     return hr;
  1164. }
  1165.  
  1166. inline HRESULT CSecurityDescriptor::Revoke(LPCTSTR pszPrincipal)
  1167. {
  1168.     HRESULT hr = RemovePrincipalFromACL(m_pDACL, pszPrincipal);
  1169.     if (SUCCEEDED(hr))
  1170.         SetSecurityDescriptorDacl(m_pSD, TRUE, m_pDACL, FALSE);
  1171.     return hr;
  1172. }
  1173.  
  1174. inline HRESULT CSecurityDescriptor::GetProcessSids(PSID* ppUserSid, PSID* ppGroupSid)
  1175. {
  1176.     BOOL bRes;
  1177.     HRESULT hr;
  1178.     HANDLE hToken = NULL;
  1179.     if (ppUserSid)
  1180.         *ppUserSid = NULL;
  1181.     if (ppGroupSid)
  1182.         *ppGroupSid = NULL;
  1183.     bRes = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken);
  1184.     if (!bRes)
  1185.     {
  1186.         // Couldn't open process token
  1187.         hr = HRESULT_FROM_WIN32(GetLastError());
  1188.         ATLASSERT(FALSE);
  1189.         return hr;
  1190.     }
  1191.     hr = GetTokenSids(hToken, ppUserSid, ppGroupSid);
  1192.     CloseHandle(hToken);
  1193.     return hr;
  1194. }
  1195.  
  1196. inline HRESULT CSecurityDescriptor::GetThreadSids(PSID* ppUserSid, PSID* ppGroupSid, BOOL bOpenAsSelf)
  1197. {
  1198.     BOOL bRes;
  1199.     HRESULT hr;
  1200.     HANDLE hToken = NULL;
  1201.     if (ppUserSid)
  1202.         *ppUserSid = NULL;
  1203.     if (ppGroupSid)
  1204.         *ppGroupSid = NULL;
  1205.     bRes = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, bOpenAsSelf, &hToken);
  1206.     if (!bRes)
  1207.     {
  1208.         // Couldn't open thread token
  1209.         hr = HRESULT_FROM_WIN32(GetLastError());
  1210.         return hr;
  1211.     }
  1212.     hr = GetTokenSids(hToken, ppUserSid, ppGroupSid);
  1213.     CloseHandle(hToken);
  1214.     return hr;
  1215. }
  1216.  
  1217. inline HRESULT CSecurityDescriptor::GetTokenSids(HANDLE hToken, PSID* ppUserSid, PSID* ppGroupSid)
  1218. {
  1219.     DWORD dwSize;
  1220.     HRESULT hr;
  1221.     PTOKEN_USER ptkUser = NULL;
  1222.     PTOKEN_PRIMARY_GROUP ptkGroup = NULL;
  1223.  
  1224.     if (ppUserSid)
  1225.         *ppUserSid = NULL;
  1226.     if (ppGroupSid)
  1227.         *ppGroupSid = NULL;
  1228.  
  1229.     if (ppUserSid)
  1230.     {
  1231.         // Get length required for TokenUser by specifying buffer length of 0
  1232.         GetTokenInformation(hToken, TokenUser, NULL, 0, &dwSize);
  1233.         hr = GetLastError();
  1234.         if (hr != ERROR_INSUFFICIENT_BUFFER)
  1235.         {
  1236.             // Expected ERROR_INSUFFICIENT_BUFFER
  1237.             ATLASSERT(FALSE);
  1238.             hr = HRESULT_FROM_WIN32(hr);
  1239.             goto failed;
  1240.         }
  1241.  
  1242.         ptkUser = (TOKEN_USER*) malloc(dwSize);
  1243.         if (ptkUser == NULL)
  1244.         {
  1245.             hr = E_OUTOFMEMORY;
  1246.             goto failed;
  1247.         }
  1248.         // Get Sid of process token.
  1249.         if (!GetTokenInformation(hToken, TokenUser, ptkUser, dwSize, &dwSize))
  1250.         {
  1251.             // Couldn't get user info
  1252.             hr = HRESULT_FROM_WIN32(GetLastError());
  1253.             ATLASSERT(FALSE);
  1254.             goto failed;
  1255.         }
  1256.  
  1257.         // Make a copy of the Sid for the return value
  1258.         dwSize = GetLengthSid(ptkUser->User.Sid);
  1259.  
  1260.         PSID pSid;
  1261.         pSid = (PSID) malloc(dwSize);
  1262.         if (pSid == NULL)
  1263.         {
  1264.             hr = E_OUTOFMEMORY;
  1265.             goto failed;
  1266.         }
  1267.         if (!CopySid(dwSize, pSid, ptkUser->User.Sid))
  1268.         {
  1269.             hr = HRESULT_FROM_WIN32(GetLastError());
  1270.             ATLASSERT(FALSE);
  1271.             goto failed;
  1272.         }
  1273.  
  1274.         ATLASSERT(IsValidSid(pSid));
  1275.         *ppUserSid = pSid;
  1276.         free(ptkUser);
  1277.     }
  1278.     if (ppGroupSid)
  1279.     {
  1280.         // Get length required for TokenPrimaryGroup by specifying buffer length of 0
  1281.         GetTokenInformation(hToken, TokenPrimaryGroup, NULL, 0, &dwSize);
  1282.         hr = GetLastError();
  1283.         if (hr != ERROR_INSUFFICIENT_BUFFER)
  1284.         {
  1285.             // Expected ERROR_INSUFFICIENT_BUFFER
  1286.             ATLASSERT(FALSE);
  1287.             hr = HRESULT_FROM_WIN32(hr);
  1288.             goto failed;
  1289.         }
  1290.  
  1291.         ptkGroup = (TOKEN_PRIMARY_GROUP*) malloc(dwSize);
  1292.         if (ptkGroup == NULL)
  1293.         {
  1294.             hr = E_OUTOFMEMORY;
  1295.             goto failed;
  1296.         }
  1297.         // Get Sid of process token.
  1298.         if (!GetTokenInformation(hToken, TokenPrimaryGroup, ptkGroup, dwSize, &dwSize))
  1299.         {
  1300.             // Couldn't get user info
  1301.             hr = HRESULT_FROM_WIN32(GetLastError());
  1302.             ATLASSERT(FALSE);
  1303.             goto failed;
  1304.         }
  1305.  
  1306.         // Make a copy of the Sid for the return value
  1307.         dwSize = GetLengthSid(ptkGroup->PrimaryGroup);
  1308.  
  1309.         PSID pSid;
  1310.         pSid = (PSID) malloc(dwSize);
  1311.         if (pSid == NULL)
  1312.         {
  1313.             hr = E_OUTOFMEMORY;
  1314.             goto failed;
  1315.         }
  1316.         if (!CopySid(dwSize, pSid, ptkGroup->PrimaryGroup))
  1317.         {
  1318.             hr = HRESULT_FROM_WIN32(GetLastError());
  1319.             ATLASSERT(FALSE);
  1320.             goto failed;
  1321.         }
  1322.  
  1323.         ATLASSERT(IsValidSid(pSid));
  1324.  
  1325.         *ppGroupSid = pSid;
  1326.         free(ptkGroup);
  1327.     }
  1328.  
  1329.     return S_OK;
  1330.  
  1331. failed:
  1332.     if (ptkUser)
  1333.         free(ptkUser);
  1334.     if (ptkGroup)
  1335.         free (ptkGroup);
  1336.     return hr;
  1337. }
  1338.  
  1339.  
  1340. inline HRESULT CSecurityDescriptor::GetCurrentUserSID(PSID *ppSid)
  1341. {
  1342.     HANDLE tkHandle;
  1343.  
  1344.     if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &tkHandle))
  1345.     {
  1346.         TOKEN_USER *tkUser;
  1347.         DWORD tkSize;
  1348.         DWORD sidLength;
  1349.  
  1350.         // Call to get size information for alloc
  1351.         GetTokenInformation(tkHandle, TokenUser, NULL, 0, &tkSize);
  1352.         tkUser = (TOKEN_USER *) malloc(tkSize);
  1353.         if (tkUser == NULL)
  1354.             return E_OUTOFMEMORY;
  1355.  
  1356.         // Now make the real call
  1357.         if (GetTokenInformation(tkHandle, TokenUser, tkUser, tkSize, &tkSize))
  1358.         {
  1359.             sidLength = GetLengthSid(tkUser->User.Sid);
  1360.             *ppSid = (PSID) malloc(sidLength);
  1361.             if (*ppSid == NULL)
  1362.                 return E_OUTOFMEMORY;
  1363.  
  1364.             memcpy(*ppSid, tkUser->User.Sid, sidLength);
  1365.             CloseHandle(tkHandle);
  1366.  
  1367.             free(tkUser);
  1368.             return S_OK;
  1369.         }
  1370.         else
  1371.         {
  1372.             free(tkUser);
  1373.             return HRESULT_FROM_WIN32(GetLastError());
  1374.         }
  1375.     }
  1376.     return HRESULT_FROM_WIN32(GetLastError());
  1377. }
  1378.  
  1379.  
  1380. inline HRESULT CSecurityDescriptor::GetPrincipalSID(LPCTSTR pszPrincipal, PSID *ppSid)
  1381. {
  1382.     HRESULT hr;
  1383.     LPTSTR pszRefDomain = NULL;
  1384.     DWORD dwDomainSize = 0;
  1385.     DWORD dwSidSize = 0;
  1386.     SID_NAME_USE snu;
  1387.  
  1388.     // Call to get size info for alloc
  1389.     LookupAccountName(NULL, pszPrincipal, *ppSid, &dwSidSize, pszRefDomain, &dwDomainSize, &snu);
  1390.  
  1391.     hr = GetLastError();
  1392.     if (hr != ERROR_INSUFFICIENT_BUFFER)
  1393.         return HRESULT_FROM_WIN32(hr);
  1394.  
  1395.     ATLTRY(pszRefDomain = new TCHAR[dwDomainSize]);
  1396.     if (pszRefDomain == NULL)
  1397.         return E_OUTOFMEMORY;
  1398.  
  1399.     *ppSid = (PSID) malloc(dwSidSize);
  1400.     if (*ppSid != NULL)
  1401.     {
  1402.         if (!LookupAccountName(NULL, pszPrincipal, *ppSid, &dwSidSize, pszRefDomain, &dwDomainSize, &snu))
  1403.         {
  1404.             free(*ppSid);
  1405.             *ppSid = NULL;
  1406.             delete[] pszRefDomain;
  1407.             return HRESULT_FROM_WIN32(GetLastError());
  1408.         }
  1409.         delete[] pszRefDomain;
  1410.         return S_OK;
  1411.     }
  1412.     delete[] pszRefDomain;
  1413.     return E_OUTOFMEMORY;
  1414. }
  1415.  
  1416.  
  1417. inline HRESULT CSecurityDescriptor::Attach(PSECURITY_DESCRIPTOR pSelfRelativeSD)
  1418. {
  1419.     PACL    pDACL = NULL;
  1420.     PACL    pSACL = NULL;
  1421.     BOOL    bDACLPresent, bSACLPresent;
  1422.     BOOL    bDefaulted;
  1423.     PACL    m_pDACL = NULL;
  1424.     ACCESS_ALLOWED_ACE* pACE;
  1425.     HRESULT hr;
  1426.     PSID    pUserSid;
  1427.     PSID    pGroupSid;
  1428.  
  1429.     hr = Initialize();
  1430.     if(FAILED(hr))
  1431.         return hr;
  1432.  
  1433.     // get the existing DACL.
  1434.     if (!GetSecurityDescriptorDacl(pSelfRelativeSD, &bDACLPresent, &pDACL, &bDefaulted))
  1435.         goto failed;
  1436.  
  1437.     if (bDACLPresent)
  1438.     {
  1439.         if (pDACL)
  1440.         {
  1441.             // allocate new DACL.
  1442.             m_pDACL = (PACL) malloc(pDACL->AclSize);
  1443.             if (m_pDACL == NULL)
  1444.             {
  1445.                 hr = E_OUTOFMEMORY;
  1446.                 goto failedMemory;
  1447.             }
  1448.  
  1449.             // initialize the DACL
  1450.             if (!InitializeAcl(m_pDACL, pDACL->AclSize, ACL_REVISION))
  1451.                 goto failed;
  1452.  
  1453.             // copy the ACES
  1454.             for (int i = 0; i < pDACL->AceCount; i++)
  1455.             {
  1456.                 if (!GetAce(pDACL, i, (void **)&pACE))
  1457.                     goto failed;
  1458.  
  1459.                 if (!AddAccessAllowedAce(m_pDACL, ACL_REVISION, pACE->Mask, (PSID)&(pACE->SidStart)))
  1460.                     goto failed;
  1461.             }
  1462.  
  1463.             if (!IsValidAcl(m_pDACL))
  1464.                 goto failed;
  1465.         }
  1466.  
  1467.         // set the DACL
  1468.         if (!SetSecurityDescriptorDacl(m_pSD, m_pDACL ? TRUE : FALSE, m_pDACL, bDefaulted))
  1469.             goto failed;
  1470.     }
  1471.  
  1472.     // get the existing SACL.
  1473.     if (!GetSecurityDescriptorSacl(pSelfRelativeSD, &bSACLPresent, &pSACL, &bDefaulted))
  1474.         goto failed;
  1475.  
  1476.     if (bSACLPresent)
  1477.     {
  1478.         if (pSACL)
  1479.         {
  1480.             // allocate new SACL.
  1481.             m_pSACL = (PACL) malloc(pSACL->AclSize);
  1482.             if (m_pSACL == NULL)
  1483.             {
  1484.                 hr = E_OUTOFMEMORY;
  1485.                 goto failedMemory;
  1486.             }
  1487.  
  1488.             // initialize the SACL
  1489.             if (!InitializeAcl(m_pSACL, pSACL->AclSize, ACL_REVISION))
  1490.                 goto failed;
  1491.  
  1492.             // copy the ACES
  1493.             for (int i = 0; i < pSACL->AceCount; i++)
  1494.             {
  1495.                 if (!GetAce(pSACL, i, (void **)&pACE))
  1496.                     goto failed;
  1497.  
  1498.                 if (!AddAccessAllowedAce(m_pSACL, ACL_REVISION, pACE->Mask, (PSID)&(pACE->SidStart)))
  1499.                     goto failed;
  1500.             }
  1501.  
  1502.             if (!IsValidAcl(m_pSACL))
  1503.                 goto failed;
  1504.         }
  1505.  
  1506.         // set the SACL
  1507.         if (!SetSecurityDescriptorSacl(m_pSD, m_pSACL ? TRUE : FALSE, m_pSACL, bDefaulted))
  1508.             goto failed;
  1509.     }
  1510.  
  1511.     if (!GetSecurityDescriptorOwner(m_pSD, &pUserSid, &bDefaulted))
  1512.         goto failed;
  1513.  
  1514.     if (FAILED(SetOwner(pUserSid, bDefaulted)))
  1515.         goto failed;
  1516.  
  1517.     if (!GetSecurityDescriptorGroup(m_pSD, &pGroupSid, &bDefaulted))
  1518.         goto failed;
  1519.  
  1520.     if (FAILED(SetGroup(pGroupSid, bDefaulted)))
  1521.         goto failed;
  1522.  
  1523.     if (!IsValidSecurityDescriptor(m_pSD))
  1524.         goto failed;
  1525.  
  1526.     return hr;
  1527.  
  1528. failed:
  1529.     hr = HRESULT_FROM_WIN32(hr);
  1530.  
  1531. failedMemory:
  1532.     if (m_pDACL)
  1533.     {
  1534.         free(m_pDACL);
  1535.         m_pDACL = NULL;
  1536.     }
  1537.     if (m_pSD)
  1538.     {
  1539.         free(m_pSD);
  1540.         m_pSD = NULL;
  1541.     }
  1542.     return hr;
  1543. }
  1544.  
  1545. inline HRESULT CSecurityDescriptor::AttachObject(HANDLE hObject)
  1546. {
  1547.     HRESULT hr;
  1548.     DWORD dwSize = 0;
  1549.     PSECURITY_DESCRIPTOR pSD = NULL;
  1550.  
  1551.     GetKernelObjectSecurity(hObject, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
  1552.         DACL_SECURITY_INFORMATION, pSD, 0, &dwSize);
  1553.  
  1554.     hr = GetLastError();
  1555.     if (hr != ERROR_INSUFFICIENT_BUFFER)
  1556.         return HRESULT_FROM_WIN32(hr);
  1557.  
  1558.     pSD = (PSECURITY_DESCRIPTOR) malloc(dwSize);
  1559.     if (pSD == NULL)
  1560.         return E_OUTOFMEMORY;
  1561.  
  1562.     if (!GetKernelObjectSecurity(hObject, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
  1563.         DACL_SECURITY_INFORMATION, pSD, dwSize, &dwSize))
  1564.     {
  1565.         hr = HRESULT_FROM_WIN32(GetLastError());
  1566.         free(pSD);
  1567.         return hr;
  1568.     }
  1569.  
  1570.     hr = Attach(pSD);
  1571.     free(pSD);
  1572.     return hr;
  1573. }
  1574.  
  1575.  
  1576. inline HRESULT CSecurityDescriptor::CopyACL(PACL pDest, PACL pSrc)
  1577. {
  1578.     ACL_SIZE_INFORMATION aclSizeInfo;
  1579.     LPVOID pAce;
  1580.     ACE_HEADER *aceHeader;
  1581.  
  1582.     if (pSrc == NULL)
  1583.         return S_OK;
  1584.  
  1585.     if (!GetAclInformation(pSrc, (LPVOID) &aclSizeInfo, sizeof(ACL_SIZE_INFORMATION), AclSizeInformation))
  1586.         return HRESULT_FROM_WIN32(GetLastError());
  1587.  
  1588.     // Copy all of the ACEs to the new ACL
  1589.     for (UINT i = 0; i < aclSizeInfo.AceCount; i++)
  1590.     {
  1591.         if (!GetAce(pSrc, i, &pAce))
  1592.             return HRESULT_FROM_WIN32(GetLastError());
  1593.  
  1594.         aceHeader = (ACE_HEADER *) pAce;
  1595.  
  1596.         if (!AddAce(pDest, ACL_REVISION, 0xffffffff, pAce, aceHeader->AceSize))
  1597.             return HRESULT_FROM_WIN32(GetLastError());
  1598.     }
  1599.  
  1600.     return S_OK;
  1601. }
  1602.  
  1603. inline HRESULT CSecurityDescriptor::AddAccessDeniedACEToACL(PACL *ppAcl, LPCTSTR pszPrincipal, DWORD dwAccessMask)
  1604. {
  1605.     ACL_SIZE_INFORMATION aclSizeInfo;
  1606.     int aclSize;
  1607.     DWORD returnValue;
  1608.     PSID principalSID;
  1609.     PACL oldACL, newACL = NULL;
  1610.  
  1611.     oldACL = *ppAcl;
  1612.  
  1613.     returnValue = GetPrincipalSID(pszPrincipal, &principalSID);
  1614.     if (FAILED(returnValue))
  1615.         return returnValue;
  1616.  
  1617.     aclSizeInfo.AclBytesInUse = 0;
  1618.     if (*ppAcl != NULL)
  1619.         GetAclInformation(oldACL, (LPVOID) &aclSizeInfo, sizeof(ACL_SIZE_INFORMATION), AclSizeInformation);
  1620.  
  1621.     aclSize = aclSizeInfo.AclBytesInUse + sizeof(ACL) + sizeof(ACCESS_DENIED_ACE) + GetLengthSid(principalSID) - sizeof(DWORD);
  1622.  
  1623.     ATLTRY(newACL = (PACL) new BYTE[aclSize]);
  1624.     if (newACL == NULL)
  1625.         return E_OUTOFMEMORY;
  1626.  
  1627.     if (!InitializeAcl(newACL, aclSize, ACL_REVISION))
  1628.     {
  1629.         free(principalSID);
  1630.         return HRESULT_FROM_WIN32(GetLastError());
  1631.     }
  1632.  
  1633.     if (!AddAccessDeniedAce(newACL, ACL_REVISION2, dwAccessMask, principalSID))
  1634.     {
  1635.         free(principalSID);
  1636.         return HRESULT_FROM_WIN32(GetLastError());
  1637.     }
  1638.  
  1639.     returnValue = CopyACL(newACL, oldACL);
  1640.     if (FAILED(returnValue))
  1641.     {
  1642.         free(principalSID);
  1643.         return returnValue;
  1644.     }
  1645.  
  1646.     *ppAcl = newACL;
  1647.  
  1648.     if (oldACL != NULL)
  1649.         free(oldACL);
  1650.     free(principalSID);
  1651.     return S_OK;
  1652. }
  1653.  
  1654.  
  1655. inline HRESULT CSecurityDescriptor::AddAccessAllowedACEToACL(PACL *ppAcl, LPCTSTR pszPrincipal, DWORD dwAccessMask)
  1656. {
  1657.     ACL_SIZE_INFORMATION aclSizeInfo;
  1658.     int aclSize;
  1659.     DWORD returnValue;
  1660.     PSID principalSID;
  1661.     PACL oldACL, newACL = NULL;
  1662.  
  1663.     oldACL = *ppAcl;
  1664.  
  1665.     returnValue = GetPrincipalSID(pszPrincipal, &principalSID);
  1666.     if (FAILED(returnValue))
  1667.         return returnValue;
  1668.  
  1669.     aclSizeInfo.AclBytesInUse = 0;
  1670.     if (*ppAcl != NULL)
  1671.         GetAclInformation(oldACL, (LPVOID) &aclSizeInfo, (DWORD) sizeof(ACL_SIZE_INFORMATION), AclSizeInformation);
  1672.  
  1673.     aclSize = aclSizeInfo.AclBytesInUse + sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(principalSID) - sizeof(DWORD);
  1674.  
  1675.     ATLTRY(newACL = (PACL) new BYTE[aclSize]);
  1676.     if (newACL == NULL)
  1677.         return E_OUTOFMEMORY;
  1678.  
  1679.     if (!InitializeAcl(newACL, aclSize, ACL_REVISION))
  1680.     {
  1681.         free(principalSID);
  1682.         return HRESULT_FROM_WIN32(GetLastError());
  1683.     }
  1684.  
  1685.     returnValue = CopyACL(newACL, oldACL);
  1686.     if (FAILED(returnValue))
  1687.     {
  1688.         free(principalSID);
  1689.         return returnValue;
  1690.     }
  1691.  
  1692.     if (!AddAccessAllowedAce(newACL, ACL_REVISION2, dwAccessMask, principalSID))
  1693.     {
  1694.         free(principalSID);
  1695.         return HRESULT_FROM_WIN32(GetLastError());
  1696.     }
  1697.  
  1698.     *ppAcl = newACL;
  1699.  
  1700.     if (oldACL != NULL)
  1701.         free(oldACL);
  1702.     free(principalSID);
  1703.     return S_OK;
  1704. }
  1705.  
  1706.  
  1707. inline HRESULT CSecurityDescriptor::RemovePrincipalFromACL(PACL pAcl, LPCTSTR pszPrincipal)
  1708. {
  1709.     ACL_SIZE_INFORMATION aclSizeInfo;
  1710.     ULONG i;
  1711.     LPVOID ace;
  1712.     ACCESS_ALLOWED_ACE *accessAllowedAce;
  1713.     ACCESS_DENIED_ACE *accessDeniedAce;
  1714.     SYSTEM_AUDIT_ACE *systemAuditAce;
  1715.     PSID principalSID;
  1716.     DWORD returnValue;
  1717.     ACE_HEADER *aceHeader;
  1718.  
  1719.     returnValue = GetPrincipalSID(pszPrincipal, &principalSID);
  1720.     if (FAILED(returnValue))
  1721.         return returnValue;
  1722.  
  1723.     GetAclInformation(pAcl, (LPVOID) &aclSizeInfo, (DWORD) sizeof(ACL_SIZE_INFORMATION), AclSizeInformation);
  1724.  
  1725.     for (i = 0; i < aclSizeInfo.AceCount; i++)
  1726.     {
  1727.         if (!GetAce(pAcl, i, &ace))
  1728.         {
  1729.             free(principalSID);
  1730.             return HRESULT_FROM_WIN32(GetLastError());
  1731.         }
  1732.  
  1733.         aceHeader = (ACE_HEADER *) ace;
  1734.  
  1735.         if (aceHeader->AceType == ACCESS_ALLOWED_ACE_TYPE)
  1736.         {
  1737.             accessAllowedAce = (ACCESS_ALLOWED_ACE *) ace;
  1738.  
  1739.             if (EqualSid(principalSID, (PSID) &accessAllowedAce->SidStart))
  1740.             {
  1741.                 DeleteAce(pAcl, i);
  1742.                 free(principalSID);
  1743.                 return S_OK;
  1744.             }
  1745.         } else
  1746.  
  1747.         if (aceHeader->AceType == ACCESS_DENIED_ACE_TYPE)
  1748.         {
  1749.             accessDeniedAce = (ACCESS_DENIED_ACE *) ace;
  1750.  
  1751.             if (EqualSid(principalSID, (PSID) &accessDeniedAce->SidStart))
  1752.             {
  1753.                 DeleteAce(pAcl, i);
  1754.                 free(principalSID);
  1755.                 return S_OK;
  1756.             }
  1757.         } else
  1758.  
  1759.         if (aceHeader->AceType == SYSTEM_AUDIT_ACE_TYPE)
  1760.         {
  1761.             systemAuditAce = (SYSTEM_AUDIT_ACE *) ace;
  1762.  
  1763.             if (EqualSid(principalSID, (PSID) &systemAuditAce->SidStart))
  1764.             {
  1765.                 DeleteAce(pAcl, i);
  1766.                 free(principalSID);
  1767.                 return S_OK;
  1768.             }
  1769.         }
  1770.     }
  1771.     free(principalSID);
  1772.     return S_OK;
  1773. }
  1774.  
  1775.  
  1776. inline HRESULT CSecurityDescriptor::SetPrivilege(LPCTSTR privilege, BOOL bEnable, HANDLE hToken)
  1777. {
  1778.     HRESULT hr;
  1779.     TOKEN_PRIVILEGES tpPrevious;
  1780.     TOKEN_PRIVILEGES tp;
  1781.     DWORD  cbPrevious = sizeof(TOKEN_PRIVILEGES);
  1782.     LUID   luid;
  1783.     HANDLE hTokenUsed;
  1784.  
  1785.     // if no token specified open process token
  1786.     if (hToken == 0)
  1787.     {
  1788.         if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hTokenUsed))
  1789.         {
  1790.             hr = HRESULT_FROM_WIN32(GetLastError());
  1791.             ATLASSERT(FALSE);
  1792.             return hr;
  1793.         }
  1794.     }
  1795.     else
  1796.         hTokenUsed = hToken;
  1797.  
  1798.     if (!LookupPrivilegeValue(NULL, privilege, &luid ))
  1799.     {
  1800.         hr = HRESULT_FROM_WIN32(GetLastError());
  1801.         ATLASSERT(FALSE);
  1802.         if (hToken == 0)
  1803.             CloseHandle(hTokenUsed);
  1804.         return hr;
  1805.     }
  1806.  
  1807.     tp.PrivilegeCount = 1;
  1808.     tp.Privileges[0].Luid = luid;
  1809.     tp.Privileges[0].Attributes = 0;
  1810.  
  1811.     if (!AdjustTokenPrivileges(hTokenUsed, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &tpPrevious, &cbPrevious))
  1812.     {
  1813.         hr = HRESULT_FROM_WIN32(GetLastError());
  1814.         ATLASSERT(FALSE);
  1815.         if (hToken == 0)
  1816.             CloseHandle(hTokenUsed);
  1817.         return hr;
  1818.     }
  1819.  
  1820.     tpPrevious.PrivilegeCount = 1;
  1821.     tpPrevious.Privileges[0].Luid = luid;
  1822.  
  1823.     if (bEnable)
  1824.         tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED);
  1825.     else
  1826.         tpPrevious.Privileges[0].Attributes ^= (SE_PRIVILEGE_ENABLED & tpPrevious.Privileges[0].Attributes);
  1827.  
  1828.     if (!AdjustTokenPrivileges(hTokenUsed, FALSE, &tpPrevious, cbPrevious, NULL, NULL))
  1829.     {
  1830.         hr = HRESULT_FROM_WIN32(GetLastError());
  1831.         ATLASSERT(FALSE);
  1832.         if (hToken == 0)
  1833.             CloseHandle(hTokenUsed);
  1834.         return hr;
  1835.     }
  1836.     return S_OK;
  1837. }
  1838. #endif // _WIN32_WCE
  1839.  
  1840. /////////////////////////////////////////////////////////////////////////////
  1841. // COM Objects
  1842.  
  1843. #define DECLARE_PROTECT_FINAL_CONSTRUCT()\
  1844.     void InternalFinalConstructAddRef() {InternalAddRef();}\
  1845.     void InternalFinalConstructRelease() {InternalRelease();}
  1846.  
  1847. template <class T1>
  1848. class CComCreator
  1849. {
  1850. public:
  1851.     static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv)
  1852.     {
  1853.         ATLASSERT(*ppv == NULL);
  1854.         HRESULT hRes = E_OUTOFMEMORY;
  1855.         T1* p = NULL;
  1856.         ATLTRY(p = new T1(pv))
  1857.         if (p != NULL)
  1858.         {
  1859.             p->SetVoid(pv);
  1860.             p->InternalFinalConstructAddRef();
  1861.             hRes = p->FinalConstruct();
  1862.             p->InternalFinalConstructRelease();
  1863.             if (hRes == S_OK)
  1864.                 hRes = p->QueryInterface(riid, ppv);
  1865.             if (hRes != S_OK)
  1866.                 delete p;
  1867.         }
  1868.         return hRes;
  1869.     }
  1870. };
  1871.  
  1872. template <class T1>
  1873. class CComInternalCreator
  1874. {
  1875. public:
  1876.     static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv)
  1877.     {
  1878.         ATLASSERT(*ppv == NULL);
  1879.         HRESULT hRes = E_OUTOFMEMORY;
  1880.         T1* p = NULL;
  1881.         ATLTRY(p = new T1(pv))
  1882.         if (p != NULL)
  1883.         {
  1884.             p->SetVoid(pv);
  1885.             p->InternalFinalConstructAddRef();
  1886.             hRes = p->FinalConstruct();
  1887.             p->InternalFinalConstructRelease();
  1888.             if (hRes == S_OK)
  1889.                 hRes = p->_InternalQueryInterface(riid, ppv);
  1890.             if (hRes != S_OK)
  1891.                 delete p;
  1892.         }
  1893.         return hRes;
  1894.     }
  1895. };
  1896.  
  1897. template <HRESULT hr>
  1898. class CComFailCreator
  1899. {
  1900. public:
  1901.     static HRESULT WINAPI CreateInstance(void*, REFIID, LPVOID*)
  1902.     {
  1903.         return hr;
  1904.     }
  1905. };
  1906.  
  1907. template <class T1, class T2>
  1908. class CComCreator2
  1909. {
  1910. public:
  1911.     static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv)
  1912.     {
  1913.         ATLASSERT(*ppv == NULL);
  1914.         return (pv == NULL) ? 
  1915.             T1::CreateInstance(NULL, riid, ppv) : 
  1916.             T2::CreateInstance(pv, riid, ppv);
  1917.     }
  1918. };
  1919.  
  1920. #define DECLARE_NOT_AGGREGATABLE(x) public:\
  1921.     typedef CComCreator2< CComCreator< CComObject< x > >, CComFailCreator<CLASS_E_NOAGGREGATION> > _CreatorClass;
  1922. #define DECLARE_AGGREGATABLE(x) public:\
  1923.     typedef CComCreator2< CComCreator< CComObject< x > >, CComCreator< CComAggObject< x > > > _CreatorClass;
  1924. #define DECLARE_ONLY_AGGREGATABLE(x) public:\
  1925.     typedef CComCreator2< CComFailCreator<E_FAIL>, CComCreator< CComAggObject< x > > > _CreatorClass;
  1926. #define DECLARE_POLY_AGGREGATABLE(x) public:\
  1927.     typedef CComCreator< CComPolyObject< x > > _CreatorClass;
  1928.  
  1929. struct _ATL_CREATORDATA
  1930. {
  1931.     _ATL_CREATORFUNC* pFunc;
  1932. };
  1933.  
  1934. template <class Creator>
  1935. class _CComCreatorData
  1936. {
  1937. public:
  1938.     static _ATL_CREATORDATA data;
  1939. };
  1940.  
  1941. template <class Creator>
  1942. _ATL_CREATORDATA _CComCreatorData<Creator>::data = {Creator::CreateInstance};
  1943.  
  1944. struct _ATL_CACHEDATA
  1945. {
  1946.     DWORD dwOffsetVar;
  1947.     _ATL_CREATORFUNC* pFunc;
  1948. };
  1949.  
  1950. template <class Creator, DWORD dwVar>
  1951. class _CComCacheData
  1952. {
  1953. public:
  1954.     static _ATL_CACHEDATA data;
  1955. };
  1956.  
  1957. template <class Creator, DWORD dwVar>
  1958. _ATL_CACHEDATA _CComCacheData<Creator, dwVar>::data = {dwVar, Creator::CreateInstance};
  1959.  
  1960. struct _ATL_CHAINDATA
  1961. {
  1962.     DWORD dwOffset;
  1963.     const _ATL_INTMAP_ENTRY* (WINAPI *pFunc)();
  1964. };
  1965.  
  1966. template <class base, class derived>
  1967. class _CComChainData
  1968. {
  1969. public:
  1970.     static _ATL_CHAINDATA data;
  1971. };
  1972.  
  1973. template <class base, class derived>
  1974. _ATL_CHAINDATA _CComChainData<base, derived>::data =
  1975.     {offsetofclass(base, derived), base::_GetEntries};
  1976.  
  1977. template <class T, const CLSID* pclsid>
  1978. class CComAggregateCreator
  1979. {
  1980. public:
  1981.     static HRESULT WINAPI CreateInstance(void* pv, REFIID/*riid*/, LPVOID* ppv)
  1982.     {
  1983.         ATLASSERT(*ppv == NULL);
  1984.         ATLASSERT(pv != NULL);
  1985.         T* p = (T*) pv;
  1986.         // Add the following line to your object if you get a message about
  1987.         // GetControllingUnknown() being undefined
  1988.         // DECLARE_GET_CONTROLLING_UNKNOWN()
  1989.         return CoCreateInstance(*pclsid, p->GetControllingUnknown(), CLSCTX_INPROC, IID_IUnknown, ppv);
  1990.     }
  1991. };
  1992.  
  1993. #ifdef _ATL_DEBUG
  1994. #define DEBUG_QI_ENTRY(x) \
  1995.         {NULL, \
  1996.         (DWORD)_T(#x), \
  1997.         (_ATL_CREATORARGFUNC*)0},
  1998. #else
  1999. #define DEBUG_QI_ENTRY(x)
  2000. #endif //_ATL_DEBUG
  2001.  
  2002. #ifdef _ATL_DEBUG_INTERFACES
  2003. #define _ATL_DECLARE_GET_UNKNOWN(x)\
  2004.     IUnknown* GetUnknown() \
  2005.     { \
  2006.         IUnknown* p; \
  2007.         _Module.AddNonAddRefThunk(_GetRawUnknown(), _T(#x), &p); \
  2008.         return p; \
  2009.     }
  2010. #else
  2011. #define _ATL_DECLARE_GET_UNKNOWN(x) IUnknown* GetUnknown() {return _GetRawUnknown();}
  2012. #endif
  2013.  
  2014. //If you get a message that FinalConstruct is ambiguous then you need to
  2015. // override it in your class and call each base class' version of this
  2016. #define BEGIN_COM_MAP(x) public: \
  2017.     typedef x _ComMapClass; \
  2018.     static HRESULT WINAPI _Cache(void* pv, REFIID iid, void** ppvObject, DWORD dw)\
  2019.     {\
  2020.         _ComMapClass* p = (_ComMapClass*)pv;\
  2021.         p->Lock();\
  2022.         HRESULT hRes = CComObjectRootBase::_Cache(pv, iid, ppvObject, dw);\
  2023.         p->Unlock();\
  2024.         return hRes;\
  2025.     }\
  2026.     IUnknown* _GetRawUnknown() \
  2027.     { ATLASSERT(_GetEntries()[0].pFunc == _ATL_SIMPLEMAPENTRY); return (IUnknown*)((int)this+_GetEntries()->dw); } \
  2028.     _ATL_DECLARE_GET_UNKNOWN(x)\
  2029.     HRESULT _InternalQueryInterface(REFIID iid, void** ppvObject) \
  2030.     { return InternalQueryInterface(this, _GetEntries(), iid, ppvObject); } \
  2031.     const static _ATL_INTMAP_ENTRY* WINAPI _GetEntries() { \
  2032.     static const _ATL_INTMAP_ENTRY _entries[] = { DEBUG_QI_ENTRY(x)
  2033.  
  2034. #define DECLARE_GET_CONTROLLING_UNKNOWN() public:\
  2035.     virtual IUnknown* GetControllingUnknown() {return GetUnknown();}
  2036.  
  2037. #ifndef _ATL_NO_UUIDOF
  2038. #define _ATL_IIDOF(x) __uuidof(x)
  2039. #else
  2040. #define _ATL_IIDOF(x) IID_##x
  2041. #endif
  2042.  
  2043. #define COM_INTERFACE_ENTRY_BREAK(x)\
  2044.     {&_ATL_IIDOF(x), \
  2045.     NULL, \
  2046.     _Break},
  2047.  
  2048. #define COM_INTERFACE_ENTRY_NOINTERFACE(x)\
  2049.     {&_ATL_IIDOF(x), \
  2050.     NULL, \
  2051.     _NoInterface},
  2052.  
  2053. #define COM_INTERFACE_ENTRY(x)\
  2054.     {&_ATL_IIDOF(x), \
  2055.     offsetofclass(x, _ComMapClass), \
  2056.     _ATL_SIMPLEMAPENTRY},
  2057.  
  2058. #define COM_INTERFACE_ENTRY_IID(iid, x)\
  2059.     {&iid,\
  2060.     offsetofclass(x, _ComMapClass),\
  2061.     _ATL_SIMPLEMAPENTRY},
  2062.  
  2063. // The impl macros are now obsolete
  2064. #define COM_INTERFACE_ENTRY_IMPL(x)\
  2065.     COM_INTERFACE_ENTRY_IID(_ATL_IIDOF(x), x##Impl<_ComMapClass>)
  2066.  
  2067. #define COM_INTERFACE_ENTRY_IMPL_IID(iid, x)\
  2068.     COM_INTERFACE_ENTRY_IID(iid, x##Impl<_ComMapClass>)
  2069. //
  2070.  
  2071. #define COM_INTERFACE_ENTRY2(x, x2)\
  2072.     {&_ATL_IIDOF(x),\
  2073.     (DWORD)((x*)(x2*)((_ComMapClass*)8))-8,\
  2074.     _ATL_SIMPLEMAPENTRY},
  2075.  
  2076. #define COM_INTERFACE_ENTRY2_IID(iid, x, x2)\
  2077.     {&iid,\
  2078.     (DWORD)((x*)(x2*)((_ComMapClass*)8))-8,\
  2079.     _ATL_SIMPLEMAPENTRY},
  2080.  
  2081. #define COM_INTERFACE_ENTRY_FUNC(iid, dw, func)\
  2082.     {&iid, \
  2083.     dw, \
  2084.     func},
  2085.  
  2086. #define COM_INTERFACE_ENTRY_FUNC_BLIND(dw, func)\
  2087.     {NULL, \
  2088.     dw, \
  2089.     func},
  2090.  
  2091. #define COM_INTERFACE_ENTRY_TEAR_OFF(iid, x)\
  2092.     {&iid,\
  2093.     (DWORD)&_CComCreatorData<\
  2094.         CComInternalCreator< CComTearOffObject< x > >\
  2095.         >::data,\
  2096.     _Creator},
  2097.  
  2098. #define COM_INTERFACE_ENTRY_CACHED_TEAR_OFF(iid, x, punk)\
  2099.     {&iid,\
  2100.     (DWORD)&_CComCacheData<\
  2101.         CComCreator< CComCachedTearOffObject< x > >,\
  2102.         (DWORD)offsetof(_ComMapClass, punk)\
  2103.         >::data,\
  2104.     _Cache},
  2105.  
  2106. #define COM_INTERFACE_ENTRY_AGGREGATE(iid, punk)\
  2107.     {&iid,\
  2108.     (DWORD)offsetof(_ComMapClass, punk),\
  2109.     _Delegate},
  2110.  
  2111. #define COM_INTERFACE_ENTRY_AGGREGATE_BLIND(punk)\
  2112.     {NULL,\
  2113.     (DWORD)offsetof(_ComMapClass, punk),\
  2114.     _Delegate},
  2115.  
  2116. #define COM_INTERFACE_ENTRY_AUTOAGGREGATE(iid, punk, clsid)\
  2117.     {&iid,\
  2118.     (DWORD)&_CComCacheData<\
  2119.         CComAggregateCreator<_ComMapClass, &clsid>,\
  2120.         (DWORD)offsetof(_ComMapClass, punk)\
  2121.         >::data,\
  2122.     _Cache},
  2123.  
  2124. #define COM_INTERFACE_ENTRY_AUTOAGGREGATE_BLIND(punk, clsid)\
  2125.     {NULL,\
  2126.     (DWORD)&_CComCacheData<\
  2127.         CComAggregateCreator<_ComMapClass, &clsid>,\
  2128.         (DWORD)offsetof(_ComMapClass, punk)\
  2129.         >::data,\
  2130.     _Cache},
  2131.  
  2132. #define COM_INTERFACE_ENTRY_CHAIN(classname)\
  2133.     {NULL,\
  2134.     (DWORD)&_CComChainData<classname, _ComMapClass>::data,\
  2135.     _Chain},
  2136.  
  2137. #ifdef _ATL_DEBUG
  2138. #define END_COM_MAP() {NULL, 0, 0}}; return &_entries[1];} \
  2139.     virtual ULONG STDMETHODCALLTYPE AddRef( void) = 0; \
  2140.     virtual ULONG STDMETHODCALLTYPE Release( void) = 0; \
  2141.     STDMETHOD(QueryInterface)(REFIID, void**) = 0;
  2142. #else
  2143. #define END_COM_MAP() {NULL, 0, 0}}; return _entries;} \
  2144.     virtual ULONG STDMETHODCALLTYPE AddRef( void) = 0; \
  2145.     virtual ULONG STDMETHODCALLTYPE Release( void) = 0; \
  2146.     STDMETHOD(QueryInterface)(REFIID, void**) = 0;
  2147. #endif // _ATL_DEBUG
  2148.  
  2149. #define BEGIN_CATEGORY_MAP(x)\
  2150.    static const struct _ATL_CATMAP_ENTRY* GetCategoryMap() {\
  2151.    static const struct _ATL_CATMAP_ENTRY pMap[] = {
  2152. #define IMPLEMENTED_CATEGORY( catid ) { _ATL_CATMAP_ENTRY_IMPLEMENTED, &catid },
  2153. #define REQUIRED_CATEGORY( catid ) { _ATL_CATMAP_ENTRY_REQUIRED, &catid },
  2154. #define END_CATEGORY_MAP()\
  2155.    { _ATL_CATMAP_ENTRY_END, NULL } };\
  2156.    return( pMap ); }
  2157.  
  2158. #define BEGIN_OBJECT_MAP(x) static _ATL_OBJMAP_ENTRY x[] = {
  2159. #define END_OBJECT_MAP()   {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}};
  2160. #define OBJECT_ENTRY(clsid, class) {&clsid, class::UpdateRegistry, class::_ClassFactoryCreatorClass::CreateInstance, class::_CreatorClass::CreateInstance, NULL, 0, class::GetObjectDescription, class::GetCategoryMap, class::ObjectMain },
  2161. #define OBJECT_ENTRY_NON_CREATEABLE(class) {&CLSID_NULL, class::UpdateRegistry, NULL, NULL, NULL, 0, NULL, class::GetCategoryMap, class::ObjectMain },
  2162.  
  2163. #ifdef _ATL_DEBUG
  2164. extern HRESULT WINAPI AtlDumpIID(REFIID iid, LPCTSTR pszClassName, HRESULT hr);
  2165. #endif // _ATL_DEBUG
  2166.  
  2167.  
  2168. // the functions in this class don't need to be virtual because
  2169. // they are called from CComObject
  2170. class CComObjectRootBase
  2171. {
  2172. public:
  2173.     CComObjectRootBase()
  2174.     {
  2175.         m_dwRef = 0L;
  2176.     }
  2177.     HRESULT FinalConstruct()
  2178.     {
  2179.         return S_OK;
  2180.     }
  2181.     // For library initialization only
  2182.     HRESULT _AtlFinalConstruct()
  2183.     {
  2184.         return S_OK;
  2185.     }
  2186.     void FinalRelease() {}
  2187.     void _AtlFinalRelease() {}
  2188.  
  2189.     //ObjectMain is called during Module::Init and Module::Term
  2190.     static void WINAPI ObjectMain(bool /* bStarting */) {}
  2191.  
  2192.     static HRESULT WINAPI InternalQueryInterface(void* pThis,
  2193.         const _ATL_INTMAP_ENTRY* pEntries, REFIID iid, void** ppvObject)
  2194.     {
  2195.         ATLASSERT(pThis != NULL);
  2196.         // First entry in the com map should be a simple map entry
  2197.         ATLASSERT(pEntries->pFunc == _ATL_SIMPLEMAPENTRY);
  2198.     #if defined(_ATL_DEBUG_INTERFACES) || defined(_ATL_DEBUG_QI)
  2199.         LPCTSTR pszClassName = (LPCTSTR) pEntries[-1].dw;
  2200.     #endif // _ATL_DEBUG_INTERFACES
  2201.         HRESULT hRes = AtlInternalQueryInterface(pThis, pEntries, iid, ppvObject);
  2202.     #ifdef _ATL_DEBUG_INTERFACES
  2203.         _Module.AddThunk((IUnknown**)ppvObject, pszClassName, iid);
  2204.     #endif // _ATL_DEBUG_INTERFACES
  2205.         return _ATLDUMPIID(iid, pszClassName, hRes);
  2206.     }
  2207.  
  2208. //Outer funcs
  2209.     ULONG OuterAddRef()
  2210.     {
  2211.         return m_pOuterUnknown->AddRef();
  2212.     }
  2213.     ULONG OuterRelease()
  2214.     {
  2215.         return m_pOuterUnknown->Release();
  2216.     }
  2217.     HRESULT OuterQueryInterface(REFIID iid, void ** ppvObject)
  2218.     {
  2219.         return m_pOuterUnknown->QueryInterface(iid, ppvObject);
  2220.     }
  2221.  
  2222.     void SetVoid(void*) {}
  2223.     void InternalFinalConstructAddRef() {}
  2224.     void InternalFinalConstructRelease()
  2225.     {
  2226.         ATLASSERT(m_dwRef == 0);
  2227.     }
  2228.     // If this assert occurs, your object has probably been deleted
  2229.     // Try using DECLARE_PROTECT_FINAL_CONSTRUCT()
  2230.  
  2231.  
  2232.     static HRESULT WINAPI _Break(void* /* pv */, REFIID iid, void** /* ppvObject */, DWORD /* dw */)
  2233.     {
  2234.         iid;
  2235.         _ATLDUMPIID(iid, _T("Break due to QI for interface "), S_OK);
  2236.         DebugBreak();
  2237.         return S_FALSE;
  2238.     }
  2239.     static HRESULT WINAPI _NoInterface(void* /* pv */, REFIID /* iid */, void** /* ppvObject */, DWORD /* dw */)
  2240.     {
  2241.         return E_NOINTERFACE;
  2242.     }
  2243.     static HRESULT WINAPI _Creator(void* pv, REFIID iid, void** ppvObject, DWORD dw)
  2244.     {
  2245.         _ATL_CREATORDATA* pcd = (_ATL_CREATORDATA*)dw;
  2246.         return pcd->pFunc(pv, iid, ppvObject);
  2247.     }
  2248.     static HRESULT WINAPI _Delegate(void* pv, REFIID iid, void** ppvObject, DWORD dw)
  2249.     {
  2250.         HRESULT hRes = E_NOINTERFACE;
  2251.         IUnknown* p = *(IUnknown**)((DWORD)pv + dw);
  2252.         if (p != NULL)
  2253.             hRes = p->QueryInterface(iid, ppvObject);
  2254.         return hRes;
  2255.     }
  2256.     static HRESULT WINAPI _Chain(void* pv, REFIID iid, void** ppvObject, DWORD dw)
  2257.     {
  2258.         _ATL_CHAINDATA* pcd = (_ATL_CHAINDATA*)dw;
  2259.         void* p = (void*)((DWORD)pv + pcd->dwOffset);
  2260.         return InternalQueryInterface(p, pcd->pFunc(), iid, ppvObject);
  2261.     }
  2262.     static HRESULT WINAPI _Cache(void* pv, REFIID iid, void** ppvObject, DWORD dw)
  2263.     {
  2264.         HRESULT hRes = E_NOINTERFACE;
  2265.         _ATL_CACHEDATA* pcd = (_ATL_CACHEDATA*)dw;
  2266.         IUnknown** pp = (IUnknown**)((DWORD)pv + pcd->dwOffsetVar);
  2267.         if (*pp == NULL)
  2268.             hRes = pcd->pFunc(pv, IID_IUnknown, (void**)pp);
  2269.         if (*pp != NULL)
  2270.             hRes = (*pp)->QueryInterface(iid, ppvObject);
  2271.         return hRes;
  2272.     }
  2273.  
  2274.     union
  2275.     {
  2276.         long m_dwRef;
  2277.         IUnknown* m_pOuterUnknown;
  2278.     };
  2279. };
  2280.  
  2281. //foward declaration
  2282. template <class ThreadModel>
  2283. class CComObjectRootEx;
  2284.  
  2285. template <class ThreadModel>
  2286. class CComObjectLockT
  2287. {
  2288. public:
  2289.     CComObjectLockT(CComObjectRootEx<ThreadModel>* p)
  2290.     {
  2291.         if (p)
  2292.             p->Lock();
  2293.         m_p = p;
  2294.     }
  2295.  
  2296.     ~CComObjectLockT()
  2297.     {
  2298.         if (m_p)
  2299.             m_p->Unlock();
  2300.     }
  2301.     CComObjectRootEx<ThreadModel>* m_p;
  2302. };
  2303.  
  2304. template <> class CComObjectLockT<CComSingleThreadModel>;
  2305.  
  2306. template <class ThreadModel>
  2307. class CComObjectRootEx : public CComObjectRootBase
  2308. {
  2309. public:
  2310.     typedef ThreadModel _ThreadModel;
  2311.     typedef _ThreadModel::AutoCriticalSection _CritSec;
  2312.     typedef CComObjectLockT<_ThreadModel> ObjectLock;
  2313.  
  2314.     ULONG InternalAddRef()
  2315.     {
  2316.         ATLASSERT(m_dwRef != -1L);
  2317.         return _ThreadModel::Increment(&m_dwRef);
  2318.     }
  2319.     ULONG InternalRelease()
  2320.     {
  2321.         ATLASSERT(m_dwRef > 0);
  2322.         return _ThreadModel::Decrement(&m_dwRef);
  2323.     }
  2324.  
  2325.     void Lock() {m_critsec.Lock();}
  2326.     void Unlock() {m_critsec.Unlock();}
  2327. private:
  2328.     _CritSec m_critsec;
  2329. };
  2330.  
  2331. template <>
  2332. class CComObjectRootEx<CComSingleThreadModel> : public CComObjectRootBase
  2333. {
  2334. public:
  2335.     typedef CComSingleThreadModel _ThreadModel;
  2336.     typedef _ThreadModel::AutoCriticalSection _CritSec;
  2337.     typedef CComObjectLockT<_ThreadModel> ObjectLock;
  2338.  
  2339.     ULONG InternalAddRef()
  2340.     {
  2341.         ATLASSERT(m_dwRef != -1L);
  2342.         return _ThreadModel::Increment(&m_dwRef);
  2343.     }
  2344.     ULONG InternalRelease()
  2345.     {
  2346.         return _ThreadModel::Decrement(&m_dwRef);
  2347.     }
  2348.  
  2349.     void Lock() {}
  2350.     void Unlock() {}
  2351. };
  2352.  
  2353. template <>
  2354. class CComObjectLockT<CComSingleThreadModel>
  2355. {
  2356. public:
  2357.     CComObjectLockT(CComObjectRootEx<CComSingleThreadModel>*) {}
  2358.     ~CComObjectLockT() {}
  2359. };
  2360.  
  2361. typedef CComObjectRootEx<CComObjectThreadModel> CComObjectRoot;
  2362.  
  2363. #if defined(_WINDLL) | defined(_USRDLL)
  2364. #define DECLARE_CLASSFACTORY_EX(cf) typedef CComCreator< CComObjectCached< cf > > _ClassFactoryCreatorClass;
  2365. #else
  2366. // don't let class factory refcount influence lock count
  2367. #define DECLARE_CLASSFACTORY_EX(cf) typedef CComCreator< CComObjectNoLock< cf > > _ClassFactoryCreatorClass;
  2368. #endif
  2369. #define DECLARE_CLASSFACTORY() DECLARE_CLASSFACTORY_EX(CComClassFactory)
  2370. #define DECLARE_CLASSFACTORY2(lic) DECLARE_CLASSFACTORY_EX(CComClassFactory2<lic>)
  2371. #define DECLARE_CLASSFACTORY_AUTO_THREAD() DECLARE_CLASSFACTORY_EX(CComClassFactoryAutoThread)
  2372. #define DECLARE_CLASSFACTORY_SINGLETON(obj) DECLARE_CLASSFACTORY_EX(CComClassFactorySingleton<obj>)
  2373.  
  2374. #define DECLARE_OBJECT_DESCRIPTION(x)\
  2375.     static LPCTSTR WINAPI GetObjectDescription()\
  2376.     {\
  2377.         return _T(x);\
  2378.     }
  2379.  
  2380. #define DECLARE_NO_REGISTRY()\
  2381.     static HRESULT WINAPI UpdateRegistry(BOOL /*bRegister*/)\
  2382.     {return S_OK;}
  2383.  
  2384. #define DECLARE_REGISTRY(class, pid, vpid, nid, flags)\
  2385.     static HRESULT WINAPI UpdateRegistry(BOOL bRegister)\
  2386.     {\
  2387.         return _Module.UpdateRegistryClass(GetObjectCLSID(), pid, vpid, nid,\
  2388.             flags, bRegister);\
  2389.     }
  2390.  
  2391. #define DECLARE_REGISTRY_RESOURCE(x)\
  2392.     static HRESULT WINAPI UpdateRegistry(BOOL bRegister)\
  2393.     {\
  2394.     return _Module.UpdateRegistryFromResource(_T(#x), bRegister);\
  2395.     }
  2396.  
  2397. #define DECLARE_REGISTRY_RESOURCEID(x)\
  2398.     static HRESULT WINAPI UpdateRegistry(BOOL bRegister)\
  2399.     {\
  2400.     return _Module.UpdateRegistryFromResource(x, bRegister);\
  2401.     }
  2402.  
  2403. //DECLARE_STATIC_* provided for backward compatibility
  2404. #ifdef _ATL_STATIC_REGISTRY
  2405. #define DECLARE_STATIC_REGISTRY_RESOURCE(x) DECLARE_REGISTRY_RESOURCE(x)
  2406. #define DECLARE_STATIC_REGISTRY_RESOURCEID(x) DECLARE_REGISTRY_RESOURCEID(x)
  2407. #endif //_ATL_STATIC_REGISTRY
  2408.  
  2409. template<class Base> class CComObject; // fwd decl
  2410.  
  2411. template <class Owner, class ThreadModel = CComObjectThreadModel>
  2412. class CComTearOffObjectBase : public CComObjectRootEx<ThreadModel>
  2413. {
  2414. public:
  2415.     typedef Owner _OwnerClass;
  2416.     CComObject<Owner>* m_pOwner;
  2417.     CComTearOffObjectBase() {m_pOwner = NULL;}
  2418. };
  2419.  
  2420. //Base is the user's class that derives from CComObjectRoot and whatever
  2421. //interfaces the user wants to support on the object
  2422. template <class Base>
  2423. class CComObject : public Base
  2424. {
  2425. public:
  2426.     typedef Base _BaseClass;
  2427.     CComObject(void* = NULL)
  2428.     {
  2429.         _Module.Lock();
  2430.     }
  2431.     // Set refcount to 1 to protect destruction
  2432.     ~CComObject()
  2433.     {
  2434.         m_dwRef = 1L;
  2435.         FinalRelease();
  2436. #ifdef _ATL_DEBUG_INTERFACES
  2437.         _Module.DeleteNonAddRefThunk(_GetRawUnknown());
  2438. #endif
  2439.         _Module.Unlock();
  2440.     }
  2441.     //If InternalAddRef or InternalRelease is undefined then your class
  2442.     //doesn't derive from CComObjectRoot
  2443.     STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();}
  2444.     STDMETHOD_(ULONG, Release)()
  2445.     {
  2446.         ULONG l = InternalRelease();
  2447.         if (l == 0)
  2448.             delete this;
  2449.         return l;
  2450.     }
  2451.     //if _InternalQueryInterface is undefined then you forgot BEGIN_COM_MAP
  2452.     STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  2453.     {return _InternalQueryInterface(iid, ppvObject);}
  2454.     template <class Q>
  2455.     HRESULT STDMETHODCALLTYPE QueryInterface(Q** pp)
  2456.     {
  2457.         return QueryInterface(__uuidof(Q), (void**)pp);
  2458.     }
  2459.  
  2460.     static HRESULT WINAPI CreateInstance(CComObject<Base>** pp);
  2461. };
  2462.  
  2463. template <class Base>
  2464. HRESULT WINAPI CComObject<Base>::CreateInstance(CComObject<Base>** pp)
  2465. {
  2466.     ATLASSERT(pp != NULL);
  2467.     HRESULT hRes = E_OUTOFMEMORY;
  2468.     CComObject<Base>* p = NULL;
  2469.     ATLTRY(p = new CComObject<Base>())
  2470.     if (p != NULL)
  2471.     {
  2472.         p->SetVoid(NULL);
  2473.         p->InternalFinalConstructAddRef();
  2474.         hRes = p->FinalConstruct();
  2475.         p->InternalFinalConstructRelease();
  2476.         if (hRes != S_OK)
  2477.         {
  2478.             delete p;
  2479.             p = NULL;
  2480.         }
  2481.     }
  2482.     *pp = p;
  2483.     return hRes;
  2484. }
  2485.  
  2486. //Base is the user's class that derives from CComObjectRoot and whatever
  2487. //interfaces the user wants to support on the object
  2488. // CComObjectCached is used primarily for class factories in DLL's
  2489. // but it is useful anytime you want to cache an object
  2490. template <class Base>
  2491. class CComObjectCached : public Base
  2492. {
  2493. public:
  2494.     typedef Base _BaseClass;
  2495.     CComObjectCached(void* = NULL){}
  2496.     // Set refcount to 1 to protect destruction
  2497.     ~CComObjectCached()
  2498.     {
  2499.         m_dwRef = 1L;
  2500.         FinalRelease();
  2501. #ifdef _ATL_DEBUG_INTERFACES
  2502.         _Module.DeleteNonAddRefThunk(_GetRawUnknown());
  2503. #endif
  2504.     }
  2505.     //If InternalAddRef or InternalRelease is undefined then your class
  2506.     //doesn't derive from CComObjectRoot
  2507.     STDMETHOD_(ULONG, AddRef)()
  2508.     {
  2509.         m_csCached.Lock();
  2510.         ULONG l = InternalAddRef();
  2511.         if (m_dwRef == 2)
  2512.             _Module.Lock();
  2513.         m_csCached.Unlock();
  2514.         return l;
  2515.     }
  2516.     STDMETHOD_(ULONG, Release)()
  2517.     {
  2518.         m_csCached.Lock();
  2519.         InternalRelease();
  2520.         ULONG l = m_dwRef;
  2521.         m_csCached.Unlock();
  2522.         if (l == 0)
  2523.             delete this;
  2524.         else if (l == 1)
  2525.             _Module.Unlock();
  2526.         return l;
  2527.     }
  2528.     //if _InternalQueryInterface is undefined then you forgot BEGIN_COM_MAP
  2529.     STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  2530.     {return _InternalQueryInterface(iid, ppvObject);}
  2531.     CComGlobalsThreadModel::AutoCriticalSection m_csCached;
  2532. };
  2533.  
  2534. //Base is the user's class that derives from CComObjectRoot and whatever
  2535. //interfaces the user wants to support on the object
  2536. template <class Base>
  2537. class CComObjectNoLock : public Base
  2538. {
  2539. public:
  2540.     typedef Base _BaseClass;
  2541.     CComObjectNoLock(void* = NULL){}
  2542.     // Set refcount to 1 to protect destruction
  2543.     ~CComObjectNoLock()
  2544.     {
  2545.         m_dwRef = 1L;
  2546.         FinalRelease();
  2547. #ifdef _ATL_DEBUG_INTERFACES
  2548.         _Module.DeleteNonAddRefThunk(_GetRawUnknown());
  2549. #endif
  2550.     }
  2551.  
  2552.     //If InternalAddRef or InternalRelease is undefined then your class
  2553.     //doesn't derive from CComObjectRoot
  2554.     STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();}
  2555.     STDMETHOD_(ULONG, Release)()
  2556.     {
  2557.         ULONG l = InternalRelease();
  2558.         if (l == 0)
  2559.             delete this;
  2560.         return l;
  2561.     }
  2562.     //if _InternalQueryInterface is undefined then you forgot BEGIN_COM_MAP
  2563.     STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  2564.     {return _InternalQueryInterface(iid, ppvObject);}
  2565. };
  2566.  
  2567. // It is possible for Base not to derive from CComObjectRoot
  2568. // However, you will need to provide FinalConstruct and InternalQueryInterface
  2569. template <class Base>
  2570. class CComObjectGlobal : public Base
  2571. {
  2572. public:
  2573.     typedef Base _BaseClass;
  2574.     CComObjectGlobal(void* = NULL){m_hResFinalConstruct = FinalConstruct();}
  2575.     ~CComObjectGlobal()
  2576.     {
  2577.         FinalRelease();
  2578. #ifdef _ATL_DEBUG_INTERFACES
  2579.         _Module.DeleteNonAddRefThunk(_GetRawUnknown());
  2580. #endif
  2581.     }
  2582.  
  2583.     STDMETHOD_(ULONG, AddRef)() {return _Module.Lock();}
  2584.     STDMETHOD_(ULONG, Release)(){return _Module.Unlock();}
  2585.     STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  2586.     {return _InternalQueryInterface(iid, ppvObject);}
  2587.     HRESULT m_hResFinalConstruct;
  2588. };
  2589.  
  2590. // It is possible for Base not to derive from CComObjectRoot
  2591. // However, you will need to provide FinalConstruct and InternalQueryInterface
  2592. template <class Base>
  2593. class CComObjectStack : public Base
  2594. {
  2595. public:
  2596.     typedef Base _BaseClass;
  2597.     CComObjectStack(void* = NULL){m_hResFinalConstruct = FinalConstruct();}
  2598.     ~CComObjectStack()
  2599.     {
  2600.         FinalRelease();
  2601. #ifdef _ATL_DEBUG_INTERFACES
  2602.         _Module.DeleteNonAddRefThunk(_GetRawUnknown());
  2603. #endif
  2604.     }
  2605.  
  2606.  
  2607.     STDMETHOD_(ULONG, AddRef)() {ATLASSERT(FALSE);return 0;}
  2608.     STDMETHOD_(ULONG, Release)(){ATLASSERT(FALSE);return 0;}
  2609.     STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  2610.     {ATLASSERT(FALSE);return E_NOINTERFACE;}
  2611.     HRESULT m_hResFinalConstruct;
  2612. };
  2613.  
  2614. template <class Base> //Base must be derived from CComObjectRoot
  2615. class CComContainedObject : public Base
  2616. {
  2617. public:
  2618.     typedef Base _BaseClass;
  2619.     CComContainedObject(void* pv) {m_pOuterUnknown = (IUnknown*)pv;}
  2620. #ifdef _ATL_DEBUG_INTERFACES
  2621.     ~CComContainedObject()
  2622.     {
  2623.         _Module.DeleteNonAddRefThunk(_GetRawUnknown());
  2624.         _Module.DeleteNonAddRefThunk(m_pOuterUnknown);
  2625.     }
  2626. #endif
  2627.  
  2628.     STDMETHOD_(ULONG, AddRef)() {return OuterAddRef();}
  2629.     STDMETHOD_(ULONG, Release)() {return OuterRelease();}
  2630.     STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  2631.     {
  2632.         HRESULT hr = OuterQueryInterface(iid, ppvObject);
  2633.         if (FAILED(hr) && _GetRawUnknown() != m_pOuterUnknown)
  2634.             hr = _InternalQueryInterface(iid, ppvObject);
  2635.         return hr;
  2636.     }
  2637.     template <class Q>
  2638.     HRESULT STDMETHODCALLTYPE QueryInterface(Q** pp)
  2639.     {
  2640.         return QueryInterface(__uuidof(Q), (void**)pp);
  2641.     }
  2642.     //GetControllingUnknown may be virtual if the Base class has declared
  2643.     //DECLARE_GET_CONTROLLING_UNKNOWN()
  2644.     IUnknown* GetControllingUnknown()
  2645.     {
  2646. #ifdef _ATL_DEBUG_INTERFACES
  2647.         IUnknown* p;
  2648.         _Module.AddNonAddRefThunk(m_pOuterUnknown, _T("CComContainedObject"), &p);
  2649.         return p;
  2650. #else
  2651.         return m_pOuterUnknown;
  2652. #endif
  2653.     }
  2654. };
  2655.  
  2656. //contained is the user's class that derives from CComObjectRoot and whatever
  2657. //interfaces the user wants to support on the object
  2658. template <class contained>
  2659. class CComAggObject :
  2660.     public IUnknown,
  2661.     public CComObjectRootEx< contained::_ThreadModel::ThreadModelNoCS >
  2662. {
  2663. public:
  2664.     typedef contained _BaseClass;
  2665.     CComAggObject(void* pv) : m_contained(pv)
  2666.     {
  2667.         _Module.Lock();
  2668.     }
  2669.     //If you get a message that this call is ambiguous then you need to
  2670.     // override it in your class and call each base class' version of this
  2671.     HRESULT FinalConstruct()
  2672.     {
  2673.         CComObjectRootEx<contained::_ThreadModel::ThreadModelNoCS>::FinalConstruct();
  2674.         return m_contained.FinalConstruct();
  2675.     }
  2676.     void FinalRelease()
  2677.     {
  2678.         CComObjectRootEx<contained::_ThreadModel::ThreadModelNoCS>::FinalRelease();
  2679.         m_contained.FinalRelease();
  2680.     }
  2681.     // Set refcount to 1 to protect destruction
  2682.     ~CComAggObject()
  2683.     {
  2684.         m_dwRef = 1L;
  2685.         FinalRelease();
  2686. #ifdef _ATL_DEBUG_INTERFACES
  2687.         _Module.DeleteNonAddRefThunk(this);
  2688. #endif
  2689.         _Module.Unlock();
  2690.     }
  2691.  
  2692.     STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();}
  2693.     STDMETHOD_(ULONG, Release)()
  2694.     {
  2695.         ULONG l = InternalRelease();
  2696.         if (l == 0)
  2697.             delete this;
  2698.         return l;
  2699.     }
  2700.     STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  2701.     {
  2702.         HRESULT hRes = S_OK;
  2703.         if (InlineIsEqualUnknown(iid))
  2704.         {
  2705.             if (ppvObject == NULL)
  2706.                 return E_POINTER;
  2707.             *ppvObject = (void*)(IUnknown*)this;
  2708.             AddRef();
  2709. #ifdef _ATL_DEBUG_INTERFACES
  2710.             _Module.AddThunk((IUnknown**)ppvObject, (LPCTSTR)contained::_GetEntries()[-1].dw, iid);
  2711. #endif // _ATL_DEBUG_INTERFACES
  2712.         }
  2713.         else
  2714.             hRes = m_contained._InternalQueryInterface(iid, ppvObject);
  2715.         return hRes;
  2716.     }
  2717.     template <class Q>
  2718.     HRESULT STDMETHODCALLTYPE QueryInterface(Q** pp)
  2719.     {
  2720.         return QueryInterface(__uuidof(Q), (void**)pp);
  2721.     }
  2722.     static HRESULT WINAPI CreateInstance(LPUNKNOWN pUnkOuter, CComAggObject<contained>** pp)
  2723.     {
  2724.         ATLASSERT(pp != NULL);
  2725.         HRESULT hRes = E_OUTOFMEMORY;
  2726.         CComAggObject<contained>* p = NULL;
  2727.         ATLTRY(p = new CComAggObject<contained>(pUnkOuter))
  2728.         if (p != NULL)
  2729.         {
  2730.             p->SetVoid(NULL);
  2731.             p->InternalFinalConstructAddRef();
  2732.             hRes = p->FinalConstruct();
  2733.             p->InternalFinalConstructRelease();
  2734.             if (hRes != S_OK)
  2735.             {
  2736.                 delete p;
  2737.                 p = NULL;
  2738.             }
  2739.         }
  2740.         *pp = p;
  2741.         return hRes;
  2742.     }
  2743.  
  2744.     CComContainedObject<contained> m_contained;
  2745. };
  2746.  
  2747. ///////////////////////////////////////////////////////////////////////////////
  2748. // CComPolyObject can be either aggregated or not aggregated
  2749.  
  2750. template <class contained>
  2751. class CComPolyObject :
  2752.     public IUnknown,
  2753.     public CComObjectRootEx< contained::_ThreadModel::ThreadModelNoCS >
  2754. {
  2755. public:
  2756.     typedef contained _BaseClass;
  2757.     CComPolyObject(void* pv) : m_contained(pv ? pv : this)
  2758.     {
  2759.         _Module.Lock();
  2760.     }
  2761.     //If you get a message that this call is ambiguous then you need to
  2762.     // override it in your class and call each base class' version of this
  2763.     HRESULT FinalConstruct()
  2764.     {
  2765.         InternalAddRef();
  2766.         CComObjectRootEx<contained::_ThreadModel::ThreadModelNoCS>::FinalConstruct();
  2767.         HRESULT hr = m_contained.FinalConstruct();
  2768.         InternalRelease();
  2769.         return hr;
  2770.     }
  2771.     void FinalRelease()
  2772.     {
  2773.         CComObjectRootEx<contained::_ThreadModel::ThreadModelNoCS>::FinalRelease();
  2774.         m_contained.FinalRelease();
  2775.     }
  2776.     // Set refcount to 1 to protect destruction
  2777.     ~CComPolyObject()
  2778.     {
  2779.         m_dwRef = 1L;
  2780.         FinalRelease();
  2781. #ifdef _ATL_DEBUG_INTERFACES
  2782.         _Module.DeleteNonAddRefThunk(this);
  2783. #endif
  2784.         _Module.Unlock();
  2785.     }
  2786.  
  2787.     STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();}
  2788.     STDMETHOD_(ULONG, Release)()
  2789.     {
  2790.         ULONG l = InternalRelease();
  2791.         if (l == 0)
  2792.             delete this;
  2793.         return l;
  2794.     }
  2795.     STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  2796.     {
  2797.         HRESULT hRes = S_OK;
  2798.         if (InlineIsEqualUnknown(iid))
  2799.         {
  2800.             if (ppvObject == NULL)
  2801.                 return E_POINTER;
  2802.             *ppvObject = (void*)(IUnknown*)this;
  2803.             AddRef();
  2804. #ifdef _ATL_DEBUG_INTERFACES
  2805.             _Module.AddThunk((IUnknown**)ppvObject, (LPCTSTR)contained::_GetEntries()[-1].dw, iid);
  2806. #endif // _ATL_DEBUG_INTERFACES
  2807.         }
  2808.         else
  2809.             hRes = m_contained._InternalQueryInterface(iid, ppvObject);
  2810.         return hRes;
  2811.     }
  2812.     template <class Q>
  2813.     HRESULT STDMETHODCALLTYPE QueryInterface(Q** pp)
  2814.     {
  2815.         return QueryInterface(__uuidof(Q), (void**)pp);
  2816.     }
  2817.     static HRESULT WINAPI CreateInstance(LPUNKNOWN pUnkOuter, CComPolyObject<contained>** pp)
  2818.     {
  2819.         ATLASSERT(pp != NULL);
  2820.         HRESULT hRes = E_OUTOFMEMORY;
  2821.         CComPolyObject<contained>* p = NULL;
  2822.         ATLTRY(p = new CComPolyObject<contained>(pUnkOuter))
  2823.         if (p != NULL)
  2824.         {
  2825.             p->SetVoid(NULL);
  2826.             p->InternalFinalConstructAddRef();
  2827.             hRes = p->FinalConstruct();
  2828.             p->InternalFinalConstructRelease();
  2829.             if (hRes != S_OK)
  2830.             {
  2831.                 delete p;
  2832.                 p = NULL;
  2833.             }
  2834.         }
  2835.         *pp = p;
  2836.         return hRes;
  2837.     }
  2838.  
  2839.     CComContainedObject<contained> m_contained;
  2840. };
  2841.  
  2842. template <class Base>
  2843. class CComTearOffObject : public Base
  2844. {
  2845. public:
  2846.     CComTearOffObject(void* pv)
  2847.     {
  2848.         ATLASSERT(m_pOwner == NULL);
  2849.         m_pOwner = reinterpret_cast<CComObject<Base::_OwnerClass>*>(pv);
  2850.         m_pOwner->AddRef();
  2851.     }
  2852.     // Set refcount to 1 to protect destruction
  2853.     ~CComTearOffObject()
  2854.     {
  2855.         m_dwRef = 1L;
  2856.         FinalRelease();
  2857. #ifdef _ATL_DEBUG_INTERFACES
  2858.         _Module.DeleteNonAddRefThunk(_GetRawUnknown());
  2859. #endif
  2860.         m_pOwner->Release();
  2861.     }
  2862.  
  2863.     STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();}
  2864.     STDMETHOD_(ULONG, Release)()
  2865.     {
  2866.         ULONG l = InternalRelease();
  2867.         if (l == 0)
  2868.             delete this;
  2869.         return l;
  2870.     }
  2871.     STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  2872.     {
  2873.         return m_pOwner->QueryInterface(iid, ppvObject);
  2874.     }
  2875. };
  2876.  
  2877. template <class contained>
  2878. class CComCachedTearOffObject :
  2879.     public IUnknown,
  2880.     public CComObjectRootEx<contained::_ThreadModel::ThreadModelNoCS>
  2881. {
  2882. public:
  2883.     typedef contained _BaseClass;
  2884.     CComCachedTearOffObject(void* pv) :
  2885.         m_contained(((contained::_OwnerClass*)pv)->GetControllingUnknown())
  2886.     {
  2887.         ATLASSERT(m_contained.m_pOwner == NULL);
  2888.         m_contained.m_pOwner = reinterpret_cast<CComObject<contained::_OwnerClass>*>(pv);
  2889.     }
  2890.     //If you get a message that this call is ambiguous then you need to
  2891.     // override it in your class and call each base class' version of this
  2892.     HRESULT FinalConstruct()
  2893.     {
  2894.         CComObjectRootEx<contained::_ThreadModel::ThreadModelNoCS>::FinalConstruct();
  2895.         return m_contained.FinalConstruct();
  2896.     }
  2897.     void FinalRelease()
  2898.     {
  2899.         CComObjectRootEx<contained::_ThreadModel::ThreadModelNoCS>::FinalRelease();
  2900.         m_contained.FinalRelease();
  2901.     }
  2902.     // Set refcount to 1 to protect destruction
  2903.     ~CComCachedTearOffObject()
  2904.     {
  2905.         m_dwRef = 1L;
  2906.         FinalRelease();
  2907. #ifdef _ATL_DEBUG_INTERFACES
  2908.         _Module.DeleteNonAddRefThunk(this);
  2909. #endif
  2910.     }
  2911.  
  2912.  
  2913.     STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();}
  2914.     STDMETHOD_(ULONG, Release)()
  2915.     {
  2916.         ULONG l = InternalRelease();
  2917.         if (l == 0)
  2918.             delete this;
  2919.         return l;
  2920.     }
  2921.     STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  2922.     {
  2923.         HRESULT hRes = S_OK;
  2924.         if (InlineIsEqualUnknown(iid))
  2925.         {
  2926.             if (ppvObject == NULL)
  2927.                 return E_POINTER;
  2928.             *ppvObject = (void*)(IUnknown*)this;
  2929.             AddRef();
  2930. #ifdef _ATL_DEBUG_INTERFACES
  2931.             _Module.AddThunk((IUnknown**)ppvObject, (LPCTSTR)contained::_GetEntries()[-1].dw, iid);
  2932. #endif // _ATL_DEBUG_INTERFACES
  2933.         }
  2934.         else
  2935.             hRes = m_contained._InternalQueryInterface(iid, ppvObject);
  2936.         return hRes;
  2937.     }
  2938.     CComContainedObject<contained> m_contained;
  2939. };
  2940.  
  2941. class CComClassFactory :
  2942.     public IClassFactory,
  2943.     public CComObjectRootEx<CComGlobalsThreadModel>
  2944. {
  2945. public:
  2946.     BEGIN_COM_MAP(CComClassFactory)
  2947.         COM_INTERFACE_ENTRY(IClassFactory)
  2948.     END_COM_MAP()
  2949.  
  2950.     // IClassFactory
  2951.     STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void** ppvObj)
  2952.     {
  2953.         ATLASSERT(m_pfnCreateInstance != NULL);
  2954.         HRESULT hRes = E_POINTER;
  2955.         if (ppvObj != NULL)
  2956.         {
  2957.             *ppvObj = NULL;
  2958.             // can't ask for anything other than IUnknown when aggregating
  2959.             
  2960.             if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid))
  2961.             {
  2962.                 ATLTRACE2(atlTraceCOM, 0, _T("CComClassFactory: asked for non IUnknown interface while creating an aggregated object"));
  2963.                 hRes = CLASS_E_NOAGGREGATION;
  2964.             }
  2965.             else
  2966.                 hRes = m_pfnCreateInstance(pUnkOuter, riid, ppvObj);
  2967.         }
  2968.         return hRes;
  2969.     }
  2970.  
  2971.     STDMETHOD(LockServer)(BOOL fLock)
  2972.     {
  2973.         if (fLock)
  2974.             _Module.Lock();
  2975.         else
  2976.             _Module.Unlock();
  2977.         return S_OK;
  2978.     }
  2979.     // helper
  2980.     void SetVoid(void* pv)
  2981.     {
  2982.         m_pfnCreateInstance = (_ATL_CREATORFUNC*)pv;
  2983.     }
  2984.     _ATL_CREATORFUNC* m_pfnCreateInstance;
  2985. };
  2986.  
  2987. template <class license>
  2988. class CComClassFactory2 : 
  2989.     public IClassFactory2,
  2990.     public CComObjectRootEx<CComGlobalsThreadModel>,
  2991.     public license
  2992. {
  2993. public:
  2994.     typedef license _LicenseClass;
  2995.     typedef CComClassFactory2<license> _ComMapClass;
  2996. BEGIN_COM_MAP(CComClassFactory2<license>)
  2997.     COM_INTERFACE_ENTRY(IClassFactory)
  2998.     COM_INTERFACE_ENTRY(IClassFactory2)
  2999. END_COM_MAP()
  3000.     // IClassFactory
  3001.     STDMETHOD(LockServer)(BOOL fLock)
  3002.     {
  3003.         if (fLock)
  3004.             _Module.Lock();
  3005.         else
  3006.             _Module.Unlock();
  3007.         return S_OK;
  3008.     }
  3009.     STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter,
  3010.         REFIID riid, void** ppvObj)
  3011.     {
  3012.         ATLASSERT(m_pfnCreateInstance != NULL);
  3013.         if (ppvObj == NULL)
  3014.             return E_POINTER;
  3015.         *ppvObj = NULL;
  3016.         if (!IsLicenseValid())
  3017.             return CLASS_E_NOTLICENSED;
  3018.  
  3019.         if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid))
  3020.             return CLASS_E_NOAGGREGATION;
  3021.         else
  3022.             return m_pfnCreateInstance(pUnkOuter, riid, ppvObj);
  3023.     }
  3024.     // IClassFactory2
  3025.     STDMETHOD(CreateInstanceLic)(IUnknown* pUnkOuter, IUnknown* pUnkReserved,
  3026.                 REFIID riid, BSTR bstrKey, void** ppvObject)
  3027.     {
  3028.         ATLASSERT(m_pfnCreateInstance != NULL);
  3029.         if (ppvObject == NULL)
  3030.             return E_POINTER;
  3031.         *ppvObject = NULL;
  3032.         if ( ((bstrKey != NULL) && !VerifyLicenseKey(bstrKey)) ||
  3033.              ((bstrKey == NULL) && !IsLicenseValid()) )
  3034.             return CLASS_E_NOTLICENSED;
  3035.         if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid))
  3036.             return CLASS_E_NOAGGREGATION;
  3037.         else
  3038.             return m_pfnCreateInstance(pUnkOuter, riid, ppvObject);
  3039.     }
  3040.     STDMETHOD(RequestLicKey)(DWORD dwReserved, BSTR* pbstrKey)
  3041.     {
  3042.         if (pbstrKey == NULL)
  3043.             return E_POINTER;
  3044.         *pbstrKey = NULL;
  3045.  
  3046.         if (!IsLicenseValid())
  3047.             return CLASS_E_NOTLICENSED;
  3048.         return GetLicenseKey(dwReserved,pbstrKey) ? S_OK : E_FAIL;
  3049.     }
  3050.     STDMETHOD(GetLicInfo)(LICINFO* pLicInfo)
  3051.     {
  3052.         if (pLicInfo == NULL)
  3053.             return E_POINTER;
  3054.         pLicInfo->cbLicInfo = sizeof(LICINFO);
  3055.         pLicInfo->fLicVerified = IsLicenseValid();
  3056.         BSTR bstr = NULL;
  3057.         pLicInfo->fRuntimeKeyAvail = GetLicenseKey(0,&bstr);
  3058.         ::SysFreeString(bstr);
  3059.         return S_OK;
  3060.     }
  3061.     void SetVoid(void* pv)
  3062.     {
  3063.         m_pfnCreateInstance = (_ATL_CREATORFUNC*)pv;
  3064.     }
  3065.     _ATL_CREATORFUNC* m_pfnCreateInstance;
  3066. };
  3067.  
  3068. /////////////////////////////////////////////////////////////////////////////////////////////
  3069. // Thread Pooling class factory
  3070.  
  3071. class CComClassFactoryAutoThread :
  3072.     public IClassFactory,
  3073.     public CComObjectRootEx<CComGlobalsThreadModel>
  3074. {
  3075. public:
  3076.     BEGIN_COM_MAP(CComClassFactoryAutoThread)
  3077.         COM_INTERFACE_ENTRY(IClassFactory)
  3078.     END_COM_MAP()
  3079.  
  3080.     // helper
  3081.     void SetVoid(void* pv)
  3082.     {
  3083.         m_pfnCreateInstance = (_ATL_CREATORFUNC*)pv;
  3084.     }
  3085.     STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter,
  3086.         REFIID riid, void** ppvObj)
  3087.     {
  3088.         ATLASSERT(m_pfnCreateInstance != NULL);
  3089.         HRESULT hRes = E_POINTER;
  3090.         if (ppvObj != NULL)
  3091.         {
  3092.             *ppvObj = NULL;
  3093.             // cannot aggregate across apartments
  3094.             ATLASSERT(pUnkOuter == NULL);
  3095.             if (pUnkOuter != NULL)
  3096.                 hRes = CLASS_E_NOAGGREGATION;
  3097.             else
  3098.                 hRes = _Module.CreateInstance(m_pfnCreateInstance, riid, ppvObj);
  3099.         }
  3100.         return hRes;
  3101.     }
  3102.     STDMETHODIMP LockServer(BOOL fLock)
  3103.     {
  3104.         if (fLock)
  3105.             _Module.Lock();
  3106.         else
  3107.             _Module.Unlock();
  3108.         return S_OK;
  3109.     }
  3110.     _ATL_CREATORFUNC* m_pfnCreateInstance;
  3111. };
  3112.  
  3113. /////////////////////////////////////////////////////////////////////////////////////////////
  3114. // Singleton Class Factory
  3115. template <class T>
  3116. class CComClassFactorySingleton : public CComClassFactory
  3117. {
  3118. public:
  3119.     void FinalRelease()
  3120.     {
  3121.         CoDisconnectObject(m_Obj.GetUnknown(), 0);
  3122.     }
  3123.  
  3124.     // IClassFactory
  3125.     STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void** ppvObj)
  3126.     {
  3127.         HRESULT hRes = E_POINTER;
  3128.         if (ppvObj != NULL)
  3129.         {
  3130.             *ppvObj = NULL;
  3131.             // aggregation is not supported in Singletons
  3132.             ATLASSERT(pUnkOuter == NULL);
  3133.             if (pUnkOuter != NULL)
  3134.                 hRes = CLASS_E_NOAGGREGATION;
  3135.             else
  3136.             {
  3137.                 if (m_Obj.m_hResFinalConstruct != S_OK)
  3138.                     hRes = m_Obj.m_hResFinalConstruct;
  3139.                 else
  3140.                     hRes = m_Obj.QueryInterface(riid, ppvObj);
  3141.             }
  3142.         }
  3143.         return hRes;
  3144.     }
  3145.     CComObjectGlobal<T> m_Obj;
  3146. };
  3147.  
  3148. template <class T, const CLSID* pclsid = &CLSID_NULL>
  3149. class CComCoClass
  3150. {
  3151. public:
  3152.     DECLARE_CLASSFACTORY()
  3153.     DECLARE_AGGREGATABLE(T)
  3154.     typedef T _CoClass;
  3155.     static const CLSID& WINAPI GetObjectCLSID() {return *pclsid;}
  3156.     static LPCTSTR WINAPI GetObjectDescription() {return NULL;}
  3157.     static const struct _ATL_CATMAP_ENTRY* GetCategoryMap() {return NULL;};
  3158.     static HRESULT WINAPI Error(LPCOLESTR lpszDesc,
  3159.         const IID& iid = GUID_NULL, HRESULT hRes = 0)
  3160.     {
  3161.         return AtlReportError(GetObjectCLSID(), lpszDesc, iid, hRes);
  3162.     }
  3163.     static HRESULT WINAPI Error(LPCOLESTR lpszDesc, DWORD dwHelpID,
  3164.         LPCOLESTR lpszHelpFile, const IID& iid = GUID_NULL, HRESULT hRes = 0)
  3165.     {
  3166.         return AtlReportError(GetObjectCLSID(), lpszDesc, dwHelpID, lpszHelpFile,
  3167.             iid, hRes);
  3168.     }
  3169.     static HRESULT WINAPI Error(UINT nID, const IID& iid = GUID_NULL,
  3170.         HRESULT hRes = 0, HINSTANCE hInst = _Module.GetResourceInstance())
  3171.     {
  3172.         return AtlReportError(GetObjectCLSID(), nID, iid, hRes, hInst);
  3173.     }
  3174.     static HRESULT WINAPI Error(UINT nID, DWORD dwHelpID,
  3175.         LPCOLESTR lpszHelpFile, const IID& iid = GUID_NULL,
  3176.         HRESULT hRes = 0, HINSTANCE hInst = _Module.GetResourceInstance())
  3177.     {
  3178.         return AtlReportError(GetObjectCLSID(), nID, dwHelpID, lpszHelpFile,
  3179.             iid, hRes, hInst);
  3180.     }
  3181. #ifndef OLE2ANSI
  3182.     static HRESULT WINAPI Error(LPCSTR lpszDesc,
  3183.         const IID& iid = GUID_NULL, HRESULT hRes = 0)
  3184.     {
  3185.         return AtlReportError(GetObjectCLSID(), lpszDesc, iid, hRes);
  3186.     }
  3187.     static HRESULT WINAPI Error(LPCSTR lpszDesc, DWORD dwHelpID,
  3188.         LPCSTR lpszHelpFile, const IID& iid = GUID_NULL, HRESULT hRes = 0)
  3189.     {
  3190.         return AtlReportError(GetObjectCLSID(), lpszDesc, dwHelpID,
  3191.             lpszHelpFile, iid, hRes);
  3192.     }
  3193. #endif
  3194.     template <class Q>
  3195.     static HRESULT CreateInstance(IUnknown* punkOuter, Q** pp)
  3196.     {
  3197.         return T::_CreatorClass::CreateInstance(punkOuter, __uuidof(Q), (void**) pp);
  3198.     }
  3199.     template <class Q>
  3200.     static HRESULT CreateInstance(Q** pp)
  3201.     {
  3202.         return T::_CreatorClass::CreateInstance(NULL, __uuidof(Q), (void**) pp);
  3203.     }
  3204. };
  3205.  
  3206. // ATL doesn't support multiple LCID's at the same time
  3207. // Whatever LCID is queried for first is the one that is used.
  3208. class CComTypeInfoHolder
  3209. {
  3210. // Should be 'protected' but can cause compiler to generate fat code.
  3211. public:
  3212.     const GUID* m_pguid;
  3213.     const GUID* m_plibid;
  3214.     WORD m_wMajor;
  3215.     WORD m_wMinor;
  3216.  
  3217.     ITypeInfo* m_pInfo;
  3218.     long m_dwRef;
  3219.     struct stringdispid
  3220.     {
  3221.         CComBSTR bstr;
  3222.         int nLen;
  3223.         DISPID id;
  3224.     };
  3225.     stringdispid* m_pMap;
  3226.     int m_nCount;
  3227.  
  3228. public:
  3229.     HRESULT GetTI(LCID lcid, ITypeInfo** ppInfo)
  3230.     {
  3231.         HRESULT hr = S_OK;
  3232.         if (m_pInfo == NULL)
  3233.             hr = GetTI(lcid);
  3234.         *ppInfo = m_pInfo;
  3235.         if (m_pInfo != NULL)
  3236.         {
  3237.             m_pInfo->AddRef();
  3238.             hr = S_OK;
  3239.         }
  3240.         return hr;
  3241.     }
  3242.     HRESULT GetTI(LCID lcid);
  3243.     HRESULT EnsureTI(LCID lcid)
  3244.     {
  3245.         HRESULT hr = S_OK;
  3246.         if (m_pInfo == NULL)
  3247.             hr = GetTI(lcid);
  3248.         return hr;
  3249.     }
  3250.  
  3251.     // This function is called by the module on exit
  3252.     // It is registered through _Module.AddTermFunc()
  3253.     static void __stdcall Cleanup(DWORD dw)
  3254.     {
  3255.         CComTypeInfoHolder* p = (CComTypeInfoHolder*) dw;
  3256.         if (p->m_pInfo != NULL)
  3257.             p->m_pInfo->Release();
  3258.         p->m_pInfo = NULL;
  3259.         delete [] p->m_pMap;
  3260.         p->m_pMap = NULL;
  3261.     }
  3262.  
  3263.     HRESULT GetTypeInfo(UINT /* itinfo */, LCID lcid, ITypeInfo** pptinfo)
  3264.     {
  3265.         HRESULT hRes = E_POINTER;
  3266.         if (pptinfo != NULL)
  3267.             hRes = GetTI(lcid, pptinfo);
  3268.         return hRes;
  3269.     }
  3270.     HRESULT GetIDsOfNames(REFIID /* riid */, LPOLESTR* rgszNames, UINT cNames,
  3271.         LCID lcid, DISPID* rgdispid)
  3272.     {
  3273.         HRESULT hRes = EnsureTI(lcid);
  3274.         if (m_pInfo != NULL)
  3275.         {
  3276.             for (int i=0; i<(int)cNames; i++)
  3277.             {
  3278.                 int n = ocslen(rgszNames[i]);
  3279.                 for (int j=m_nCount-1; j>=0; j--)
  3280.                 {
  3281.                     if ((n == m_pMap[j].nLen) &&
  3282.                         (memcmp(m_pMap[j].bstr, rgszNames[i], m_pMap[j].nLen * sizeof(OLECHAR)) == 0))
  3283.                     {
  3284.                         rgdispid[i] = m_pMap[j].id;
  3285.                         break;
  3286.                     }
  3287.                 }
  3288.                 if (j < 0)
  3289.                 {
  3290.                     hRes = m_pInfo->GetIDsOfNames(rgszNames + i, 1, &rgdispid[i]);
  3291.                     if (FAILED(hRes))
  3292.                         break;
  3293.                 }
  3294.             }
  3295.         }
  3296.         return hRes;
  3297.     }
  3298.  
  3299.     HRESULT Invoke(IDispatch* p, DISPID dispidMember, REFIID /* riid */,
  3300.         LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
  3301.         EXCEPINFO* pexcepinfo, UINT* puArgErr)
  3302.     {
  3303.         HRESULT hRes = EnsureTI(lcid);
  3304.         if (m_pInfo != NULL)
  3305.             hRes = m_pInfo->Invoke(p, dispidMember, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
  3306.         return hRes;
  3307.     }
  3308.     HRESULT LoadNameCache(ITypeInfo* pTypeInfo)
  3309.     {
  3310.         TYPEATTR* pta;
  3311.         HRESULT hr = pTypeInfo->GetTypeAttr(&pta);
  3312.         if (SUCCEEDED(hr))
  3313.         {
  3314.             m_nCount = pta->cFuncs;
  3315.             m_pMap = m_nCount == 0 ? 0 : new stringdispid[m_nCount];
  3316.             for (int i=0; i<m_nCount; i++)
  3317.             {
  3318.                 FUNCDESC* pfd;
  3319.                 if (SUCCEEDED(pTypeInfo->GetFuncDesc(i, &pfd)))
  3320.                 {
  3321.                     CComBSTR bstrName;
  3322.                     if (SUCCEEDED(pTypeInfo->GetDocumentation(pfd->memid, &bstrName, NULL, NULL, NULL)))
  3323.                     {
  3324.                         m_pMap[i].bstr.Attach(bstrName.Detach());
  3325.                         m_pMap[i].nLen = SysStringLen(m_pMap[i].bstr);
  3326.                         m_pMap[i].id = pfd->memid;
  3327.                     }
  3328.                     pTypeInfo->ReleaseFuncDesc(pfd);
  3329.                 }
  3330.             }
  3331.             pTypeInfo->ReleaseTypeAttr(pta);
  3332.         }
  3333.         return S_OK;
  3334.     }
  3335. };
  3336.  
  3337.  
  3338. inline HRESULT CComTypeInfoHolder::GetTI(LCID lcid)
  3339. {
  3340.     //If this assert occurs then most likely didn't initialize properly
  3341.     ATLASSERT(m_plibid != NULL && m_pguid != NULL);
  3342.     ATLASSERT(!InlineIsEqualGUID(*m_plibid, GUID_NULL) && "Did you forget to pass the LIBID to CComModule::Init?");
  3343.  
  3344.     if (m_pInfo != NULL)
  3345.         return S_OK;
  3346.     HRESULT hRes = E_FAIL;
  3347.     EnterCriticalSection(&_Module.m_csTypeInfoHolder);
  3348.     if (m_pInfo == NULL)
  3349.     {
  3350.         ITypeLib* pTypeLib;
  3351.         hRes = LoadRegTypeLib(*m_plibid, m_wMajor, m_wMinor, lcid, &pTypeLib);
  3352.         if (SUCCEEDED(hRes))
  3353.         {
  3354.             CComPtr<ITypeInfo> spTypeInfo;
  3355.             hRes = pTypeLib->GetTypeInfoOfGuid(*m_pguid, &spTypeInfo);
  3356.             if (SUCCEEDED(hRes))
  3357.             {
  3358.                 CComPtr<ITypeInfo> spInfo(spTypeInfo);
  3359.                 CComPtr<ITypeInfo2> spTypeInfo2;
  3360. #if defined(_WIN32_WCE)
  3361.                 if (SUCCEEDED(spTypeInfo->QueryInterface(__uuidof(ITypeInfo2), (void**)&spTypeInfo2)))
  3362. #else // _WIN32_WCE
  3363.                 if (SUCCEEDED(spTypeInfo->QueryInterface(&spTypeInfo2))) 
  3364.                     spInfo = spTypeInfo2;
  3365. #endif // _WIN32_WCE
  3366.  
  3367.                 LoadNameCache(spInfo);
  3368.                 m_pInfo = spInfo.Detach();
  3369.             }
  3370.             pTypeLib->Release();
  3371.         }
  3372.     }
  3373.     LeaveCriticalSection(&_Module.m_csTypeInfoHolder);
  3374.     _Module.AddTermFunc(Cleanup, (DWORD)this);
  3375.     return hRes;
  3376. }
  3377.  
  3378. //////////////////////////////////////////////////////////////////////////////
  3379. // IObjectWithSite
  3380. //
  3381. template <class T>
  3382. class ATL_NO_VTABLE IObjectWithSiteImpl : public IObjectWithSite
  3383. {
  3384. public:
  3385.     STDMETHOD(SetSite)(IUnknown *pUnkSite)
  3386.     {
  3387.         ATLTRACE2(atlTraceCOM, 0, _T("IObjectWithSiteImpl::SetSite\n"));
  3388.         T* pT = static_cast<T*>(this);
  3389.         pT->m_spUnkSite = pUnkSite;
  3390.         return S_OK;
  3391.     }
  3392.     STDMETHOD(GetSite)(REFIID riid, void **ppvSite)
  3393.     {
  3394.         ATLTRACE2(atlTraceCOM, 0, _T("IObjectWithSiteImpl::GetSite\n"));
  3395.         T* pT = static_cast<T*>(this);
  3396.         ATLASSERT(ppvSite);
  3397.         HRESULT hRes = E_POINTER;
  3398.         if (ppvSite != NULL)
  3399.         {
  3400.             if (pT->m_spUnkSite)
  3401.                 hRes = pT->m_spUnkSite->QueryInterface(riid, ppvSite);
  3402.             else
  3403.             {
  3404.                 *ppvSite = NULL;
  3405.                 hRes = E_FAIL;
  3406.             }
  3407.         }
  3408.         return hRes;
  3409.     }
  3410.  
  3411.     HRESULT SetChildSite(IUnknown* punkChild)
  3412.     {
  3413.         if (punkChild == NULL)
  3414.             return E_POINTER;
  3415.  
  3416.         HRESULT hr;
  3417.         CComPtr<IObjectWithSite> spChildSite;
  3418.         hr = punkChild->QueryInterface(IID_IObjectWithSite, (void**)&spChildSite);
  3419.         if (SUCCEEDED(hr))
  3420.             hr = spChildSite->SetSite((IUnknown*)this);
  3421.  
  3422.         return hr;
  3423.     }
  3424.  
  3425.     static HRESULT SetChildSite(IUnknown* punkChild, IUnknown* punkParent)
  3426.     {
  3427.         return AtlSetChildSite(punkChild, punkParent);
  3428.     }
  3429.  
  3430.     CComPtr<IUnknown> m_spUnkSite;
  3431. };
  3432.  
  3433. #if !defined(_WIN32_WCE)
  3434. //////////////////////////////////////////////////////////////////////////////
  3435. // IServiceProvider
  3436. //
  3437. template <class T>
  3438. class ATL_NO_VTABLE IServiceProviderImpl : public IServiceProvider
  3439. {
  3440. public:
  3441.     STDMETHOD(QueryService)(REFGUID guidService, REFIID riid, void** ppvObject)
  3442.     {
  3443.         ATLTRACE2(atlTraceCOM, 0, _T("IServiceProviderImpl::QueryService\n"));
  3444.         T* pT = static_cast<T*>(this);
  3445.         return pT->_InternalQueryService(guidService, riid, ppvObject);
  3446.     }
  3447. };
  3448.  
  3449. #define BEGIN_SERVICE_MAP(x) public: \
  3450.     HRESULT _InternalQueryService(REFGUID guidService, REFIID riid, void** ppvObject) \
  3451.     {
  3452.  
  3453. #define SERVICE_ENTRY(x) \
  3454.         if (InlineIsEqualGUID(guidService, x)) \
  3455.             return QueryInterface(riid, ppvObject);
  3456.  
  3457. #define SERVICE_ENTRY_CHAIN(x) \
  3458.         CComQIPtr<IServiceProvider, &IID_IServiceProvider> spProvider(x); \
  3459.         if (spProvider != NULL) \
  3460.             return spProvider->QueryService(guidService, riid, ppvObject);
  3461.  
  3462. #define END_SERVICE_MAP() \
  3463.         return E_NOINTERFACE; \
  3464.     }
  3465. #endif // _WIN32_WCE
  3466.  
  3467.  
  3468. /////////////////////////////////////////////////////////////////////////////
  3469. // IDispEventImpl
  3470.  
  3471. #ifdef _ATL_DLL
  3472. ATLAPI AtlGetObjectSourceInterface(IUnknown* punkObj, GUID* plibid, IID* piid, unsigned short* pdwMajor, unsigned short* pdwMinor);
  3473. #else
  3474. #if defined(_WIN32_WCE)
  3475. ATLAPI AtlGetObjectSourceInterface(IUnknown* punkObj, GUID* plibid, IID* piid, unsigned short* pdwMajor, unsigned short* pdwMinor);
  3476. #else // _WIN32_WCE
  3477. ATLINLINE ATLAPI AtlGetObjectSourceInterface(IUnknown* punkObj, GUID* plibid, IID* piid, unsigned short* pdwMajor, unsigned short* pdwMinor)
  3478. {
  3479.     HRESULT hr = E_FAIL;
  3480.     if (punkObj != NULL)
  3481.     {
  3482.         CComPtr<IDispatch> spDispatch;
  3483.         hr = punkObj->QueryInterface(IID_IDispatch, (void**)&spDispatch);
  3484.         if (SUCCEEDED(hr))
  3485.         {
  3486.             CComPtr<ITypeInfo> spTypeInfo;
  3487.             hr = spDispatch->GetTypeInfo(0, 0, &spTypeInfo);
  3488.             if (SUCCEEDED(hr))
  3489.             {
  3490.                 CComPtr<ITypeLib> spTypeLib;
  3491.                 hr = spTypeInfo->GetContainingTypeLib(&spTypeLib, 0);
  3492.                 if (SUCCEEDED(hr))
  3493.                 {
  3494.                     TLIBATTR* plibAttr;
  3495.                     hr = spTypeLib->GetLibAttr(&plibAttr);
  3496.                     if (SUCCEEDED(hr))
  3497.                     {
  3498.                         memcpy(plibid, &plibAttr->guid, sizeof(GUID));
  3499.                         *pdwMajor = plibAttr->wMajorVerNum;
  3500.                         *pdwMinor = plibAttr->wMinorVerNum;
  3501.                         spTypeLib->ReleaseTLibAttr(plibAttr);
  3502.                         // First see if the object is willing to tell us about the
  3503.                         // default source interface via IProvideClassInfo2
  3504.                         CComPtr<IProvideClassInfo2> spInfo;
  3505.                         hr = punkObj->QueryInterface(IID_IProvideClassInfo2, (void**)&spInfo);
  3506.                         if (SUCCEEDED(hr) && spInfo != NULL)
  3507.                             hr = spInfo->GetGUID(GUIDKIND_DEFAULT_SOURCE_DISP_IID, piid);
  3508.                         else
  3509.                         {
  3510.                             // No, we have to go hunt for it
  3511.                             CComPtr<ITypeInfo> spInfoCoClass;
  3512.                             // If we have a clsid, use that
  3513.                             // Otherwise, try to locate the clsid from IPersist
  3514.                             CComPtr<IPersist> spPersist;
  3515.                             CLSID clsid;
  3516.                             hr = punkObj->QueryInterface(IID_IPersist, (void**)&spPersist);
  3517.                             if (SUCCEEDED(hr))
  3518.                             {
  3519.                                 hr = spPersist->GetClassID(&clsid);
  3520.                                 if (SUCCEEDED(hr))
  3521.                                 {
  3522.                                     hr = spTypeLib->GetTypeInfoOfGuid(clsid, &spInfoCoClass);
  3523.                                     if (SUCCEEDED(hr))
  3524.                                     {
  3525.                                         TYPEATTR* pAttr=NULL;
  3526.                                         spInfoCoClass->GetTypeAttr(&pAttr);
  3527.                                         if (pAttr != NULL)
  3528.                                         {
  3529.                                             HREFTYPE hRef;
  3530.                                             for (int i = 0; i < pAttr->cImplTypes; i++)
  3531.                                             {
  3532.                                                 int nType;
  3533.                                                 hr = spInfoCoClass->GetImplTypeFlags(i, &nType);
  3534.                                                 if (SUCCEEDED(hr))
  3535.                                                 {
  3536.                                                     if (nType == (IMPLTYPEFLAG_FDEFAULT | IMPLTYPEFLAG_FSOURCE))
  3537.                                                     {
  3538.                                                         // we found it
  3539.                                                         hr = spInfoCoClass->GetRefTypeOfImplType(i, &hRef);
  3540.                                                         if (SUCCEEDED(hr))
  3541.                                                         {
  3542.                                                             CComPtr<ITypeInfo> spInfo;
  3543.                                                             hr = spInfoCoClass->GetRefTypeInfo(hRef, &spInfo);
  3544.                                                             if (SUCCEEDED(hr))
  3545.                                                             {
  3546.                                                                 TYPEATTR* pAttrIF;
  3547.                                                                 spInfo->GetTypeAttr(&pAttrIF);
  3548.                                                                 if (pAttrIF != NULL)
  3549.                                                                 {
  3550.                                                                     memcpy(piid, &pAttrIF->guid, sizeof(GUID));
  3551.                                                                 }
  3552.                                                                 spInfo->ReleaseTypeAttr(pAttrIF);
  3553.                                                             }
  3554.                                                         }
  3555.                                                         break;
  3556.                                                     }
  3557.                                                 }
  3558.                                             }
  3559.                                             spInfoCoClass->ReleaseTypeAttr(pAttr);
  3560.                                         }
  3561.                                     }
  3562.                                 }
  3563.                             }
  3564.                         }
  3565.                     }
  3566.                 }
  3567.             }
  3568.         }
  3569.     }
  3570.     return hr;
  3571. }
  3572. #endif // _WIN32_WCE
  3573. #endif // _ATL_DLL
  3574.  
  3575.  
  3576. #if defined(_M_ALPHA)
  3577.     #pragma message("ALPHA code for CComStdCallThunk needs to be verified!")
  3578.     #pragma pack(push,4)
  3579.     template <class T>
  3580.     class CComStdCallThunk
  3581.     {
  3582.     public:
  3583.         typedef void (__stdcall T::*TMFP)();
  3584.  
  3585.         void* pVtable;
  3586.         void* pFunc;
  3587.         DWORD ldah_at;      //  ldah    at, HIWORD(func)
  3588.         DWORD ldah_a0;      //  ldah    a0, HIWORD(this)
  3589.         DWORD lda_at;       //  lda     at, LOWORD(func)(at)
  3590.         DWORD lda_a0;       //  lda     a0, LOWORD(this)(a0)
  3591.         DWORD jmp;          //  jmp     zero,(at),0
  3592.         void Init(TMFP dw, void* pThis)
  3593.         {
  3594.             union {
  3595.                 DWORD dwFunc;
  3596.                 TMFP pfn;
  3597.             } pfn;
  3598.             pfn.pfn = dw;
  3599.             pVtable = &pFunc;
  3600.             pFunc = &m_mov;
  3601.             thunk.ldah_at = (0x279f0000 | HIWORD(pFunc)) + (LOWORD(pFunc)>>15);
  3602.             thunk.ldah_a0 = (0x261f0000 | HIWORD(pThis)) + (LOWORD(pThis)>>15);
  3603.             thunk.lda_at = 0x239c0000 | LOWORD(pFunc);
  3604.             thunk.lda_a0 = 0x22100000 | LOWORD(pThis);
  3605.             thunk.jmp = 0x6bfc0000;
  3606.             FlushInstructionCache(GetCurrentProcess(), this, sizeof(CComStdCallThunk));
  3607.         }
  3608.     };
  3609.     #pragma pack(pop)
  3610. #elif defined (_M_IX86)
  3611.     #pragma pack(push,1)
  3612.     template <class T>
  3613.     class CComStdCallThunk
  3614.     {
  3615.     public:
  3616.         typedef void (__stdcall T::*TMFP)();
  3617.  
  3618.         void* pVtable;
  3619.         void* pFunc;
  3620.         DWORD    m_mov;          // mov dword ptr [esp+4], pThis
  3621.         DWORD   m_this;         //
  3622.         BYTE    m_jmp;          // jmp func
  3623.         DWORD   m_relproc;      // relative jmp
  3624.         void Init(TMFP dw, void* pThis)
  3625.         {
  3626.             union {
  3627.                 DWORD dwFunc;
  3628.                 TMFP pfn;
  3629.             } pfn;
  3630.             pfn.pfn = dw;
  3631.             pVtable = &pFunc;
  3632.             pFunc = &m_mov;
  3633.             m_mov = 0x042444C7;
  3634.             m_this = (DWORD)pThis;
  3635.             m_jmp = 0xE9;
  3636.             m_relproc = (int)pfn.dwFunc - ((int)this+sizeof(CComStdCallThunk));
  3637.             FlushInstructionCache(GetCurrentProcess(), this, sizeof(CComStdCallThunk));
  3638.         }
  3639.     };
  3640.     #pragma pack(pop)
  3641. #endif
  3642.  
  3643. #ifndef _ATL_MAX_VARTYPES
  3644. #define _ATL_MAX_VARTYPES 8
  3645. #endif
  3646.  
  3647. struct _ATL_FUNC_INFO
  3648. {
  3649.     CALLCONV cc;
  3650.     VARTYPE vtReturn;
  3651.     SHORT nParams;
  3652.     VARTYPE pVarTypes[_ATL_MAX_VARTYPES];
  3653. };
  3654.  
  3655. class ATL_NO_VTABLE _IDispEvent
  3656. {
  3657. public:
  3658.     _IDispEvent() {m_dwEventCookie = 0xFEFEFEFE;}
  3659.     //this method needs a different name than QueryInterface
  3660.     STDMETHOD(_LocDEQueryInterface)(REFIID riid, void ** ppvObject) = 0;
  3661.     virtual ULONG STDMETHODCALLTYPE AddRef(void) = 0;
  3662.     virtual ULONG STDMETHODCALLTYPE Release(void) = 0;
  3663.     GUID m_libid; // used for dynamic case
  3664.     IID m_iid; // used for dynamic case
  3665.     unsigned short m_wMajorVerNum;    // Major version number. used for dynamic case
  3666.     unsigned short m_wMinorVerNum;    // Minor version number. used for dynamic case
  3667.     DWORD m_dwEventCookie;
  3668.     HRESULT DispEventAdvise(IUnknown* pUnk, const IID* piid)
  3669.     {
  3670.         ATLASSERT(m_dwEventCookie == 0xFEFEFEFE);
  3671.         return AtlAdvise(pUnk, (IUnknown*)this, *piid, &m_dwEventCookie);
  3672.     }
  3673.     HRESULT DispEventUnadvise(IUnknown* pUnk, const IID* piid)
  3674.     {
  3675.         HRESULT hr = AtlUnadvise(pUnk, *piid, m_dwEventCookie);
  3676.         m_dwEventCookie = 0xFEFEFEFE;
  3677.         return hr;
  3678.     }
  3679. };
  3680.  
  3681. template <UINT nID, const IID* piid>
  3682. class ATL_NO_VTABLE _IDispEventLocator : public _IDispEvent
  3683. {
  3684. public:
  3685. };
  3686.  
  3687. template <UINT nID, class T, const IID* pdiid>
  3688. class ATL_NO_VTABLE IDispEventSimpleImpl : public _IDispEventLocator<nID, pdiid>
  3689. {
  3690. public:
  3691.     STDMETHOD(_LocDEQueryInterface)(REFIID riid, void ** ppvObject)
  3692.     {
  3693.         if (InlineIsEqualGUID(riid, *pdiid) || 
  3694.             InlineIsEqualUnknown(riid) ||
  3695.             InlineIsEqualGUID(riid, IID_IDispatch) ||
  3696.             InlineIsEqualGUID(riid, m_iid))
  3697.         {
  3698.             if (ppvObject == NULL)
  3699.                 return E_POINTER;
  3700.             *ppvObject = this;
  3701.             AddRef();
  3702. #ifdef _ATL_DEBUG_INTERFACES
  3703.             _Module.AddThunk((IUnknown**)ppvObject, _T("IDispEventImpl"), riid);
  3704. #endif // _ATL_DEBUG_INTERFACES
  3705.             return S_OK;
  3706.         }
  3707.         else
  3708.             return E_NOINTERFACE;
  3709.     }
  3710.  
  3711.     // These are here only to support use in non-COM objects    
  3712.     virtual ULONG STDMETHODCALLTYPE AddRef()
  3713.     {
  3714.         return 1;
  3715.     }
  3716.     virtual ULONG STDMETHODCALLTYPE Release()
  3717.     {
  3718.         return 1;
  3719.     }
  3720.  
  3721.     STDMETHOD(GetTypeInfoCount)(UINT* pctinfo)
  3722.     {return E_NOTIMPL;}
  3723.  
  3724.     STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
  3725.     {return E_NOTIMPL;}
  3726.  
  3727.     STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR* rgszNames, UINT cNames,
  3728.         LCID lcid, DISPID* rgdispid)
  3729.     {return E_NOTIMPL;}
  3730.  
  3731. #if defined(_WIN32_WCE)
  3732.     UINT GetStackSize(UINT nParams, VARIANTARG** pVarArgs, VARTYPE vtResult)
  3733.     {
  3734.         // sizeof 'this' pointer
  3735.         UINT nCount = sizeof(T*);
  3736. #ifdef _ALIGN_STACK
  3737.         nCount = (nCount + (_ALIGN_STACK-1)) & ~(_ALIGN_STACK-1);
  3738. #endif
  3739.         // count bytes in return value
  3740.         nCount += _afxRetVal[vtResult];
  3741. #ifdef _ALIGN_STACK
  3742.         nCount = (nCount + (_ALIGN_STACK-1)) & ~(_ALIGN_STACK-1);
  3743. #endif
  3744.  
  3745.         // count arguments
  3746.         for(int i = 0; i < (int)nParams; i++)
  3747.         {
  3748.             if(pVarArgs[i]->vt != VT_MFCMARKER)
  3749.             {
  3750.                 // align if necessary
  3751.                 // get and add appropriate byte count
  3752.                 const UINT* rgnBytes;
  3753.                 if(pVarArgs[i]->vt & VT_BYREF )
  3754.                     rgnBytes = _afxByRef;
  3755.                 else
  3756.                     rgnBytes = _afxByValue;
  3757. #ifdef _ALIGN_DOUBLES
  3758.                 // align doubles on 8 byte for some platforms
  3759.                 if (pVarArgs[i]->vt == VT_R8)
  3760.                     nCount = (nCount + _ALIGN_DOUBLES-1) & ~(_ALIGN_DOUBLES-1);
  3761. #endif
  3762.                 nCount += rgnBytes[pVarArgs[i]->vt & ~VT_BYREF];
  3763. #ifdef _ALIGN_STACK
  3764.                 nCount = (nCount + (_ALIGN_STACK-1)) & ~(_ALIGN_STACK-1);
  3765. #endif
  3766.             }
  3767.         }
  3768. #if defined(_ALIGN_DOUBLES) && defined(_SHADOW_DOUBLES)
  3769.         // align doubles on 8 byte for some platforms
  3770.         nCount = (nCount + _ALIGN_DOUBLES-1) & ~(_ALIGN_DOUBLES-1);
  3771. #endif
  3772.         return nCount;
  3773.     }
  3774.  
  3775. // push arguments on stack appropriate for C++ call (compiler dependent)
  3776. #ifndef _SHADOW_DOUBLES
  3777.     SCODE PushStackArgs(BYTE* pStack, VARIANTARG** pVarArgs /*const BYTE* pbParams*/,
  3778.         void* pResult, VARTYPE vtResult, DISPPARAMS* pDispParams, UINT* puArgErr,
  3779.         VARIANT* rgTempVars)
  3780. #else
  3781.     SCODE PushStackArgs(BYTE* pStack, VARIANTARG** pVarArgs/*const BYTE* pbParams*/,
  3782.         void* pResult, VARTYPE vtResult, DISPPARAMS* pDispParams, UINT* puArgErr,
  3783.         VARIANT* rgTempVars, UINT nSizeArgs)
  3784. #endif
  3785.     {
  3786.         ATLASSERT(pStack != NULL);
  3787.         ATLASSERT(pResult != NULL);
  3788.         ATLASSERT(pDispParams != NULL);
  3789.         ATLASSERT(puArgErr != NULL);
  3790.  
  3791. #ifdef _SHADOW_DOUBLES
  3792.         double* pDoubleShadow = (double*)(pStack + nSizeArgs);
  3793.         double* pDoubleShadowMax = pDoubleShadow + _SHADOW_DOUBLES;
  3794. #endif
  3795.  
  3796.         // C++ member functions use the __thiscall convention, where parameters
  3797.         //  are pushed last to first.  Assuming the stack grows down, this means
  3798.         //  that the first parameter is at the lowest memory address in the
  3799.         //  stack frame and the last parameter is at the highest address.
  3800.  
  3801. #ifdef _RETVAL_FIRST
  3802.         // push any necessary return value stuff on the stack (pre args)
  3803.         //  (an ambient pointer is pushed to stack relative data)
  3804.         if (vtResult == VT_CY || vtResult == VT_VARIANT)
  3805.         {
  3806. #ifdef _ALIGN_STACK
  3807.             ASSERT(((DWORD)pStack & (_ALIGN_STACK-1)) == 0);
  3808. #endif
  3809.             *(_STACK_PTR*)pStack = (_STACK_PTR)pResult;
  3810.             pStack += sizeof(_STACK_PTR);
  3811. #ifdef _ALIGN_STACK
  3812.             ASSERT(((DWORD)pStack & (_ALIGN_STACK-1)) == 0);
  3813. #endif
  3814.         }
  3815. #endif //_RETVAL_FIRST
  3816.  
  3817.         // push the 'this' pointer
  3818. #ifdef _ALIGN_STACK
  3819.         ASSERT(((DWORD)pStack & (_ALIGN_STACK-1)) == 0);
  3820. #endif
  3821.         *(_STACK_PTR*)pStack = (_STACK_PTR)(T*)this;
  3822.         pStack += sizeof(_STACK_PTR);
  3823. #ifdef _ALIGN_STACK
  3824.         ASSERT(((DWORD)pStack & (_ALIGN_STACK-1)) == 0);
  3825. #endif
  3826.  
  3827. #ifndef _RETVAL_FIRST
  3828.         // push any necessary return value stuff on the stack (post args)
  3829.         //  (an ambient pointer is pushed to stack relative data)
  3830.         if (vtResult == VT_CY || vtResult == VT_VARIANT)
  3831.         {
  3832. #ifdef _ALIGN_STACK
  3833.             ASSERT(((DWORD)pStack & (_ALIGN_STACK-1)) == 0);
  3834. #endif
  3835.             *(_STACK_PTR*)pStack = (_STACK_PTR)pResult;
  3836.             pStack += sizeof(_STACK_PTR);
  3837. #ifdef _ALIGN_STACK
  3838.             ASSERT(((DWORD)pStack & (_ALIGN_STACK-1)) == 0);
  3839. #endif
  3840.         }
  3841. #endif //!_RETVAL_FIRST
  3842.  
  3843.     // push the arguments (first to last, low address to high address)
  3844.         VARIANT* pArgs = pDispParams->rgvarg;
  3845.         BOOL bNamedArgs = FALSE;
  3846.         int iArg = pDispParams->cArgs; // start with positional arguments
  3847.         int iArgMin = pDispParams->cNamedArgs;
  3848.  
  3849.         UINT i;
  3850.         for( i = 0; i < pDispParams->cArgs; i++)
  3851.         {
  3852.             --iArg; // move to next arg
  3853.  
  3854.             // convert MFC parameter type to IDispatch VARTYPE
  3855.             VARTYPE vt = pVarArgs[i]->vt;
  3856.             VARIANT* pArg;
  3857.             if (iArg >= iArgMin)
  3858.             {
  3859.                 // hit named args before using all positional args?
  3860.                 if (vt == VT_MFCMARKER)
  3861.                     break;
  3862.  
  3863.                 // argument specified by caller -- use it
  3864.                 pArg = &pArgs[iArg];
  3865.                 if (vt != VT_VARIANT && vt != pArg->vt)
  3866.                 {
  3867.                     // argument is not of appropriate type, attempt to coerce it
  3868.                     VARIANT* pArgTemp = &rgTempVars[iArg];
  3869.                     ATLASSERT(pArgTemp->vt == VT_EMPTY);
  3870.                     VARTYPE vtTarget = vt;
  3871.                     if (pArg->vt != vtTarget)
  3872.                     {
  3873.                         SCODE sc = VariantChangeType(pArgTemp, pArg, 0, vtTarget);
  3874.                         if (FAILED(sc))
  3875.                         {
  3876.                             ATLTRACE(_T("Warning: automation argument coercion failed.\n"));
  3877.                             *puArgErr = iArg;
  3878.                             return sc;
  3879.                         }
  3880.                         ATLASSERT(pArgTemp->vt == vtTarget);
  3881.                     }
  3882.                     pArg = pArgTemp;
  3883.                 }
  3884.             }
  3885.             else
  3886.             {
  3887.                 if (vt == VT_MFCMARKER)
  3888.                 {
  3889.                     // start processing named arguments
  3890.                     iArg = pDispParams->cNamedArgs;
  3891.                     iArgMin = 0;
  3892.                     bNamedArgs = TRUE;
  3893.                     continue;
  3894.                 }
  3895.  
  3896.                 if (bNamedArgs || vt != VT_VARIANT)
  3897.                     break;  // function not expecting optional argument
  3898.  
  3899.                 // argument not specified by caller -- provide default variant
  3900.                 static VARIANT vaDefault;   // Note: really is 'const'
  3901.                 vaDefault.vt = VT_ERROR;
  3902.                 vaDefault.scode = DISP_E_PARAMNOTFOUND;
  3903.                 pArg = &vaDefault;
  3904.             }
  3905.  
  3906.             // push parameter value on the stack
  3907.             switch (vt)
  3908.             {
  3909.             // by value parameters
  3910.             case VT_UI1:
  3911.                 *(_STACK_INT*)pStack = pArg->bVal; // 'BYTE' is passed as 'int'
  3912.                 pStack += sizeof(_STACK_INT);
  3913.                 break;
  3914.             case VT_I2:
  3915.                 *(_STACK_INT*)pStack = pArg->iVal;
  3916.                 pStack += sizeof(_STACK_INT);   // 'short' is passed as 'int'
  3917.                 break;
  3918.             case VT_I4:
  3919.             case VT_INT:
  3920.                 *(_STACK_LONG*)pStack = pArg->lVal;
  3921.                 pStack += sizeof(_STACK_LONG);
  3922.                 break;
  3923.             case VT_R4:
  3924.                 *(_STACK_FLOAT*)pStack = (_STACK_FLOAT)pArg->fltVal;
  3925.                 pStack += sizeof(_STACK_FLOAT);
  3926. #ifdef _SHADOW_DOUBLES
  3927.             if (pDoubleShadow < pDoubleShadowMax)
  3928.                 *pDoubleShadow++ = (double)pArg->fltVal;
  3929. #endif
  3930.             break;
  3931.             case VT_R8:
  3932. #ifdef _ALIGN_DOUBLES
  3933.                 // align doubles on 8 byte for some platforms
  3934.                 pStack = (BYTE*)(((DWORD)pStack + _ALIGN_DOUBLES-1) &
  3935.                     ~(_ALIGN_DOUBLES-1));
  3936. #endif
  3937.                 *(_STACK_DOUBLE*)pStack = (_STACK_DOUBLE)pArg->dblVal;
  3938.                 pStack += sizeof(_STACK_DOUBLE);
  3939. #ifdef _SHADOW_DOUBLES
  3940.                 if (pDoubleShadow < pDoubleShadowMax)
  3941.                     *pDoubleShadow++ = pArg->dblVal;
  3942. #endif
  3943.             break;
  3944.             case VT_DATE:
  3945. #ifdef _ALIGN_DOUBLES
  3946.                 // align doubles on 8 byte for some platforms
  3947.                 pStack = (BYTE*)(((DWORD)pStack + _ALIGN_DOUBLES-1) &
  3948.                     ~(_ALIGN_DOUBLES-1));
  3949. #endif
  3950.                 *(_STACK_DOUBLE*)pStack = (_STACK_DOUBLE)pArg->date;
  3951.                 pStack += sizeof(_STACK_DOUBLE);
  3952. #ifdef _SHADOW_DOUBLES
  3953.                 if (pDoubleShadow < pDoubleShadowMax)
  3954.                     *pDoubleShadow++ = pArg->date;
  3955. #endif
  3956.                 break;
  3957.             case VT_CY:
  3958.                 *(CY*)pStack = pArg->cyVal;
  3959.                 pStack += sizeof(CY);
  3960.                 break;
  3961.             case VT_BSTR:
  3962.                 *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->bstrVal;
  3963.                 pStack += sizeof(_STACK_PTR);
  3964.                 break;
  3965.             case VT_ERROR:
  3966.                 *(_STACK_LONG*)pStack = (_STACK_LONG)pArg->scode;
  3967.                 pStack += sizeof(_STACK_LONG);
  3968.                 break;
  3969.             case VT_BOOL:
  3970.                 *(_STACK_LONG*)pStack = (_STACK_LONG)(V_BOOL(pArg) != 0);
  3971.                 pStack += sizeof(_STACK_LONG);
  3972.                 break;
  3973.             case VT_VARIANT:
  3974.                 *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pvarVal;
  3975.                 pStack += sizeof(_STACK_PTR);
  3976.                 break;
  3977.             case VT_DISPATCH:
  3978.             case VT_UNKNOWN:
  3979.                 *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->punkVal;
  3980.                 pStack += sizeof(_STACK_PTR);
  3981.                 break;
  3982.  
  3983.             // by reference parameters
  3984.             case VT_UI2|VT_BYREF:
  3985.                 *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pbVal;
  3986.                 pStack += sizeof(_STACK_PTR);
  3987.                 break;
  3988.             case VT_I2|VT_BYREF:
  3989.                 *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->piVal;
  3990.                 pStack += sizeof(_STACK_PTR);
  3991.                 break;
  3992.             case VT_I4|VT_BYREF:
  3993.             case VT_INT|VT_BYREF:
  3994.                 *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->plVal;
  3995.                 pStack += sizeof(_STACK_PTR);
  3996.                 break;
  3997.             case VT_R4|VT_BYREF:
  3998.                 *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pfltVal;
  3999.                 pStack += sizeof(_STACK_PTR);
  4000.                 break;
  4001.             case VT_R8|VT_BYREF:
  4002.                 *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pdblVal;
  4003.                 pStack += sizeof(_STACK_PTR);
  4004.                 break;
  4005.             case VT_DATE|VT_BYREF:
  4006.                 *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pdate;
  4007.                 pStack += sizeof(_STACK_PTR);
  4008.                 break;
  4009.             case VT_CY|VT_BYREF:
  4010.                 *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pcyVal;
  4011.                 pStack += sizeof(_STACK_PTR);
  4012.                 break;
  4013.             case VT_BSTR|VT_BYREF:
  4014.                 *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pbstrVal;
  4015.                 pStack += sizeof(_STACK_PTR);
  4016.                 break;
  4017.             case VT_ERROR|VT_BYREF:
  4018.                 *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pscode;
  4019.                 pStack += sizeof(_STACK_PTR);
  4020.                 break;
  4021.             case VT_BOOL|VT_BYREF:
  4022.                 *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pboolVal;
  4023.                 pStack += sizeof(_STACK_PTR);
  4024.                 break;
  4025.             case VT_VARIANT|VT_BYREF:
  4026.                 *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->pvarVal;
  4027.                 pStack += sizeof(_STACK_PTR);
  4028.                 break;
  4029.             case VT_DISPATCH|VT_BYREF:
  4030.             case VT_UNKNOWN|VT_BYREF:
  4031.                 *(_STACK_PTR*)pStack = (_STACK_PTR)pArg->ppunkVal;
  4032.                 pStack += sizeof(_STACK_PTR);
  4033.                 break;
  4034.  
  4035.             default:
  4036.                 ATLASSERT(FALSE);
  4037.             }
  4038.  
  4039. #ifdef _ALIGN_STACK
  4040.             // align stack as appropriate for next parameter
  4041.             pStack = (BYTE*)(((DWORD)pStack + (_ALIGN_STACK-1)) &
  4042.                 ~(_ALIGN_STACK-1));
  4043.             ASSERT(((DWORD)pStack & (_ALIGN_STACK-1)) == 0);
  4044. #endif
  4045.         }
  4046.  
  4047.         // check that all source arguments were consumed
  4048.         if (iArg > 0)
  4049.         {
  4050.             *puArgErr = iArg;
  4051.             return DISP_E_BADPARAMCOUNT;
  4052.         }
  4053.     // check that all target arguments were filled
  4054.         if(i < pDispParams->cArgs)
  4055.         {
  4056.             *puArgErr = pDispParams->cArgs;
  4057.             return DISP_E_PARAMNOTOPTIONAL;
  4058.         }
  4059.         return S_OK;    // success!
  4060.     }
  4061.  
  4062.     //typedef void (__stdcall T::*AFX_PMSG)(void);
  4063.  
  4064. #endif // _WIN32_WCE
  4065.  
  4066.  
  4067.     STDMETHOD(Invoke)(DISPID dispidMember, REFIID riid,
  4068.         LCID lcid, WORD /*wFlags*/, DISPPARAMS* pdispparams, VARIANT* pvarResult,
  4069.         EXCEPINFO* /*pexcepinfo*/, UINT* /*puArgErr*/)
  4070.     {
  4071.         T* pT = static_cast<T*>(this);
  4072.         const _ATL_EVENT_ENTRY<T>* pMap = T::_GetSinkMap();
  4073.         const _ATL_EVENT_ENTRY<T>* pFound = NULL;
  4074.         void (__stdcall T::*pEvent)() = NULL;
  4075.         while (pMap->piid != NULL)
  4076.         {
  4077.             if ((pMap->nControlID == nID) && (pMap->dispid == dispidMember) && 
  4078.                 (pMap->piid == pdiid)) //comparing pointers here should be adequate
  4079.             {
  4080.                 pFound = pMap;
  4081.                 break;
  4082.             }
  4083.             pMap++;
  4084.         }
  4085.         if (pFound == NULL)
  4086.             return S_OK;
  4087.         
  4088.  
  4089.         _ATL_FUNC_INFO info;
  4090.         _ATL_FUNC_INFO* pInfo;
  4091.         if (pFound->pInfo != NULL)
  4092.             pInfo = pFound->pInfo;
  4093.         else
  4094.         {
  4095.             pInfo = &info;
  4096.             HRESULT hr = GetFuncInfoFromId(*pdiid, dispidMember, lcid, info);
  4097.             if (FAILED(hr))
  4098.                 return S_OK;
  4099.         }
  4100. #if defined(_WIN32_WCE)
  4101.         // special union used only to hold largest return value possible
  4102.         union AFX_RESULT
  4103.         {
  4104.             VARIANT vaVal;
  4105.             CY cyVal;
  4106.             float fltVal;
  4107.             double dblVal;
  4108.             DWORD nVal;
  4109.         };
  4110.  
  4111.         VARIANTARG** pVarArgs = info.nParams ? (VARIANTARG**)alloca(sizeof(VARIANTARG*)*info.nParams) : 0;
  4112.         for (int i=0; i<info.nParams; i++)
  4113.             pVarArgs[i] = &pdispparams->rgvarg[info.nParams - i - 1];
  4114.  
  4115.         CComVariant tmpResult;
  4116.         if (pvarResult == NULL)
  4117.             pvarResult = &tmpResult;
  4118.  
  4119.         // get default function and parameters
  4120.         UINT iArg, nParams = info.nParams;
  4121.  
  4122.         // get default function and return value information
  4123.         DWORD* pfn1 = (DWORD*)(&(pFound->pfn));
  4124.         DWORD pfn = *pfn1;
  4125.     
  4126.         VARTYPE vtResult = info.vtReturn;
  4127.  
  4128.         // allocate temporary space for VARIANT temps created by VariantChangeType
  4129.         VARIANT* rgTempVars =
  4130.             (VARIANT*)_alloca(pdispparams->cArgs * sizeof(VARIANT));
  4131.         if (rgTempVars == NULL)
  4132.         {
  4133.             ATLTRACE(_T("Error: stack overflow in IDispatch::Invoke!\n"));
  4134.             return E_OUTOFMEMORY;
  4135.         }
  4136.         memset(rgTempVars, 0, pdispparams->cArgs * sizeof(VARIANT));
  4137.  
  4138.         // determine size of arguments and allocate stack space
  4139.         UINT nSizeArgs = GetStackSize(nParams, pVarArgs, vtResult);
  4140.         ATLASSERT(nSizeArgs != 0);
  4141.         if (nSizeArgs < _STACK_MIN)
  4142.             nSizeArgs = _STACK_MIN;
  4143.         BYTE* pStack = (BYTE*)_alloca(nSizeArgs + _SCRATCH_SIZE);
  4144.         if (pStack == NULL)
  4145.         {
  4146.             ATLTRACE(_T("Error: stack overflow in IDispatch::Invoke!\n"));
  4147.             return E_OUTOFMEMORY;
  4148.         }
  4149.  
  4150.         // push all the args on to the stack allocated memory
  4151.         AFX_RESULT result;
  4152.         UINT uArgErr;
  4153. #ifndef _SHADOW_DOUBLES
  4154.         SCODE sc = PushStackArgs(pStack, pVarArgs, &result, vtResult, pdispparams, &uArgErr, rgTempVars);
  4155. #else
  4156.         SCODE sc = PushStackArgs(pStack, pVarArgs, &result, vtResult, pdispparams, &uArgErr, rgTempVars, nSizeArgs);
  4157. #endif
  4158.         pStack += _STACK_OFFSET;
  4159.  
  4160.         DWORD dwResult = 0;
  4161.         if (sc == S_OK)
  4162.         {
  4163.             // PushStackArgs will fail on argument mismatches
  4164.             DWORD (__stdcall *pfnDispatch)(DWORD, void*, UINT) = &_AtlCEDispatchCall;
  4165.  
  4166.             // floating point return values are a special case
  4167.             if(pfnDispatch)
  4168.                 switch (vtResult)
  4169.                 {
  4170.                     case VT_R4:
  4171.                         result.fltVal = ((float (*)(DWORD, void*, UINT))
  4172.                             pfnDispatch)(pfn, pStack, nSizeArgs);
  4173.                         break;
  4174.                     case VT_R8:
  4175.                         result.dblVal = ((double (*)(DWORD, void*, UINT))
  4176.                             pfnDispatch)(pfn, pStack, nSizeArgs);
  4177.                         break;
  4178.                     case VT_DATE:
  4179.                         result.dblVal = ((DATE (*)(DWORD, void*, UINT))
  4180.                             pfnDispatch)(pfn, pStack, nSizeArgs);
  4181.                         break;
  4182.                     default:
  4183.                         dwResult = (unsigned long)pfnDispatch((DWORD)pfn, pStack, nSizeArgs);
  4184.                         break;
  4185.                 }
  4186.         }
  4187.  
  4188.         // free temporaries created by VariantChangeType
  4189.         for (iArg = 0; iArg < (UINT)pdispparams->cArgs; ++iArg)
  4190.             VariantClear(&rgTempVars[iArg]);
  4191.  
  4192.         // handle error during PushStackParams
  4193.         if (sc != S_OK)
  4194.             return sc;
  4195.  
  4196.         // property puts don't touch the return value
  4197.         if (pvarResult != NULL)
  4198.         {
  4199.             // clear pvarResult just in case
  4200.             pvarResult->vt = vtResult;
  4201.  
  4202.             // build return value VARIANT from result union
  4203.             switch (vtResult)
  4204.             {
  4205.             case VT_UI2:
  4206.                 pvarResult->bVal = (BYTE)dwResult;
  4207.                 break;
  4208.             case VT_I2:
  4209.                 pvarResult->iVal = (short)dwResult;
  4210.                 break;
  4211.             case VT_I4:
  4212.                 pvarResult->lVal = (long)dwResult;
  4213.                 break;
  4214.             case VT_R4:
  4215.                 pvarResult->fltVal = result.fltVal;
  4216.                 break;
  4217.             case VT_R8:
  4218.                 pvarResult->dblVal = result.dblVal;
  4219.                 break;
  4220.             case VT_CY:
  4221.                 pvarResult->cyVal = result.cyVal;
  4222.                 break;
  4223.             case VT_DATE:
  4224.                 pvarResult->date = result.dblVal;
  4225.                 break;
  4226.             case VT_BSTR:
  4227.                 pvarResult->bstrVal = (BSTR)dwResult;
  4228.                 break;
  4229.             case VT_ERROR:
  4230.                 pvarResult->scode = (SCODE)dwResult;
  4231.                 break;
  4232.             case VT_BOOL:
  4233.                 V_BOOL(pvarResult) = (VARIANT_BOOL)((BOOL)dwResult != 0 ? -1 : 0);
  4234.                 break;
  4235.             case VT_VARIANT:
  4236.                 *pvarResult = result.vaVal;
  4237.                 break;
  4238.             case VT_DISPATCH:
  4239.             case VT_UNKNOWN:
  4240.                 pvarResult->punkVal = (LPUNKNOWN)dwResult; // already AddRef
  4241.                 break;
  4242.             }
  4243.         }
  4244.         else
  4245.         {
  4246.             // free unused return value
  4247.             switch (vtResult)
  4248.             {
  4249.             case VT_BSTR:
  4250.                 if ((BSTR)dwResult != NULL)
  4251.                     SysFreeString((BSTR)dwResult);
  4252.                 break;
  4253.             case VT_DISPATCH:
  4254.             case VT_UNKNOWN:
  4255.                 if ((LPUNKNOWN)dwResult != 0)
  4256.                     ((LPUNKNOWN)dwResult)->Release();
  4257.                 break;
  4258.             case VT_VARIANT:
  4259.                 VariantClear(&result.vaVal);
  4260.                 break;
  4261.             }
  4262.         }
  4263. #else
  4264.         InvokeFromFuncInfo(pFound->pfn, *pInfo, pdispparams, pvarResult);
  4265. #endif    // _WIN32_WCE
  4266.         return S_OK;
  4267.     }
  4268.  
  4269. #if !defined(_WIN32_WCE)
  4270.     //Helper for invoking the event
  4271.     HRESULT InvokeFromFuncInfo(void (__stdcall T::*pEvent)(), _ATL_FUNC_INFO& info, DISPPARAMS* pdispparams, VARIANT* pvarResult)
  4272.     {
  4273.         T* pT = static_cast<T*>(this);
  4274.         VARIANTARG** pVarArgs = info.nParams ? (VARIANTARG**)alloca(sizeof(VARIANTARG*)*info.nParams) : 0;
  4275.         for (int i=0; i<info.nParams; i++)
  4276.             pVarArgs[i] = &pdispparams->rgvarg[info.nParams - i - 1];
  4277.  
  4278.         CComStdCallThunk<T> thunk;
  4279.         thunk.Init(pEvent, pT);
  4280.         CComVariant tmpResult;
  4281.         if (pvarResult == NULL)
  4282.             pvarResult = &tmpResult;
  4283.  
  4284.  
  4285.         HRESULT hr = DispCallFunc(
  4286.             &thunk,
  4287.             0,
  4288.             info.cc,
  4289.             info.vtReturn,
  4290.             info.nParams,
  4291.             info.pVarTypes,
  4292.             pVarArgs,
  4293.             pvarResult);
  4294.         ATLASSERT(SUCCEEDED(hr));
  4295.  
  4296.         return hr;
  4297.     }
  4298. #endif // _WIN32_WCE
  4299.  
  4300.     //Helper for finding the function index for a DISPID
  4301.     virtual HRESULT GetFuncInfoFromId(const IID& iid, DISPID dispidMember, LCID lcid, _ATL_FUNC_INFO& info)
  4302.     {
  4303.         return E_NOTIMPL;
  4304.     }
  4305.     //Helpers for sinking events on random IUnknown*
  4306.     HRESULT DispEventAdvise(IUnknown* pUnk, const IID* piid)
  4307.     {
  4308.         ATLASSERT(m_dwEventCookie == 0xFEFEFEFE);
  4309.         return AtlAdvise(pUnk, (IUnknown*)this, *piid, &m_dwEventCookie);
  4310.     }
  4311.     HRESULT DispEventUnadvise(IUnknown* pUnk, const IID* piid)
  4312.     {
  4313.         HRESULT hr = AtlUnadvise(pUnk, *piid, m_dwEventCookie);
  4314.         m_dwEventCookie = 0xFEFEFEFE;
  4315.         return hr;
  4316.     }
  4317.     HRESULT DispEventAdvise(IUnknown* pUnk)
  4318.     {
  4319.         return _IDispEvent::DispEventAdvise(pUnk, pdiid);
  4320.     }
  4321.     HRESULT DispEventUnadvise(IUnknown* pUnk)
  4322.     {
  4323.         return _IDispEvent::DispEventUnadvise(pUnk, pdiid);
  4324.     }
  4325. };
  4326.  
  4327. //Helper for advising connections points from a sink map
  4328. template <class T>
  4329. inline HRESULT AtlAdviseSinkMap(T* pT, bool bAdvise)
  4330. {
  4331.     ATLASSERT(::IsWindow(pT->m_hWnd));
  4332.     const _ATL_EVENT_ENTRY<T>* pEntries = T::_GetSinkMap();
  4333.     if (pEntries == NULL)
  4334.         return S_OK;
  4335.     HRESULT hr = S_OK;
  4336.     while (pEntries->piid != NULL)
  4337.     {
  4338.         _IDispEvent* pDE = (_IDispEvent*)((DWORD)pT+pEntries->nOffset);
  4339.         bool bNotAdvised = pDE->m_dwEventCookie == 0xFEFEFEFE;
  4340.         if (bAdvise ^ bNotAdvised)
  4341.         {
  4342.             pEntries++;
  4343.             continue;
  4344.         }
  4345.         hr = E_FAIL;
  4346.         HWND h = pT->GetDlgItem(pEntries->nControlID);
  4347.         ATLASSERT(h != NULL);
  4348.         if (h != NULL)
  4349.         {
  4350.             CComPtr<IUnknown> spUnk;
  4351.             AtlAxGetControl(h, &spUnk);
  4352.             ATLASSERT(spUnk != NULL);
  4353.             if (spUnk != NULL)
  4354.             {
  4355.                 if (bAdvise)
  4356.                 {
  4357.                     if (!InlineIsEqualGUID(IID_NULL, *pEntries->piid))
  4358.                         hr = pDE->DispEventAdvise(spUnk, pEntries->piid);
  4359.                     else
  4360.                     {
  4361.                         AtlGetObjectSourceInterface(spUnk, &pDE->m_libid, &pDE->m_iid, &pDE->m_wMajorVerNum, &pDE->m_wMinorVerNum);
  4362.                         hr = pDE->DispEventAdvise(spUnk, &pDE->m_iid);
  4363.                     }
  4364.                 }
  4365.                 else
  4366.                 {
  4367.                     if (!InlineIsEqualGUID(IID_NULL, *pEntries->piid))
  4368.                         hr = pDE->DispEventUnadvise(spUnk, pEntries->piid);
  4369.                     else
  4370.                         hr = pDE->DispEventUnadvise(spUnk, &pDE->m_iid);
  4371.                 }
  4372.                 ATLASSERT(hr == S_OK);
  4373.             }
  4374.         }
  4375.         if (FAILED(hr))
  4376.             break;
  4377.         pEntries++;
  4378.     }
  4379.     return hr;
  4380. }
  4381.  
  4382. template <UINT nID, class T, const IID* pdiid = &IID_NULL, const GUID* plibid = &GUID_NULL, 
  4383.     WORD wMajor = 0, WORD wMinor = 0, class tihclass = CComTypeInfoHolder>
  4384. class ATL_NO_VTABLE IDispEventImpl : public IDispEventSimpleImpl<nID, T, pdiid>
  4385. {
  4386. public:
  4387.     typedef tihclass _tihclass;
  4388.  
  4389.     IDispEventImpl()
  4390.     {
  4391.         m_libid = *plibid;
  4392.         m_iid = *pdiid;
  4393.         m_wMajorVerNum = wMajor;
  4394.         m_wMinorVerNum = wMinor;
  4395.     }
  4396.  
  4397.     STDMETHOD(GetTypeInfoCount)(UINT* pctinfo)
  4398.     {*pctinfo = 1; return S_OK;}
  4399.  
  4400.     STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
  4401.     {return _tih.GetTypeInfo(itinfo, lcid, pptinfo);}
  4402.  
  4403.     STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR* rgszNames, UINT cNames,
  4404.         LCID lcid, DISPID* rgdispid)
  4405.     {return _tih.GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);}
  4406.  
  4407.     //Helper for finding the function index for a DISPID
  4408.     HRESULT GetFuncInfoFromId(const IID& /*iid*/, DISPID dispidMember, LCID lcid, _ATL_FUNC_INFO& info)
  4409.     {
  4410.         CComPtr<ITypeInfo> spTypeInfo;
  4411.         if (InlineIsEqualGUID(*_tih.m_plibid, GUID_NULL))
  4412.         {
  4413.             _tih.m_plibid = &m_libid;
  4414.             _tih.m_pguid = &m_iid;
  4415.             _tih.m_wMajor = m_wMajorVerNum;
  4416.             _tih.m_wMinor = m_wMinorVerNum;
  4417.         }
  4418.         HRESULT hr = _tih.GetTI(lcid, &spTypeInfo);
  4419.         if (FAILED(hr))
  4420.             return hr;
  4421.         CComQIPtr<ITypeInfo2, &IID_ITypeInfo2> spTypeInfo2 = spTypeInfo;
  4422.         FUNCDESC* pFuncDesc = NULL;
  4423.         if (spTypeInfo2 != NULL)
  4424.         {
  4425.             UINT nIndex;
  4426.             hr = spTypeInfo2->GetFuncIndexOfMemId(dispidMember, INVOKE_FUNC, &nIndex);
  4427.             if (FAILED(hr))
  4428.                 return hr;
  4429.             hr = spTypeInfo->GetFuncDesc(nIndex, &pFuncDesc);
  4430.             if (FAILED(hr))
  4431.                 return hr;
  4432.         }
  4433.         else // search for funcdesc
  4434.         {
  4435.             TYPEATTR* pAttr;
  4436.             hr = spTypeInfo->GetTypeAttr(&pAttr);
  4437.             if (FAILED(hr))
  4438.                 return hr;
  4439.             for (int i=0;i<pAttr->cFuncs;i++)
  4440.             {
  4441.                 hr = spTypeInfo->GetFuncDesc(i, &pFuncDesc);
  4442.                 if (FAILED(hr))
  4443.                     return hr;
  4444.                 if (pFuncDesc->memid == dispidMember)
  4445.                     break;
  4446.                 spTypeInfo->ReleaseFuncDesc(pFuncDesc);
  4447.                 pFuncDesc = NULL;
  4448.             }
  4449.             spTypeInfo->ReleaseTypeAttr(pAttr);
  4450.             if (pFuncDesc == NULL)
  4451.                 return E_FAIL;
  4452.         }
  4453.  
  4454.         // If this assert occurs, then add a #define _ATL_MAX_VARTYPES nnnn
  4455.         // before including atlcom.h
  4456.         ATLASSERT(pFuncDesc->cParams <= _ATL_MAX_VARTYPES);
  4457.         if (pFuncDesc->cParams > _ATL_MAX_VARTYPES)
  4458.             return E_FAIL;
  4459.  
  4460.         for (int i=0; i<pFuncDesc->cParams; i++)
  4461.         {
  4462.             info.pVarTypes[i] = pFuncDesc->lprgelemdescParam[pFuncDesc->cParams - i - 1].tdesc.vt;
  4463.             if (info.pVarTypes[i] == VT_PTR)
  4464.                 info.pVarTypes[i] = pFuncDesc->lprgelemdescParam[pFuncDesc->cParams - i - 1].tdesc.lptdesc->vt | VT_BYREF;
  4465.             if (info.pVarTypes[i] == VT_USERDEFINED)
  4466.                 info.pVarTypes[i] = GetUserDefinedType(spTypeInfo,pFuncDesc->lprgelemdescParam[pFuncDesc->cParams-i-1].tdesc.hreftype);
  4467.         }
  4468.  
  4469.         VARTYPE vtReturn = pFuncDesc->elemdescFunc.tdesc.vt;
  4470.         switch(vtReturn)
  4471.         {
  4472.         case VT_INT:
  4473.             vtReturn = VT_I4;
  4474.             break;
  4475.         case VT_UINT:
  4476.             vtReturn = VT_UI4;
  4477.             break;
  4478.         case VT_VOID:
  4479.             vtReturn = VT_EMPTY; // this is how DispCallFunc() represents void
  4480.             break;
  4481.         case VT_HRESULT:
  4482.             vtReturn = VT_ERROR;
  4483.             break;
  4484.         }
  4485.         info.vtReturn = vtReturn;
  4486.         info.cc = pFuncDesc->callconv;
  4487.         info.nParams = pFuncDesc->cParams;
  4488.         spTypeInfo->ReleaseFuncDesc(pFuncDesc);
  4489.         return S_OK;
  4490.     }
  4491.     VARTYPE GetUserDefinedType(ITypeInfo *pTI, HREFTYPE hrt)
  4492.     {
  4493.         CComPtr<ITypeInfo> spTypeInfo;
  4494.         VARTYPE vt = VT_USERDEFINED;
  4495.         HRESULT hr = E_FAIL;
  4496.         hr = pTI->GetRefTypeInfo(hrt, &spTypeInfo);
  4497.         if(FAILED(hr))
  4498.             return vt;
  4499.         TYPEATTR *pta=NULL;
  4500.  
  4501.         spTypeInfo->GetTypeAttr(&pta);
  4502.         if(pta && pta->typekind == TKIND_ALIAS)
  4503.         {
  4504.             if (pta->tdescAlias.vt == VT_USERDEFINED)
  4505.                 GetUserDefinedType(spTypeInfo,pta->tdescAlias.hreftype);
  4506.             else
  4507.                 vt = pta->tdescAlias.vt;
  4508.         }
  4509.     
  4510.         if(pta)
  4511.             spTypeInfo->ReleaseTypeAttr(pta);
  4512.         return vt;
  4513.  
  4514.     }
  4515. protected:
  4516.     static _tihclass _tih;
  4517.     static HRESULT GetTI(LCID lcid, ITypeInfo** ppInfo)
  4518.     {return _tih.GetTI(lcid, ppInfo);}
  4519. };
  4520.  
  4521.  
  4522. template <UINT nID, class T, const IID* piid, const GUID* plibid, WORD wMajor, WORD wMinor, class tihclass>
  4523. IDispEventImpl<nID, T, piid, plibid, wMajor, wMinor, tihclass>::_tihclass
  4524. IDispEventImpl<nID, T, piid, plibid, wMajor, wMinor, tihclass>::_tih =
  4525.     {piid, plibid, wMajor, wMinor, NULL, 0, NULL, 0};
  4526.  
  4527. template <class T>
  4528. struct _ATL_EVENT_ENTRY
  4529. {
  4530.     UINT nControlID;            //ID identifying object instance
  4531.     const IID* piid;            //dispinterface IID
  4532.     int nOffset;                //offset of dispinterface from this pointer
  4533.     DISPID dispid;                //DISPID of method/property
  4534.     void (__stdcall T::*pfn)();    //method to invoke
  4535.     _ATL_FUNC_INFO* pInfo;
  4536. };
  4537.  
  4538.  
  4539.  
  4540. //Sink map is used to set up event handling
  4541. #define BEGIN_SINK_MAP(_class)\
  4542.     static const _ATL_EVENT_ENTRY<_class>* _GetSinkMap()\
  4543.     {\
  4544.         typedef _class _atl_event_classtype;\
  4545.         static const _ATL_EVENT_ENTRY<_class> map[] = {
  4546.  
  4547.  
  4548. #define SINK_ENTRY_INFO(id, iid, dispid, fn, info) {id, &iid, (int)(static_cast<_IDispEventLocator<id, &iid>*>((_atl_event_classtype*)8))-8, dispid, (void (__stdcall _atl_event_classtype::*)())fn, info},
  4549. #define SINK_ENTRY_EX(id, iid, dispid, fn) SINK_ENTRY_INFO(id, iid, dispid, fn, NULL)
  4550. #define SINK_ENTRY(id, dispid, fn) SINK_ENTRY_EX(id, IID_NULL, dispid, fn)
  4551. #define END_SINK_MAP() {0, NULL, 0, 0, NULL, NULL} }; return map;}
  4552.  
  4553. /////////////////////////////////////////////////////////////////////////////
  4554. // IDispatchImpl
  4555.  
  4556. template <class T, const IID* piid, const GUID* plibid = &CComModule::m_libid, WORD wMajor = 1,
  4557. WORD wMinor = 0, class tihclass = CComTypeInfoHolder>
  4558. class ATL_NO_VTABLE IDispatchImpl : public T
  4559. {
  4560. public:
  4561.     typedef tihclass _tihclass;
  4562. // IDispatch
  4563.     STDMETHOD(GetTypeInfoCount)(UINT* pctinfo)
  4564.     {
  4565.         *pctinfo = 1;
  4566.         return S_OK;
  4567.     }
  4568.     STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
  4569.     {
  4570.         return _tih.GetTypeInfo(itinfo, lcid, pptinfo);
  4571.     }
  4572.     STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR* rgszNames, UINT cNames,
  4573.         LCID lcid, DISPID* rgdispid)
  4574.     {
  4575.         return _tih.GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
  4576.     }
  4577.     STDMETHOD(Invoke)(DISPID dispidMember, REFIID riid,
  4578.         LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
  4579.         EXCEPINFO* pexcepinfo, UINT* puArgErr)
  4580.     {
  4581.         return _tih.Invoke((IDispatch*)this, dispidMember, riid, lcid,
  4582.         wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
  4583.     }
  4584. protected:
  4585.     static _tihclass _tih;
  4586.     static HRESULT GetTI(LCID lcid, ITypeInfo** ppInfo)
  4587.     {
  4588.         return _tih.GetTI(lcid, ppInfo);
  4589.     }
  4590. };
  4591.  
  4592. template <class T, const IID* piid, const GUID* plibid, WORD wMajor, WORD wMinor, class tihclass>
  4593. IDispatchImpl<T, piid, plibid, wMajor, wMinor, tihclass>::_tihclass
  4594. IDispatchImpl<T, piid, plibid, wMajor, wMinor, tihclass>::_tih =
  4595. {piid, plibid, wMajor, wMinor, NULL, 0, NULL, 0};
  4596.  
  4597.  
  4598. /////////////////////////////////////////////////////////////////////////////
  4599. // IProvideClassInfoImpl
  4600. template <const CLSID* pcoclsid, const GUID* plibid = &CComModule::m_libid,
  4601. WORD wMajor = 1, WORD wMinor = 0, class tihclass = CComTypeInfoHolder>
  4602. class ATL_NO_VTABLE IProvideClassInfoImpl : public IProvideClassInfo
  4603. {
  4604. public:
  4605.     typedef tihclass _tihclass;
  4606.  
  4607.     STDMETHOD(GetClassInfo)(ITypeInfo** pptinfo)
  4608.     {
  4609.         return _tih.GetTypeInfo(0, LANG_NEUTRAL, pptinfo);
  4610.     }
  4611.  
  4612. protected:
  4613.     static _tihclass _tih;
  4614. };
  4615.  
  4616. template <const CLSID* pcoclsid, const GUID* plibid, WORD wMajor, WORD wMinor, class tihclass>
  4617. IProvideClassInfoImpl<pcoclsid, plibid, wMajor, wMinor, tihclass>::_tihclass
  4618. IProvideClassInfoImpl<pcoclsid, plibid, wMajor, wMinor, tihclass>::_tih =
  4619. {pcoclsid,plibid, wMajor, wMinor, NULL, 0, NULL, 0};
  4620.  
  4621. /////////////////////////////////////////////////////////////////////////////
  4622. // IProvideClassInfo2Impl
  4623. template <const CLSID* pcoclsid, const IID* psrcid, const GUID* plibid = &CComModule::m_libid,
  4624. WORD wMajor = 1, WORD wMinor = 0, class tihclass = CComTypeInfoHolder>
  4625. class ATL_NO_VTABLE IProvideClassInfo2Impl : public IProvideClassInfo2
  4626. {
  4627. public:
  4628.     typedef tihclass _tihclass;
  4629.  
  4630.     STDMETHOD(GetClassInfo)(ITypeInfo** pptinfo)
  4631.     {
  4632.         return _tih.GetTypeInfo(0, LANG_NEUTRAL, pptinfo);
  4633.     }
  4634.     STDMETHOD(GetGUID)(DWORD dwGuidKind, GUID* pGUID)
  4635.     {
  4636.         if (pGUID == NULL)
  4637.             return E_POINTER;
  4638.  
  4639.         if (dwGuidKind == GUIDKIND_DEFAULT_SOURCE_DISP_IID && psrcid)
  4640.         {
  4641.             *pGUID = *psrcid;
  4642.             return S_OK;
  4643.         }
  4644.         *pGUID = GUID_NULL;
  4645.         return E_FAIL;
  4646.     }
  4647.  
  4648. protected:
  4649.     static _tihclass _tih;
  4650. };
  4651.  
  4652.  
  4653. template <const CLSID* pcoclsid, const IID* psrcid, const GUID* plibid, WORD wMajor, WORD wMinor, class tihclass>
  4654. IProvideClassInfo2Impl<pcoclsid, psrcid, plibid, wMajor, wMinor, tihclass>::_tihclass
  4655. IProvideClassInfo2Impl<pcoclsid, psrcid, plibid, wMajor, wMinor, tihclass>::_tih =
  4656. {pcoclsid,plibid, wMajor, wMinor, NULL, 0, NULL, 0};
  4657.  
  4658.  
  4659. /////////////////////////////////////////////////////////////////////////////
  4660. // ISupportErrorInfoImpl
  4661.  
  4662. template <const IID* piid>
  4663. class ATL_NO_VTABLE ISupportErrorInfoImpl : public ISupportErrorInfo
  4664. {
  4665. public:
  4666.     STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid)
  4667.     {
  4668.         return (InlineIsEqualGUID(riid,*piid)) ? S_OK : S_FALSE;
  4669.     }
  4670. };
  4671.  
  4672.  
  4673. /////////////////////////////////////////////////////////////////////////////
  4674. // CComEnumImpl
  4675.  
  4676. // These _CopyXXX classes are used with enumerators in order to control
  4677. // how enumerated items are initialized, copied, and deleted
  4678.  
  4679. // Default is shallow copy with no special init or cleanup
  4680. template <class T>
  4681. class _Copy
  4682. {
  4683. public:
  4684.     static HRESULT copy(T* p1, T* p2) {memcpy(p1, p2, sizeof(T)); return S_OK;}
  4685.     static void init(T*) {}
  4686.     static void destroy(T*) {}
  4687. };
  4688.  
  4689. template<>
  4690. class _Copy<VARIANT>
  4691. {
  4692. public:
  4693.     static HRESULT copy(VARIANT* p1, VARIANT* p2) {return VariantCopy(p1, p2);}
  4694.     static void init(VARIANT* p) {p->vt = VT_EMPTY;}
  4695.     static void destroy(VARIANT* p) {VariantClear(p);}
  4696. };
  4697.  
  4698. template<>
  4699. class _Copy<LPOLESTR>
  4700. {
  4701. public:
  4702.     static HRESULT copy(LPOLESTR* p1, LPOLESTR* p2)
  4703.     {
  4704.         HRESULT hr = S_OK;
  4705.         (*p1) = (LPOLESTR)CoTaskMemAlloc(sizeof(OLECHAR)*(ocslen(*p2)+1));
  4706.         if (*p1 == NULL)
  4707.             hr = E_OUTOFMEMORY;
  4708.         else
  4709.             ocscpy(*p1,*p2);
  4710.         return hr;
  4711.     }
  4712.     static void init(LPOLESTR* p) {*p = NULL;}
  4713.     static void destroy(LPOLESTR* p) { CoTaskMemFree(*p);}
  4714. };
  4715.  
  4716. template<>
  4717. class _Copy<OLEVERB>
  4718. {
  4719. public:
  4720.     static HRESULT copy(OLEVERB* p1, OLEVERB* p2)
  4721.     {
  4722.         HRESULT hr = S_OK;
  4723.         *p1 = *p2;
  4724.         if (p2->lpszVerbName == NULL)
  4725.             return S_OK;
  4726.         p1->lpszVerbName = (LPOLESTR)CoTaskMemAlloc(sizeof(OLECHAR)*(ocslen(p2->lpszVerbName)+1));
  4727.         if (p1->lpszVerbName == NULL)
  4728.             hr = E_OUTOFMEMORY;
  4729.         else
  4730.             ocscpy(p1->lpszVerbName,p2->lpszVerbName);
  4731.         return hr;
  4732.     }
  4733.     static void init(OLEVERB* p) { p->lpszVerbName = NULL;}
  4734.     static void destroy(OLEVERB* p) { if (p->lpszVerbName) CoTaskMemFree(p->lpszVerbName);}
  4735. };
  4736.  
  4737. template<>
  4738. class _Copy<CONNECTDATA>
  4739. {
  4740. public:
  4741.     static HRESULT copy(CONNECTDATA* p1, CONNECTDATA* p2)
  4742.     {
  4743.         *p1 = *p2;
  4744.         if (p1->pUnk)
  4745.             p1->pUnk->AddRef();
  4746.         return S_OK;
  4747.     }
  4748.     static void init(CONNECTDATA* ) {}
  4749.     static void destroy(CONNECTDATA* p) {if (p->pUnk) p->pUnk->Release();}
  4750. };
  4751.  
  4752. template <class T>
  4753. class _CopyInterface
  4754. {
  4755. public:
  4756.     static HRESULT copy(T** p1, T** p2)
  4757.     {
  4758.         *p1 = *p2;
  4759.         if (*p1)
  4760.             (*p1)->AddRef();
  4761.         return S_OK;
  4762.     }
  4763.     static void init(T** ) {}
  4764.     static void destroy(T** p) {if (*p) (*p)->Release();}
  4765. };
  4766.  
  4767. template<class T>
  4768. class ATL_NO_VTABLE CComIEnum : public IUnknown
  4769. {
  4770. public:
  4771.     STDMETHOD(Next)(ULONG celt, T* rgelt, ULONG* pceltFetched) = 0;
  4772.     STDMETHOD(Skip)(ULONG celt) = 0;
  4773.     STDMETHOD(Reset)(void) = 0;
  4774.     STDMETHOD(Clone)(CComIEnum<T>** ppEnum) = 0;
  4775. };
  4776.  
  4777.  
  4778. enum CComEnumFlags
  4779. {
  4780.     //see FlagBits in CComEnumImpl
  4781.     AtlFlagNoCopy = 0,
  4782.     AtlFlagTakeOwnership = 2,
  4783.     AtlFlagCopy = 3 // copy implies ownership
  4784. };
  4785.  
  4786. template <class Base, const IID* piid, class T, class Copy>
  4787. class ATL_NO_VTABLE CComEnumImpl : public Base
  4788. {
  4789. public:
  4790.     CComEnumImpl() {m_begin = m_end = m_iter = NULL; m_dwFlags = 0;}
  4791.     ~CComEnumImpl();
  4792.     STDMETHOD(Next)(ULONG celt, T* rgelt, ULONG* pceltFetched);
  4793.     STDMETHOD(Skip)(ULONG celt);
  4794.     STDMETHOD(Reset)(void){m_iter = m_begin;return S_OK;}
  4795.     STDMETHOD(Clone)(Base** ppEnum);
  4796.     HRESULT Init(T* begin, T* end, IUnknown* pUnk,
  4797.         CComEnumFlags flags = AtlFlagNoCopy);
  4798.     CComPtr<IUnknown> m_spUnk;
  4799.     T* m_begin;
  4800.     T* m_end;
  4801.     T* m_iter;
  4802.     DWORD m_dwFlags;
  4803. protected:
  4804.     enum FlagBits
  4805.     {
  4806.         BitCopy=1,
  4807.         BitOwn=2
  4808.     };
  4809. };
  4810.  
  4811. template <class Base, const IID* piid, class T, class Copy>
  4812. CComEnumImpl<Base, piid, T, Copy>::~CComEnumImpl()
  4813. {
  4814.     if (m_dwFlags & BitOwn)
  4815.     {
  4816.         for (T* p = m_begin; p != m_end; p++)
  4817.             Copy::destroy(p);
  4818.         delete [] m_begin;
  4819.     }
  4820. }
  4821.  
  4822. template <class Base, const IID* piid, class T, class Copy>
  4823. STDMETHODIMP CComEnumImpl<Base, piid, T, Copy>::Next(ULONG celt, T* rgelt,
  4824.     ULONG* pceltFetched)
  4825. {
  4826.     if (rgelt == NULL || (celt != 1 && pceltFetched == NULL))
  4827.         return E_POINTER;
  4828.     if (m_begin == NULL || m_end == NULL || m_iter == NULL)
  4829.         return E_FAIL;
  4830.     ULONG nRem = (ULONG)(m_end - m_iter);
  4831.     HRESULT hRes = S_OK;
  4832.     if (nRem < celt)
  4833.         hRes = S_FALSE;
  4834.     ULONG nMin = min(celt, nRem);
  4835.     if (pceltFetched != NULL)
  4836.         *pceltFetched = nMin;
  4837.     T* pelt = rgelt;
  4838.     while(nMin--)
  4839.     {
  4840.         HRESULT hr = Copy::copy(pelt, m_iter);
  4841.         if (FAILED(hr))
  4842.         {
  4843.             while (rgelt < pelt)
  4844.                 Copy::destroy(rgelt++);
  4845.             if (pceltFetched != NULL)
  4846.                 *pceltFetched = 0;
  4847.             return hr;
  4848.         }
  4849.         pelt++;
  4850.         m_iter++;
  4851.     }
  4852.     return hRes;
  4853. }
  4854.  
  4855. template <class Base, const IID* piid, class T, class Copy>
  4856. STDMETHODIMP CComEnumImpl<Base, piid, T, Copy>::Skip(ULONG celt)
  4857. {
  4858.     m_iter += celt;
  4859.     if (m_iter <= m_end)
  4860.         return S_OK;
  4861.     m_iter = m_end;
  4862.     return S_FALSE;
  4863. }
  4864.  
  4865. template <class Base, const IID* piid, class T, class Copy>
  4866. STDMETHODIMP CComEnumImpl<Base, piid, T, Copy>::Clone(Base** ppEnum)
  4867. {
  4868.     typedef CComObject<CComEnum<Base, piid, T, Copy> > _class;
  4869.     HRESULT hRes = E_POINTER;
  4870.     if (ppEnum != NULL)
  4871.     {
  4872.         *ppEnum = NULL;
  4873.         _class* p;
  4874.         hRes = _class::CreateInstance(&p);
  4875.         if (SUCCEEDED(hRes))
  4876.         {
  4877.             // If the data is a copy then we need to keep "this" object around
  4878.             hRes = p->Init(m_begin, m_end, (m_dwFlags & BitCopy) ? this : m_spUnk);
  4879.             if (SUCCEEDED(hRes))
  4880.             {
  4881.                 p->m_iter = m_iter;
  4882.                 hRes = p->_InternalQueryInterface(*piid, (void**)ppEnum);
  4883.             }
  4884.             if (FAILED(hRes))
  4885.                 delete p;
  4886.         }
  4887.     }
  4888.     return hRes;
  4889. }
  4890.  
  4891. template <class Base, const IID* piid, class T, class Copy>
  4892. HRESULT CComEnumImpl<Base, piid, T, Copy>::Init(T* begin, T* end, IUnknown* pUnk,
  4893.     CComEnumFlags flags)
  4894. {
  4895.     if (flags == AtlFlagCopy)
  4896.     {
  4897.         ATLASSERT(m_begin == NULL); //Init called twice?
  4898.         ATLTRY(m_begin = new T[end-begin])
  4899.         m_iter = m_begin;
  4900.         if (m_begin == NULL)
  4901.             return E_OUTOFMEMORY;
  4902.         for (T* i=begin; i != end; i++)
  4903.         {
  4904.             Copy::init(m_iter);
  4905.             HRESULT hr = Copy::copy(m_iter, i);
  4906.             if (FAILED(hr))
  4907.             {
  4908.                 T* p = m_begin;
  4909.                 while (p < m_iter)
  4910.                     Copy::destroy(p++);
  4911.                 delete [] m_begin;
  4912.                 m_begin = m_end = m_iter = NULL;
  4913.                 return hr;
  4914.             }
  4915.             m_iter++;
  4916.         }
  4917.         m_end = m_begin + (end-begin);
  4918.     }
  4919.     else
  4920.     {
  4921.         m_begin = begin;
  4922.         m_end = end;
  4923.     }
  4924.     m_spUnk = pUnk;
  4925.     m_iter = m_begin;
  4926.     m_dwFlags = flags;
  4927.     return S_OK;
  4928. }
  4929.  
  4930. template <class Base, const IID* piid, class T, class Copy, class ThreadModel = CComObjectThreadModel>
  4931. class ATL_NO_VTABLE CComEnum :
  4932.     public CComEnumImpl<Base, piid, T, Copy>,
  4933.     public CComObjectRootEx< ThreadModel >
  4934. {
  4935. public:
  4936.     typedef CComEnum<Base, piid, T, Copy > _CComEnum;
  4937.     typedef CComEnumImpl<Base, piid, T, Copy > _CComEnumBase;
  4938.     BEGIN_COM_MAP(_CComEnum)
  4939.         COM_INTERFACE_ENTRY_IID(*piid, _CComEnumBase)
  4940.     END_COM_MAP()
  4941. };
  4942.  
  4943. template <class Base, const IID* piid, class T, class Copy, class CollType>
  4944. class ATL_NO_VTABLE IEnumOnSTLImpl : public Base
  4945. {
  4946. public:
  4947.     HRESULT Init(IUnknown *pUnkForRelease, CollType& collection)
  4948.     {
  4949.         m_spUnk = pUnkForRelease;
  4950.         m_pcollection = &collection;
  4951.         m_iter = m_pcollection->begin();
  4952.         return S_OK;
  4953.     }
  4954.     STDMETHOD(Next)(ULONG celt, T* rgelt, ULONG* pceltFetched);
  4955.     STDMETHOD(Skip)(ULONG celt);
  4956.     STDMETHOD(Reset)(void)
  4957.     {
  4958.         if (m_pcollection == NULL)
  4959.             return E_FAIL;
  4960.         m_iter = m_pcollection->begin();
  4961.         return S_OK;
  4962.     }
  4963.     STDMETHOD(Clone)(Base** ppEnum);
  4964. //Data
  4965.     CComPtr<IUnknown> m_spUnk;
  4966.     CollType* m_pcollection;
  4967.     CollType::iterator m_iter;
  4968. };
  4969.  
  4970. template <class Base, const IID* piid, class T, class Copy, class CollType>
  4971. STDMETHODIMP IEnumOnSTLImpl<Base, piid, T, Copy, CollType>::Next(ULONG celt, T* rgelt,
  4972.     ULONG* pceltFetched)
  4973. {
  4974.     if (rgelt == NULL || (celt != 1 && pceltFetched == NULL))
  4975.         return E_POINTER;
  4976.     if (m_pcollection == NULL)
  4977.         return E_FAIL;
  4978.  
  4979.     ULONG nActual = 0;
  4980.     HRESULT hr = S_OK;
  4981.     T* pelt = rgelt;
  4982.     while (SUCCEEDED(hr) && m_iter != m_pcollection->end() && nActual < celt)
  4983.     {
  4984.         hr = Copy::copy(pelt, &*m_iter);
  4985.         if (FAILED(hr))
  4986.         {
  4987.             while (rgelt < pelt)
  4988.                 Copy::destroy(rgelt++);
  4989.             nActual = 0;
  4990.         }
  4991.         else
  4992.         {
  4993.             pelt++;
  4994.             m_iter++;
  4995.             nActual++;
  4996.         }
  4997.     }
  4998.     if (pceltFetched)
  4999.         *pceltFetched = nActual;
  5000.     if (SUCCEEDED(hr) && (nActual < celt))
  5001.         hr = S_FALSE;
  5002.     return hr;
  5003. }
  5004.  
  5005. template <class Base, const IID* piid, class T, class Copy, class CollType>
  5006. STDMETHODIMP IEnumOnSTLImpl<Base, piid, T, Copy, CollType>::Skip(ULONG celt)
  5007. {
  5008.     HRESULT hr = S_OK;
  5009.     while (celt--)
  5010.     {
  5011.         if (m_iter != m_pcollection->end())
  5012.             m_iter++;
  5013.         else
  5014.         {
  5015.             hr = S_FALSE;
  5016.             break;
  5017.         }
  5018.     }
  5019.     return hr;
  5020. }
  5021.  
  5022. template <class Base, const IID* piid, class T, class Copy, class CollType>
  5023. STDMETHODIMP IEnumOnSTLImpl<Base, piid, T, Copy, CollType>::Clone(Base** ppEnum)
  5024. {
  5025.     typedef CComObject<CComEnumOnSTL<Base, piid, T, Copy, CollType> > _class;
  5026.     HRESULT hRes = E_POINTER;
  5027.     if (ppEnum != NULL)
  5028.     {
  5029.         *ppEnum = NULL;
  5030.         _class* p;
  5031.         hRes = _class::CreateInstance(&p);
  5032.         if (SUCCEEDED(hRes))
  5033.         {
  5034.             hRes = p->Init(m_spUnk, *m_pcollection);
  5035.             if (SUCCEEDED(hRes))
  5036.             {
  5037.                 p->m_iter = m_iter;
  5038.                 hRes = p->_InternalQueryInterface(*piid, (void**)ppEnum);
  5039.             }
  5040.             if (FAILED(hRes))
  5041.                 delete p;
  5042.         }
  5043.     }
  5044.     return hRes;
  5045. }
  5046.  
  5047. template <class Base, const IID* piid, class T, class Copy, class CollType, class ThreadModel = CComObjectThreadModel>
  5048. class ATL_NO_VTABLE CComEnumOnSTL :
  5049.     public IEnumOnSTLImpl<Base, piid, T, Copy, CollType>,
  5050.     public CComObjectRootEx< ThreadModel >
  5051. {
  5052. public:
  5053.     typedef CComEnumOnSTL<Base, piid, T, Copy, CollType, ThreadModel > _CComEnum;
  5054.     typedef IEnumOnSTLImpl<Base, piid, T, Copy, CollType > _CComEnumBase;
  5055.     BEGIN_COM_MAP(_CComEnum)
  5056.         COM_INTERFACE_ENTRY_IID(*piid, _CComEnumBase)
  5057.     END_COM_MAP()
  5058. };
  5059.  
  5060. template <class T, class CollType, class ItemType, class CopyItem, class EnumType>
  5061. class ICollectionOnSTLImpl : public T
  5062. {
  5063. public:
  5064.     STDMETHOD(get_Count)(long* pcount)
  5065.     {
  5066.         if (pcount == NULL)
  5067.             return E_POINTER;
  5068.         *pcount = m_coll.size();
  5069.         return S_OK;
  5070.     }
  5071.     STDMETHOD(get_Item)(long Index, ItemType* pvar)
  5072.     {
  5073.         //Index is 1-based
  5074.         if (pvar == NULL)
  5075.             return E_POINTER;
  5076.         HRESULT hr = E_FAIL;
  5077.         Index--;
  5078.         CollType::iterator iter = m_coll.begin();
  5079.         while (iter != m_coll.end() && Index > 0)
  5080.         {
  5081.             iter++;
  5082.             Index--;
  5083.         }
  5084.         if (iter != m_coll.end())
  5085.             hr = CopyItem::copy(pvar, &*iter);
  5086.         return hr;
  5087.     }
  5088.     STDMETHOD(get__NewEnum)(IUnknown** ppUnk)
  5089.     {
  5090.         if (ppUnk == NULL)
  5091.             return E_POINTER;
  5092.         *ppUnk = NULL;
  5093.         HRESULT hRes = S_OK;
  5094.         CComObject<EnumType>* p;
  5095.         hRes = CComObject<EnumType>::CreateInstance(&p);
  5096.         if (SUCCEEDED(hRes))
  5097.         {
  5098.             hRes = p->Init(this, m_coll);
  5099.             if (hRes == S_OK)
  5100.                 hRes = p->QueryInterface(IID_IUnknown, (void**)ppUnk);
  5101.         }
  5102.         if (hRes != S_OK)
  5103.             delete p;
  5104.         return hRes;
  5105.     }
  5106.     CollType m_coll;
  5107. };
  5108.  
  5109. //////////////////////////////////////////////////////////////////////////////
  5110. // ISpecifyPropertyPagesImpl
  5111. template <class T>
  5112. class ATL_NO_VTABLE ISpecifyPropertyPagesImpl : public ISpecifyPropertyPages
  5113. {
  5114. public:
  5115.     // ISpecifyPropertyPages
  5116.     //
  5117.     STDMETHOD(GetPages)(CAUUID* pPages)
  5118.     {
  5119.         ATLTRACE2(atlTraceCOM, 0, _T("ISpecifyPropertyPagesImpl::GetPages\n"));
  5120.         ATL_PROPMAP_ENTRY* pMap = T::GetPropertyMap();
  5121.         return GetPagesHelper(pPages, pMap);
  5122.     }
  5123. protected:
  5124.     HRESULT GetPagesHelper(CAUUID* pPages, ATL_PROPMAP_ENTRY* pMap)
  5125.     {
  5126.         ATLASSERT(pMap != NULL);
  5127.         if (pMap == NULL)
  5128.             return E_POINTER;
  5129.  
  5130.         int nCnt = 0;
  5131.         // Get count of unique pages to alloc the array
  5132.         for (int i = 0; pMap[i].pclsidPropPage != NULL; i++)
  5133.         {
  5134.             // only allow non data entry types
  5135.             if (pMap[i].vt == 0)
  5136.             {
  5137.                 // Does this property have a page?  CLSID_NULL means it does not
  5138.                 if (!InlineIsEqualGUID(*pMap[i].pclsidPropPage, CLSID_NULL))
  5139.                     nCnt++;
  5140.             }
  5141.         }
  5142.         pPages->pElems = (GUID*) CoTaskMemAlloc(sizeof(CLSID)*nCnt);
  5143.         if (pPages->pElems == NULL)
  5144.             return E_OUTOFMEMORY;
  5145.         // reset count of items we have added to the array
  5146.         nCnt = 0;
  5147.         for (i = 0; pMap[i].pclsidPropPage != NULL; i++)
  5148.         {
  5149.             // only allow non data entry types
  5150.             if (pMap[i].vt == 0)
  5151.             {
  5152.                 // Does this property have a page?  CLSID_NULL means it does not
  5153.                 if (!InlineIsEqualGUID(*pMap[i].pclsidPropPage, CLSID_NULL))
  5154.                 {
  5155.                     BOOL bFound = FALSE;
  5156.                     // Search through array we are building up to see
  5157.                     // if it is already in there
  5158.                     for (int j=0; j<nCnt; j++)
  5159.                     {
  5160.                         if (InlineIsEqualGUID(*(pMap[i].pclsidPropPage), pPages->pElems[j]))
  5161.                         {
  5162.                             // It's already there, so no need to add it again
  5163.                             bFound = TRUE;
  5164.                             break;
  5165.                         }
  5166.                     }
  5167.                     // If we didn't find it in there then add it
  5168.                     if (!bFound)
  5169.                         pPages->pElems[nCnt++] = *pMap[i].pclsidPropPage;
  5170.                 }
  5171.             }
  5172.         }
  5173.         pPages->cElems = nCnt;
  5174.         return S_OK;
  5175.     }
  5176.  
  5177. };
  5178.  
  5179. #ifndef _ATL_NO_CONNECTION_POINTS
  5180. /////////////////////////////////////////////////////////////////////////////
  5181. // Connection Points
  5182.  
  5183. struct _ATL_CONNMAP_ENTRY
  5184. {
  5185.     DWORD dwOffset;
  5186. };
  5187.  
  5188.  
  5189. // We want the offset of the connection point relative to the connection
  5190. // point container base class
  5191. #define BEGIN_CONNECTION_POINT_MAP(x)\
  5192.     typedef x _atl_conn_classtype;\
  5193.     static const _ATL_CONNMAP_ENTRY* GetConnMap(int* pnEntries) {\
  5194.     static const _ATL_CONNMAP_ENTRY _entries[] = {
  5195. // CONNECTION_POINT_ENTRY computes the offset of the connection point to the
  5196. // IConnectionPointContainer interface
  5197. #define CONNECTION_POINT_ENTRY(iid){offsetofclass(_ICPLocator<&iid>, _atl_conn_classtype)-\
  5198.     offsetofclass(IConnectionPointContainerImpl<_atl_conn_classtype>, _atl_conn_classtype)},
  5199. #define END_CONNECTION_POINT_MAP() {(DWORD)-1} }; \
  5200.     if (pnEntries) *pnEntries = sizeof(_entries)/sizeof(_ATL_CONNMAP_ENTRY) - 1; \
  5201.     return _entries;}
  5202.  
  5203.  
  5204. #ifndef _DEFAULT_VECTORLENGTH
  5205. #define _DEFAULT_VECTORLENGTH 4
  5206. #endif
  5207.  
  5208. template <unsigned int nMaxSize>
  5209. class CComUnkArray
  5210. {
  5211. public:
  5212.     CComUnkArray()
  5213.     {
  5214.         memset(m_arr, 0, sizeof(IUnknown*)*nMaxSize);
  5215.     }
  5216.     DWORD Add(IUnknown* pUnk);
  5217.     BOOL Remove(DWORD dwCookie);
  5218.     static DWORD WINAPI GetCookie(IUnknown** pp)
  5219.     {
  5220.         return (DWORD)pp;
  5221.     }
  5222.     static IUnknown* WINAPI GetUnknown(DWORD dwCookie)
  5223.     {
  5224.         return dwCookie ? *(IUnknown**)dwCookie : 0;
  5225.     }
  5226.     IUnknown** begin()
  5227.     {
  5228.         return &m_arr[0];
  5229.     }
  5230.     IUnknown** end()
  5231.     {
  5232.         return &m_arr[nMaxSize];
  5233.     }
  5234. protected:
  5235.     IUnknown* m_arr[nMaxSize];
  5236. };
  5237.  
  5238. template <unsigned int nMaxSize>
  5239. inline DWORD CComUnkArray<nMaxSize>::Add(IUnknown* pUnk)
  5240. {
  5241.     for (IUnknown** pp = begin();pp<end();pp++)
  5242.     {
  5243.         if (*pp == NULL)
  5244.         {
  5245.             *pp = pUnk;
  5246.             return (DWORD)pp; // return cookie
  5247.         }
  5248.     }
  5249.     // If this fires then you need a larger array
  5250.     ATLASSERT(0);
  5251.     return 0;
  5252. }
  5253.  
  5254. template <unsigned int nMaxSize>
  5255. inline BOOL CComUnkArray<nMaxSize>::Remove(DWORD dwCookie)
  5256. {
  5257.     IUnknown** pp = (IUnknown**)dwCookie;
  5258.     BOOL b = ((pp >= begin()) && (pp < end()));
  5259.     if (b)
  5260.         *pp = NULL;
  5261.     return b;
  5262. }
  5263.  
  5264. template<>
  5265. class CComUnkArray<1>
  5266. {
  5267. public:
  5268.     CComUnkArray()
  5269.     {
  5270.         m_arr[0] = NULL;
  5271.     }
  5272.     DWORD Add(IUnknown* pUnk)
  5273.     {
  5274.         if (m_arr[0] != NULL)
  5275.         {
  5276.             // If this fires then you need a larger array
  5277.             ATLASSERT(0);
  5278.             return 0;
  5279.         }
  5280.         m_arr[0] = pUnk;
  5281.         return (DWORD)&m_arr[0];
  5282.     }
  5283.     BOOL Remove(DWORD dwCookie)
  5284.     {
  5285.         if (dwCookie != (DWORD)&m_arr[0])
  5286.             return FALSE;
  5287.         m_arr[0] = NULL;
  5288.         return TRUE;
  5289.     }
  5290.     static DWORD WINAPI GetCookie(IUnknown** pp)
  5291.     {
  5292.         return (DWORD)pp;
  5293.     }
  5294.     static IUnknown* WINAPI GetUnknown(DWORD dwCookie)
  5295.     {
  5296.         return dwCookie ? *(IUnknown**)dwCookie : 0;
  5297.     }
  5298.     IUnknown** begin()
  5299.     {
  5300.         return &m_arr[0];
  5301.     }
  5302.     IUnknown** end()
  5303.     {
  5304.         return (&m_arr[0])+1;
  5305.     }
  5306. protected:
  5307.     IUnknown* m_arr[1];
  5308. };
  5309.  
  5310. class CComDynamicUnkArray
  5311. {
  5312. public:
  5313.     CComDynamicUnkArray()
  5314.     {
  5315.         m_nSize = 0;
  5316.         m_ppUnk = NULL;
  5317.     }
  5318.  
  5319.     ~CComDynamicUnkArray()
  5320.     {
  5321.         if (m_nSize > 1)
  5322.             free(m_ppUnk);
  5323.     }
  5324.     DWORD Add(IUnknown* pUnk);
  5325.     BOOL Remove(DWORD dwCookie);
  5326.     static DWORD WINAPI GetCookie(IUnknown** pp)
  5327.     {
  5328.         return (DWORD)*pp;
  5329.     }
  5330.     static IUnknown* WINAPI GetUnknown(DWORD dwCookie)
  5331.     {
  5332.         return (IUnknown*)dwCookie;
  5333.     }
  5334.     IUnknown** begin()
  5335.     {
  5336.         return (m_nSize < 2) ? &m_pUnk : m_ppUnk;
  5337.     }
  5338.     IUnknown** end()
  5339.     {
  5340.         return (m_nSize < 2) ? (&m_pUnk)+m_nSize : &m_ppUnk[m_nSize];
  5341.     }
  5342.  
  5343.     IUnknown* GetAt(int nIndex)
  5344.     {
  5345.         if (nIndex < 0 || nIndex >= m_nSize)
  5346.             return NULL;
  5347.  
  5348.         return (m_nSize < 2) ? m_pUnk : m_ppUnk[nIndex];
  5349.     }
  5350.     int GetSize() const
  5351.     {
  5352.         return m_nSize;
  5353.     }
  5354.  
  5355.     void clear()
  5356.     {
  5357.         if (m_nSize > 1)
  5358.             free(m_ppUnk);
  5359.         m_nSize = 0;
  5360.     }
  5361. protected:
  5362.     union
  5363.     {
  5364.         IUnknown** m_ppUnk;
  5365.         IUnknown* m_pUnk;
  5366.     };
  5367.     int m_nSize;
  5368. };
  5369.  
  5370. inline DWORD CComDynamicUnkArray::Add(IUnknown* pUnk)
  5371. {
  5372.     IUnknown** pp = NULL;
  5373.     if (m_nSize == 0) // no connections
  5374.     {
  5375.         m_pUnk = pUnk;
  5376.         m_nSize = 1;
  5377.         return (DWORD)m_pUnk;
  5378.     }
  5379.     else if (m_nSize == 1)
  5380.     {
  5381.         //create array
  5382.         pp = (IUnknown**)malloc(sizeof(IUnknown*)*_DEFAULT_VECTORLENGTH);
  5383.         if (pp == NULL)
  5384.             return 0;
  5385.         memset(pp, 0, sizeof(IUnknown*)*_DEFAULT_VECTORLENGTH);
  5386.         *pp = m_pUnk;
  5387.         m_ppUnk = pp;
  5388.         m_nSize = _DEFAULT_VECTORLENGTH;
  5389.     }
  5390.     for (pp = begin();pp<end();pp++)
  5391.     {
  5392.         if (*pp == NULL)
  5393.         {
  5394.             *pp = pUnk;
  5395.             return (DWORD)pUnk;
  5396.         }
  5397.     }
  5398.     int nAlloc = m_nSize*2;
  5399.     pp = (IUnknown**)realloc(m_ppUnk, sizeof(IUnknown*)*nAlloc);
  5400.     if (pp == NULL)
  5401.         return 0;
  5402.     m_ppUnk = pp;
  5403.     memset(&m_ppUnk[m_nSize], 0, sizeof(IUnknown*)*m_nSize);
  5404.     m_ppUnk[m_nSize] = pUnk;
  5405.     m_nSize = nAlloc;
  5406.     return (DWORD)pUnk;
  5407. }
  5408.  
  5409. inline BOOL CComDynamicUnkArray::Remove(DWORD dwCookie)
  5410. {
  5411.     IUnknown** pp;
  5412.     if (dwCookie == NULL)
  5413.         return FALSE;
  5414.     if (m_nSize == 0)
  5415.         return FALSE;
  5416.     if (m_nSize == 1)
  5417.     {
  5418.         if ((DWORD)m_pUnk == dwCookie)
  5419.         {
  5420.             m_nSize = 0;
  5421.             return TRUE;
  5422.         }
  5423.         return FALSE;
  5424.     }
  5425.     for (pp=begin();pp<end();pp++)
  5426.     {
  5427.         if ((DWORD)*pp == dwCookie)
  5428.         {
  5429.             *pp = NULL;
  5430.             return TRUE;
  5431.         }
  5432.     }
  5433.     return FALSE;
  5434. }
  5435.  
  5436. template <const IID* piid>
  5437. class ATL_NO_VTABLE _ICPLocator
  5438. {
  5439. public:
  5440.     //this method needs a different name than QueryInterface
  5441.     STDMETHOD(_LocCPQueryInterface)(REFIID riid, void ** ppvObject) = 0;
  5442.     virtual ULONG STDMETHODCALLTYPE AddRef(void) = 0;\
  5443.     virtual ULONG STDMETHODCALLTYPE Release(void) = 0;
  5444. };
  5445.  
  5446. template <class T, const IID* piid, class CDV = CComDynamicUnkArray >
  5447. class ATL_NO_VTABLE IConnectionPointImpl : public _ICPLocator<piid>
  5448. {
  5449.     typedef CComEnum<IEnumConnections, &IID_IEnumConnections, CONNECTDATA,
  5450.         _Copy<CONNECTDATA> > CComEnumConnections;
  5451.     typedef CDV _CDV;
  5452. public:
  5453.     ~IConnectionPointImpl();
  5454.     STDMETHOD(_LocCPQueryInterface)(REFIID riid, void ** ppvObject)
  5455.     {
  5456.         if (InlineIsEqualGUID(riid, IID_IConnectionPoint) || InlineIsEqualUnknown(riid))
  5457.         {
  5458.             if (ppvObject == NULL)
  5459.                 return E_POINTER;
  5460.             *ppvObject = this;
  5461.             AddRef();
  5462. #ifdef _ATL_DEBUG_INTERFACES
  5463.             _Module.AddThunk((IUnknown**)ppvObject, _T("IConnectionPointImpl"), riid);
  5464. #endif // _ATL_DEBUG_INTERFACES
  5465.             return S_OK;
  5466.         }
  5467.         else
  5468.             return E_NOINTERFACE;
  5469.     }
  5470.  
  5471.     STDMETHOD(GetConnectionInterface)(IID* piid2)
  5472.     {
  5473.         if (piid2 == NULL)
  5474.             return E_POINTER;
  5475.         *piid2 = *piid;
  5476.         return S_OK;
  5477.     }
  5478.     STDMETHOD(GetConnectionPointContainer)(IConnectionPointContainer** ppCPC)
  5479.     {
  5480.         T* pT = static_cast<T*>(this);
  5481.         // No need to check ppCPC for NULL since QI will do that for us
  5482.         return pT->QueryInterface(IID_IConnectionPointContainer, (void**)ppCPC);
  5483.     }
  5484.     STDMETHOD(Advise)(IUnknown* pUnkSink, DWORD* pdwCookie);
  5485.     STDMETHOD(Unadvise)(DWORD dwCookie);
  5486.     STDMETHOD(EnumConnections)(IEnumConnections** ppEnum);
  5487.     CDV m_vec;
  5488. };
  5489.  
  5490. template <class T, const IID* piid, class CDV>
  5491. IConnectionPointImpl<T, piid, CDV>::~IConnectionPointImpl()
  5492. {
  5493.     IUnknown** pp = m_vec.begin();
  5494.     while (pp < m_vec.end())
  5495.     {
  5496.         if (*pp != NULL)
  5497.             (*pp)->Release();
  5498.         pp++;
  5499.     }
  5500. }
  5501.  
  5502. template <class T, const IID* piid, class CDV>
  5503. STDMETHODIMP IConnectionPointImpl<T, piid, CDV>::Advise(IUnknown* pUnkSink,
  5504.     DWORD* pdwCookie)
  5505. {
  5506.     T* pT = static_cast<T*>(this);
  5507.     IUnknown* p;
  5508.     HRESULT hRes = S_OK;
  5509.     if (pUnkSink == NULL || pdwCookie == NULL)
  5510.         return E_POINTER;
  5511.     IID iid;
  5512.     GetConnectionInterface(&iid);
  5513.     hRes = pUnkSink->QueryInterface(iid, (void**)&p);
  5514.     if (SUCCEEDED(hRes))
  5515.     {
  5516.         pT->Lock();
  5517.         *pdwCookie = m_vec.Add(p);
  5518.         hRes = (*pdwCookie != NULL) ? S_OK : CONNECT_E_ADVISELIMIT;
  5519.         pT->Unlock();
  5520.         if (hRes != S_OK)
  5521.             p->Release();
  5522.     }
  5523.     else if (hRes == E_NOINTERFACE)
  5524.         hRes = CONNECT_E_CANNOTCONNECT;
  5525.     if (FAILED(hRes))
  5526.         *pdwCookie = 0;
  5527.     return hRes;
  5528. }
  5529.  
  5530. template <class T, const IID* piid, class CDV>
  5531. STDMETHODIMP IConnectionPointImpl<T, piid, CDV>::Unadvise(DWORD dwCookie)
  5532. {
  5533.     T* pT = static_cast<T*>(this);
  5534.     pT->Lock();
  5535.     IUnknown* p = _CDV::GetUnknown(dwCookie);
  5536.     HRESULT hRes = m_vec.Remove(dwCookie) ? S_OK : CONNECT_E_NOCONNECTION;
  5537.     pT->Unlock();
  5538.     if (hRes == S_OK && p != NULL)
  5539.         p->Release();
  5540.     return hRes;
  5541. }
  5542.  
  5543. template <class T, const IID* piid, class CDV>
  5544. STDMETHODIMP IConnectionPointImpl<T, piid, CDV>::EnumConnections(
  5545.     IEnumConnections** ppEnum)
  5546. {
  5547.     if (ppEnum == NULL)
  5548.         return E_POINTER;
  5549.     *ppEnum = NULL;
  5550.     CComObject<CComEnumConnections>* pEnum = NULL;
  5551.     ATLTRY(pEnum = new CComObject<CComEnumConnections>)
  5552.     if (pEnum == NULL)
  5553.         return E_OUTOFMEMORY;
  5554.     T* pT = static_cast<T*>(this);
  5555.     pT->Lock();
  5556.     CONNECTDATA* pcd = NULL;
  5557.     ATLTRY(pcd = new CONNECTDATA[m_vec.end()-m_vec.begin()])
  5558.     if (pcd == NULL)
  5559.     {
  5560.         delete pEnum;
  5561.         pT->Unlock();
  5562.         return E_OUTOFMEMORY;
  5563.     }
  5564.     CONNECTDATA* pend = pcd;
  5565.     // Copy the valid CONNECTDATA's
  5566.     for (IUnknown** pp = m_vec.begin();pp<m_vec.end();pp++)
  5567.     {
  5568.         if (*pp != NULL)
  5569.         {
  5570.             (*pp)->AddRef();
  5571.             pend->pUnk = *pp;
  5572.             pend->dwCookie = _CDV::GetCookie(pp);
  5573.             pend++;
  5574.         }
  5575.     }
  5576.     // don't copy the data, but transfer ownership to it
  5577.     pEnum->Init(pcd, pend, NULL, AtlFlagTakeOwnership);
  5578.     pT->Unlock();
  5579.     HRESULT hRes = pEnum->_InternalQueryInterface(IID_IEnumConnections, (void**)ppEnum);
  5580.     if (FAILED(hRes))
  5581.         delete pEnum;
  5582.     return hRes;
  5583. }
  5584.  
  5585. /////////////////////////////////////////////////////////////////////////////
  5586. // IConnectionPointContainerImpl
  5587.  
  5588. template <class T>
  5589. class ATL_NO_VTABLE IConnectionPointContainerImpl : public IConnectionPointContainer
  5590. {
  5591.     typedef CComEnum<IEnumConnectionPoints,
  5592.         &IID_IEnumConnectionPoints, IConnectionPoint*,
  5593.         _CopyInterface<IConnectionPoint> >
  5594.         CComEnumConnectionPoints;
  5595. public:
  5596.     STDMETHOD(EnumConnectionPoints)(IEnumConnectionPoints** ppEnum)
  5597.     {
  5598.         if (ppEnum == NULL)
  5599.             return E_POINTER;
  5600.         *ppEnum = NULL;
  5601.         CComEnumConnectionPoints* pEnum = NULL;
  5602.         ATLTRY(pEnum = new CComObject<CComEnumConnectionPoints>)
  5603.         if (pEnum == NULL)
  5604.             return E_OUTOFMEMORY;
  5605.  
  5606.         int nCPCount;
  5607.         const _ATL_CONNMAP_ENTRY* pEntry = T::GetConnMap(&nCPCount);
  5608.  
  5609.         // allocate an initialize a vector of connection point object pointers
  5610.         IConnectionPoint** ppCP = (IConnectionPoint**)alloca(sizeof(IConnectionPoint*)*nCPCount);
  5611.  
  5612.         int i = 0;
  5613.         while (pEntry->dwOffset != (DWORD)-1)
  5614.         {
  5615.             ppCP[i++] = (IConnectionPoint*)((int)this+pEntry->dwOffset);
  5616.             pEntry++;
  5617.         }
  5618.  
  5619.         // copy the pointers: they will AddRef this object
  5620.         HRESULT hRes = pEnum->Init((IConnectionPoint**)&ppCP[0],
  5621.             (IConnectionPoint**)&ppCP[nCPCount],
  5622.             reinterpret_cast<IConnectionPointContainer*>(this), AtlFlagCopy);
  5623.         if (FAILED(hRes))
  5624.         {
  5625.             delete pEnum;
  5626.             return hRes;
  5627.         }
  5628.         hRes = pEnum->QueryInterface(IID_IEnumConnectionPoints, (void**)ppEnum);
  5629.         if (FAILED(hRes))
  5630.             delete pEnum;
  5631.         return hRes;
  5632.     }
  5633.     STDMETHOD(FindConnectionPoint)(REFIID riid, IConnectionPoint** ppCP)
  5634.     {
  5635.         if (ppCP == NULL)
  5636.             return E_POINTER;
  5637.         *ppCP = NULL;
  5638.         HRESULT hRes = CONNECT_E_NOCONNECTION;
  5639.         const _ATL_CONNMAP_ENTRY* pEntry = T::GetConnMap(NULL);
  5640.         IID iid;
  5641.         while (pEntry->dwOffset != (DWORD)-1)
  5642.         {
  5643.             IConnectionPoint* pCP =
  5644.                 (IConnectionPoint*)((int)this+pEntry->dwOffset);
  5645.             if (SUCCEEDED(pCP->GetConnectionInterface(&iid)) &&
  5646.                 InlineIsEqualGUID(riid, iid))
  5647.             {
  5648.                 *ppCP = pCP;
  5649.                 pCP->AddRef();
  5650.                 hRes = S_OK;
  5651.                 break;
  5652.             }
  5653.             pEntry++;
  5654.         }
  5655.         return hRes;
  5656.     }
  5657. };
  5658.  
  5659.  
  5660. #endif //!_ATL_NO_CONNECTION_POINTS
  5661.  
  5662. #pragma pack(pop)
  5663.  
  5664. /////////////////////////////////////////////////////////////////////////////
  5665. // CComAutoThreadModule
  5666.  
  5667. template <class ThreadAllocator>
  5668. inline HRESULT CComAutoThreadModule<ThreadAllocator>::Init(_ATL_OBJMAP_ENTRY* p, HINSTANCE h, const GUID* plibid, int nThreads)
  5669. {
  5670.     m_nThreads = nThreads;
  5671.     m_pApartments = NULL;
  5672.     ATLTRY(m_pApartments = new CComApartment[m_nThreads]);
  5673.     ATLASSERT(m_pApartments != NULL);
  5674.     if(m_pApartments == NULL)
  5675.         return E_OUTOFMEMORY;
  5676.     for (int i = 0; i < nThreads; i++)
  5677.         m_pApartments[i].m_hThread = CreateThread(NULL, 0, CComApartment::_Apartment, (void*)&m_pApartments[i], 0, &m_pApartments[i].m_dwThreadID);
  5678.     CComApartment::ATL_CREATE_OBJECT = RegisterWindowMessage(_T("ATL_CREATE_OBJECT"));
  5679.     return CComModule::Init(p, h, plibid);
  5680. }
  5681.  
  5682. template <class ThreadAllocator>
  5683. inline LONG CComAutoThreadModule<ThreadAllocator>::Lock()
  5684. {
  5685.     LONG l = CComModule::Lock();
  5686.     DWORD dwThreadID = GetCurrentThreadId();
  5687.     for (int i=0; i < m_nThreads; i++)
  5688.     {
  5689.         if (m_pApartments[i].m_dwThreadID == dwThreadID)
  5690.         {
  5691.             m_pApartments[i].Lock();
  5692.             break;
  5693.         }
  5694.     }
  5695.     return l;
  5696. }
  5697.  
  5698. template <class ThreadAllocator>
  5699. inline LONG CComAutoThreadModule<ThreadAllocator>::Unlock()
  5700. {
  5701.     LONG l = CComModule::Unlock();
  5702.     DWORD dwThreadID = GetCurrentThreadId();
  5703.     for (int i=0; i < m_nThreads; i++)
  5704.     {
  5705.         if (m_pApartments[i].m_dwThreadID == dwThreadID)
  5706.         {
  5707.             m_pApartments[i].Unlock();
  5708.             break;
  5709.         }
  5710.     }
  5711.     return l;
  5712. }
  5713.  
  5714. template <class ThreadAllocator>
  5715. HRESULT CComAutoThreadModule<ThreadAllocator>::CreateInstance(void* pfnCreateInstance, REFIID riid, void** ppvObj)
  5716. {
  5717.     _ATL_CREATORFUNC* pFunc = (_ATL_CREATORFUNC*) pfnCreateInstance;
  5718.     _AtlAptCreateObjData data;
  5719.     data.pfnCreateInstance = pFunc;
  5720.     data.piid = &riid;
  5721.     data.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  5722.     data.hRes = S_OK;
  5723.     int nThread = m_Allocator.GetThread(m_pApartments, m_nThreads);
  5724.     ::PostThreadMessage(m_pApartments[nThread].m_dwThreadID, CComApartment::ATL_CREATE_OBJECT, 0, (LPARAM)&data);
  5725.     AtlWaitWithMessageLoop(data.hEvent);
  5726.     CloseHandle(data.hEvent);
  5727.     if (SUCCEEDED(data.hRes))
  5728.         data.hRes = CoGetInterfaceAndReleaseStream(data.pStream, riid, ppvObj);
  5729.     return data.hRes;
  5730. }
  5731.  
  5732. template <class ThreadAllocator>
  5733. CComAutoThreadModule<ThreadAllocator>::~CComAutoThreadModule()
  5734. {
  5735.     for (int i=0; i < m_nThreads; i++)
  5736.     {
  5737.         ::PostThreadMessage(m_pApartments[i].m_dwThreadID, WM_QUIT, 0, 0);
  5738.         ::WaitForSingleObject(m_pApartments[i].m_hThread, INFINITE);
  5739.     }
  5740.     delete[] m_pApartments;
  5741. }
  5742.  
  5743.  
  5744. }; //namespace ATL
  5745.  
  5746. #endif // __ATLCOM_H__
  5747.  
  5748. /////////////////////////////////////////////////////////////////////////////
  5749.