设为首页 加入收藏

TOP

ATL接口映射宏详解(一)
2012-11-04 15:22:38 来源: 作者: 【 】 浏览:1242
Tags:ATL 接口 映射 详解


  ATL中定义了很多接口映射宏,有几个还是比较重要的,虽然好象没有必要把它所有的细节都弄得很清楚,但深入学习的过程中也可以顺带学一学其他的ATL类,对它的机制也可以更清楚一些,应该还是会有些好处的吧。

  以后将分别介绍ATL中各个形式为COM_INTERFACE_ENTRY_XX的接口映射宏。并将按照从易到难的顺序讲解,每一部分都将建立在前一部分的基础上。每一部分都将通过分析实际的调用函数堆栈来进行分析,堆栈的写法是从下向上。文中所涉及的代码都为略写,只列出相关部分。

  一、COM_INTERFACE_ENTRY(x)

  首先我们从一个最典型的应用开始:

  定义一个最简单的ATL DLL:

class ATL_NO_VTABLE CMyObject :
public CComObjectRootEx,
public CComCoClass,
public IDispatchImpl
{
.....
BEGIN_COM_MAP(CMyObject)
COM_INTERFACE_ENTRY(IMyObject) //一个双接口
COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()
END_COM_MAP()
.....
};

  编写一段最简单的查询接口代码:

IUnknown *pUnk;
IMyObject *pMyObject;
CoCreateInstance(CLSID_MyObject, NULL, CLSCTX_INPROC_SERVER,
IID_IUnknown, (void **)&pUnk);
pUnk->QueryInterface(IID_IMyObject, (void **)&pMyObject);

  执行客户代码,首先我们看看组件对象是如何被创建的。 函数调用堆栈一:

4...........
3.ATL::CComCreator >::CreateInstance(...)
2.ATL::CComCreator2 >,
ATL::CComCreator > >::CreateInstance(...)
1.ATL::CComClassFactory::CreateInstance(...)
4.ATL::AtlModuleGetClassObject(...)
9.ATL::AtlInternalQueryInterface(...)
8.ATL::CComObjectRootBase::InternalQueryInterface(...)
7.ATL::CComClassFactory::_InternalQueryInterface(...)
6.ATL::CComObjectCached::QueryInterface(...)
5.ATL::CComCreator >::
CreateInstance(...)
4.ATL::AtlModuleGetClassObject(...)
3.ATL::CComModule::GetClassObject(...)
2.DllGetClassObject(...)
1.CoCreateInstance(...)(客户端)

  解释如下:

  1:CoCreateInstance(CLSID_MyObject, NULL, CLSCTX_INPROC_SERVER,IID_IUnknown, (void **)&pUnk);

  其内部将调用OLE API函数CoGetClassObject(), 而CoGetClassObject则会通过LoadLibrary(...)装入DLL,并调用DLL中的DllGetClassObject()函数。

  2:STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)

  {
   return _Module.GetClassObject(rclsid, riid, ppv);
  }

  其中值得注意的是_Module变量,在DLL中定义了全局变量:

CComModule _Module;

  ATL通过一组宏:

BEGIN_OBJECT_MAP(ObjectMap)
OBJECT_ENTRY(CLSID_MyObject, CMyObject)
END_OBJECT_MAP()
#define BEGIN_OBJECT_MAP(x) static _ATL_OBJMAP_ENTRY x[] = {
#define END_OBJECT_MAP() {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}};
#define OBJECT_ENTRY(clsid, class) {&clsid, class::UpdateRegistry,
class::_ClassFactoryCreatorClass::CreateInstance, //关键
class::_CreatorClass::CreateInstance,
NULL, 0, class::GetObjectDescription,
class::GetCategoryMap, class::ObjectMain },

  生成一个静态全局_ATL_OBJMAP_ENTRY型数组:ObjectMap[]; 然后ATL又在

BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/

{
.....
_Module.Init(ObjectMap, hInstance, &LIBID_TEST2Lib);
.....
}

  初始化_Module

  注意在有的情况下是在InitInstance()中初始化_Module,那么_Module初始化都做了些什么呢,其实他什么也没做,在CComModule::Init中,它调用AtlModuleInit(_ATL_MODULE* pM, _ATL_OBJMAP_ENTRY* p, HINSTANCE h),在其中关键的只有一句:pM->m_pObjMap = p;可见_Module仅仅是把这个全局对象映射数组
ObjectMap[]给存了起来。那么为什么可以通过_Module.GetClassObject得到类厂呢?

  其实关键在于我们的组件CMyObject继承的又一个基类CComCoClass! 在CComCoClass中缺省定义了一个宏DECLARE_CLASSFACTORY()而 #define DECLARE_CLASSFACTORY() DECLARE_CLASSFACTORY_EX(CComClassFactory)
#define DECLARE_CLASSFACTORY_EX(cf)
typedef CComCreator > _ClassFactoryCreatorClass;

  CComCreator,CComObjectCached我们暂且不管,但一看到CComClassFactory,顾名思义,我们就知道我们要的类厂终于出现了!每个组件内部原来都有一个类厂对象。绕了一大圈,我们现在已经知道了_Module中包含了我们所要的每个组件的类厂对象,这对目前来说已经足够了,现在继续路由下去!

3:HRESULT CComModule::GetClassObject(REFCLSID rclsid,REFIID riid,LPVOID* ppv)
{
return AtlModuleGetClassObject(this, rclsid, riid, ppv);
}

  CComModule::GetClassObject的实现非常简单,仅仅是调用ATL的API函数。

首页 上一页 1 2 3 4 5 6 7 下一页 尾页 1/7/7
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇基于VC实现Java和Matlab的通信 下一篇用ATL实现VC插件

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: