1、idl定义outgoing 接口(_ICtrlNetworkEvent)。
// 此文件将由 MIDL 工具处理以
// 产生类型库(Ctrl.tlb)和封送处理代码。
import "oaidl.idl";
import "ocidl.idl";
[
uuid(FFD6C786-5D9B-4206-9F63-ACD3BEFF6481),
version(1.0),
helpstring("MediaCtrl 1.0 类型库")
]
library CtrlLib
{
importlib("stdole2.tlb");
[
uuid(FFD6C786-5D9B-4206-9F63-ACD3BEFF648B),
helpstring("_ICtrlNetworkEvent")
]
dispinterface _ICtrlNetworkEvent
{
properties:
methods:
[id(1), helpstring("method OnNetStateChanged")] HRESULT OnNetworkStateChanged([in] BOOL bOnLine);
};
[
uuid(FFD6C786-5D9B-4206-9F63-ACD3BEFF6488),
helpstring("Ctrl Class")
]
coclass Ctrl
{
//[default] interface ICtrl;
//[default, source] dispinterface _ICtrlEvents;
[source] dispinterface _ICtrlNetworkEvent;
};
};
2、发布者(server)(com object)实现一个连接点类。增加连接点映射。
//_ICtrlNetworkEvent .h
#pragma once
template<class T>
class CProxy_ICtrlNetworkEvent : public IConnectionPointImpl<T, &__uuidof(_ICtrlNetworkEvent), CComDynamicUnkArray>
{
public:
HRESULT Fire_OnNetworkStateChanged(BOOL bOnline)
{
HRESULT hr = S_OK;
T * pThis = static_cast<T*> (this);
int s = m_vec.GetSize();
for (int i = 0; i < s; i++)
{
pThis->Lock();
CComPtr<IUnknown> punkConnection = m_vec.GetAt(i);
pThis->Unlock();
IDispatch * pConnection = static_cast<IDispatch *>(punkConnection.p);
if (pConnection)
{
CComVariant avarParams[1];
avarParams[0] = bOnline;
avarParams[0].vt = VT_BOOL;
CComVariant varResult;
DISPPARAMS params = { avarParams, NULL, 1, 0 };
hr = pConnection->Invoke(1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, ¶ms, &varResult, NULL, NULL);//1 对应方法的dispid
}
}
return hr;
}
};
//发布者
#include "_CtrlNetworkEvent_CP.h"
class ATL_NO_VTABLE CCtrl :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CCtrl, &CLSID_Ctrl>,
public IConnectionPointContainerImpl<CCtrl>,
public CProxy_ICtrlNetworkEvent<CCtrl>,
public IDispatchImpl<ICtrl, &IID_ICtrl, &LIBID_CtrlLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,
{
public:
CCtrl();
DECLARE_REGISTRY_RESOURCEID(IDR_CTRL)
BEGIN_COM_MAP(CCtrl)
COM_INTERFACE_ENTRY(ICtrl)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(IConnectionPointContainer)
END_COM_MAP()
BEGIN_CONNECTION_POINT_MAP(CCtrl)
CONNECTION_POINT_ENTRY(__uuidof(_ICtrlNetworkEvent))
END_CONNECTION_POINT_MAP()
DECLARE_PROTECT_FINAL_CONSTRUCT()
//functions
};
3、订阅者(client)(com object)实现outgoing接口。增加sink映射。
//事件实现类,实现outgoing接口
//CtrlNetworkEvent.h
#pragma once
class CCtrlNetworkEvent :public IDispEventSimpleImpl<1, CCtrlNetworkEvent, &DIID__ICtrlNetworkEvent>
{
public:
CCtrlNetworkEvent(){};
virtual ~CCtrlNetworkEvent(){};
inline virtual void __stdcall OnNetworkStateChanged(BOOL bOnline){};
static _ATL_FUNC_INFO FuncInfo_OnNetworkStateChanged;
BEGIN_SINK_MAP(CCtrlNetworkEvent)
SINK_ENTRY_INFO(1, DIID__ICtrlNetworkEvent, 1, OnNetworkStateChanged,&FuncInfo_OnNetworkStateChanged)
END_SINK_MAP()
};
//CtrlNetworkEvent.c
#pragma once
#include "CtrlNetworkEvent.h"
_ATL_FUNC_INFO CCtrlNetworkEvent::FuncInfo_OnNetworkStateChanged= { CC_STDCALL, VT_EMPTY, 1, {VT_BOOL}};
//事件订阅者
//CtrlFrame.h
#include "CtrlNetworkEvent.h"
class CCtrlFrame : public CCtrlNetworkEvent
{
public:
CCtrlFrame(void);
~CCtrlFrame(void);
//_ICtrlNetworkEvent
virtual void __stdcall OnNetworkStateChanged(BOOL bOnline);
//others
private:
CComPtr<ICtrl>m_spCtrl;
};
4、通常在订阅者类中实现对发布者的事件连接。DispEventAdvise();/DispEvent
//CtrlFrame.cpp
//把事件实现编译进来,该头文件也可以加在工程中的任意cpp文件中。
#include "CtrlNetworkEvent.c"
void Init()
{
hr = CCtrlNetworkEvent::DispEventAdvise(m_spCtrl, &__uuidof(_ICtrlNetworkEvent));//m_spCtrl为Ctrl
}
void Finit()
{
CCtrlNetworkEvent::DispEventUnadvise(m_spCtrl, &__uuidof(_ICtrlNetworkEvent));
}