分享

C++调用ATL事件连接点

 QomoIT 2011-12-08
在调用者工程中,需要增加“接收器”对象,添加一般的C++类对象,从IDispatch 派生,然后完成继承的虚函数,如创建
CSink类,继承自IDispatch ,完成Simple16库中触发事件的接收器。
// 头文件
#pragma once
#include "oaidl.h"
class CSink :
 public IDispatch
{
public:
 CSink(void);
 ~CSink(void);
 
 STDMETHOD(QueryInterface)(const struct _GUID &iid,void ** ppv);
 ULONG __stdcall AddRef(void);
 ULONG __stdcall Release(void);
 // IDispatch
 STDMETHOD(GetTypeInfoCount)(unsigned int *);
 STDMETHOD(GetTypeInfo)(unsigned int,unsigned long,struct ITypeInfo ** );
 STDMETHOD(GetIDsOfNames)(const IID &,LPOLESTR *,UINT,LCID,DISPID *);
 STDMETHOD(Invoke)(long dispID,const struct _GUID &,unsigned long,unsigned short,struct tagDISPPARAMS * pParams,struct tagVARIANT *,struct tagEXCEPINFO *,unsigned int *);
};
 
// CPP文件
#include "StdAfx.h"
#include "Sink.h"
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::GetTypeInfoCount(unsigned int *)
{ return E_NOTIMPL; } // 不用实现,反正也不用
STDMETHODIMP CSink::GetTypeInfo(unsigned int,unsigned long,struct ITypeInfo ** )
{ return E_NOTIMPL; } // 不用实现,反正也不用
STDMETHODIMP CSink::GetIDsOfNames(const IID &,LPOLESTR *,UINT,LCID,DISPID *)
{ return E_NOTIMPL; } // 不用实现,反正也不用
STDMETHODIMP CSink::Invoke(
         long dispID,
         const struct _GUID &,
         unsigned long,
         unsigned short,
struct tagDISPPARAMS * pParams,
struct tagVARIANT *,
struct tagEXCEPINFO *,
 unsigned int *)
{       // 只需要实现这个就足够啦
 switch(dispID)
 {
 case 1: //根据不同的dispID,完成不同的回调函数
//   if( !m_pEdit )
//   {
//    AfxMessageBox( _T("没有调用 SetResultWnd() 设置显示结果的窗口") );
//   }
//   else
  {
   CString str;
   str.Format( _T("%d"), pParams->rgvarg[0].lVal );
   AfxMessageBox(str);
//   m_pEdit->SetWindowText( str );
  }
  break;
 case 2:
  {
   CString str;
   str.Format(_T("%d"), pParams->rgvarg[0].lVal);
   CString strData;
   strData = pParams->rgvarg[1].bstrVal;
  }
  break;
 default:
  AfxMessageBox( _T("怎么可能,根本就没有这个号码的函数呀") );
  break;
 }
 return S_OK;
}
假设是基于对话框的MFC应用程序,可以在Dlg中的头文件中做如下定义:
// 接收器对象
 CSink m_Sink;
 // 组件接口指针
 // 采用import DLL方式引入库时由于使用了命名空间,所以在使用库中的接口或对象时需要加入库的名称和::(Simple16Lib::)
 // 二采用import tlb no_namespace方式引入库时,不需要使用命名空间
 /*Simple16Lib::*/IDispConnectPtr m_spObj;
 // 连接点指针
 CComQIPtr<IConnectionPoint> m_spCP;
 // 连接点的cookie
 DWORD m_dwCookie;
 
// 在CPP文中的可以使用如下代码创建对象
m_dwCookie = 0;
 HRESULT hr = m_spObj.CreateInstance(_T("Simple16.DispConnect"));
 if (FAILED(hr))
 {
  AfxMessageBox(_T("没有注册还是没有初始化?"));
  CDialog::OnCancel();
 }
 // 得到连接点容器接口
 CComQIPtr<IConnectionPointContainer> spContainer(m_spObj);
 if (!spContainer)
 {
  AfxMessageBox(_T("组件没有提供连接点功能"));
 }
 // 得到连接点
 spContainer->FindConnectionPoint(__uuidof(/*Simple16Lib::*/_IDispConnectEvents), &m_spCP);
 if (!m_spCP)
 {
  AfxMessageBox(_T("没有找到连接点接口"));
 }
/* 第二个连接点
 spContainer->FindConnectionPoint(__uuidof(/*Simple16Lib::*/_IDispConnectEvents2), &m_spCPTime);
 if (!m_spCPTime)
 {
  AfxMessageBox(_T("没有找到Time连接点接口"));
 }
*/
 // 连接
 hr = m_spCP->Advise(&m_Sink, &m_dwCookie);
 if (FAILED(hr))
 {
  AfxMessageBox(_T("连接失败"));
 }
/*
 hr = m_spCPTime->Advise(&m_SinkTime, &m_dwCookieTime);
 if (FAILED(hr))
 {
  AfxMessageBox(_T("连接Time失败"));
 }
*/
 
在需要断开连接的地方使用:
if (m_spCP)
 {
  m_spCP->Unadvise(m_dwCookie);
  m_spCP.Release();
 }

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多