C++調用ATL事件連接點

在調用者工程中,需要增加“接收器”對象,添加一般的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();
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章