При отображении событий DWebBrowserEvents2 зависает программная навигация - PullRequest
0 голосов
/ 13 октября 2010

Я разместил этот вопрос на форумах MSDN, но мой опыт показал лучшее качество ответа здесь, на Stack Overflow, поэтому я также публикую здесь.Как я уже писал несколько раз ранее, я работаю над инфраструктурой автоматизации браузера, автоматизируя Internet Explorer из внешнего процесса.Моя архитектура выглядит следующим образом: у меня есть сервер, который открывает именованный канал, на который мой клиент автоматизации передает команды.Сервер интерпретирует команды и выполняет их для объекта IWebBrowser2, который я обернул в свой собственный класс C ++.Все работает нормально, пока я не попытаюсь утопить события в экземпляре IE.Мой класс-оболочка реализует IDispEventSimpleImpl, но когда я пытаюсь обработать события, экземпляр браузера не отвечает ни на какие сообщения, ни программно, ни через пользовательский интерфейс.Вот два моих основных метода с наибольшей актуальностью:

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 # я использую один поток с блокировкой ввода / вывода на конвейере, как я (думаю, я) здесь.Если приведенного фрагмента кода недостаточно для указания диагноза, я более чем рад предоставить полное решение Visual Studio 2008, демонстрирующее эту трудность.

1 Ответ

2 голосов
/ 13 октября 2010

Ваше приложение становится com-сервером, предоставляя приемники событий. Ком-приложению нужны активные «насос сообщений».

Если вы блокируете рассылку сообщений, когда выполняете команду pipe / dispatch, тогда он не позволит IE вызывать ваш приемник событий.

C # может просто работать для других скрытых окон, которые у него есть, и, тем не менее, вы настроили остальную часть этого приложения.

...