前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >CoInitialize浅析一

CoInitialize浅析一

作者头像
全栈程序员站长
发布2022-09-07 09:39:28
5180
发布2022-09-07 09:39:28
举报

大家好,又见面了,我是你们的朋友全栈君。

大家都知道程序中若要使用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 ; server出现意外情况。

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内容的改动都未进行相互排斥保护,这是由于全部对该结构的改动操作都在当前线程内部进行,因此也就不存在多线程同步的问题;而对于一些全局信息的改动则都进行了保护。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/155692.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档