一.客户端获取连接点IConnectionPoint
LRESULT CMyDlg::OnCreateDoDuck(WORD wNotifyCode, WORD wID, HWND hwndCtl, BOOL& bHandled)
{
HRESULT hr;
IUnknown* pUnk = NULL;
IConnectionPointContainer* pConnPtContainer = NULL;
hr = CoCreateInstance(CLSID_DuckDoer, NULL, CLSCTX_LOCAL_SERVER, IID_IUnknown, (void**)&pUnk);
if (!SUCCEEDED(hr))
{
::MessageBox(m_hWnd, _T("Could not create DuckDoer object. Make sure the server is registered."),
_T("Object Instantiation Error."), MB_OK | MB_ICONINFORMATION);
return 0L;
}
ATLENSURE(pUnk != NULL);
hr = pUnk->QueryInterface(IID_IConnectionPointContainer, (void**)&pConnPtContainer);
ATLENSURE(SUCCEEDED(hr) && pConnPtContainer != NULL);
hr = pConnPtContainer->FindConnectionPoint(IID_IDuckInt, &m_pIDuckConnectionPoint);
ATLENSURE(SUCCEEDED(hr) && m_pIDuckConnectionPoint != NULL);
ATLENSURE(m_pDuckInt != NULL);
pUnk->Release();
pConnPtContainer->Release();
return 0L;
}
二.服务器和客户端都是一个exe,所以此时服务器会开启一个窗体
class CAtlDuckModule : public CAtlExeModuleT< CAtlDuckModule >
{
public:
DECLARE_REGISTRY_APPID_RESOURCEID(IDR_Atlduck, "{120B7294-65BF-11D0-9DDC-00A0C9034892}")
DECLARE_LIBID(LIBID_ATLDUCKLib)
HRESULT PreMessageLoop(int nShowCmd)
{
_ASSERT(CDuckDoer::m_pDlg == NULL);
CDuckDoer::m_pDlg = new CDuckDoerDlg();
CDuckDoer::m_pDlg->Create(NULL);
CDuckDoer::m_pDlg->ShowWindow(SW_SHOWNORMAL);
_ASSERT(CDuckDoer::m_pDlg != NULL);
HRESULT hr = CAtlExeModuleT<CAtlDuckModule>::PreMessageLoop(nShowCmd);
if (FAILED(hr))
return hr;
return S_OK;
}
};
三.客户端发送服务端一个接收器(调用Advise)
LRESULT CMyDlg::OnAdvise(WORD , WORD wID, HWND , BOOL& )
{
HRESULT hr;
ATLENSURE(m_pIDuckConnectionPoint != NULL);
hr = m_pIDuckConnectionPoint->Advise((IUnknown*)m_pDuckInt, &m_dwCookie);
return 0;
}
四.服务器端将此接收器存放起来
STDMETHODIMP CDuckDoer::Advise(IUnknown* pUnk, DWORD* pdwCookie)
{
if (!m_bLocked) // lock the server on the first advise received
{
((IDuckDoer*)this)->AddRef();
m_bLocked = TRUE;
}
HRESULT hr = CProxyIDuckInt<CDuckDoer>::Advise(pUnk, pdwCookie);
if (SUCCEEDED(hr))
{
…
}
return hr;
}
细节在CProxyIDuckInt<CDuckDoer>::Advise内部
五.服务器端通知客户端
LRESULT CDuckDoerDlg::OnQuack(WORD , WORD , HWND , BOOL& )
{
USES_CONVERSION;
TCHAR szWhosCalling[100];
_tcscpy_s(szWhosCalling, 100, _T("Server Quacking for Sink No. XX."));
CComBSTR szOut(szWhosCalling);
m_pObject->Fire_Quack(szOut);
return 1;
}
Fire_Quack代码可以自动生成,客户端必须有一个类实现了IDuckInt接口(就是通过调用Advise传入的接口)