zoukankan      html  css  js  c++  java
  • ATL 线程触发事件解决方案

    步骤1

    将下以代码另存为:ATLCPImplMT.h,将ATLCPImplMT.h复制应用项目

    // This is a supplement to the Active Template Library 3.0.
    // Copyright (C) 2000 Microsoft Corporation
    // All rights reserved.
    //
    // This source code is only intended for illustration.

    #ifndef __CPIMPLMT_H__
    #define __CPIMPLMT_H__

    #include <atlcom.h>

    //////////////////////////////////////////////////////////////////////////////
    // IConnectionPointImplMT: Used instead of IConnectionPointImpl:
    template <class T, const IID* piid, class CDV = CComDynamicUnkArray>
    class ATL_NO_VTABLE IConnectionPointImplMT : public _ICPLocator<piid>
    {
     typedef CComEnum<IEnumConnections, &IID_IEnumConnections, CONNECTDATA,
      _Copy<CONNECTDATA> > CComEnumConnections;

     // Use CDV, but store DWORDs instead of IUnknown pointers.
     // ASSUMPTION: sizeof(DWORD) == sizeof(IUnknown *):
     typedef CDV _CDV;
    public:
     // Added constructor:
     IConnectionPointImplMT();

     ~IConnectionPointImplMT();
     STDMETHOD(_LocCPQueryInterface)(REFIID riid, void ** ppvObject)
     {
      if (InlineIsEqualGUID(riid, IID_IConnectionPoint) || InlineIsEqualUnknown(riid))
      {
       if (ppvObject == NULL)
        return E_POINTER;
       *ppvObject = this;
       AddRef();
    #ifdef _ATL_DEBUG_INTERFACES
       _Module.AddThunk((IUnknown**)ppvObject, _T("IConnectionPointImplMT"), riid);
    #endif // _ATL_DEBUG_INTERFACES
       return S_OK;
      }
      else
       return E_NOINTERFACE;
     }

     STDMETHOD(GetConnectionInterface)(IID* piid2)
     {
      if (piid2 == NULL)
       return E_POINTER;
      *piid2 = *piid;
      return S_OK;
     }
     STDMETHOD(GetConnectionPointContainer)(IConnectionPointContainer** ppCPC)
     {
      T* pT = static_cast<T*>(this);
      // No need to check ppCPC for NULL since QI will do that for us
      return pT->QueryInterface(IID_IConnectionPointContainer, (void**)ppCPC);
     }
     STDMETHOD(Advise)(IUnknown* pUnkSink, DWORD* pdwCookie);
     STDMETHOD(Unadvise)(DWORD dwCookie);
     STDMETHOD(EnumConnections)(IEnumConnections** ppEnum);
     CDV m_vec;

     // Using the GIT for access across threads:
     IGlobalInterfaceTable *m_pGIT;

     // Need a separate critical section object:
     CComGlobalsThreadModel::AutoCriticalSection m_CPMTCritSec;

     // For each generated function (named Fire_{EventName}) within the proxy class:
     // Comment out the following lines, within the generated for loop:
     // pT->Lock();
     // CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex);
     // pT->Unlock();
     //
     // Instead, use this function as follows:
     // CComPtr<IUnknown> sp;
     // sp.Attach (GetInterfaceAt(nConnectionIndex));
     LPUNKNOWN GetInterfaceAt(int nConnectionIndex);
    };

    template <class T, const IID* piid, class CDV>
    IConnectionPointImplMT<T, piid, CDV>::IConnectionPointImplMT()
    {
     // Get the GIT per-process singleton:
     CoCreateInstance(CLSID_StdGlobalInterfaceTable, 0,
      CLSCTX_INPROC_SERVER,
      IID_IGlobalInterfaceTable,
      reinterpret_cast<void**>(&m_pGIT));
     ATLASSERT(m_pGIT != NULL);
    }

    template <class T, const IID* piid, class CDV>
    IConnectionPointImplMT<T, piid, CDV>::~IConnectionPointImplMT()
    {
     // Revoke interfaces from the GIT:
     DWORD* pDWCookie = (DWORD *)(m_vec.begin());
     while (pDWCookie < (DWORD *) (m_vec.end()))
     {
      if (*pDWCookie != NULL)
      {
       m_pGIT->RevokeInterfaceFromGlobal(*pDWCookie);
      }
      pDWCookie++;
     }
    }

    template <class T, const IID* piid, class CDV>
    STDMETHODIMP IConnectionPointImplMT<T, piid, CDV>::Advise(IUnknown* pUnkSink,
     DWORD* pdwCookie)
    {
     IUnknown* p;
     HRESULT hRes = S_OK;
     if (pUnkSink == NULL || pdwCookie == NULL)
      return E_POINTER;
     IID iid;
     GetConnectionInterface(&iid);
     hRes = pUnkSink->QueryInterface(iid, (void**)&p);
     if (SUCCEEDED(hRes))
     {
      m_CPMTCritSec.Lock();
      DWORD dwGITCookie;
      hRes = m_pGIT->RegisterInterfaceInGlobal(
       p, iid, &dwGITCookie);
      if(hRes == S_OK)
      {
       // Using the CCom(Dynamic)UnkArray to store the cookie instead of an IUnknown *:
       *pdwCookie = m_vec.Add(reinterpret_cast<IUnknown *>(dwGITCookie));
       hRes = (*pdwCookie != NULL) ? S_OK : CONNECT_E_ADVISELIMIT;

       if (hRes != S_OK)
        m_pGIT->RevokeInterfaceFromGlobal(dwGITCookie);
      }
      m_CPMTCritSec.Unlock();
      // GIT will have AddRef'ed p:
      p->Release();
     }
     else if (hRes == E_NOINTERFACE)
      hRes = CONNECT_E_CANNOTCONNECT;
     if (FAILED(hRes))
      *pdwCookie = 0;
     return hRes;
    }

    template <class T, const IID* piid, class CDV>
    STDMETHODIMP IConnectionPointImplMT<T, piid, CDV>::Unadvise(DWORD dwCookie)
    {
     m_CPMTCritSec.Lock();
     
        //DWORD dwGITCookie = (DWORD)_CDV::GetUnknown(dwCookie);

        DWORD dwGITCookie = (DWORD)m_vec.GetUnknown(dwCookie);

     HRESULT hRes = m_vec.Remove(dwCookie) ? S_OK : CONNECT_E_NOCONNECTION;
     m_CPMTCritSec.Unlock();
     if (hRes == S_OK && dwGITCookie != NULL)
     {
      hRes = m_pGIT->RevokeInterfaceFromGlobal(dwGITCookie);
     }

     return hRes;
    }

    template <class T, const IID* piid, class CDV>
    STDMETHODIMP IConnectionPointImplMT<T, piid, CDV>::EnumConnections(
     IEnumConnections** ppEnum)
    {
     if (ppEnum == NULL)
      return E_POINTER;
     *ppEnum = NULL;
     CComObject<CComEnumConnections>* pEnum = NULL;
     ATLTRY(pEnum = new CComObject<CComEnumConnections>)
     if (pEnum == NULL)
      return E_OUTOFMEMORY;
     m_CPMTCritSec.Lock();
     CONNECTDATA* pcd = NULL;
     ATLTRY(pcd = new CONNECTDATA[m_vec.end()-m_vec.begin()])
     if (pcd == NULL)
     {
      delete pEnum;
      m_CPMTCritSec.Unlock();
      return E_OUTOFMEMORY;
     }
     CONNECTDATA* pend = pcd;
     // Copy the valid CONNECTDATA's
     for (DWORD* pDWCookie = (DWORD *)(m_vec.begin());pDWCookie<(DWORD *)(m_vec.end());pDWCookie++)
     {
      if (*pDWCookie != NULL)
      {
       IID iid;
       GetConnectionInterface(&iid);
       IUnknown *pUnk;

       HRESULT hr = m_pGIT->GetInterfaceFromGlobal(
        *pDWCookie, iid, reinterpret_cast<void **>(&pUnk));

       if(hr == S_OK)
       {
        // AddRef() implicit in GetInterfaceFromGlobal():
        pend->pUnk = pUnk;
        
                    //pend->dwCookie = _CDV::GetCookie(reinterpret_cast<IUnknown **>(pDWCookie));    
                    pend->dwCookie = m_vec.GetCookie(reinterpret_cast<IUnknown **>(pDWCookie));

                    pend++;
       }
      }
     }
     // don't copy the data, but transfer ownership to it
     pEnum->Init(pcd, pend, NULL, AtlFlagTakeOwnership);
     m_CPMTCritSec.Unlock();
     HRESULT hRes = pEnum->_InternalQueryInterface(IID_IEnumConnections, (void**)ppEnum);
     if (FAILED(hRes))
      delete pEnum;
     return hRes;
    }

    template <class T, const IID* piid, class CDV>
    LPUNKNOWN IConnectionPointImplMT<T, piid, CDV>::GetInterfaceAt(
     int nConnectionIndex)
    {
     m_CPMTCritSec.Lock();

     LPUNKNOWN pUnk = NULL;
     // IConnectionPointImplMT Vector stores DWORDs instead of IUnknown pointers,
     // explicit cast required:
     DWORD dwGITCookie = (DWORD)(m_vec.GetAt(nConnectionIndex));
     if (dwGITCookie != NULL)
     {
      IID iid;
      GetConnectionInterface(&iid);
      HRESULT hr = m_pGIT->GetInterfaceFromGlobal(
       dwGITCookie, iid, reinterpret_cast<void **>(&pUnk));
      ATLASSERT(hr == S_OK);
     }

     m_CPMTCritSec.Unlock();

     return pUnk;
    }

    #endif // __CPIMPLMT_H__

    步骤2

    找到项目_xxxxxEvents_CP.h

    template<class T>

    class CProxy_IXXXEvents :

      public IConnectionPointImpl<T, &__uuidof(_IXXXEvents)>

    改为:

    template<class T>

    class CProxy_IXXXEvents :

    public IConnectionPointImplMT<T, &__uuidof(_IXXXEvents), CComDynamicUnkArray>

     

    在CProxy_IXXXEvents类实现中,修改触发函数Fire_XXXX(…),将   pThis->Lock();

                         CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);

                         pThis->Unlock();

                         修改为:

                         CComPtr<IUnknown> punkConnection;

                punkConnection.Attach (GetInterfaceAt(iConnection));

    步骤3

    在你的调用线程中,记着要在线程开始和结束时初始化和卸载com库,调用CoInitializeEx(NULL, COINIT_MULTITHREADED);和CoUninitialize();函数;现在可以在其他线程中调用触发函数Fire_XXX函数了!

    本人测试环境VS2008+SP1

  • 相关阅读:
    synchronized介绍
    volatile介绍
    docker开启远程访问
    docker时间同步解决办法
    spring boot集成docker
    vue踩坑-Error: listen EADDRNOTAVAIL 192.168.1.122:8081
    大前端(全栈)学习路线指南
    做前端技术方案选型的时候,你是怎么做决策的?
    小程序源码丢失了怎么在微信平台反编译找回
    做前端技术方案选型的时候,你是怎么做决策的?
  • 原文地址:https://www.cnblogs.com/ytjjyy/p/2453352.html
Copyright © 2011-2022 走看看