5

具体的な例を次に示します。

を呼び出してIWeBrowser2インターフェイスを作成しますwb.CoCreateInstance(CLSID_InternetExplorer, 0, CLSCTX_SERVER);。これにより、プロセスから実行中の iexplore.exe プロセスのいずれかにマーシャリングされたインターフェイスが提供され、たまたまスレッド Aにこのブラウザー タブが含まれています。

次に、 IGlobalInterfaceTableを使用してこのインターフェイスの Cookie を取得し、それをスレッド Bに渡し、そこからマーシャリングされたインターフェイスを要求します。

質問:スレッド A でプロキシへのプロキシを取得するか、または IE プロセスでインスタンスに直接プロキシを取得しますか?


ただし、インスタンスへの独自の参照を使用して、インスタンスへの直接プロキシを取得することは賢明なようです。

スレッド A を終了すると、そこで作成した Cookie が無効になり、作成した Web ブラウザーへのインターフェイス ポインターを取得 (および閉じる) できなくなります。これは、スレッドの終了時に破棄されるサンクがそのスレッドにない限り意味がありません。

編集:ああ、両方のスレッドがSTAです。

4

2 に答える 2

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

要点は次のとおりです。

  • インターフェイスを登録したスレッドを終了すると、Cookie が無効になります。
  • 既にマーシャリングされたインターフェイスは有効なままです。(この場合、つまり。)

これは、他のスレッドのオブジェクトではなく、IE プロセスへのプロキシを取得することを意味します。

于 2010-11-19T21:39:27.030 に答える
1

アウトプロセス サーバーを要求したため、スレッド A で既にプロキシを取得しています。次に何が起こるかは、スレッド A が住んでいるアパートメントの種類 (CoInitializeEx() への引数) によって異なります。それが MTA である場合、スレッド B で同じプロキシを確実に取得します。これも MTA であると仮定します。追加された参照カウントは、スレッド A が終了した場合にそれを維持する必要があります。STA の場合、100% 確信はありませんが、新しいものを入手する必要があると思います。テストは簡単ですが、スレッド A のスレッドを使用するだけで、新しいスレッドを作成する必要がある場合は RPC_E_WRONGTHREAD が返されます。

IGlobalInterfaceTable::RevokeInterfaceFromGlobal() を呼び出さない限り、スレッド A の終了がスレッド B のプロキシを強制終了する理由について、私は十分な説明を持っていません。あなたが通常行うこと。

于 2010-10-26T19:19:15.110 に答える