现在我有一个DLL形式的COM组件,是一个Apartment-Thread模型的组件。现在我在一个Worker线程中调用这个COM。按照《COM的原理与应用》里面说得,worker线程相对于COM机制中的Multi-Thread模型,所以COM库会另外生成一个UI线程来容纳这个COM组件,而那个Worker线程要用proxy-stub机制来访问这个COM组件。但是这样岂不是效率太低了,如果我只有这一个worker线程访问COM组件,根本不会造成COM组件的访问冲突,也要这样来实现吗?谢谢!!

解决方案 »

  1.   

    跨越套间访问的两种规则:汇集和全局接口表
    To make an interface pointer available to all apartments in the process, the apartment that owns the interface pointer must register it with the GIT by calling the RegisterInterfaceInGlobal method. The GIT will return a DWORD to the caller that represents the pointer globally across all apartments in the process. This DWORD can be used from any apartment in the process to unmarshal a new proxy by calling the GetInterfaceFromGlobal method. This DWORD can be used to unmarshal proxies repeatedly until a call to RevokeInterfaceFromGlobal invalidates the global interface pointer. Applications that use the global interface table usually bind a single process-wide interface pointer at startup:IGlobalInterfaceTable *g_pGIT = 0;
    HRESULT InitOnce(void) {
       assert(g_pGIT == 0);
       return CoCreateInstance(CLSID_StdGlobalInterfaceTable, 0,
                CLSCTX_INPROC_SERVER, 
                IID_IGlobalInterfaceTable, 
                (void**)&g_pGIT);
    }
    Once the global interface table is available, passing an interface pointer to another apartment simply means registering the pointer with the global interface table:HRESULT WritePtrToGlobalVariable(IRacer *pRacer) {
    // where to write the marshaled ptr
       extern DWORD g_dwCookie;
    // thread synchronization
       extern HANDLE g_heventWritten;
    // write marshaled object reference to global variable
       HRESULT hr = g_pGIT->RegisterInterfaceInGlobal(
                       IID_IRacer, pRacer, &g_dwCookie);
    // signal other thread that ptr is now available
       SetEvent(g_heventWritten);
       return hr;
    }
    The following code correctly unmarshals the object reference and can be called from any apartment in the same process:HRESULT ReadPtrFromGlobalVariable(IRacer * &rpRacer, 
                                   bool bLastUnmarshal) {
    // where to write the marshaled ptr
       extern DWORD g_dwCookie;
    // thread synchronization
       extern HANDLE g_heventWritten;
    // wait for other thread to signal that ptr is available
       WaitForSingleObject(g_heventWritten, INFINITE);
    // read marshaled object reference from global variable
       HRESULT hr = g_pGIT->GetInterfaceFromGlobal(
                     g_dwCookie, IID_IRacer, (void**)&rpRacer);
    // if we are the last to unmarshal, revoke the pointer
       if (bLastUnmarshal)
          g_pGIT->RevokeInterfaceFromGlobal(g_dwCookie);
       return hr;
    }
    Note that a critical difference between these code fragments and the examples using CoMarshalInterThreadInterfaceInStream is that the GIT-based code supports unmarshaling more than one proxy.7 It may seem odd that the global variable is an interface pointer that is initialized in the writer’s apartment and used from the reader’s apartment. This inconsistency is addressed by the documentation for CoMarshalInterThreadInterfaceInStream, which states that the resultant IStream interface pointer can be accessed from any apartment in the process.
      

  2.   

    你如果只有这一个worker线程访问COM组件,可以让线程进入STA就行了,为什么要进入MTA?
      

  3.   

    选择STA还是MTA主要取决于你实现的组件是否线程安全。
      

  4.   

    to wyljery:你是说即便是一个worker线程,只要在调用CoInitializeEx的时候,指定
    是ApartmentThread,就可以进入STA?我一直以为要进入STA,线程一定要有自己的消息
    循环。to zylstudy:我得组件是线程不安全的,但是我现在要在一个Worker线程中调用它。
      

  5.   

    调用CoInitializeEx指定ApartmentThread可以进入STA,但调用线程必须要有自己的消息循环,否则Apartment-Thread模型的组件就会没有响应
      

  6.   

    问题就在这里啊,我只想生成一个Worker线程,因而不会有消息循环,这样的话是不是就无法进入STA了?
      

  7.   

    问题是我现在这个线程是一个Worker线程,启动后,调用COM组件完成一些事情后,就退出了。加入
    消息循环,我如何退出呢?