基於VC編寫COM連接點事件的分析介紹

來源:互聯網
上載者:User

COM 中的典型方案是讓用戶端對象執行個體化伺服器對象,然後調用這些對象。然而,沒有一種特殊機制的話,這些伺服器對象將很難轉向並回調到用戶端對象。COM 連接點便提供了這種特殊機制,實現了伺服器和用戶端之間的雙向通訊。使用連接點,伺服器能夠在伺服器上發生某些事件時調用用戶端。

原理如:

有了連接點,伺服器可通過定義一個介面來指定它能夠引發的事件。伺服器上引發事件時,要採取操作的用戶端會向伺服器進行自行註冊。隨後,用戶端會提供伺服器所定義介面的實現。

用戶端可通過一些標準機制向伺服器進行自行註冊。COM 為此提供了 IConnectionPointContainer 和 IConnectionPoint 介面。

COM 連接點伺服器的用戶端可用 C++ 和 C# Managed 程式碼來編寫。C++ 用戶端會註冊一個類的執行個體,該類提供了接收器介面的實現。託管用戶端會註冊單個事件的委託,因而會按每個事件通知方法建立單個接收器,具體參考C#的互操作部分內容。

一、連接點程式編寫
1、使用ATL建立組件程式。
2、添加ATL SIMPLE OBJECT,支援連接點事件。
註:如果當時沒有現在連接點事件,可以在.idl檔案中手動添加。比如

複製代碼 代碼如下: [
uuid(57CCB7A5-F3B6-4990-91CD-33A82E1AAA46),
helpstring("IFunEvent dispinterface")
]
dispinterface _IFunEvent
{
properties:
// 事件介面沒有任何屬性
methods:
[id(1), helpstring("方法OnResult")] HRESULT OnResult([out,retval] LONG* retval);
[id(2), helpstring("方法OnType")] HRESULT OnType([in] LONG nType);
}

3、因為支援連接點事件,這樣將會自動產生一個 _XXXEVENT源介面。我們在其中增加想要觸發的方法。
4、選擇組件下的事件對象,彈出對話方塊選擇添加方法。可以繼續添加多個方法…
5、實現方法(其實組件裡只是做方法的申明,客戶調用時才實現這些方法)。實現時選中組件/類,按右鍵,在快顯功能表中選中implement connection....
就會產生CProxy_xxxEvent類,裡面有Fire函數的實現,都是自動產生的。
6、完成組件的其他介面函數。
組件的連接點編寫比較簡單,關鍵是如何在用戶端實現事件監聽與接收。在.NET下很容易實現。但在VC中比較繁瑣。
二、連接點用戶端實現(VC)
1、包含“工程_i.h”標頭檔,引入“工程.tlb”ole庫檔案。比如:
#include "ATLDemo_i.h"
#import "ATLDemo.tlb" named_guids raw_interfaces_only
2、建立一個類:由_IXXXEvent派生過來。(XXX為實際事件名)
實作類別各個虛函數重載,如果_IXXXEvent是IUnkown介面只需要重載QueryInterface、AddRef、Release函數;如果_IXXXEvent是雙向介面需要重載實現IUnkown介面三個函數和IDispatch介面四個函數。
實現事件功能,通過函數、用SINK_ENTRY_INFO實現事件的映射、Invoke函數裡面實現(通過事件ID)三種方法之一來實現。
用SINK_ENTRY_INFO實現事件的映射
如: 複製代碼 代碼如下:BEGIN_SINK_MAP(CEventSink)
SINK_ENTRY_INFO(1,DIID__INew01Events,DISPID_MSG,Msg,&MsgInfo)
END_SINK_MAP()

我在組件中定義了一個Msf函數,所以在這裡對其進行訊息隱射。然後實現Msg方法。
3、如何調用
3.1使用工程支援COM,使用afxoleinit或者CoInitialize/Un CoInitialize
3.2得到組件介面
3.3得到連接點容器,尋找連接點。
3.4利用Advise將一個監聽對象傳給組件,這樣當事件發生的時候事件就會響應。在不使用時,通過UnAdvise來中斷連線時間點事件。同時也利用AfxConnectionAdvice將監聽對象傳給組件介面。
3.5 釋放資源。
具體代碼如下:複製代碼 代碼如下:#pragma once

#include "ATLDemo_i.h"
#import "ATLDemo.tlb" named_guids raw_interfaces_only

class CSkin : public _IFunEvent
{
public:
CSkin(void);
~CSkin(void);
private:
DWORD m_dwRefCount;
public:
STDMETHODIMP Fire_OnType( LONG nType)
{
CString strTemp;
strTemp.Format(_T("The result is %d"), nType);
AfxMessageBox(strTemp);
return S_OK;;
}
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject)
{
if (iid == DIID__IFunEvent)
{
m_dwRefCount++;
*ppvObject = (void *)this;
return S_OK;
}

if (iid == IID_IUnknown)
{
m_dwRefCount++;
*ppvObject = (void *)this;
return S_OK;
}

return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE AddRef()
{
m_dwRefCount++;
return m_dwRefCount;
}

ULONG STDMETHODCALLTYPE Release()
{
ULONG l;

l = m_dwRefCount--;

if ( 0 == m_dwRefCount)
{
delete this;
}

return l;
}

HRESULT STDMETHODCALLTYPE GetTypeInfoCount(
/* [out] */ __RPC__out UINT *pctinfo)
{
return S_OK;
}

HRESULT STDMETHODCALLTYPE GetTypeInfo(
/* [in] */ UINT iTInfo,
/* [in] */ LCID lcid,
/* [out] */ __RPC__deref_out_opt ITypeInfo **ppTInfo)
{
return S_OK;
}

HRESULT STDMETHODCALLTYPE GetIDsOfNames(
/* [in] */ __RPC__in REFIID riid,
/* [size_is][in] */ __RPC__in_ecount_full(cNames) LPOLESTR *rgszNames,
/* [range][in] */ UINT cNames,
/* [in] */ LCID lcid,
/* [size_is][out] */ __RPC__out_ecount_full(cNames) DISPID *rgDispId)
{
return S_OK;
}

/* [local] */ HRESULT STDMETHODCALLTYPE Invoke(
/* [in] */ DISPID dispIdMember,
/* [in] */ REFIID riid,
/* [in] */ LCID lcid,
/* [in] */ WORD wFlags,
/* [out][in] */ DISPPARAMS *pDispParams,
/* [out] */ VARIANT *pVarResult,
/* [out] */ EXCEPINFO *pExcepInfo,
/* [out] */ UINT *puArgErr)
{
switch(dispIdMember) // 根據不同的dispIdMember,完成不同的回呼函數,事件函數的ID編號
{
case 2:
{
// 1st param : [in] long lValue.
VARIANT varlValue;
long lValue = 0;
VariantInit(&varlValue);
VariantClear(&varlValue);
varlValue = (pDispParams->rgvarg)[0];
lValue = V_I4(&varlValue);
Fire_OnType(lValue);
}
break;
default: break;
}

return S_OK;
}
};

#include "StdAfx.h"
#include "Skin.h"

CSkin::CSkin(void)
{
m_dwRefCount =0;
}

CSkin::~CSkin(void)
{
}

實現部分:複製代碼 代碼如下:CoInitialize(NULL);

CComPtr<IFun> pFun;
HRESULT hr = pFun.CoCreateInstance(CLSID_Fun);
if(hr!=S_OK)
{
return ;
}

IConnectionPointContainer *pCPC;
hr = pFun->QueryInterface(IID_IConnectionPointContainer,(void **)&pCPC);
if(!SUCCEEDED(hr))
{
return ;
}
IConnectionPoint *pCP;
hr = pCPC->FindConnectionPoint(DIID__IFunEvent,&pCP);
if ( !SUCCEEDED(hr) )
{
return ;
}
pCPC->Release();

IUnknown *pSinkUnk;
CSkin *pSink = new CSkin();
hr = pSink->QueryInterface(IID_IUnknown,(void **)&pSinkUnk);
DWORD dwAdvise;
hr = pCP->Advise(pSinkUnk,&dwAdvise);//接收器與連接點建立關聯

LONG c = 0;
pFun->Add(1,5,&c);
//pCP->Unadvise(dwAdvise) //中斷連線時間點事件
pCP->Release();
pFun.Release();

CoUninitialize();

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.