代码改变世界

ATL 连接点例子(atlduck)

  Clingingboy  阅读(2257)  评论(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传入的接口)

编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示