昨天心情不好写太少了,今天在补一段
究竟注册了些什么,当时认识在InprocServer中写上dll路径啊
有了这个在调用CoGetClassObject的时候会加载这个dll,有了这个dll
就有了DllGetClassObject
这个是com的简单流程,也是com执行的秘密
但ATL做了什么,它帮我们写了这个DLLGetClassObject
在ATL中有这个ATLComModuleGetClassObject的函数来完成DllGetClassObject
的工作
在这个函数里面会扫描我昨天说的那个对象映射表,就是那一堆连续的_ATL_OBJMAP_ENTRY
结构,从这个结构里面获取一个pfnGetClassObject函数,有了这个函数就可以生成对应GUID
的类厂了,有了类厂你知道怎么做了吧?
这个对象表中在这个函数调过之后把这个类厂放入pCF中(就是缓存了类厂)
你直接使用CAtlModuleT类的GetClassObject来取类厂的时候取的实际就是这个类厂。
很明显,从这个可以看出,类厂永远是单实例的,而真正的对象就是这个类厂产生的,
呵呵,好像.net中我写数据库的时候写的DataProvider,单例模式+工厂模式
由于c++没有静态的构造函数,而com简单的模拟了这个操作,
_ATL_OBJMAP_ENTRY中有个ObjectMain函数,这个函数将在dll加载的时候被初始化,就是程序会
自动调用所有对象表中的所有的ObjectMain,而且永远只调用一次,这就实现了类级的初始化,
和静态构造函数是一样的。
说来说去,关键是这个对象映射表
#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)
简单的看看这个宏,里面放入了:自己的对象生成函数,自己类厂的生成函数,注册函数,
ObjectMain,当然有clsid,GetCategoryMap也是个注册时候用的函数,它将用来注册对象类别
同时在程序中一定会有很多对象,但它并不对外公开,它通常会被公开的对象构造,在ATL中它叫
做不可创建对象。
它也有个相对应的宏,
#define OBJECT_ENTRY_NON_CREATEABLE_EX_AUTO(clsid, class) /
__declspec(selectany) ATL::_ATL_OBJMAP_ENTRY __objMap_##class = {&clsid, class::UpdateRegistry, NULL, NULL, NULL, 0, NULL, 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)
简单看一下,这个宏和上面的宏不同之前就在于,它没有类厂生成函数和对象生成函数,这个就
表示它一定不会被创建,至少不会由com那套逻辑来创建。
那么既然说了这个表就不能不提这个表的使用,这个可能是ATL比较得意的地方
没有对象都会创建这个结构,这些结构将注册一个表,但这些一定要放在一起才能算是一个表
可是明显,它们是一个一个创建的,在内存中它们理应离散的放置
但主要这个宏的后面几行
__declspec(allocate("ATL$__m"))在ATL$__m段中放了这个结构,这样就使得这个结构在表中是在
这个数据段中连续。
就说这么多吧,上班了。