• 2009-03-17

    My first ATL COM with connection point - [ATL]

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://xingzhesun.blogbus.com/logs/36677081.html

    ///

    1.连接点 事件接口_IAddEvents包含连个方法AddCompleted 和IsOK
    2.两个接口IAdd和ISub
    IAdd 中的方法包括AddLongVal和IsOK在该方法中都fire一个事件。
    Fire事件的过程:
    Fire Event->Fire_EventHandle(CProxy_IAddEvents)->Invoke方法(客户端从IAddEvent派生)->调用客户端的方法。

    // SHM.idl : IDL source for SHM
    //

    // This file will be processed by the MIDL tool to
    // produce the type library (SHM.tlb) and marshalling code.

    import "oaidl.idl";
    import "ocidl.idl";

    [
     object,
     uuid(A986F54E-A7C9-4B16-B542-450BAAAF84F5),
     dual,
     nonextensible,
     helpstring("IAdd Interface"),
     pointer_default(unique)
    ]
    interface IAdd : IDispatch{
     [id(1), helpstring("method AddLongVal")] HRESULT AddLongVal([in] LONG lVal, [in] LONG rVal, [out,retval] LONG* retVal);
     [id(2), helpstring("method IsOK")] HRESULT IsOK([in] BSTR bstrOK);
    };
    [
     object,
     uuid(480C3EF7-812E-4818-9860-6729B56C62F2),
     dual,
     nonextensible,
     helpstring("ISub Interface"),
     pointer_default(unique)
    ]

    interface ISub : IDispatch{
     [id(1), helpstring("method SubFun")] HRESULT SubFun([in] LONG lVal, [in] LONG rVal, [out,retval] LONG* retVal);
    };
    [
     uuid(7002FB8A-F615-4710-81AB-716F1A3ADD06),
     version(1.0),
     helpstring("SHM 1.0 Type Library")
    ]
    library SHMLib
    {
     importlib("stdole2.tlb");
     [
      uuid(5F66AE9F-1DFC-4621-B7A7-D0EFE04E0118),
      helpstring("_IAddEvents Interface")
     ]
     dispinterface _IAddEvents
     {
      properties:
      methods:
       [id(1), helpstring("method AddCompleted")] HRESULT AddCompleted([in] LONG val);
       [id(2), helpstring("method AddOK")] HRESULT IsOK(BSTR* szOK);
     };
     [
      uuid(AD7ABE60-1865-45E4-AE0B-ED16B1A9F5D1),
      helpstring("Add Class")
     ]
     coclass Add
     {
      [default] interface IAdd;
      interface ISub;
      [default, source] dispinterface _IAddEvents;
     };
    };

     

    ///CAdd

    // Add.h : Declaration of the CAdd

    #pragma once
    #include "resource.h"       // main symbols

    #include "SHM_i.h"
    #include "_IAddEvents_CP.h"


    #if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)
    #error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms."
    #endif

     

    // CAdd

    class ATL_NO_VTABLE CAdd :
     public CComObjectRootEx<CComSingleThreadModel>,
     public CComCoClass<CAdd, &CLSID_Add>,
     public IConnectionPointContainerImpl<CAdd>,
     public CProxy_IAddEvents<CAdd>,
     public IDispatchImpl<IAdd, &IID_IAdd, &LIBID_SHMLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,
     public IDispatchImpl<_IAddEvents, &__uuidof(_IAddEvents), &LIBID_SHMLib, /* wMajor = */ 1, /* wMinor = */ 0>,
     public IDispatchImpl<ISub, &__uuidof(ISub), &LIBID_SHMLib, /* wMajor = */ 1, /* wMinor = */ 0>
    {
    public:
     CAdd()
     {
     }

     DECLARE_REGISTRY_RESOURCEID(IDR_ADD)


     BEGIN_COM_MAP(CAdd)
      COM_INTERFACE_ENTRY(IAdd)
      COM_INTERFACE_ENTRY2(IDispatch, _IAddEvents)
      COM_INTERFACE_ENTRY(IConnectionPointContainer)
      COM_INTERFACE_ENTRY(_IAddEvents)
      COM_INTERFACE_ENTRY(ISub)
     END_COM_MAP()

     BEGIN_CONNECTION_POINT_MAP(CAdd)
      CONNECTION_POINT_ENTRY(__uuidof(_IAddEvents))
     END_CONNECTION_POINT_MAP()


     DECLARE_PROTECT_FINAL_CONSTRUCT()

     HRESULT FinalConstruct()
     {
      return S_OK;
     }

     void FinalRelease()
     {
     }

    public:

     STDMETHOD(AddLongVal)(LONG lVal, LONG rVal, LONG* retVal);

     // _IAddEvents Methods
    public:
     STDMETHOD(AddCompleted)( LONG val)
     {
      // Add your function implementation here.
      return E_NOTIMPL;
     }

     STDMETHOD(IsOK)(BSTR bstrOK);

     // ISub Methods
    public:
     STDMETHOD(SubFun)( LONG lVal,  LONG rVal,  LONG * retVal)
     {
      *retVal = lVal - rVal;
      return S_OK;
     }
    };

    OBJECT_ENTRY_AUTO(__uuidof(Add), CAdd)

    ///CProxy_IAddEvents<T>

    #pragma once

    template<class T>
    class CProxy_IAddEvents :
     public IConnectionPointImpl<T, &__uuidof(_IAddEvents)>
    {
    public:
     HRESULT Fire_AddCompleted( LONG val)
     {
      HRESULT hr = S_OK;
      T * pThis = static_cast<T *>(this);
      int cConnections = m_vec.GetSize();

      for (int iConnection = 0; iConnection < cConnections; iConnection++)
      {
       pThis->Lock();
       CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);
       pThis->Unlock();

       IDispatch * pConnection = static_cast<IDispatch *>(punkConnection.p);

       if (pConnection)
       {
        CComVariant avarParams[1];
        avarParams[0] = val;
        avarParams[0].vt = VT_I4;
        CComVariant varResult;

        DISPPARAMS params = { avarParams, NULL, 1, 0 };
        hr = pConnection->Invoke(1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, &varResult, NULL, NULL);
       }
      }
      return hr;
     }

     HRESULT Fire_IsOK( BSTR bstrOK)
     {
      HRESULT hr = S_OK;
      T * pThis = static_cast<T *>(this);
      int cConnections = m_vec.GetSize();

      for (int iConnection = 0; iConnection < cConnections; iConnection++)
      {
       pThis->Lock();
       CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);
       pThis->Unlock();

       IDispatch * pConnection = static_cast<IDispatch *>(punkConnection.p);

       if (pConnection)
       {
        CComVariant avarParams[1];
        avarParams[0] = bstrOK;
        avarParams[0].vt = VT_BSTR;
        CComVariant varResult;

        DISPPARAMS params = { avarParams, NULL, 1, 0 };
        hr = pConnection->Invoke(2, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, &varResult, NULL, NULL);
       }
      }
      return hr;
     }
    };

    ///client

    // Client.cpp : Defines the entry point for the application.
    //

    #include "stdafx.h"
    #include "Client.h"
    #include <atlbase.h>
    #include <atlcom.h>
    #include <atlimpl.cpp>
    #include "..\shm\SHM_i.h"
    #include "..\shm\SHM_i.C"


    #define MAX_LOADSTRING 100

    // Global Variables:
    HINSTANCE hInst;        // current instance
    TCHAR szTitle[MAX_LOADSTRING];     // The title bar text
    TCHAR szWindowClass[MAX_LOADSTRING];   // the main window class name

    CComModule _Module;


    class CUserATLCom
    {
    public:
     CUserATLCom()
     {
      CoInitialize(NULL);
     }
     ~CUserATLCom()
     {
      CoUninitialize();
     }
    };


    class CAddEvents:public CComObjectRoot
     , public _IAddEvents
    {
    public:
     CAddEvents(){};

    BEGIN_COM_MAP(CAddEvents)
     COM_INTERFACE_ENTRY(IDispatch)
     COM_INTERFACE_ENTRY(_IAddEvents)
    END_COM_MAP()

    // IUnknown


    //IAddEvents
    public:
     STDMETHODIMP GetTypeInfoCount(UINT *)
     {
      return E_NOTIMPL;
     }

     STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo ** ppTInfo)
     {
      return E_NOTIMPL;
     }

     STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID *rgDisID)
     {
      return E_NOTIMPL;
     }

     STDMETHODIMP Invoke(DISPID dispIdMember,
          REFIID riid,
          LCID lcid,
          WORD wFlags,
          DISPPARAMS* pDisParams,
          VARIANT* pVarResult,
          EXCEPINFO* pExcepInfo,
          UINT* pnArgErr)
     {
      switch(dispIdMember)
      {
      case 0x1:
       { if (pDisParams->cArgs != 1)
        {
         return DISP_E_BADPARAMCOUNT;
        }
        if (pDisParams->cNamedArgs)
        {
         return DISP_E_NONAMEDARGS;
        }

        //Coerce the argument into a long
        HRESULT hr;
        VARIANTARG var;
        VariantInit(&var);
        hr = VariantChangeType(&var, &(pDisParams->rgvarg[0]), 0, VT_I4);


        if FAILED(hr)
        {
         return DISP_E_BADVARTYPE;
        }

        AddCompleted(var.lVal);

        break;

       }
      case 0x2:
       {
        if (pDisParams->cArgs != 1)
        {
         return DISP_E_BADPARAMCOUNT;
        }
        if (pDisParams->cNamedArgs)
        {
         return DISP_E_NONAMEDARGS;
        }

        //Coerce the argument into a long
        HRESULT hr;
        VARIANTARG var;
        VariantInit(&var);
        hr = VariantChangeType(&var, &(pDisParams->rgvarg[0]), 0, VT_BSTR);


        if FAILED(hr)
        {
         return DISP_E_BADVARTYPE;
        }

        AddOk(var.bstrVal);
       }

       break;
       default:
        {
         ATLASSERT(FALSE);
        }
          break;
      }
     }

     STDMETHODIMP AddCompleted( LONG val)
     {
      LONG i = val;
      return S_OK;
     }


     STDMETHODIMP AddOk(BSTR bstrOK)
     {
      CComBSTR str(bstrOK);
      return S_OK;
     }
    };
    CUserATLCom _gUserATL;

    // Forward declarations of functions included in this code module:
    ATOM    MyRegisterClass(HINSTANCE hInstance);
    BOOL    InitInstance(HINSTANCE, int);
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);

    int APIENTRY _tWinMain(HINSTANCE hInstance,
                         HINSTANCE hPrevInstance,
                         LPTSTR    lpCmdLine,
                         int       nCmdShow)
    {
     UNREFERENCED_PARAMETER(hPrevInstance);
     UNREFERENCED_PARAMETER(lpCmdLine);

     _Module.Init(NULL, hInstance);

     //get Add com
     CComPtr<IAdd> ptrAdd;
     HRESULT hr;
     hr = CoCreateInstance(CLSID_Add, NULL, CLSCTX_SERVER, IID_IAdd, (void**)&ptrAdd);

     //get Add events
      CComObject<CAddEvents>* ptrAddEvents;
      CComObject<CAddEvents>::CreateInstance(&ptrAddEvents);
     
     //get pointer to the IUNKNOWN interface
     CComPtr<IUnknown>ptrEventsUnk = ptrAddEvents;


     DWORD dwCookie;
     hr = AtlAdvise(ptrAdd,ptrEventsUnk, DIID__IAddEvents, &dwCookie);
     if (FAILED(hr))
     {
      ATLASSERT(FALSE);
     }


     //fire connection point
     LONG lVal;
     ptrAdd->AddLongVal(1, 2, &lVal);
     ptrAdd->IsOK(BSTR("a"));


     //unadvise
     AtlUnadvise(ptrAdd, DIID__IAddEvents, dwCookie);


     //queryInter ISub interface
     CComPtr<ISub> ptrSub;
     hr = ptrAdd->QueryInterface(IID_ISub, (void**)&ptrSub);

     if(FAILED(hr))
     {
      ATLASSERT(FALSE);
     }

     //call the function of ISub
     ptrSub->SubFun(4,1,&lVal);


     return 1;

     
    }

     

     


    历史上的今天:


    收藏到:Del.icio.us




    评论

  • 你好!我最近也在写关于COM的一个东西,有点问题没弄明白,进程外的服务能用连接点吗?我就是我想用连接点实现两个进程通信,一个是MFC一个是ATL。方便的话能否回答帮一下忙。谢谢!!!