From out-of-process, what is the proper way to get an IWebBrowser2 interface from an instance of IE?
I am working on a browser automation framework, which automates Internet Explorer, as well as other browsers. I am running into an intermittent problem when attempting to launch IE. The framework launches IE using the IELaunchURL API if it is present, and uses CreateProcess if not. The code to obtain the IWebBrowser2 interface is as follows:
// hwndBrowser is obtained by calling ::EnumWindows() with a function that
// compares the process ID of the window handle to the known process ID of
// the IE instance.
CComPtr<IHTMLDocument2> document;
LRESULT result;
::SendMessageTimeout(hwndBrowser,
WM_HTML_GETOBJECT,
0L,
0L,
SMTO_ABORTIFHUNG,
1000,
(PDWORD_PTR)&result);
// oleacc_instance_handle is obtained from ::LoadLibrary("oleacc.dll")
LPFNOBJECTFROMLRESULT object_pointer = reinterpret_cast<LPFNOBJECTFROMLRESULT>(
::GetProcAddress(oleacc_instance_handle, "ObjectFromLresult"));
if (object_pointer != NULL) {
HRESULT hr = (*object_pointer)(result,
IID_IHTMLDocument2,
0,
reinterpret_cast<void **>(&document));
if (SUCCEEDED(hr)) {
CComPtr<IHTMLWindow2> window;
hr = document->get_parentWindow(&window);
if (SUCCEEDED(hr)) {
// http://support.microsoft.com/kb/257717
CComQIPtr<IServiceProvider> provider(window);
if (provider) {
CComPtr<IServiceProvider> child_provider;
hr = provider->QueryService(SID_STopLevelBrowser,
IID_IServiceProv开发者_C百科ider,
reinterpret_cast<void **>(&child_provider));
if (SUCCEEDED(hr)) {
IWebBrowser2* browser;
hr = child_provider->QueryService(SID_SWebBrowserApp,
IID_IWebBrowser2,
reinterpret_cast<void **>(&browser));
if (SUCCEEDED(hr)) {
// The IWebBrowser2 pointer is passed back to the caller.
// process_window_info->pBrowser = browser;
}
}
}
}
}
}
Now for the problem: It seems that we can always successfully retrieve the IHTMLDocument2 object. However, when we attempt to call get_parentWindow(), we sometimes receive a "class not registered" result (0x80040154 REGDB_E_CLASSNOTREG), most often when launching a new instance of IE after closing a previous one. We can get the IWebBrowser2 interface by omitting the call to get_parentWindow() and simply calling QueryService directly on the document, but we will receive this error further down the line when we try to manipulate parts of the document. What could cause the get_parentWindow() call to fail?
Note that the entirety of the code can be found in context here.
The problem was in the use of threading in the application. We were not properly waiting for a thread to terminate before launching a new instance of IE.
精彩评论