下沉DWebBrowserEvents2事件似乎挂起程序化导航

时间:2010-10-12 21:28:50

标签: c++ internet-explorer events iwebbrowser2

我在MSDN论坛上发布了这个问题,但我的经验在Stack Overflow上的答案质量更好,所以我也在这里发帖。正如我之前多次发布的那样,我正在开发一个浏览器自动化框架,从外部流程自动化Internet Explorer。我的架构如下:我有一个服务器打开一个命名管道,我的自动化客户端将命令推送到该管道。服务器解释命令,并在IWebBrowser2对象上执行它们,我已经将它包装在我自己的C ++类中。一切正常,直到我尝试在IE实例上接收事件。我的包装器类实现了IDispEventSimpleImpl,但是当我尝试接收事件时,浏览器实例不会以编程方式或通过UI响应任何通信。以下是我最主要的两种相关方法:

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框架抽象的东西,但不管它是什么,对我来说都不是很明显。

为了帮助我从错误中吸取教训,我很欣赏指向.NET Framework正在做的事情以使其工作。在C#版本中,我使用的是一个在管道上阻塞I / O的线程,就像我(我想)我在这里一样。如果发布的代码段不足以指向诊断,我非常乐意提供完整的Visual Studio 2008解决方案来证明难度。

1 个答案:

答案 0 :(得分:2)

您的应用通过提供事件接收器成为com服务器。该应用程序需要有效的“消息泵”。

如果在执行管道/调度命令时阻止消息泵,则会阻止IE调用事件接收器。

C#可能只适用于其他隐藏的窗口,但是你已经设置了该应用程序的其余部分。