好久没有写博客了,今天记录下,作为一个程序猿,多记录点东西还是好的。最近比较懒,总是想写点东西来着,终于动手了,当你觉得晚的时候恰恰是最早的,勉励下自己
梳理一下一个进程内的 COM 组件,从代码组织到真正创建的过程
1. 首先前期编译的时候,利用ALT模板可以方便的将创建 COM对象的函数加入到一个特定的段中,这一点利用了编译器的特性,首先创建一个 类似于 SA 段,命名为start 和一个 SZ的段命名为end ,将创建COM对象的需要结构指针分配到段 SM中,这样在编译的时候根据字母的顺序,从[SA SM SZ] 的顺序排布,这样就可以方便找到创建COM对象的函数。
关于这个创建COM对象的需要结构 主要包含了这些信息
1). CLSID 这个好理解,根据不同的CLSID来请求不同的COM类
2). 一个叫CF的指针,即对应COM的ClassFactory接口指针
3). 对应的ClassFactory的CreateInstance函数,当要创建一个Com对象的时候会遍历之前所说的预先分配好的段,逐个比较CLSID,找到后会先去检查2所说的指针是否为空,如果是的话就调用这个函数对其进行初始化。
4).。。。这里还有些参数,忘记了,弄了补上,大致是调用3中函数的参数,
创建一个COM对象的时候首先会调用CreateInstance 来获取该对象的 IUKOWN接口,然后由于COM QI的对称性,可以获得ClassFactory接口指针,通过该指针来调用CreateInstance来创建COM对象,这里为什么没有直接获取ClassFactory接口,我的理解是IUKOWN是通用的,任何接口肯定支持,然后查询 任何接口 可以让代码通用。
说说CreateInstance,在定义一个COM的类的时候会在其内部定义几个宏,类似 BEGIN_COM_MAP() ,END_COM_MAP()这个两个宏大概就是定义IUKOWN的接口,如addref、release、QI这些,然后在这两个宏之间会有一个宏,具体名字叫什么忘记了类似 COM_MAP(需要支持的接口),它的作用是为这个类厂初始化一个static的数组,这个数组中记录了如下重要的信息
1). 支持接口的IID
2) . 该接口对IUKOWN的偏移,具体是通过一个ATL的宏来做到的, 对一个常数强制转换为IUKOWN 然后再强制转换为 应的接口,两次结果相减就得到了相对偏移
在QueryInterface的时候 会调到内部的 QI 它的实现就是在这个数组里面逐个寻找有没有匹配的iid 有的话就创建COM对象并返回