MFC中实现连接点(下)
来源:互联网 发布:格式化软件 编辑:程序博客网 时间:2024/06/06 02:33
3.添加基类为CCmdTarget的类CConnObject.在类声明文件CConnObject1.h中加上#include “IConnObject.h”,在类声明中写入:
protected:
……
//声明实现IEventServer接口的嵌套类
BEGIN_INTERFACE_PART(EventServer,IEventServer)
STDMETHOD(DoSomething)();
END_INTERFACE_PART(EventServer)
DECLARE_INTERFACE_MAP()
//声明实现连接点的嵌套类
BEGIN_CONNECTION_PART(CConnObject,SampleConnPoint)
CONNECTION_IID(IID_IEventSink)
END_CONNECTION_PART(SampleConnPoint)
DECLARE_CONNECTION_MAP()
DECLARE_OLECREATE(CConnObject)
说明:BEGIN_CONNECTION_PART和END_CONNECTION_PART宏声明了实现连接点的嵌套类 SampleConnPoint,并且是基于CConnectionPoint类的,如果需要重载CConnectionPoint类的成员函数或者添加 自己的成员函数,可以在这两个宏中声明.这里,CONNECTION_IID宏重载了CConnectionPoint::GetIID()函数.使用 DECLARE_CONNECTION-MAP()宏声明连接点映射表.
4.在类CConnObject的实现文件中写入
IMPLEMENT_OLECREATE(CConnObject,"ConnObject",
0xee888b01, 0xea9c, 0x11d3, 0x97, 0xb5, 0x52, 0x54, 0xab, 0x19, 0x19, 0x30);
BEGIN_INTERFACE_MAP(CConnObject,CCmdTarget)
INTERFACE_PART(CConnObject,IID_IEventServer,EventServer)
INTERFACE_PART(CConnObject,IID_IConnectionPointContainer,ConnPtContainer)
END_INTERFACE_MAP()
BEGIN_CONNECTION_MAP(CConnObject,CCmdTarget)
CONNECTION_PART(CConnObject,IID_IEventSink,SampleConnPoint)
END_CONNECTION_MAP()
说明:A.必须在接口映射中写入INTERFACE_PART(CConnObject, IID_IConnectionPointContainer,ConnPtContainer)以实现 IConnectionPointContainer接口.注意,CCmdTarget类内嵌有才ConnPtContainer类以实现 IConnectionPointContainer接口,并用m_xConnPtContainer加以记录.
B.用BEGIN_CONNECTION_MAP和END_CONNECTION_MAP宏实现连接点映射.CONNECTION_PART定义了实现连接点的类.
5.在CConnObject::CConnObject()中写入:
EnableConnections();
6.实现IEventServer接口
IEventServer接口是基于IUnknown接口的,实现IUnknown接口的方法这里不在赘述.在实现文件中写入:
STDMETHODIMP
CConnObject::XEventServer::DoSomething()
{
//DoSomething
METHOD_PROLOGUE(CConnObject,EventServer)
pThis->FireEvent();
return S_OK;
}
DoSomething()方法可以为客户提供需要的服务.这里着重的是可连接对象在此处触发客户事件接收器的事件,FireEvent()函数是ConnObject类实现的专门触发事件的的函数,代码如下:
void CConnObject::FireEvent()
{
//获取连接点上的连接指针队列
const CPtrArray* pConnections = m_xSampleConnPoint.GetConnections();
ASSERT(pConnections!=NULL);
int cConnections = pConnections->GetSize();
IEventSink* pIEventSink;
//对每一个连接触发事件
for(int i = 0; i < cConnections; i++)
{
//获取客户事件接收器接口指针
pIEventSink = (IEventSink*)(pConnections->GetAt(i));
ASSERT(pIEventSink!=NULL);
//调用客户事件接受器事件处理函数
//此函数是出接口定义,由客户事件接收器实现的
pIEventSink->EventHandle();
}
}
3、客户事件接收器(Sink)
事件接收器也是COM对象,也可以用嵌套类来实现,但是它只是客户的一个内部对象,所以可以没有CLSID和类厂.下面示例是一个对话框程 序,对话框有三个按钮:”连接”(IDC_CONNECT),”断开”(IDC_DISCONNECT),”事件”(IDC_EVENT).
1.创建一个基于对话框的工程:ConnClient.
2.在CConnClientDlg中首先加入#include “IConnObject.h”,然后在对话框类声明中声明事件接收器嵌套类:
BEGIN_INTERFACE_PART(EventSink,IEventSink)
STDMETHOD(EventHandle)();
END_INTERFACE_PART(EventSink)
同时声明几个私有变量:
private:
LPCONNECTIONPOINTCONTAINER pConnPtCont;//记录组件对象
//IConnectionPointContainer接口指针
LPCONNECTIONPOINT pConnPt;//记录连接点接口指针
DWORD m_dwCookie;//记录连接标识
IUnknown* m_pIUnknown;//用以记录组件对象IUnknown接口指针
3.实现事件接收器:
STDMETHODIMP_(ULONG)
CConnClientDlg::XEventSink::AddRef()
{
return 1;
}
STDMETHODIMP_(ULONG)
CConnClientDlg::XEventSink::Release()
{
return 0;
}
STDMETHODIMP
CConnClientDlg::XEventSink::QueryInterface(REFIID riid,void** ppvObj)
{
METHOD_PROLOGUE(CConnClientDlg,EventSink)
if(IsEqualIID(riid,IID_IUnknown)||
IsEqualIID(riid,IID_IEventSink))
{
*ppvObj = this;
AddRef();
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
STDMETHODIMP
CConnClientDlg::XEventSink::EventHandle() //此函数将被可连接对象调用
{
::AfxMessageBox("源对象向事件接收器发出了的通知!");
return S_OK;
}
4.初始化COM库并创建组件对象实例
在CConnClientDlg::OninitDialog()中写入:
HRESULT hResult;
hResult = ::CoInitialize(NULL);
if(FAILED(hResult))
{
::AfxMessageBox("不能初始化COM库!");
return FALSE;
}
m_pIUnknown = NULL;
hResult = ::CoCreateInstance(CLSID_ConnObject,NULL,
CLSCTX_INPROC_SERVER,IID_IUnknown,(void**)&m_pIUnknown);
if(FAILED(hResult))
{
m_pIUnknown = NULL;
::AfxMessageBox("不能创建ConnObject对象!");
return FALSE;
}
m_dwCookie = 0;//预置连接标识为0
5.在按钮”连接”(IDC_CONNECT)的CLICK事件处理函数void CConnClientDlg::OnConnect()中写入:
void CConnClientDlg::OnConnect()
{
if(m_dwCookie!=0)
{
return;
}
if(m_pIUnknown!=NULL)
{
HRESULT hResult;
hResult = m_pIUnknown->QueryInterface(IID_IConnectionPointContainer,
(void**)&pConnPtCont);
if(FAILED(hResult))
{
::AfxMessageBox("不能获取对象的IConnectionPointContainer接口!");
return;
}
ASSERT(pConnPtCont!=NULL);
hResult = pConnPtCont->FindConnectionPoint(IID_IEventSink,&pConnPt);
if(FAILED(hResult))
{
pConnPtCont->Release();
::AfxMessageBox("不能获取对象的IEventSink连接点接口!");
return;
}
ASSERT(pConnPt!=NULL);
//获取事件接收器指针
IUnknown* pIEventSink;
m_xEventSink.QueryInterface(IID_IUnknown,(void**)&pIEventSink);
//通过连接点接口的Advise方法将事件接收器指针传给可连接对象
if(SUCCEEDED(pConnPt->Advise(pIEventSink,&m_dwCookie)))
{
::AfxMessageBox("与可连接对象ConnObject建立连接成功!");
}
else
{
::AfxMessageBox("不能与ConnObject建立连接!");
}
pConnPt->Release();
pConnPtCont->Release();
return;
}
}
上述代码与可连接对象的连接点建立连接.
6.编写按钮”断开”(IDC_DISCONNECT)的CLICK处理函数如下:
void CConnClientDlg::OnDisconnect()
{
if(m_dwCookie==0)
{
return;
}
pConnPt->Unadvise(m_dwCookie);
pConnPt->Release();
pConnPtCont->Release();
m_dwCookie = 0;
}
7.编写按钮”事件”(IDC_EVENT)的CLICK处理函数:
void CConnClientDlg::OnEvent()
{
if(m_pIUnknown!=NULL)
{
IEventServer* pIEventServer;
HRESULT hResult;
hResult = m_pIUnknown->QueryInterface(IID_IEventServer,(void**)&pIEventServer);
if(FAILED(hResult))
{
::AfxMessageBox("不能获取IEventServer接口!");
return;
}
pIEventServer->DoSomething();
}
}
这里,客户调用组件提供的服务DoSomething(),而正如前面所看到的,组件对象将在这个函数中触发一个由客户事件接收器处理(CConnClientDlg::XEventSink::EventHandle())的事件.
8.在退出应用时:
void CConnClientDlg::OnCancel()
{
m_pIUnknown->Release();
::CoUninitialize();
CDialog::OnCancel();
}
运行程序后,首先点击”连接”,然后点击”事件”按钮,这时将弹出MessageBox,并提示” 源对象向事件接收器发出了的通知!”.
小结
正是由于有了可连接对象这一机制,实现了客户与组件对象的双向通信,使组件对象具有了事件机制.这种类似于”服务器推送(Server push)”的技术在分布式应用系统中十分重要.
本文所举示例是用基于IUnknown接口实现的,其实,用自动化接口IDispatch作为出接口更为方便.需要说明的
是,用ATL来写可连接对象更为简洁,MSDN文档中有一个示例.
- MFC中实现连接点(下)
- MFC中实现连接点(上)
- MFC下连接点编程
- ATL中连接到连接点对象的实现
- ATL中连接到连接点对象的实现
- COM中的可连接对象与连接点机制及其MFC程序实现
- COM中的可连接对象与连接点机制及其MFC程序实现
- COM中的可连接对象与连接点机制及其MFC程序实现
- COM中的可连接对象与连接点机制及其MFC程序实现
- COM中的可连接对象与连接点机制及其MFC程序实现
- 11.MFC中实现可连接对象和接收器
- MFC下数据库的连接
- MFC利用Socket实现连接
- MFC中对话框工程下Datagrid控件实现分页
- 自定义类实现连接点
- MFC中连接SQL 数据库
- MFC下读取TXT点云文件
- MFC下读取TXT点云文件
- 占位:数据采集器
- 占位:SQL Server性能查看
- struts的标签库
- 漫步奥格瑞玛 Portal Scene Manager
- LMERR的PASCAL版本
- MFC中实现连接点(下)
- js 跳转
- 初次使用Gdi+
- 微软开发主管临别诤言
- WSAStartup()
- js 获得各种高度和宽度http://hi.baidu.com/jameszou/blog/item/680119d1cdf9a8d1562c847c.html
- MFC中实现连接点(上)
- 旧习惯稍不留神就回来了
- 如何创建单文档多视的结构