windows - 编码一个编码接口(interface)是否给我一个到代理或原始接口(interface)的编码器?

标签 windows com marshalling out-of-process

这是一个具体的例子:

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

现在我使用 IGlobalInterfaceTable要获取此接口(interface)的 cookie,请将其传递到我的线程 B 并从那里请求编码接口(interface)。

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

在我看来,我将获得实例的直接代理并引用它,这似乎是明智的,
但是:

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

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

最佳答案

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

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

底线是这样的:

  • 结束注册接口(interface)的线程会使 cookie 无效。
  • 已经编码的接口(interface)保持有效。 (在这种情况下,就是这样。)

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

关于windows - 编码一个编码接口(interface)是否给我一个到代理或原始接口(interface)的编码器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4025294/

相关文章:

c# - 如何在 c#.net 中将结构转换为字节数组,但结构大小仅在运行时定义

python - Windows XP GTK 应用程序 Glib 导入错误

c# - 有没有人将 rpy2 与 py2exe 一起使用?

com - 什么可能导致 Vb6 运行时错误 430

c# - 如何将 float 组从 c# 编码到 c,然后在 c 中编辑数组,同时让 c# 能够立即引用更新后的数组

java - 如何从服务器URL接收Json数据?

c# - 如何在 Windows 中加密文件夹?

Java 文件锁定和 Windows - 锁不是 "absolute"吗?

windows - 设置 Windows 终端的默认位置(预览)

.net - 在 Visual Studio 中进行调试和不进行调试时,.NET 程序的行为有何不同?