大家都知道程序中若要使用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. SQL Server on Linux 理由浅析

    SQL Server on Linux 理由浅析 今天的爆炸性新闻<SQL Server on Linux>基本上在各大科技媒体上刷屏了 大家看到这个新闻都觉得非常震精,而美股,今天微软开 ...

  3. 【深入浅出jQuery】源码浅析--整体架构

    最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...

  4. 高性能IO模型浅析

    高性能IO模型浅析 服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种: (1)同步阻塞IO(Blocking IO):即传统的IO模型. (2)同步非阻塞IO(Non-blocking  ...

  5. netty5 HTTP协议栈浅析与实践

      一.说在前面的话 前段时间,工作上需要做一个针对视频质量的统计分析系统,各端(PC端.移动端和 WEB端)将视频质量数据放在一个 HTTP 请求中上报到服务器,服务器对数据进行解析.分拣后从不同的 ...

  6. Jvm 内存浅析 及 GC个人学习总结

    从诞生至今,20多年过去,Java至今仍是使用最为广泛的语言.这仰赖于Java提供的各种技术和特性,让开发人员能优雅的编写高效的程序.今天我们就来说说Java的一项基本但非常重要的技术内存管理 了解C ...

  7. 从源码浅析MVC的MvcRouteHandler、MvcHandler和MvcHttpHandler

    熟悉WebForm开发的朋友一定都知道,Page类必须实现一个接口,就是IHttpHandler.HttpHandler是一个HTTP请求的真正处理中心,在HttpHandler容器中,ASP.NET ...

  8. 【深入浅出jQuery】源码浅析2--奇技淫巧

    最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...

  9. 浅析匿名函数、lambda表达式、闭包(closure)区别与作用

    浅析匿名函数.lambda表达式.闭包(closure)区别与作用 所有的主流编程语言都对函数式编程有支持,比如c++11.python和java中有lambda表达式.lua和JavaScript中 ...

随机推荐

  1. How to Develop blade and soul Skills

    How to Develop Skills Each skill can be improved for variation effects. Some will boost more strengt ...

  2. winform学习笔记02

    Hashtable 数据遍历的几种方式 ---Hashtable 在集合中称为键值对,它的每一个元素的类型是 DictionaryEntry,由于Hashtable对象的键和值都是Object类型,决 ...

  3. 一个比较通用的makefile

    .PHONY : all clean DEBUG := YES CC := gcc CXX := g++ LD := g++ AR := ar rc HOME_PATH := $(realpath . ...

  4. repcache实现memcached主从

    1.repcached介绍 repcached是日本人开发的实现memcached复制功能,它是一个单 master单 slave的方案,但它的 master/slave都是可读写的,而且可以相互同步 ...

  5. ROS笔记——创建简单的主题发布节点和主题订阅节点

    在安装好ROS后,接着学习如何创建节点和节点之间的通信方式,以一个简单的主题发布节点和主题订阅节点说明. 节点是连接ROS网络等可执行文件,是实现某些功能的软件包,也是一个主要计算执行的进程. 一.创 ...

  6. 面试复习(C++)之希尔排序

    #include<iostream> using namespace std; void Shellsort(int *a,int len) { int gap; ;gap>;gap ...

  7. DotNetBar for Windows Forms 12.2.0.7_冰河之刃重打包版原创发布-带官方示例程序版

    关于 DotNetBar for Windows Forms 12.2.0.7_冰河之刃重打包版 --------------------11.8.0.8_冰河之刃重打包版-------------- ...

  8. linux配置网卡绑定

    1.确定好要绑定的那两个网口 我这边要绑定的是两个业务口  em2.em3 2.配置ifcfg-bond0.em2.em3 3.修改配置文件/etc/modprcode.d/disk.conf 底部添 ...

  9. 作业七:团队项目——Alpha版本冲刺阶段010

    今日安排:组内成员讨论 今日进程:组内成员讨论结束,并有明确的解决办法,每个人准备实践

  10. window下安装jupyter

    1.Install [Anaconda](https://docs.continuum.io/anaconda/install#anaconda-install) 实际上安装了anaconda就已经安 ...