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

  • 相关阅读:
    [APIO2016]划艇
    C# 循环的判断会进来几次
    C# 性能分析 反射 VS 配置文件 VS 预编译
    C# 性能分析 反射 VS 配置文件 VS 预编译
    AutoHotKey 用打码的快捷键
    AutoHotKey 用打码的快捷键
    C# 通过编程的方法在桌面创建回收站快捷方式
    C# 通过编程的方法在桌面创建回收站快捷方式
    C# 条件编译
    C# 条件编译
  • 原文地址:https://www.cnblogs.com/zhaoxinshanwei/p/4222288.html
Copyright © 2020-2023  润新知