2010-10-12 34 views
0

我發佈了這個問題在MSDN論壇上,但我的經驗已經在堆棧溢出這裏的答案更好的質量,所以我在這裏發佈。正如我之前幾次發佈的那樣,我正在研究瀏覽器自動化框架,從外部過程中自動化Internet Explorer。我的架構如下:我有一臺服務器,它打開一個命名管道,我的自動化客戶端將命令推送到該管道。服務器解釋這些命令,並在IWebBrowser2對象上執行它們,IWebBrowser2對象已包裝在我自己的C++類中。一切工作正常,直到我試圖吸收事件的IE實例。我的包裝類實現了IDispEventSimpleImpl,但是當我嘗試吸收事件時,瀏覽器實例無法以編程方式或通過UI對任何通信作出響應。下面是我的主要兩種方法最相關:下沉DWebBrowserEvents2事件似乎掛起程序化導航

void BrowserManager::Start(void) 
{ 
    CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); 
    std::basic_string<TCHAR> pipeName =L"\\\\.\\pipe\\managerpipe"; 
    HANDLE hPipe = ::CreateNamedPipe(pipeName.c_str(), 
    PIPE_ACCESS_DUPLEX, 
    PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 
    PIPE_UNLIMITED_INSTANCES, 
    1024, 
    1024, 
    0, 
    NULL); 

    if (hPipe == INVALID_HANDLE_VALUE) 
    { 
    DWORD dwError = ::GetLastError(); 
    } 

    this->m_isRunning = true; 

    while (this->m_isRunning) 
    { 
    BOOL result = ::ConnectNamedPipe(hPipe, NULL); 
    std::vector<CHAR> inputBuffer(1024); 
    DWORD bytesRead = 0; 
    ::ReadFile(hPipe, &inputBuffer[0], 1024, &bytesRead, NULL); 

    std::string command = &inputBuffer[0]; 
    std::string response = DispatchCommand(command); 

    std::vector<CHAR> outputBuffer(response.begin(), response.end()); 
    ::WriteFile(hPipe, &outputBuffer[0], outputBuffer.size(), &bytesRead, NULL); 
    ::FlushFileBuffers(hPipe); 
    ::DisconnectNamedPipe(hPipe); 

    if (strcmp(command.c_str(), "quit\r\n") == 0) 
    { 
     this->m_isRunning = false; 
    } 
    } 

    ::CloseHandle(hPipe); 
    CoUninitialize(); 
} 

std::string BrowserManager::DispatchCommand(std::string command) 
{ 
    std::string response; 
    if (strcmp(command.c_str(), "start\r\n") == 0) 
    { 
    // Launch the browser process using CreateProcess on XP 
    // or IELaunchURL on Vista or higher. This is done on a 
    // low-integrity thread so we have the correct integrity. 
    DWORD procId = this->m_factory->LaunchBrowserProcess(); 
    CComPtr<IWebBrowser2> pBrowser(this->m_factory->AttachToBrowser(procId)); 
    BrowserWrapper wrapper(pBrowser); 
    this->m_wrapper = wrapper; 
    response = "started"; 
    } 
    else if (strcmp(command.c_str(), "goto\r\n") == 0) 
    { 
    this->m_wrapper.GoToUrl("http://www.google.com/"); 
    response = "navigated"; 
    } 
    else if (strcmp(command.c_str(), "quit\r\n") == 0) 
    { 
    this->m_wrapper.CloseBrowser(); 
    response = "closed"; 
    } 
    else 
    { 
    response = "invalid command"; 
    } 

    return response; 
} 

有趣的是,我的原型在C#中同樣的機制轉換成非託管C++之前,爲了確保我試圖將工作,因爲我的C++技能不是在與我的C#技能水平相同。不用說,它在C#中可以正常工作,但是這個組件需要寫入非託管代碼。我敢肯定,我忽視了.NET Framework抽象化的東西,但不管它是什麼,它對我來說都不是顯而易見的。

爲了幫助我從我的錯誤中學習,我會很感激一個指向.NET Framework爲了讓它工作而做的事。在C#版本中,我使用單個線程來阻塞管道上的I/O,就像我在這裏(想我)。如果發佈的代碼片段不足以指向診斷,那麼我很樂意提供一個完整的Visual Studio 2008解決方案來展示難度。

+0

標題提到DWebBrowserEvents2它沒有在代碼中顯示。 – 2010-10-12 22:04:23

回答

2

通過提供事件接收器,您的應用程序正在成爲com服務器。該公司的應用程序需要積極的'消息泵'(S)。

如果您在執行管道/調度命令時阻塞了消息泵,那麼它將阻止IE調用事件接收器。

C#可能僅適用於其他隱藏窗口,但您已設置該應用程序的其餘部分。

+0

這一定是這裏發生的事情。它看起來像.NET Framework產生額外的線程,當你沉沒DWebBrowserEvents2事件。此COM互操作代碼必須是在單線程控制檯應用程序(通常沒有消息循環)中運行時處理所有跨線程編組的東西。現在我只需要弄清楚如何在我的非託管C++代碼中完成類似的事情。 – JimEvans 2010-10-13 10:52:10