大家好!前几天刚到一家新公司,我参与的系统中是完全基于COM组件的开发,其中用到了大量的Connection Point方法,被逼无奈,只好抱一抱佛脚了,经过一段时间的学习,总算有了一些体会,来与大家分享一下,各位莫笑。
让我们用示例来说明:
COM服务器:
1.新建一个COM对象CA实现IA接口,利用向导来实现这一步。
2.添加IEvent接口的定义,并将它声明为COM对象A的外部接口(Outgoing Interface)
// CSDN.idl : IDL source for CSDN.dll //
// This file will be processed by the MIDL tool to // produce the type library (CSDN.tlb) and marshalling code.
import "oaidl.idl"; import "ocidl.idl"; [ object, uuid(2EE8F461-7200-4C13-A2FC-2552F8773089), dual, helpstring("IA Interface"), pointer_default(unique) ] interface IA : IDispatch {
[id(1), helpstring("method Init")] HRESULT Init(); };
[ object, uuid(C5C88155-7CAB-4109-9610-234A6AD529DC), dual, helpstring("IEvent Interface"), pointer_default(unique) ]
interface IEvent : IUnknown { [id(1), helpstring("method OnDataChanged")] HRESULT OnDataChanged(); };
[ uuid(477B6435-238C-43AF-95DA-2F890256DF43), version(1.0), helpstring("CSDN 1.0 Type Library") ] library CSDNLib { importlib("stdole32.tlb"); importlib("stdole2.tlb");
[ uuid(1FBB2F1E-E12E-4CE6-88EA-704E1CAE1091), helpstring("A Class") ] coclass A { [default] interface IA; [source] interface IEvent; }; };//end
其中红色代码为手工添加.IEvent UUID由GUIDGEN.EXE生成.IEvent 添加方法OnDataChanged.在客户端调用时添加功能代码,我们将在接口IEvent的Init方法中回调其方法。此处为Connection Point之精粹.在ActiveX中事件的实现方法也以此技术为基础.
3.编译程序后,点击COM对象Implement Connection Point...选项后,选中IEvent。则ATL向导将为我们生成新的实现联接点的COM对象CA。
class ATL_NO_VTABLE CA : public CComObjectRootEx<CComSingleThreadModel>, public CComCoClass<CA, &CLSID_A>, public IDispatchImpl<IA, &IID_IA, &LIBID_CSDNLib>, public CProxyIEvent< CA >, public IConnectionPointContainerImpl<CA>
4.实现IA接口的Init方法
STDMETHODIMP CA::Init() { AFX_MANAGE_STATE(AfxGetStaticModuleState())
Fire_OnDataChanged();
return S_OK; }
编译程序后,COM服务器的编码写成.
COM客户端实现:
1.实现接收器类
file://Event.h
class CEvent : public IEvent { public: // IUnknown ULONG __stdcall AddRef(); ULONG __stdcall Release(); HRESULT __stdcall QueryInterface(REFIID iid, void** ppv); //IEvent public: STDMETHOD(OnDataChanged)(); public: CEvent():m_cRef(0){} virtual ~CEvent(){} private: long m_cRef; };//end
//Event.cpp
ULONG CEvent::AddRef()
{ return InterlockedIncrement(&m_cRef); }
ULONG CEvent::Release() { if (InterlockedDecrement(&m_cRef) != 0) return m_cRef; delete this; return 0; }
HRESULT CEvent::QueryInterface(REFIID riid, void** ppv) { if (riid == IID_IUnknown) { *ppv = (IUnknown*)this; } else if (riid == IID_IEvent) { *ppv = (IEvent*)this; } else { *ppv = NULL; return E_NOINTERFACE; } AddRef(); return S_OK; }
STDMETHODIMP CEvent::OnDataChanged() { AfxMessageBox(_T("OnDataChanged!")); return S_OK; }
//end
在CEvent::OnDataChanged()中添加的实现将由接口IA的Init方法回调。
2.客户端实现代码
void CCSDNClientDlg::OnButton1()
{
CoInitialize(NULL);
IA* pIA = NULL; CEvent* pEvent = NULL; HRESULT hr = CoCreateInstance(CLSID_A,NULL, CLSCTX_INPROC_SERVER, IID_IA, (void**)&pIA);
if ( FAILED(hr) ) { AfxMessageBox("Initalize com failed!"); return ; } // if
IConnectionPointContainer* pConnectionPointContainer = NULL; IConnectionPoint* pConnectionPoint = NULL ;
pEvent= new CEvent(); pEvent->AddRef();
DWORD dwCookie;
hr = pIA->QueryInterface(IID_IConnectionPointContainer, (void**) &pConnectionPointContainer); //IRecord->Release(); ASSERT(SUCCEEDED(hr));
hr = pConnectionPointContainer->FindConnectionPoint(IID_IEvent, &pConnectionPoint);
ASSERT(SUCCEEDED(hr)); ConnectionPoint->Advise((IUnknown*)pEvent, &dwCookie); pConnectionPoint->Release();
hr = pIA->Init();//此处将激发事件OnDataChanged()
ASSERT(SUCCEEDED(hr));
hr = pConnectionPointContainer->FindConnectionPoint(IID_IEvent, &pConnectionPoint);
ASSERT(SUCCEEDED(hr)); pConnectionPoint->Unadvise(dwCookie); pConnectionPoint->Release();
pConnectionPointContainer->Release(); pIA->Release();
pEvent->Release(); // delete pEvent;
CoUninitialize(); }
//end
文笔不好,见谅了!
以上代码在VC++6.0中调试通过。
2001.8.23 
|