我在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解决方案来证明难度。
答案 0 :(得分:2)
您的应用通过提供事件接收器成为com服务器。该应用程序需要有效的“消息泵”。
如果在执行管道/调度命令时阻止消息泵,则会阻止IE调用事件接收器。
C#可能只适用于其他隐藏的窗口,但是你已经设置了该应用程序的其余部分。