Does the marshaled interface march, giving me a marshaller for the proxy or the original interface?

Here is a concrete example:

I am creating an IWeBrowser2 interface by calling wb.CoCreateInstance(CLSID_InternetExplorer, 0, CLSCTX_SERVER);. This gives me an interface with marshaling from my process depending on which of the iexplore.exe processes contains this browser tab in my stream A.

Now I use IGlobalInterfaceTable to get a cookie for this interface, pass it to my stream B and request a marshaled interface from there.

Question: Do I get a proxy proxy in my stream A or directly in the instance in the IE process?

It seems reasonable to me that I get a direct proxy to the instance with my link to it, however :

If I end my stream A, the cookie I created becomes invalid and I cannot receive (and close) the web browser interface pointers that I created more. This does not make sense if there is no thread in this thread that is destroyed when the thread terminates.

Edit: Oh, both threads are STAs.

+5
source share
2 answers

I finally had time to figure out what was going on, so I wrote a short test to see what was going on.

// 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;
}

The bottom line shows the following:

  • , , cookie.
  • . ( .)

, - IE, .

+2

- A, . , , , A, CoInitializeEx(). MTA, - B, , MTA. , Thread A . STA, 100%, , . btw, A, RPC_E_WRONGTHREAD, .

, A exit B. IGlobalInterfaceTable:: RevokeInterfaceFromGlobal(). .

+1

All Articles