`
阿尔萨斯
  • 浏览: 4472110 次
社区版块
存档分类
最新评论

ATL7.1创建连接点组件

 
阅读更多
基础理论:
1) 源对象和接收器对象
接收器对象实现某个接口,源对象拥有该接口的指针,源对象可以调用该接口的方法。从而形成源对象以事件的方式通知接受器对象的效果。一个连接包含两部分,源对象和接收器对象。如图:
ISpeaker接口和_ISpeakerEvents接口对于各自的实现对象Demagogue和EarPolitic对象来说,只是个普通的接口。但是,由于Demagogue拥有了EarPolitic对象实现的_ISpeakerEvents接口的指针,使得_ISpeakerEvents变得特殊起来,Demagogue可以调用它的方法来通知EarPolitic对象,形成了“事件”。
2) 建立/断开连接
连接由EarPolitic对象建立,连接也由EarPolitic对象断开。
如果EarPolitic对象要建立连接,它需要通知Demagogue对象它已经实现了_ISpeakerEvents接口。如果要断开连接,它也需要通知Demagogue对象。如何通知呢:Demaogogue对象应该针对_ISpeakerEvents接口实现一个对应接口IConForSpeakerEvents,该接口要提供Advise和UnAdvise两个方法,这样EarPolitic对象通过调用这两个方法来通知Demagogue对象建立连接或者断开连接。
3)连接点
IConForSpeakerEvents接口存在的目的只是为了让EarPolitic对象获得建立、断开对_ISpeakerEvents接口的方法。因此可以把连接事件接口的动作抽象出来,交由IConnectionPoint(连接点)来管理。
连接点允许接收器对象将事件接口的指针传送给源对象。接收器对象通过调用源对象的IConnectionPoint接口的方法Advise来建立连接。IConnectionPoint接口的方法Unadvise用来断开连接。(也可以运用AtlAdvise和AtlUnadvise函数来简化工作)。
IConnectionPoint : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE GetConnectionInterface(
/* [out] */ IID *pIID) = 0;
virtual HRESULT STDMETHODCALLTYPE GetConnectionPointContainer(
/* [out] */ IConnectionPointContainer **ppCPC) = 0;
virtual HRESULT STDMETHODCALLTYPE Advise(
/* [in] */ IUnknown *pUnkSink,
/* [out] */ DWORD *pdwCookie) = 0;
virtual HRESULT STDMETHODCALLTYPE Unadvise(
/* [in] */ DWORD dwCookie) = 0;
virtual HRESULT STDMETHODCALLTYPE EnumConnections(
/* [out] */ IEnumConnections **ppEnum) = 0;
};
Advise方法我们可以看出EarPolitic对象的指针交给了连接点对象后,Demagogue对象会在合适的时候调用该接口的方法,形成“事件”。
4) 同时支持多个连接点
一个连接点对象对应一个事件接口,所以如果有不止一个事件接口,就应该有不止一个的连接点对象为其提供连接服务。
IConnectionPointContainer作为包容器,可以包容若干个IConnectionPoint对象。这就实现了同时支持多个连接点。
ATL中,IConnectionPointImpl类是用来实现IConnectionPoint对象的。ATL中,连接点映射表用来存放连接点的必要信息,该表中的每个表项存放连接点接口的GUID。比如:
IConnectionPointContainer接口负责管理多个IConnectionPoint接口。请看定义:
IConnectionPointContainer : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE EnumConnectionPoints(
/* [out] */ IEnumConnectionPoints **ppEnum) = 0;
virtual HRESULT STDMETHODCALLTYPE FindConnectionPoint(
/* [in] */ REFIID riid,
/* [out] */ IConnectionPoint **ppCP) = 0;
};
FindConnectionPoint方法可以很方便的获得容器内部管理的连接对象指针,而IEnumConnectionPoints接口是为了方便枚举容器内部的每个连接对象接口的。
IEnumConnectionPoints : public IUnknown
{
public:
virtual /* [local] */ HRESULT STDMETHODCALLTYPE Next(
/* [in] */ ULONG cConnections,
/* [length_is][size_is][out] */ LPCONNECTIONPOINT *ppCP, // typedef IConnectionPoint* LPCONNECTIONPOINT;
/* [out] */ ULONG *pcFetched) = 0;
virtual HRESULT STDMETHODCALLTYPE Skip(
/* [in] */ ULONG cConnections) = 0;
virtual HRESULT STDMETHODCALLTYPE Reset( void) = 0;
virtual HRESULT STDMETHODCALLTYPE Clone(
/* [out] */ IEnumConnectionPoints **ppEnum) = 0;
};
连接点容器管理了不止一个的连接点,那么这些连接点的信息是如何存储的呢?ATL中使用了连接点映射表来存放连接点管理的事件接口的IID.下面的宏
BEGIN_CONNECTION_POINT_MAP(CDemagogue)
CONNECTION_POINT_ENTRY(DIID__ISpeakerEvents)
END_CONNECTION_POINT_MAP()
用来将DIID__ISpeakerEvents存放到连接点映射表中。
我们的组件类必须保存事件接口指针,如何保存呢,我们的类从CProxy_IEvent1Events<CMyClass>中派生。CProxy_IEvent1Events类又从IConnectionPointImpl类派生。IConnectionPointImpl类里面有一个成员变量m_vec,这通常是一个CComDynamicUnkArray类的变量,CComDynamicUnkArray内部维护了IUnknown**数组
当EarPolitic对象调用IConnectionPointImpl::Advise方法建立连接时,实际上该事件接口指针被加入到m_vec变量中。因此当我们需要激发事件时,实际上就是找到m_vec中保存的对应的接口指针,并调用相应的方法。
CProxy_IEvent1Events将提供很多名称类似于Fire_OnMethod的方法,这些辅助方法将帮助我们发出事件。
工程范例:
1)创建EventSource的ATL项目
2)添加组件类
注意由于COM+采用的事件方式与COM不同,所以,不要选择添加COM+1.0组件,而应该选择添加ATL简单对象。
支持连接点
向导生成后我们检查代码:
idl文件里面
import "oaidl.idl";
import "ocidl.idl";
[
object,
uuid(C74F7F62-D315-4BF6-9422-9B80D68DB4FA),
dual,
nonextensible,
helpstring("ISample 接口"),
pointer_default(unique)
]
interface ISample : IDispatch{
};
[
uuid(48D59498-7F95-4C2B-B3C3-B5DA3B407025),
version(1.0),
helpstring("EventSource 1.0 类型库")
]
library EventSourceLib
{
importlib("stdole2.tlb");
[
uuid(87A653F3-F08F-4C1F-B091-5F8FAA894E3C),
helpstring("_ISample事件接口")
]
dispinterface _ISampleEvents
{
properties:
methods:
};
[
uuid(6CC7B493-5F8E-4C08-B66D-D9E5FD2342E0),
helpstring("Sample Class")
]
coclass Sample
{
[default] interface ISample;
[default, source] dispinterface _ISampleEvents;
};
};
红色的就是本组件首选的事件接口。ISampleEvents接口目前没有提供方法和属性。
类的声明如下:
class ATL_NO_VTABLE CSample :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CSample, &CLSID_Sample>,
public ISupportErrorInfo,
public IConnectionPointContainerImpl<CSample>,
public CProxy_ISampleEvents<CSample>,
public IDispatchImpl<ISample, &IID_ISample, &LIBID_EventSourceLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
IConnectionPointContainerImpl和CProxy_ISampleEvents<CSample>两个父类是关键。
BEGIN_COM_MAP(CSample)
COM_INTERFACE_ENTRY(ISample)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(ISupportErrorInfo)
COM_INTERFACE_ENTRY(IConnectionPointContainer)
END_COM_MAP()
COM MAP宏表明了对象支持IConnectionPointContainer接口
BEGIN_CONNECTION_POINT_MAP(CSample)
CONNECTION_POINT_ENTRY(__uuidof(_ISampleEvents))
END_CONNECTION_POINT_MAP()
上面这个宏将_ISampleEvents接口的IID保存到连接点映射表中。
3)添加事件方法
我们现在想要在_ISampleEvents接口上添加方法OnEvent1(BSTR Msg);当该事件被激发时,通过参数Msg将传递给接收对象一个BSTR。在未来的设计中,接收对象将显示这个Msg。我们将通过向导帮我们实现这个事件方法。
右键点击_IsampleEvents接口,选择“添加方法“。填写下面的对话框。
完成后idl文件将作如下增加:
dispinterface _ISampleEvents
{
properties:
methods:
[id(1), helpstring("方法OnEvent1")] HRESULT OnEvent1([in] BSTR Msg);
};
我们手工的在CProxy_ISampleEvents类添加共有成员函数,该函数辅助激发事件
HRESULT Fire_OnEvent1(BSTR Msg)
{
CComVariant varResult;
T* pT=static_cast<T*>(this);
int nConIndex;
CComVariant* pvars=new CComVariant[1];
int nConnections=m_vec.GetSize();
for(nConIndex=0;nConIndex<nConnections;nConIndex++)
{
CComPtr<IUnknown> sp=m_vec.GetAt(nConIndex);
IDispatch* pDispatch=reinterpret_cast<IDispatch*>(sp.p);
if(pDispatch!=NULL)
{
VariantClear(&varResult);
pvars[0].vt=VT_BSTR;
pvars[0].bstrVal=SysAllocString(Msg);
DISPPARAMS disp={pvars,NULL,1,0};
pDispatch->Invoke(0x1,IID_NULL,LOCALE_USER_DEFAULT,DISPATCH_METHOD,&disp,&varResult,NULL,NULL);
}
}
return varResult.scode;
}
通过向导实现Fire_OnEvent1方法也很简单,右键点击CSample,添加连接点,如图:
点击完成后,向导将生成Fire_OnEvent1的实现代码。
最后,我们添加一个ISample接口的方法Start,当该方法被调用时,他将激发_ISampleEvents接口的事件方法OnEvent1。该方法的实现很简单
STDMETHODIMP CSample::Start(void)
{
// TODO: 在此添加实现代码
CComBSTR Msg(L"haha");
Fire_OnEvent1(Msg);
return S_OK;
}
一切好了,我们下面将编写接受器对象。
分享到:
评论

相关推荐

    WDK7.1.0分离出的ATL7.1

    6. **连接点**:ATL提供了连接点支持,使得一个对象可以暴露自己的事件或方法供其他对象调用。 7. **优化的内存管理**:ATL的内存管理机制有助于减少内存泄漏和提高性能。 WDK中的ATL7.1特别适用于驱动程序开发,...

    迅雷 atl71.dll 文件下载

    5. **连接点**:ATL提供了对连接点的支持,允许COM组件之间进行事件传递。 6. **字符串处理**:ATL包含了一些高效字符串处理的函数和宏,以减少内存分配和释放的开销。 7. **模板元编程**:ATL使用模板元编程技术...

    ATL71.DLL

    4. **连接点**:ATL支持连接点(Connection Points)机制,允许对象向其他对象发布事件或接收事件。 5. ** ATL Simple Objects**:提供了一组基础对象,如CComObject、CComCoClass等,可以快速创建简单的COM对象。 6...

    Visual C++实践与提高-COM和COM+篇『PDF』

    4.1.4 建立接收器与连接点的连接 4.1.5 获得出接口的类型信息 4.2 结构化存储 4.2.1 什么叫结构化存储和复合文件 4.2.2 存储对象和IStorage接口 4.2.2.1 IStorage接口 4.2.2.2 获得IStorage指针 4.2.2.3 释放STATSTG...

    COM技术内幕——微软组件对象模型--随书源代码

    CruiseYoung提供的带有详细书签的电子书籍目录 ... 该资料是《COM技术内幕——微软组件对象模型》一书的随书源代码 COM技术内幕——微软... 13.5 事件和连接点 290 13.5.1 IEnumXXX 292 13.6 本章小结 293 结束语 294

    从.NET库模拟COM连接点

    本文将深入探讨如何从一个MFC/ATL COM客户端模拟COM连接点来访问VB.NET库,这对于那些需要在现有COM系统中集成.NET组件的开发者来说尤其重要。 首先,理解COM连接点的概念至关重要。COM连接点是一种机制,允许COM...

    VC++数据库编程

    - **ATL对数据库访问的支持**:利用ATL创建高性能的数据库访问组件。 #### 三、数据库开发过程 - **阶段1:调查与分析**:明确业务需求。 - **阶段2:数据建模**:设计数据库表结构。 - **阶段3:功能设计**:确定...

    MFC+Access 数据库编程

    ### MFC+Access 数据库编程知识点详解 #### 一、基础知识篇 **1.1 数据库基本原理** - **概述**:数据库是按照一定结构存储和管理数据的仓库。它不仅包括存储数据本身,还包括相应的元数据(描述数据的数据)。在...

    VC数据库编程三步教学

    - **ATL对数据库访问的支持**:ATL支持创建高性能的数据库访问组件,可以用于开发复杂的应用程序。 #### 三、数据库开发过程 ##### 3.1 阶段1:调查与分析 - **目的**:明确项目的需求,包括业务流程、数据流图、...

    在新窗口中打开一个URL

    在Windows编程环境中,特别是使用Visual Studio(如VC7.0, VC7.1, 或者VC6)进行MFC (Microsoft Foundation Classes) 或ATL (Active Template Library) 开发时,实现这一功能会涉及一些关键的技术点。 1. **MFC中的...

    ActiveX托管的WTL类

    ActiveX托管的WTL类是Windows Template Library (WTL)框架的一个重要组成部分,它扩展了ATL(Active Template Library)的功能,使得在C++中创建和管理ActiveX控件变得更加简便。WTL是一个轻量级的库,主要用于构建...

    大丽花调试设备浏览器栏

    6. **与ATL项目集成**:对于使用ATL技术构建的COM组件和ActiveX控件,大丽花调试设备浏览器栏能提供更深入的调试支持。 提供的压缩文件`Dahlia-Debug-Device-Browser-Bar.pdf`很可能是该工具的使用手册或详细文档,...

    McGraw C++程序调试实用手册

    16.2 创建一个ATL多边形工程 16.2.1 优化模块代码 16.2.2 测试控件 16.3 调试ATLCOM控件 16.4 小结 第17章 STL和 MFC编程 17.l 产生一个STL和MFC应用程序 17.1.l 复数 17.1.2 模板语法 17.1.3 基本的...

Global site tag (gtag.js) - Google Analytics