zoukankan      html  css  js  c++  java
  • 回调方式进行COM组件对外消息传递


    情景:被调用者--COM组件;调用者---外部程序
    作用:COM组件 到 外部程序 的消息传递
    方法:
    1.外部程序通过接口类对象,访问接口类的方法。COM对象通过连接点方式,进行消息的反向传递。
    2.外部程序通过接口类对象,访问接口类的方法。外部程序对接口类设置回调指针,进行消息的回调。

    本文讲第二种方法。
    直接上代码:

    1.添加新的接口类Iww,作为回调函数类。类似连接点对象的作用。

    interface Iww : IUnknown{
    [helpstring("method Fire_Result")] HRESULT Fire_Result([in] LONG nResult);
    };
    

      

    2.原有COM对象接口类,添加一个设置回调函数的方法Advise。

    interface Ivv : IUnknown{
    [helpstring("method Advise")] HRESULT Advise(Iww* pCallBack, [out] LONG* pdwCookie);
    [helpstring("method UnAdvise")] HRESULT UnAdvise(LONG dwCookie);
    [helpstring("method Add")] HRESULT Add(LONG n1, LONG n2);
    };
    

      

    接口类对象:

    class ATL_NO_VTABLE Cvv :
    public CComObjectRootEx<CComSingleThreadModel>,
    public CComCoClass<Cvv, &CLSID_vv>,
    public Ivv
    {
    public:
    Cvv()
    {
    for(int i=0; i<10; i++)	// 初始化所有的回调接口为 NULL
    {
    m_pCallBack[i] = NULL;
    }
    }
    
    DECLARE_REGISTRY_RESOURCEID(IDR_VV)
    
    
    BEGIN_COM_MAP(Cvv)
    COM_INTERFACE_ENTRY(Ivv)
    END_COM_MAP()
    
     
    
    DECLARE_PROTECT_FINAL_CONSTRUCT()
    
    HRESULT FinalConstruct()
    {
    return S_OK;
    }
    
    void FinalRelease()
    {
    }
    
    public:
    
    private:
    Iww * m_pCallBack[10];
    public:
    STDMETHOD(Advise)(Iww* pCallBack, LONG* pdwCookie);
    STDMETHOD(UnAdvise)(LONG dwCookie);
    STDMETHOD(Add)(LONG n1, LONG n2);
    };
    
    OBJECT_ENTRY_AUTO(__uuidof(vv), Cvv)
    
    STDMETHODIMP Cvv::Advise(Iww* pCallBack, LONG* pdwCookie)
    {
    // TODO: Add your implementation code here
    if( NULL == pCallBack )
    return E_INVALIDARG;
    
    for( int i=0; i<10; i++)	// 寻找一个保存该接口指针的位置
    {
    if( NULL == m_pCallBack[i] )	// 找到了
    {
    m_pCallBack[i] = pCallBack;	// 保存到数组中
    m_pCallBack[i]->AddRef();	// 指针计数器 +1
    
    *pdwCookie = i + 1;	// cookie 就是数组下标
    // +1 的目的是避免使用0,因为0表示无效
    
    return S_OK;
    }
    }
    return E_OUTOFMEMORY;	// 超过10个连接,内存不够用啦
    }
    
    STDMETHODIMP Cvv::UnAdvise(LONG dwCookie)
    {
    // TODO: Add your implementation code here
    if( dwCookie<1 || dwCookie>10 )	// 这是谁干的呀?乱给参数
    return E_INVALIDARG;
    
    if( NULL == m_pCallBack[ dwCookie - 1 ] )	// 参数错误,或该接口指针已经无效了
    return E_INVALIDARG;
    
    m_pCallBack[ dwCookie -1 ]->Release();	// 指针计数器 -1
    m_pCallBack[ dwCookie -1 ] = NULL;	// 空出该下标的数组元素
    
    return S_OK;
    }
    
    STDMETHODIMP Cvv::Add(LONG n1, LONG n2)
    {
    // TODO: Add your implementation code here
    long nResult = n1 + n2;
    for( int i=0; i<10; i++)
    {
    if( m_pCallBack[i] )	//如果回调接口有效
    m_pCallBack[i]->Fire_Result( nResult );	// 则发出事件/通知
    }
    
    return S_OK;
    }
    

      

    3.外部程序,新建一个类继承Iww,并实现raw_Fire_Result方法。
    #import "..ee.tlb" no_namespace

    class CSink :public Iww
    {
    public:
    CSink(void);
    ~CSink(void);
    
    STDMETHOD(QueryInterface)(const struct _GUID &iid,void ** ppv);
    ULONG __stdcall CSink::AddRef(void);
    ULONG __stdcall CSink::Release(void);
    STDMETHOD(raw_Fire_Result)(long);
    };
    CSink::CSink(void)
    {
    }
    
    CSink::~CSink(void)
    {
    }
    // STDMETHODIMP 是宏,等价于 long __stdcall
    STDMETHODIMP CSink::QueryInterface(const struct _GUID &iid,void ** ppv)
    {
    *ppv=this;
    return S_OK;
    }
    
    ULONG __stdcall CSink::AddRef(void)
    {	return 1;	}	// 做个假的就可以,因为反正这个对象在程序结束前是不会退出的
    
    ULONG __stdcall CSink::Release(void)
    {	return 0;	}	// 做个假的就可以,因为反正这个对象在程序结束前是不会退出的
    
    STDMETHODIMP CSink::raw_Fire_Result(long nResult)
    {	
    // 如果完成了连接,当计算有结果后,该函数会被调用。完成组件通知的功能
    CString str;
    str.Format(_T("%d"),nResult);
    MessageBox(str);
    return S_OK;
    }
    

      

    4.调用步骤

    CSink m_sink;
    IvvPtr m_spCom;
    DWORD m_dwCookie;
    
    HRESULT hr = m_spCom.CreateInstance(__uuidof(vv) );
    if( FAILED( hr ) )
    {
    AfxMessageBox( _T("COM对象初始化失败") );
    CDialog::OnCancel();	
    }
    hr = m_spCom->Advise( &m_sink, (long *)&m_dwCookie );
    if( SUCCEEDED( hr ) )
    {
    AfxMessageBox( _T("Advise调用成功。已经正确连接") );
    }
    else
    {
    AfxMessageBox( _T("Advise 调用失败") );
    }
    m_spCom->Add(1,5);
    

      

  • 相关阅读:
    86. Partition List
    2. Add Two Numbers
    55. Jump Game
    70. Climbing Stairs
    53. Maximum Subarray
    64. Minimum Path Sum
    122. Best Time to Buy and Sell Stock II
    以场景为中心的产品设计方法
    那些产品经理犯过最大的错
    Axure教程:如何使用动态面板?动态面板功能详解
  • 原文地址:https://www.cnblogs.com/bigfi/p/7096071.html
Copyright © 2011-2022 走看看