代码改变世界

ATL 连接点例子(atlduck)

2011-07-16 20:44  Clingingboy  阅读(2247)  评论(0编辑  收藏  举报

 

一.客户端获取连接点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传入的接口)