CoInitialize浅析一
大家都知道程序中若要使用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浅析一的更多相关文章
- CoInitialize浅析二
最近工作比较忙,在粗略分析了CoInitialize之后我们一直没有再深入研究,下面言归正传.前面我们初步了解到了CoInitialize其实是通过调用CoInitializeEx来实现功能的,而后者 ...
- SQL Server on Linux 理由浅析
SQL Server on Linux 理由浅析 今天的爆炸性新闻<SQL Server on Linux>基本上在各大科技媒体上刷屏了 大家看到这个新闻都觉得非常震精,而美股,今天微软开 ...
- 【深入浅出jQuery】源码浅析--整体架构
最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...
- 高性能IO模型浅析
高性能IO模型浅析 服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种: (1)同步阻塞IO(Blocking IO):即传统的IO模型. (2)同步非阻塞IO(Non-blocking ...
- netty5 HTTP协议栈浅析与实践
一.说在前面的话 前段时间,工作上需要做一个针对视频质量的统计分析系统,各端(PC端.移动端和 WEB端)将视频质量数据放在一个 HTTP 请求中上报到服务器,服务器对数据进行解析.分拣后从不同的 ...
- Jvm 内存浅析 及 GC个人学习总结
从诞生至今,20多年过去,Java至今仍是使用最为广泛的语言.这仰赖于Java提供的各种技术和特性,让开发人员能优雅的编写高效的程序.今天我们就来说说Java的一项基本但非常重要的技术内存管理 了解C ...
- 从源码浅析MVC的MvcRouteHandler、MvcHandler和MvcHttpHandler
熟悉WebForm开发的朋友一定都知道,Page类必须实现一个接口,就是IHttpHandler.HttpHandler是一个HTTP请求的真正处理中心,在HttpHandler容器中,ASP.NET ...
- 【深入浅出jQuery】源码浅析2--奇技淫巧
最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...
- 浅析匿名函数、lambda表达式、闭包(closure)区别与作用
浅析匿名函数.lambda表达式.闭包(closure)区别与作用 所有的主流编程语言都对函数式编程有支持,比如c++11.python和java中有lambda表达式.lua和JavaScript中 ...
随机推荐
- asp.netajax开发应用心得-accordation控件的事件处理
今天,再次运行以前的项目时,发现按钮的单击事件不起作用了,加了断点之后发现根本没有触发该事件.... 按照网上找到的答案,有的说把控件删掉重新拖拽一个进去,虽然以前也遇到过控件失效,重新拖拽有效的时候 ...
- URL优化之IIS7如何开启伪静态
iis7跟IIS6开启伪静态重写的方式不一样,iis6是在网站属性里面的ISAPI筛选器里面添加,但是iis7添加伪静态重写,需要下载一个url重写插件. II7/7.5用的是web.config配置 ...
- 前端神器Sublime Text3 常用插件&常用快捷键
Sublime Text3常用插件 使用Package Control组件安装 也可以安装package control组件,然后直接在线安装: 按Ctrl+`调出console(注:安装有QQ输入法 ...
- using border-radius to make a worker
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="U ...
- Three.Js学习第一天
因为工作需求,最近接触到了ThreeJs库,国内学习文档的确少,所以在这里写下bolgs记录学习史,并且给后面学习的人尽一份微博之力. 3D场景依靠WebGL技术.目前支持比较好的浏览器,谷歌.火狐. ...
- Java中获取长度length和size的问题
1.length属性是针对Java中的数组来说的,要求数组的长度可以用其length属性: 2.length()方法是针对字符串来说的,要求一个字符串的长度就要用到它的length()方法: 3.ja ...
- linux环境下安装jdk
1.查看系统自带的jdk #RPM -qa|grep jdk 若存在则删除 jdk-1.7.0_67-fcs.x86_64 #rpm -e --nodeps jdk-1.7.0_67-fcs.x86_ ...
- IE 文档模式
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv= ...
- 一些pc端web事件移动端不再可行
1.onkeyUp,onkeyDown,onkeyPress等事件不再管用,要用oninput代替 2.onclick事件会有延迟,因为手机需要等待判断是否是双击事件(ondblclick).所以 ...
- 排序系列 之 简单选择排序及其改进算法 —— Java实现
简单选择排序算法: 基本思想: 在待排序数据中,选出最小的一个数与第一个位置的数交换:然后在剩下的数中选出最小的数与第二个数交换:依次类推,直至循环到只剩下两个数进行比较为止. 实例: 0.初始状态 ...