ATL7中OBJECT_ENTRY_AUTO宏是如何实现com对象映射表

来源:互联网 发布:c语言入门材料 编辑:程序博客网 时间:2024/06/08 06:49

在ATL3.0中,是通过对象映射表来注册服务器。 BEGIN_OBJECT_MAP(ObjectMap)

   OBJECT_ENTRY(CLSID_MyCircleCollectionCreator, CMyCircleCollectionCreator)
END_OBJECT_MAP( )
当ATL注册服务器时,最终调用到AtlModuleRegisterServer函数进行服务器注册。对于组件支持的所有对象,它创建一个注册表项进行注册,注册过程结束。
 
但是,在ATL7中,以上三个宏都已经过时,取而代之的是宏OBJECT_ENTRY_AUTO。下面我们就来分析宏OBJECT_ENTRY_AUTO的实现。
 
二、宏OBJECT_ENTRY_AUTO的定义。
1.    我们首先看看_ATL_OBJMAP_ENTRY的定义:
struct _ATL_OBJMAP_ENTRY30
{
    const CLSID* pclsid;
    HRESULT (WINAPI *pfnUpdateRegistry)(BOOL bRegister);
    _ATL_CREATORFUNC* pfnGetClassObject;
    _ATL_CREATORFUNC* pfnCreateInstance;
    IUnknown* pCF;
    DWORD dwRegister;
    _ATL_DESCRIPTIONFUNC* pfnGetObjectDescription;
    _ATL_CATMAPFUNC* pfnGetCategoryMap;
};
typedef _ATL_OBJMAP_ENTRY30 _ATL_OBJMAP_ENTRY;
 
2.    宏OBJECT_ENTRY_AUTO的定义如下:
#define OBJECT_ENTRY_AUTO(clsid, class)
    __declspec(selectany) ATL::_ATL_OBJMAP_ENTRY __objMap_##class = /
{   /
&clsid,/
class::UpdateRegistry,/
class::_ClassFactoryCreatorClass::CreateInstance,/
class::_CreatorClass::CreateInstance, /
NULL, /
0, /
class::GetObjectDescription, /
class::GetCategoryMap,
class::ObjectMain };/
 /
extern "C" __declspec(allocate("ATL$__m")) /
__declspec(selectany) ATL::_ATL_OBJMAP_ENTRY * const __pobjMap_##class /
 = &__objMap_##class; /
    OBJECT_ENTRY_PRAGMA(class)
3.    接下来我们看一个辅助的宏OBJECT_ENTRY_PRAGMA,它的定义如下:
#define OBJECT_ENTRY_PRAGMA(class) /
 __pragma(comment(linker, "/include:___pobjMap_" #class));
 
三、宏OBJECT_ENTRY_AUTO的功能
1.    结构体_ATL_OBJMAP_ENTRY就不用多说了,和ATL3是完全一样的。
2.    宏OBJECT_ENTRY_AUTO的功能:
1)    使用clsid, class的信息,生成_ATL_OBJMAP_ENTRY的一个实例,变量名为__objMap_加上class的实际值。
2)    声明1)所生成实例的一个指针,并赋值为1)生成的实例的地址。但是指针被放在ATL$_m段中。
3.    宏OBJECT_ENTRY_PRAGMA的功能是告诉连接器向符号表中添加符号___objMap_加上class的实际值。注:在X86平台下,符号名为声明的名字前加下划线。所以在OBJECT_ENTRY_PRAGMA宏中,pobjMap之前有三个下划线。
四、在哪部分代码中使用OBJECT_ENTRY_AUTO
创建ATL7.0工程时:
1.      如果使用的是非属性化编程,那么它在COM类的头文件中,它由向导自动生成,千万不要删除该宏,否则将不能够创建该类的实例。 而这样的错误又是非常难发现的。
2.      如果使用的是属性化编程,那么在COM类的前面有coclass属性,编译器将向代码中插入一些代码完成以下功能:
l        添加COM类的基类
l        产生注册代码
l        产生接口映射表
l        产生对象映射项,即宏OBJECT_ENTRY_AUTO
所以在代码中,你实际看不到OBJECT_ENTRY_AUTO。
五、OBJECT_ENTRY_AUTO和系统其他部分的协作,这里分析对象映射表的建立及使用。
如果使用非属性化编程,那么用户可以生成任意合法COM类名称;如果使用属性化编程,我们根本不知道_ATL_OBJMAP_ENTRY指针变量的名字,这些对于ATL库来讲,它不可能预先知道用户定义的COM类的名字。那么它是如何遍历对象映射表,来进行更新注册表呢?
答案在于对象映射表的建立,我们先来看映射表的开始项、结束项。他们的定义如下:
__declspec(selectany) __declspec(allocate("ATL$__a")) _ATL_OBJMAP_ENTRY* __pobjMapEntryFirst = NULL;
__declspec(selectany) __declspec(allocate("ATL$__z")) _ATL_OBJMAP_ENTRY* __pobjMapEntryLast = NULL;
分析如下:
l        需要注意的是,__pobjMapEntryFirst、__pobjMapEntryLast分别被放置在段ATL$_a和ATL$_z中。
l                再次需要注意的是,通过宏OBJECT_ENTRY_AUTO放置的变量在ATL$_m中。
l        当连接器布局代码时,它按根据的名称,按照字母排序的规则,排列所有段。这样在段ATL$_a中的变量出现在段ATL$_z所有变量之前。
l        最后使用#pragma comment(linker, "/merge:ATL=.rdata"),将三个段中的所有数据合并到段.rdata只读数据段中。
l        最后形成的布局可能如下:

__pobjMapEntryFirst
 
UserDefinedPtr1
UserDefinedPtr2
 
__pobjMapEntryLast


通过这种方式,就形成了对象映射表。而在ATL库中,可以根据__pobjMapEntryFirst、__pobjMapEntryLast来定位对象映射表,对其中的所有对象进行注册。
 
http://blog.csdn.net/terryc007/article/details/2601982
原创粉丝点击