编组封送接口是否为代理或原始接口提供了编组器?

Foz*_*ozi 5 windows com marshalling out-of-process

这是一个具体的例子:

我通过调用创建了一个IWeBrowser2接口wb.CoCreateInstance(CLSID_InternetExplorer, 0, CLSCTX_SERVER);.这给了我一个从我的进程到任何正在运行的iexplore.exe进程的编组接口恰好包含在我的线程A中的这个浏览器选项卡.

现在我使用IGlobalInterfaceTable获取此接口的cookie,将其传递给我的线程B并从那里请求封送接口.

问题:我是在线程A中获取代理还是直接获取IE进程中的实例?

我似乎明智的是,我会通过自己的引用获得实例的直接代理,
但是:

如果我结束我的线程A,我在那里创建的cookie变得无效,我无法检索(并关闭)我创建的Web浏览器的接口指针.这没有意义,除非该线程中有一个thunk在线程退出时被销毁.

编辑:哦,两个线程都是STA.

Foz*_*ozi 2

我终于有时间弄清楚发生了什么,所以我写了一个简短的测试来看看发生了什么。

// MarshalTest.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

enum { WM_THEREYOUGO = WM_USER+1, WM_THANKYOU, WM_YOURWELCOME };

DWORD WINAPI TheOtherThread(DWORD * main_thread_id)
{
    MSG msg = { 0 };
    HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
    assert(SUCCEEDED(hr));

    {
        // create web browser
        CComPtr<IWebBrowser2> wb;
        hr = wb.CoCreateInstance(CLSID_InternetExplorer, 0, CLSCTX_SERVER);
        assert(SUCCEEDED(hr) && wb);

        // navigate
        hr = wb->Navigate2(&CComVariant(_T("stackoverflow.com")), &CComVariant(0), &CComVariant(_T("")), &CComVariant(), &CComVariant());
        assert(SUCCEEDED(hr));
        hr = wb->put_Visible(VARIANT_TRUE);
        assert(SUCCEEDED(hr));

        // Marshal
        DWORD the_cookie = 0;
        {
            CComPtr<IGlobalInterfaceTable> com_broker;
            hr = com_broker.CoCreateInstance(CLSID_StdGlobalInterfaceTable);
            assert(SUCCEEDED(hr));
            hr = com_broker->RegisterInterfaceInGlobal(wb, __uuidof(IWebBrowser2), &the_cookie);
        }

        // notify main thread
        PostThreadMessage(*main_thread_id, WM_THEREYOUGO, the_cookie, NULL);

        // message loop
        while(GetMessage(&msg, 0, 0, 0)) {
            if(msg.hwnd == NULL) {
                // thread message
                switch(msg.message) {
                    case WM_THANKYOU:
                        PostQuitMessage(0);
                        break;
                }
            } else {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
    }

    CoUninitialize();

    PostThreadMessage(*main_thread_id, WM_YOURWELCOME, 0, NULL);
    return msg.wParam;
}


int _tmain(int argc, _TCHAR* argv[])
{
    MSG msg = {0};
    DWORD main_thread_id = GetCurrentThreadId();

    HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
    assert(SUCCEEDED(hr));
    {
        DWORD ThreadId = 0;
        HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)TheOtherThread, &main_thread_id, 0, &ThreadId);

        DWORD the_cookie = 0;

        CComPtr<IWebBrowser2> wb, wb2;

        while(GetMessage(&msg, 0, 0, 0)) {
            if(msg.hwnd == NULL) {
                // thread message
                switch(msg.message) {
                    case WM_THEREYOUGO:
                        // we got the cookie.
                        the_cookie = msg.wParam;

                        // get the browser. This should work.
                        {
                            CComPtr<IGlobalInterfaceTable> com_broker;
                            hr = com_broker.CoCreateInstance(CLSID_StdGlobalInterfaceTable);
                            assert(SUCCEEDED(hr));
                            hr = com_broker->GetInterfaceFromGlobal(the_cookie, __uuidof(IWebBrowser2), (void**)&wb);
                            assert(SUCCEEDED(hr) && wb);
                        }

                        // do something with it.
                        hr = wb->put_FullScreen(VARIANT_TRUE);
                        assert(SUCCEEDED(hr));

                        // signal the other thread.
                        PostThreadMessage(ThreadId, WM_THANKYOU, 0, NULL);
                        break;

                    case WM_YOURWELCOME:
                        // the other thread has ended.
                        PostQuitMessage(0);
                        break;
                }
            } else {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }

        // the other thread has ended. Try getting the interface again.
        {
            CComPtr<IGlobalInterfaceTable> com_broker;
            hr = com_broker.CoCreateInstance(CLSID_StdGlobalInterfaceTable);
            assert(SUCCEEDED(hr));
            hr = com_broker->GetInterfaceFromGlobal(the_cookie, __uuidof(IWebBrowser2), (void**)&wb2);
            //assert(SUCCEEDED(hr) && wb2); // this fails, hr == E_INVALIDARG.

            // clean up, will not be executed.
            if(SUCCEEDED(hr)) {
                hr = com_broker->RevokeInterfaceFromGlobal(the_cookie);
            }
        }

        // try using it
        if(wb2) {
            hr = wb2->put_FullScreen(VARIANT_FALSE);
            assert(SUCCEEDED(hr));
        } else if(wb) {
            // this succeeds
            hr = wb->put_FullScreen(VARIANT_FALSE);
            assert(SUCCEEDED(hr));
        }

        CloseHandle(hThread);
    }

    CoUninitialize();
    return msg.wParam;
}
Run Code Online (Sandbox Code Playgroud)

底线是这个:

  • 结束注册接口的线程会使 cookie 失效。
  • 已编组的接口保持有效。(在本例中,就是这样。)

这意味着我获得了 IE 进程的代理,而不是其他线程的对象。