WEB开发网
开发学院软件开发VC 用ATL建立轻量级的COM对象(4) 阅读

用ATL建立轻量级的COM对象(4)

 2006-07-21 11:44:34 来源:WEB开发网   
核心提示: (*ppv = LPBYTE(pThis) + pEntries[n].dw)->AddRef();这个偏移量的初始化通常参照基类接口的偏移量,如果pFunc非空且不等于_ATL_SIMPLEMAPENTRY,用ATL建立轻量级的COM对象(4)(3),则它指向的函数将被调用,将这个
(*ppv = LPBYTE(pThis) + pEntries[n].dw)->AddRef();这个偏移量的初始化通常参照基类接口的偏移量。如果pFunc非空且不等于_ATL_SIMPLEMAPENTRY,则它指向的函数将被调用,将这个指针作为第一个参数传递给对象而第二个参数是多用途值dw。 return pEntries[n].pFunc(pThis, riid, ppv,
             pEntries[n].dw);
这个接口映射的最后一个入口将使用pFunc值,指示映射的结束。 如果没有在映射中发现任何接口则InternalQueryInterface 会返回E_NOINTERFACE。 接口映射通常为ATL的接口映射宏。ATL提供17个不同的宏,它们支持大多数用于实现接口的普通技术(多继承,嵌套类,聚合或者tear-offs。)这些宏及其相应的原始代码请参见附表三。下面是一个使用CComObjectRootEx和接口映射实现IPager2 和IMessageSource类的例子: class CPager
 : public IMessageSource, public IPager2,
  public CComObjectRootEx<CComMultiThreadModel>{
public:
  CPager(void) {}
  virtual ~CPager(void) {}
BEGIN_COM_MAP(CPager)
  COM_INTERFACE_ENTRY(IMessageSource)
  COM_INTERFACE_ENTRY(IPager2)
  COM_INTERFACE_ENTRY(IPager)
END_COM_MAP()
  STDMETHODIMP GetNextMessage(OLECHAR **ppwsz);
  STDMETHODIMP SendMessage(const COLECHAR * pwsz);
  STDMETHODIMP SendUrgentMessage(void);
};
前面的代码产生的接口映射如下: { &IID_IMessageSource, 0, _ATL_SIMPLEMAPENTRY },
{ &IID_IPager2, 4, _ATL_SIMPLEMAPENTRY },
 { &IID_IPager, 4, _ATL_SIMPLEMAPENTRY},
 { 0, 0, 0 }
  在建立接口映射时,ATL假设映射中第一个入口是个简单映射入口并用它来满足对IID_IUnknown.的请求。 除了支持IUnknown外,ATL提供大量缺省的COM接口实现。ATL用一个简单的命名规范来为这些实现命名,它们大多数都是作为模板类来实现的,带有一个模板参数,而这些模板参数才是是既要实现的类。 一个简单的例子是IObjectWithSite接口,它一般用于为某个对象提供一个指向激活现场的指针。ATL为这个指针提供了一个缺省的实现:IObjectWithSiteImpl。此类提供了一个IObjectWithSite兼容的二进制签名并且实现了所有的IObjectWithSite方法。为了使用ATL内建的实现,你只需要添加基类实现(用适当的模板参数),然后在接口映射中添加一个入口输出经过QueryInterface实现的接口。 例如,为了使用ATL的IObjectWithSite实现,按照如下步骤来做: class CPager
 : public CComObjectRootEx,
  public IPager,
  public IObjectWithSiteImpl
 {
public:
BEGIN_COM_MAP(CPager)
  COM_INTERFACE_ENTRY(IPager)
  COM_INTERFACE_ENTRY_IMPL(IObjectWithSite)
END_INTERFACE_MAP()
  STDMETHODIMP SendMessage(const COLECHAR * pwsz);
};
由于使用了ATL内建的实现类,也就有了COM_INTERFACE_ENTRY_IMPL宏。之所以要用只个宏是因为许多ATL的缺省实现不从它们实现的接口派生。这样的话就导致标准的COM_ INTERFACE_ENTRY宏返回不正确的偏移量。例如,因为CPager不从IObjectWithSite派生,用于计算偏移量的强制类型转换就不会在对象中反映,而是用起始位置代替。 在这个例子中,IObjectWithSiteImpl没有基类。而是按照在IObjectWithSite中一样的顺序声明它的虚函数,产生全兼容的vtable(虚表)结构。ATL使用这个有点不可思议的技术,原因是它允许缺省实现支持接口的引用计数,这一点使用常规多继承技术是很难做到的。 IDispatchImpl也是一个常用的ATL缺省实现。这个类实现用于双接口的四个IDispatch方法,由你的类实现IDispatch::Invoke所不能完成的方法。不像大多数其它的ATL实现,这个类实际上是从一个COM接口派生的,有几个模板参数: template <
  class T,      // 双接口
  const IID* piid,  // 双接口IID
  const GUID* plibid, // 包含类型库TypeLib
  WORD wMajor = 1,  // 类型库的版本
  WORD wMinor = 0,  //类型库的版本
  class tihclass = CComTypeInfoHolder
>
class IDispatchImpl : public T { ... };
假设两个接口是DIPager 和 DIMessageSource。这个类的使用如下:
class CPager
: public CComObjectRootEx<CComMultiThreadModel>,
  public IDispatchImpl<DIMessageSource,
      &IID_DIMessageSource, &LIBID_PagerLib>,
  public IDispatchImpl<DIPager,
      &IID_DIPager, &LIBID_PagerLib>
{
public:
BEGIN_COM_MAP(CPager)
  COM_INTERFACE_ENTRY(DIMessageSource)
  COM_INTERFACE_ENTRY(DIPager)
// 下一个接口指定DIPager为缺省 [default]
  COM_INTERFACE_ENTRY2(IDispatch, DIPager)
END_INTERFACE_MAP()
  STDMETHODIMP SendMessage(BSTR pwsz);
  STDMETHODIMP GetNextMessage(BSTR *ppwsz);
};
ATL的第一个版本使用CComDualImpl名字,现在它只是IDispatchImpl预处理的一个别名,以便允许1.x版本和2.x版本的工程能在一起编译。(待续)

上一页  1 2 3 

Tags:ATL 建立 轻量级

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接