大家都知道程序中若要使用COM组件则必须要先调用CoInitialize,该函数主要是用来初始化COM运行环境。但这个函数的作用域是以线程为单位还是以进程为单位呢?也许大家已经通过测试程序摸索出答案,没错,是以线程为单位。今天我们就稍微再深入一下,通过分析CoInitialize的具体实现来印证我们的想法。

我们先来看看CoInitialize的汇编

769B2A24                 mov     edi, edi

769B2A26                 push    ebp

769B2A27                 mov     ebp, esp

769B2A29                 push    2               ; dwCoInit

769B2A2B                 push    [ebp+8] ; pvReserved

769B2A2E                 call   _CoInitializeEx@8 ; CoInitializeEx(x,x)

769B2A33                 pop     ebp

769B2A34                 retn    4

可以看到,其中的实现还是比较简单的,它只是简单地调用了CoInitializeEx,将第二个参数设置为2,即COINIT_APARTMENTTHREADED。我们再来看看CoInitializeEx的实现

769AEF5B                 mov     edi, edi

769AEF5D                 push    ebp

769AEF5E                 mov     ebp, esp

769AEF60                 push    ecx

769AEF61                 push    ebx

769AEF62                 mov     ebx, [ebp+0C]

769AEF65                 mov     eax, ebx

769AEF67                 and    eax, 0Eh      ; 检查参数是否正确,目前第二个参数只用了一个字节

769AEF6A                 cmp     eax, ebx

769AEF6C                 jnz     loc_76A0B8C7

769AEF72                 push    edi

769AEF73                 xor     edi, edi

769AEF75                 cmp     [ebp+8], edi       ; 判断第一个参数是否为NULL

769AEF78                 jnz     loc_76A0B8D1

769AEF7E

769AEF7Eloc_769AEF7E:

769AEF7E                 call    ?IsRunningInRPCSS@@YGHXZ ;IsRunningInRPCSS(void)

769AEF83                 test    eax, eax                                                          ;判断当前进程是否是RPCSS

769AEF85                 jnz     loc_76A0B8ED                                             ;如果是(即返回非0)则返回“灾难性故障”的错误

769AEF8B                 mov     eax, large fs:18h

769AEF91                 mov     eax, [eax+0F80h]

769AEF97                 cmp     eax, edi

769AEF99                 mov     [ebp+8], eax

769AEF9C                 jz      loc_769ADF26                                              ; 判断当前线程中的struct tagSOleTlsData结构体是否分配,若未分配则进行分配

769AEFA2

769AEFA2loc_769AEFA2:

769AEFA2                 push    esi

769AEFA3                 push    edi             ; __int32

769AEFA4                 push    ebx             ; unsigned __int32

769AEFA5                 xor     esi, esi

769AEFA7                 inc     esi

769AEFA8                 push    esi             ; int

769AEFA9                 push    esi             ; int

769AEFAA                 call    ?NotifyInitializeSpies@@YGJHHKJ@Z ;NotifyInitializeSpies(int,int,ulong,long)

769AEFAF                 call    ?IsThreadInNTA@@YGHXZ ; IsThreadInNTA(void)

769AEFB4                 test    eax, eax

769AEFB6                 jnz     loc_769DAFAD                                            ; 如果是 则返回“无法在设置线程模式后对其加以更改。”的错误

769AEFBC                 mov     eax, [ebp+8]

769AEFBF                 mov     ecx, [eax+0Ch]

769AEFC2                 test    ch, 10h                                                          ;判断标识第4位(从第0位开始)是否置位

769AEFC5                 jnz     loc_769D9D20                                              ; 服务器出现意外情况。

769AEFCB                 mov     edx, ebx

769AEFCD                 and     edx, 2

769AEFD0                 mov     [ebp-4], edx

769AEFD3                 jz      short loc_769AEFDE                      ; 非COINIT_APARTMENTTHREADED模式

769AEFD5                 test    ch, 1                                                                    ;判断标识第0位是否置位

769AEFD8                 jnz     loc_769DAFAD                                            ; 返回“无法在设置线程模式后对其加以更改。”的错误

769AEFDE

769AEFDEloc_769AEFDE:

769AEFDE                 cmp     edx, edi

769AEFE0                 jz      loc_769DAFA5                                             ; 非COINIT_APARTMENTTHREADED模式

769AEFE6

769AEFE6loc_769AEFE6:

769AEFE6                 test    bl, 8

769AEFE9                 jnz     loc_76A0B901                                              ;第二个参数中COINIT_SPEED_OVER_MEMORY标识位被设置,即为单线程套件

769AEFEF

769AEFEFloc_769AEFEF:

769AEFEF                 add     eax, 18h

769AEFF2                 inc     dword ptr [eax]                               ; tagSOleTlsData.dwReserved1[0]++;

769AEFF4                 cmp     [eax], esi

769AEFF6                 jnz     loc_769ADBF9                                             ; 判断tagSOleTlsData.dwReserved1[0]==1?

769AEFFC                 test    edx, edx

769AEFFE                 mov     ebx, offset?gMTAInitLock@@3VCOleStaticMutexSem@@A ; COleStaticMutexSem gMTAInitLock

769AF003                 jz      loc_769DAFF2                                              ; 第二个参数未设置COINIT_APARTMENTTHREADED标识,即为多线程套件

769AF009

769AF009loc_769AF009:

769AF009                 mov     esi, offset?g_mxsSingleThreadOle@@3VCOleStaticMutexSem@@A ; COleStaticMutexSemg_mxsSingleThreadOle

769AF00E                 mov     ecx, esi

769AF010                 call    ?Request@COleStaticMutexSem@@QAEXXZ ;COleStaticMutexSem::Request(void)

769AF015                 push    [ebp+0C]

769AF018                 lea     eax, [ebp+8]

769AF01B                 push    eax

769AF01C                 call    ?wCoInitializeEx@@YGJAAVCOleTls@@K@Z ;wCoInitializeEx(COleTls &,ulong)  调用wCoInitializeEx

769AF021                 mov     ecx, esi

769AF023                 mov     edi, eax

769AF025                 call    ?Release@COleStaticMutexSem@@QAEXXZ ;COleStaticMutexSem::Release(void)

769AF02A                 test    edi, edi

769AF02C                 jl      loc_76A0B90C

769AF032

769AF032loc_769AF032:

769AF032                 cmp     [ebp-4], 0

769AF036                 jz      loc_769DB004                   ; 第二个参数未设置COINIT_APARTMENTTHREADED标识,即为多线程套件

769AF03C

769AF03C loc_769AF03C:                           ; CODE XREF:CoInitializeEx(x,x)+2C0B6j

769AF03C                xor     esi, esi

769AF03E                 inc     esi

769AF03F

769AF03F loc_769AF03F:

769AF03F                 push    edi             ; __int32

769AF040                 push    [ebp+0C]  ; unsigned__int32

769AF043                 push    0              ; int

769AF045                 push    esi             ; int

769AF046                 call    ?NotifyInitializeSpies@@YGJHHKJ@Z ;NotifyInitializeSpies(int,int,ulong,long)

769AF04B                 pop     esi

769AF04C

769AF04C loc_769AF04C:

769AF04C                 pop     edi

769AF04D

769AF04Dloc_769AF04D:

769AF04D                 pop     ebx

769AF04E                 leave

769AF04F                 retn    8

其中有几点请注意:

1、在第一个参数为非空时,该函数会判断当前进程是否为EXCEL;

2、该函数也会判断当前进程是否为RPCSS,该进程的用途请大家另行查阅;检查进程是否为RPCSS的方法主要是:先判断当前进程是否有载入Windows目录下\\system32\\rpcss.dll,如果未载入则当前进程不是RPCSS;若载入了,则获取该DLL中名为WhichService的导出函数,如果未找到该函数也认为当前进程是RPCSS;若找到,并该函数的返回值大于等于0,且作为该函数参数的指针所指向的值为2则当前进程不是RPCSS,否则当前进程即为RPCSS。

3、每个线程的TEB结构向后偏移0x0F80的地方存放struct tagSOleTlsData的指针,该结构的声明如下:

typedef structtagSOleTlsData

{

void *pvReserved0[2];

DWORD dwReserved0[3];

void *pvReserved1[1];

DWORD dwReserved1[3];

void *pvReserved2[4];

DWORD dwReserved2[1];

void *pCurrentCtx;

} SOleTlsData;

该结构中存放了当前线程有关COM的环境信息,这个结构体中各个域的定义微软貌似没有公开。线程启动后,在没有该线程调用CoInitialize或CoInitializeEx之前,该指针为空。第一次调用上述函数后,为该线程从堆上分配该结构的内存并将其指针保存至TEB+0x0F80处。

4、我们注意到,所有对struct tagSOleTlsData内容的修改都未进行互斥保护,这是因为所有对该结构的修改操作都在当前线程内部进行,因此也就不存在多线程同步的问题;而对于一些全局信息的修改则都进行了保护。

CoInitialize浅析一相关推荐

  1. CoInitialize浅析二

    最近工作比较忙,在粗略分析了CoInitialize之后我们一直没有再深入研究,下面言归正传.前面我们初步了解到了CoInitialize其实是通过调用CoInitializeEx来实现功能的,而后者 ...

  2. CoInitialize浅析

    之一: 大家都知道程序中若要使用COM组件则必须要先调用CoInitialize,该函数主要是用来初始化COM运行环境.但这个函数的作用域是以线程为单位还是以进程为单位呢?也许大家已经通过测试程序摸索 ...

  3. COM组件浅析(三)- 使用C/C++操作Adobe Illustrator

    目录 创建工程,并增加COM模板代码 启动Illustrator.Application newApp函数声明 实现newApp方法 代码分析 CLSID C/C++ IDispatch与Java D ...

  4. 浅析 JavaScript 中的 函数 uncurrying 反柯里化

    柯里化 柯里化又称部分求值,其含义是给函数分步传递参数,每次传递参数后部分应用参数,并返回一个更具体的函数接受剩下的参数,这中间可嵌套多层这样的接受部分参数函数,直至返回最后结果. 因此柯里化的过程是 ...

  5. 浅析Python中bytes和str区别

    本博转载自:Chown-Jane-Y的浅析Python3中的bytes和str类型 Python 3最重要的新特性之一是对字符串和二进制数据流做了明确的区分.文本总是Unicode,由str类型表示, ...

  6. 学习《Linux设备模型浅析之设备篇》笔记(深挖一)

    这篇文章既然说了是浅析,那就是跳过了一些东西,我们把这些跳过的东西给它尽可能的补回来 今天登陆 lxr.free-electrons.com 发现内核版本已经升级到3.15了,那以后都使用3.15的源 ...

  7. 学习《Linux设备模型浅析之设备篇》笔记(一)

    最近在学习Linux设备模型,前面几篇文章也是读这篇的时候遇到问题,然后为了搞清楚先转去摸索才写出来的. 当然了,刚开始是先读到<Linux那些事儿之我是Sysfs>,搞不清楚才去读的&l ...

  8. 架构周报| 浅析MySQL JDBC连接配置上的两个误区

    经典案例 \\ 浅析MySQL JDBC连接配置上的两个误区:相信使用MySQL的同学都配置过它的JDBC驱动,多数人会直接从哪里贴一段URL过来,然后稍作修改就上去了,对应的连接池配置也是一样的,很 ...

  9. 超级账本(Hyperledger Fabric)之权限管理浅析

    链客,专为开发者而生,有问必答! 此文章来自区块链技术社区,未经允许拒绝转载. 超级账本(Hyperledger Fabric)之权限管理浅析 超级账本是联盟链的代表,而其相对于共链(例如比特币,以太 ...

最新文章

  1. oracle不能用uuid,Oracle 应用之--VirtualBox UUID问题
  2. ES6中this的三种用法
  3. 【MASHIII调制器】MASHIII调制器的Simulink建模与仿真
  4. 网络文学平台如何借力智能推荐,实现阅读体验全面提升?
  5. 通讯录链表实现之C++
  6. linux 命令调试分析core文件,linux环境下dump vmcore文件分析
  7. MacOSX64位机器上gcc编译32位x264静态库
  8. delphi datasnap断线后再次连接_电脑连接WiFi后经常出现断线断开连接问题的解决方法...
  9. 谁考了第k名(信息学奥赛一本通-T1176)
  10. 给笔记本更换SSD硬盘
  11. python朴素贝叶斯分类的手写数字识别_关于利用机器学习进行手写数字的的识别...
  12. Hive编程指南(含目录,高清,免费)
  13. 罗技鼠标驱动ghub怎么设置?
  14. XSS过滤绕过总结_xss绕过字符过滤
  15. 捷豹:车到用时方知养,可知彼时恨太迟
  16. php接入飞鹅打印机
  17. 微信公众号里面使用地图导航
  18. iOS GPUImage研究序一:内置滤镜
  19. 如何找win10 软件商店里下载的python路径并删除
  20. osgEarth .earth 文件详情

热门文章

  1. ASP网页FLASH图片播放只能在老版Internet Explorer 正常显示,最新主流浏览器都不支持,哪位大伽有好的代码改动妙招烦请赐教,谢谢
  2. JSON-SCHEMA + AJV的坑
  3. python中的递归(Recursion)
  4. java id3v2 乱码_【图】(更新最终解决办法)解决 奔驰 U盘 音乐信息乱码问题! 一招搞定~...
  5. 电力行业企业管理软件
  6. 玩绝地求生,PUBG时,按Caps Lock键(字母大小写转换键)切回桌面
  7. php 响应式博客源码,PHP响应式青春博客源码
  8. win10取消开机密码方法
  9. 苹果6s照相快门声音设置_原来苹果手机自带扫描仪,学会这2个方法,纸质档一键电子化...
  10. java 代码以管理员身份运行 cmd命令_Win10 开启以管理员身份运行