ATL实现Connection Point的一种简单的方法

类别:VC语言 点击:0 评论:0 推荐:

 

 

大家好!前几天刚到一家新公司,我参与的系统中是完全基于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.实现接收器类

file://Event.h

class CEvent  : public IEvent
{
public:
// IUnknown
 ULONG __stdcall AddRef();
 ULONG __stdcall Release();
 HRESULT __stdcall QueryInterface(REFIID iid, void** ppv);
//IEvent
public:
 STDMETHOD(OnDataChanged)();
public:
 CEvent():m_cRef(0){}
 virtual ~CEvent(){}
private:
 long m_cRef;
};//end

//Event.cpp

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;
}

//end

在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

本文地址:http://com.8s8s.com/it/it3077.htm