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

  • 相关阅读:
    Java实现 蓝桥杯VIP 算法训练 字符串逆序
    Java实现 蓝桥杯VIP 算法训练 字符串逆序
    Java实现 蓝桥杯VIP 算法训练 最长字符串
    Java实现 蓝桥杯VIP 算法训练 最长字符串
    Java实现 蓝桥杯VIP 算法训练 最长字符串
    Java实现 蓝桥杯VIP 算法训练 最长字符串
    Java实现 蓝桥杯VIP 算法训练 最长字符串
    Java实现 蓝桥杯VIP 算法训练 成绩的等级输出
    Java实现 蓝桥杯VIP 算法训练 成绩的等级输出
    Qt 自定义model实现文件系统的文件名排序
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/4079657.html
Copyright © 2011-2022 走看看