Я разместил этот вопрос на форумах MSDN, но мой опыт был лучшим качеством ответа здесь, в Stack Overflow, поэтому я также размещаю здесь. Как я уже писал несколько раз раньше, я работаю над каркасом автоматизации браузера, автоматизируя Internet Explorer из внешнего процесса. Моя архитектура выглядит следующим образом: у меня есть сервер, который открывает именованный канал, который мой клиент автоматизации нажимает на команды. Сервер интерпретирует команды и выполняет их на объекте IWebBrowser2, который я завернул в свой собственный класс C++. Все работает нормально, пока я не попытаюсь потопить события в IE-экземпляре. Мой класс-оболочка реализует IDispEventSimpleImpl, но когда я пытаюсь потопить события, экземпляр браузера не отвечает ни на какое общение, ни программно, ни через пользовательский интерфейс. Вот мои основные два метода с наиболее актуальными:Понижение событий 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# я использую единственный поток с блокировкой ввода-вывода на трубе, как и я (думаю, я) здесь. Если опубликованного фрагмента кода недостаточно, чтобы указать на диагноз, я более чем счастлив предоставить полное решение Visual Studio 2008, демонстрирующее трудности.
В названии упоминается DWebBrowserEvents2, который не показан в коде. –