大家好!前几天刚到一家新公司,我参与的系统中是完全基于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.实现接收器类
class CEvent : public IEvent
{
public:
// IUnknown
ULONG __stdcall AddRef();
ULONG __stdcall Release();
HRESULT __stdcall QueryInterface(REFIID iid, void** ppv);
public:
STDMETHOD(OnDataChanged)();
public:
CEvent():m_cRef(0){}
virtual ~CEvent(){}
private:
long m_cRef;
};//end
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;
}
在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