• 回调方式进行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);
    

      

  • 相关阅读:
    投资理财知识小结1
    iOS中异常处理机制使用小结
    iOS中NSBundle使用小结
    ant design vue a-cascader 级联选择器 数据回显
    hbase数据存储及数据访问原理
    第15章: Prometheus监控Kubernetes资源与应用
    第14章:部署Java网站项目案例
    第13章:Kubernetes 鉴权框架与用户权限分配
    第12章:有状态应用部署
    第11章:Pod数据持久化
  • 原文地址:https://www.cnblogs.com/bigfi/p/7096071.html
Copyright © 2020-2023  润新知