std::wstring BrowserWrapper::GetTitle() { CComPtr<IDispatch> dispatch; HRESULT hr = this->browser_->get_Document(&dispatch); if (FAILED(hr)) { LOGHR(DEBUG, hr) << "Unable to get document"; return L""; } CComPtr<IHTMLDocument2> doc; hr = dispatch->QueryInterface(&doc); if (FAILED(hr)) { LOGHR(WARN, hr) << "Have document but cannot cast"; return L""; } CComBSTR title; hr = doc->get_title(&title); if (FAILED(hr)) { LOGHR(WARN, hr) << "Unable to get document title"; return L""; } std::wstring title_string = (BSTR)title; return title_string; }
bool ScriptWrapper::CreateAnonymousFunction(IDispatch* script_engine, DISPID eval_id, const std::wstring& script, VARIANT* result) { CComVariant script_variant(script.c_str()); DISPPARAMS parameters = {0}; memset(¶meters, 0, sizeof parameters); parameters.cArgs = 1; parameters.rgvarg = &script_variant; parameters.cNamedArgs = 0; EXCEPINFO exception; memset(&exception, 0, sizeof exception); HRESULT hr = script_engine->Invoke(eval_id, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, ¶meters, result, &exception, 0); if (FAILED(hr)) { if (DISP_E_EXCEPTION == hr) { LOGHR(INFO, hr) << "Exception message was: " << _bstr_t(exception.bstrDescription) << ": " << _bstr_t(script_variant); } else { LOGHR(DEBUG, hr) << "Failed to compile: " << _bstr_t(script_variant); } if (result) { result->vt = VT_USERDEFINED; if (exception.bstrDescription != NULL) { result->bstrVal = ::SysAllocStringByteLen((char*)exception.bstrDescription, ::SysStringByteLen(exception.bstrDescription)); } else { result->bstrVal = ::SysAllocStringByteLen(NULL, 0); } } return false; } return true; }
void BrowserWrapper::GetDocument(IHTMLDocument2 **doc) { CComPtr<IHTMLWindow2> window; if (this->focused_frame_window_ == NULL) { CComPtr<IDispatch> dispatch; HRESULT hr = this->browser_->get_Document(&dispatch); if (FAILED(hr)) { LOGHR(DEBUG, hr) << "Unable to get document"; return; } CComPtr<IHTMLDocument2> dispatch_doc; hr = dispatch->QueryInterface(&dispatch_doc); if (FAILED(hr)) { LOGHR(WARN, hr) << "Have document but cannot cast"; return; } dispatch_doc->get_parentWindow(&window); } else { window = this->focused_frame_window_; } if (window) { bool result = this->GetDocumentFromWindow(window, doc); if (!result) { LOG(WARN) << "Cannot get document"; } } }
std::string DocumentHost::GetPageSource() { LOG(TRACE) << "Entering DocumentHost::GetPageSource"; CComPtr<IHTMLDocument2> doc; this->GetDocument(&doc); CComPtr<IHTMLDocument3> doc3; CComQIPtr<IHTMLDocument3> doc_qi_pointer(doc); if (doc_qi_pointer) { doc3 = doc_qi_pointer.Detach(); } if (!doc3) { LOG(WARN) << "Unable to get document object, QueryInterface to IHTMLDocument3 failed"; return ""; } CComPtr<IHTMLElement> document_element; HRESULT hr = doc3->get_documentElement(&document_element); if (FAILED(hr)) { LOGHR(WARN, hr) << "Unable to get document element from page, call to IHTMLDocument3::get_documentElement failed"; return ""; } CComBSTR html; hr = document_element->get_outerHTML(&html); if (FAILED(hr)) { LOGHR(WARN, hr) << "Have document element but cannot read source, call to IHTMLElement::get_outerHTML failed"; return ""; } std::string page_source = CW2A(html, CP_UTF8); return page_source; }
void DocumentHost::SetFocusedFrameToParent() { LOG(TRACE) << "Entering DocumentHost::SetFocusedFrameToParent"; // Three possible outcomes. // Outcome 1: Already at top-level browsing context. No-op. if (this->focused_frame_window_ != NULL) { CComPtr<IHTMLWindow2> parent_window; HRESULT hr = this->focused_frame_window_->get_parent(&parent_window); if (FAILED(hr)) { LOGHR(WARN, hr) << "IHTMLWindow2::get_parent call failed."; } CComPtr<IHTMLWindow2> top_window; hr = this->focused_frame_window_->get_top(&top_window); if (FAILED(hr)) { LOGHR(WARN, hr) << "IHTMLWindow2::get_top call failed."; } if (top_window.IsEqualObject(parent_window)) { // Outcome 2: Focus is on a frame one level deep, making the // parent the top-level browsing context. Set focused frame // pointer to NULL. this->focused_frame_window_ = NULL; } else { // Outcome 3: Focus is on a frame more than one level deep. // Set focused frame pointer to parent frame. this->focused_frame_window_ = parent_window; } } }
bool VariantUtilities::GetVariantObjectPropertyValue(IDispatch* variant_object_dispatch, std::wstring property_name, VARIANT* property_value) { LPOLESTR property_name_pointer = reinterpret_cast<LPOLESTR>(const_cast<wchar_t*>(property_name.data())); DISPID dispid_property; HRESULT hr = variant_object_dispatch->GetIDsOfNames(IID_NULL, &property_name_pointer, 1, LOCALE_USER_DEFAULT, &dispid_property); if (FAILED(hr)) { LOGHR(WARN, hr) << "Unable to get dispatch ID (dispid) for property " << StringUtilities::ToString(property_name); return false; } // get the value of eval result DISPPARAMS no_args_dispatch_parameters = { 0 }; hr = variant_object_dispatch->Invoke(dispid_property, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &no_args_dispatch_parameters, property_value, NULL, NULL); if (FAILED(hr)) { LOGHR(WARN, hr) << "Unable to get result for property " << StringUtilities::ToString(property_name); return false; } return true; }
std::string DocumentHost::GetPageSource() { LOG(TRACE) << "Entering DocumentHost::GetPageSource"; CComPtr<IHTMLDocument2> doc; this->GetDocument(&doc); CComPtr<IHTMLDocument3> doc3; HRESULT hr = doc->QueryInterface<IHTMLDocument3>(&doc3); if (FAILED(hr) || !doc3) { LOG(WARN) << "Unable to get document object, QueryInterface to IHTMLDocument3 failed"; return ""; } CComPtr<IHTMLElement> document_element; hr = doc3->get_documentElement(&document_element); if (FAILED(hr) || !document_element) { LOGHR(WARN, hr) << "Unable to get document element from page, call to IHTMLDocument3::get_documentElement failed"; return ""; } CComBSTR html; hr = document_element->get_outerHTML(&html); if (FAILED(hr)) { LOGHR(WARN, hr) << "Have document element but cannot read source, call to IHTMLElement::get_outerHTML failed"; return ""; } std::wstring converted_html = html; std::string page_source = StringUtilities::ToString(converted_html); return page_source; }
void Browser::GetDocument(IHTMLDocument2** doc) { LOG(TRACE) << "Entering Browser::GetDocument"; CComPtr<IHTMLWindow2> window; if (this->focused_frame_window() == NULL) { LOG(INFO) << "No child frame focus. Focus is on top-level frame"; CComPtr<IDispatch> dispatch; HRESULT hr = this->browser_->get_Document(&dispatch); if (FAILED(hr)) { LOGHR(WARN, hr) << "Unable to get document, IWebBrowser2::get_Document call failed"; return; } CComPtr<IHTMLDocument2> dispatch_doc; hr = dispatch->QueryInterface(&dispatch_doc); if (FAILED(hr)) { LOGHR(WARN, hr) << "Have document but cannot cast, IDispatch::QueryInterface call failed"; return; } dispatch_doc->get_parentWindow(&window); } else { window = this->focused_frame_window(); } if (window) { bool result = this->GetDocumentFromWindow(window, doc); if (!result) { LOG(WARN) << "Cannot get document"; } } else { LOG(WARN) << "No window is found"; } }
std::string Browser::GetTitle() { LOG(TRACE) << "Entering Browser::GetTitle"; CComPtr<IDispatch> dispatch; HRESULT hr = this->browser_->get_Document(&dispatch); if (FAILED(hr)) { LOGHR(WARN, hr) << "Unable to get document, IWebBrowser2::get_Document call failed"; return ""; } CComPtr<IHTMLDocument2> doc; hr = dispatch->QueryInterface(&doc); if (FAILED(hr)) { LOGHR(WARN, hr) << "Have document but cannot cast, IDispatch::QueryInterface call failed"; return ""; } CComBSTR title; hr = doc->get_title(&title); if (FAILED(hr)) { LOGHR(WARN, hr) << "Unable to get document title, call to IHTMLDocument2::get_title failed"; return ""; } std::wstring converted_title = title; std::string title_string = StringUtilities::ToString(converted_title); return title_string; }
HWND Browser::GetBrowserWindowHandle() { LOG(TRACE) << "Entering Browser::GetBrowserWindowHandle"; HWND hwnd = NULL; CComPtr<IServiceProvider> service_provider; HRESULT hr = this->browser_->QueryInterface(IID_IServiceProvider, reinterpret_cast<void**>(&service_provider)); if (SUCCEEDED(hr)) { CComPtr<IOleWindow> window; hr = service_provider->QueryService(SID_SShellBrowser, IID_IOleWindow, reinterpret_cast<void**>(&window)); if (SUCCEEDED(hr)) { // This gets the TabWindowClass window in IE 7 and 8, // and the top-level window frame in IE 6. window->GetWindow(&hwnd); } else { LOGHR(WARN, hr) << "Unable to get window, call to IOleWindow::QueryService for SID_SShellBrowser failed"; } } else { LOGHR(WARN, hr) << "Unable to get service, call to IWebBrowser2::QueryInterface for IID_IServiceProvider failed"; } return hwnd; }
bool Script::CreateAnonymousFunction(VARIANT* result) { LOG(TRACE) << "Entering Script::CreateAnonymousFunction"; std::wstring function_eval_script = L"window.document.__webdriver_script_fn = "; function_eval_script.append(this->source_code_.c_str()); CComBSTR code(function_eval_script.c_str()); CComBSTR lang(L"JScript"); CComVariant exec_script_result; CComPtr<IHTMLWindow2> window; HRESULT hr = this->script_engine_host_->get_parentWindow(&window); if (FAILED(hr)) { LOGHR(WARN, hr) << "Unable to get parent window, call to IHTMLDocument2::get_parentWindow failed"; return false; } //LAM: General Access Denied Error ( could be protected mode ) hr = window->execScript(code, lang, &exec_script_result); if (FAILED(hr)) { LOGHR(WARN, hr) << "Unable to execute code, call to IHTMLWindow2::execScript failed"; LOG(ERROR) << "Unable to execute code, call to IHTMLWindow2::execScript failed"; return false; } bool get_result_success = VariantUtilities::GetVariantObjectPropertyValue( this->script_engine_host_, L"__webdriver_script_fn", result); return get_result_success; }
std::string Browser::GetWindowName() { LOG(TRACE) << "Entering Browser::GetWindowName"; CComPtr<IDispatch> dispatch; HRESULT hr = this->browser_->get_Document(&dispatch); if (FAILED(hr)) { LOGHR(WARN, hr) << "Unable to get document, IWebBrowser2::get_Document call failed"; return ""; } CComQIPtr<IHTMLDocument2> doc(dispatch); if (!doc) { LOGHR(WARN, hr) << "Have document but cannot cast, IDispatch::QueryInterface call failed"; return ""; } CComPtr<IHTMLWindow2> window; hr = doc->get_parentWindow(&window); if (FAILED(hr)) { LOGHR(WARN, hr) << "Unable to get parent window, call to IHTMLDocument2::get_parentWindow failed"; return ""; } std::string name = ""; CComBSTR window_name; hr = window->get_name(&window_name); if (window_name) { name = CW2A(window_name, CP_UTF8); } else { LOG(WARN) << "Unable to get window name, IHTMLWindow2::get_name failed or returned a NULL value"; } return name; }
void ScreenshotCommandHandler::ExecuteInternal( const IECommandExecutor& executor, const ParametersMap& command_parameters, Response* response) { LOG(TRACE) << "Entering ScreenshotCommandHandler::ExecuteInternal"; BrowserHandle browser_wrapper; int status_code = executor.GetCurrentBrowser(&browser_wrapper); if (status_code != WD_SUCCESS) { response->SetErrorResponse(status_code, "Unable to get browser"); return; } bool isSameColour = true; HRESULT hr; int i = 0; int tries = 4; const bool should_resize_window = executor.enable_full_page_screenshot(); do { this->ClearImage(); this->image_ = new CImage(); if (should_resize_window) { hr = this->CaptureFullPage(browser_wrapper); } else { hr = this->CaptureViewport(browser_wrapper); } if (FAILED(hr)) { LOGHR(WARN, hr) << "Failed to capture browser image at " << i << " try"; this->ClearImage(); response->SetSuccessResponse(""); return; } isSameColour = IsSameColour(); if (isSameColour) { ::Sleep(2000); LOG(DEBUG) << "Failed to capture non single color browser image at " << i << " try"; } i++; } while ((i < tries) && isSameColour); // now either correct or single color image is got std::string base64_screenshot = ""; hr = this->GetBase64Data(base64_screenshot); if (FAILED(hr)) { LOGHR(WARN, hr) << "Unable to transform browser image to Base64 format"; this->ClearImage(); response->SetSuccessResponse(""); return; } this->ClearImage(); response->SetSuccessResponse(base64_screenshot); }
bool DocumentHost::IsHtmlPage(IHTMLDocument2* doc) { LOG(TRACE) << "Entering DocumentHost::IsHtmlPage"; CComBSTR type; HRESULT hr = doc->get_mimeType(&type); if (FAILED(hr)) { LOGHR(WARN, hr) << "Unable to get mime type for document, call to IHTMLDocument2::get_mimeType failed"; return false; } // Call once to get the required buffer size, then again to fill // the buffer. DWORD mime_type_name_buffer_size = 0; hr = ::AssocQueryString(0, ASSOCSTR_FRIENDLYDOCNAME, L".htm", NULL, NULL, &mime_type_name_buffer_size); std::vector<wchar_t> mime_type_name_buffer(mime_type_name_buffer_size); hr = ::AssocQueryString(0, ASSOCSTR_FRIENDLYDOCNAME, L".htm", NULL, &mime_type_name_buffer[0], &mime_type_name_buffer_size); if (FAILED(hr)) { LOGHR(WARN, hr) << "Call to AssocQueryString failed in getting friendly name of .htm documents"; return false; } std::wstring mime_type_name = &mime_type_name_buffer[0]; std::wstring type_string = type; if (type_string == mime_type_name) { return true; } // If the user set Firefox as a default browser at any point, the MIME type // appears to be "sticky". This isn't elegant, but it appears to alleviate // the worst symptoms. Tested by using both Safari and Opera as the default // browser, even after setting IE as the default after Firefox (so the chain // of defaults looks like (IE -> Firefox -> IE -> Opera) if (L"Firefox HTML Document" == mime_type_name) { LOG(INFO) << "It looks like Firefox was once the default browser. " << "Guessing the page type from mime type alone"; return true; } return false; }
std::string Alert::GetDirectUIDialogText() { LOG(TRACE) << "Entering Alert::GetDirectUIDialogText"; std::string alert_text_value = ""; HWND direct_ui_child_handle = this->GetDirectUIChild(); CComPtr<IAccessible> window_object; HRESULT hr = ::AccessibleObjectFromWindow( direct_ui_child_handle, OBJID_WINDOW, IID_IAccessible, reinterpret_cast<void**>(&window_object)); if (FAILED(hr)) { LOGHR(WARN, hr) << "Failed to get Active Accessibility window object from dialog"; return alert_text_value; } // ASSUMPTION: There is an object with the role of "pane" as a child of // the window object. CComPtr<IAccessible> pane_object = this->GetChildWithRole(window_object, ROLE_SYSTEM_PANE, 0); if (!pane_object) { LOG(WARN) << "Failed to get Active Accessibility pane child object from window"; return alert_text_value; } // ASSUMPTION: The second "static text" accessibility object is the one // that contains the message. CComPtr<IAccessible> message_text_object = this->GetChildWithRole( pane_object, ROLE_SYSTEM_STATICTEXT, 1); if (!message_text_object) { LOG(WARN) << "Failed to get Active Accessibility text child object from pane"; return alert_text_value; } CComVariant child_id; child_id.vt = VT_I4; child_id.lVal = CHILDID_SELF; CComBSTR text_bstr; hr = message_text_object->get_accName(child_id, &text_bstr); if (FAILED(hr)) { LOGHR(WARN, hr) << "Failed to get accName property from text object"; return alert_text_value; } std::wstring text = text_bstr; alert_text_value = StringUtilities::ToString(text); return alert_text_value; }
bool Script::CreateAnonymousFunction(VARIANT* result) { LOG(TRACE) << "Entering Script::CreateAnonymousFunction"; CComBSTR function_eval_script(L"window.document.__webdriver_script_fn = "); HRESULT hr = function_eval_script.Append(this->source_code_.c_str()); CComBSTR code(function_eval_script); CComBSTR lang(L"JScript"); CComVariant exec_script_result; CComPtr<IHTMLWindow2> window; hr = this->script_engine_host_->get_parentWindow(&window); if (FAILED(hr)) { LOGHR(WARN, hr) << "Unable to get parent window, call to IHTMLDocument2::get_parentWindow failed"; return false; } hr = window->execScript(code, lang, &exec_script_result); if (FAILED(hr)) { LOGHR(WARN, hr) << "Unable to execute code, call to IHTMLWindow2::execScript failed"; return false; } OLECHAR FAR* function_object_name = L"__webdriver_script_fn"; DISPID dispid_function_object; hr = this->script_engine_host_->GetIDsOfNames(IID_NULL, &function_object_name, 1, LOCALE_USER_DEFAULT, &dispid_function_object); if (FAILED(hr)) { LOGHR(WARN, hr) << "Unable to get id of name __webdriver_script_fn"; return false; } // get the value of eval result DISPPARAMS no_args_dispatch_parameters = { NULL, NULL, 0, 0 }; hr = this->script_engine_host_->Invoke(dispid_function_object, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &no_args_dispatch_parameters, result, NULL, NULL); if (FAILED(hr)) { LOGHR(WARN, hr) << "Unable to get value of eval result"; return false; } return true; }
bool Element::IsAttachedToDom() { // Verify that the element is still valid by getting the document // element and calling IHTMLElement::contains() to see if the document // contains this element. if (this->element_) { CComPtr<IHTMLDOMNode2> node; HRESULT hr = this->element_->QueryInterface<IHTMLDOMNode2>(&node); if (FAILED(hr)) { LOGHR(WARN, hr) << "Unable to cast element to IHTMLDomNode2"; return false; } CComPtr<IDispatch> dispatch_doc; hr = node->get_ownerDocument(&dispatch_doc); if (FAILED(hr)) { LOGHR(WARN, hr) << "Unable to locate owning document, call to IHTMLDOMNode2::get_ownerDocument failed"; return false; } if (dispatch_doc) { CComPtr<IHTMLDocument3> doc; hr = dispatch_doc.QueryInterface<IHTMLDocument3>(&doc); if (FAILED(hr)) { LOGHR(WARN, hr) << "Found document but it's not the expected type (IHTMLDocument3)"; return false; } CComPtr<IHTMLElement> document_element; hr = doc->get_documentElement(&document_element); if (FAILED(hr)) { LOGHR(WARN, hr) << "Unable to locate document element, call to IHTMLDocument3::get_documentElement failed"; return false; } if (document_element) { VARIANT_BOOL contains(VARIANT_FALSE); hr = document_element->contains(this->element_, &contains); if (FAILED(hr)) { LOGHR(WARN, hr) << "Call to IHTMLElement::contains failed"; return false; } return contains == VARIANT_TRUE; } } } return false; }
int DocumentHost::AddCookie(const std::string& cookie) { LOG(TRACE) << "Entering DocumentHost::AddCookie"; CComBSTR cookie_bstr(CA2W(cookie.c_str(), CP_UTF8)); CComPtr<IHTMLDocument2> doc; this->GetDocument(&doc); if (!doc) { LOG(WARN) << "Unable to get document"; return EUNHANDLEDERROR; } if (!this->IsHtmlPage(doc)) { LOG(WARN) << "Unable to add cookie, document does not appear to be an HTML page"; return ENOSUCHDOCUMENT; } HRESULT hr = doc->put_cookie(cookie_bstr); if (FAILED(hr)) { LOGHR(WARN, hr) << "Unable to put cookie to document, call to IHTMLDocument2::put_cookie failed"; return EUNHANDLEDERROR; } return SUCCESS; }
int DocumentHost::SetFocusedFrameByElement(IHTMLElement* frame_element) { LOG(TRACE) << "Entering DocumentHost::SetFocusedFrameByElement"; HRESULT hr = S_OK; if (!frame_element) { this->focused_frame_window_ = NULL; return SUCCESS; } CComQIPtr<IHTMLFrameBase2> frame_base(frame_element); if (!frame_base) { LOG(WARN) << "IHTMLElement is not a FRAME or IFRAME element"; return ENOSUCHFRAME; } CComQIPtr<IHTMLWindow2> interim_result; hr = frame_base->get_contentWindow(&interim_result); if (FAILED(hr)) { LOGHR(WARN, hr) << "Cannot get contentWindow from IHTMLFrameBase2, call to IHTMLFrameBase2::get_contentWindow failed"; return ENOSUCHFRAME; } this->focused_frame_window_ = interim_result; return SUCCESS; }
bool BrowserFactory::GetDocumentFromWindowHandle(HWND window_handle, IHTMLDocument2** document) { LOG(TRACE) << "Entering BrowserFactory::GetDocumentFromWindowHandle"; if (window_handle != NULL && this->oleacc_instance_handle_) { LRESULT result; ::SendMessageTimeout(window_handle, this->html_getobject_msg_, 0L, 0L, SMTO_ABORTIFHUNG, 1000, reinterpret_cast<PDWORD_PTR>(&result)); LPFNOBJECTFROMLRESULT object_pointer = reinterpret_cast<LPFNOBJECTFROMLRESULT>(::GetProcAddress(this->oleacc_instance_handle_, "ObjectFromLresult")); if (object_pointer != NULL) { HRESULT hr; hr = (*object_pointer)(result, IID_IHTMLDocument2, 0, reinterpret_cast<void**>(document)); if (SUCCEEDED(hr)) { return true; } else { LOGHR(WARN, hr) << "Unable to convert document object pointer to IHTMLDocument2 object via ObjectFromLresult"; } } else { LOG(WARN) << "Unable to get address of ObjectFromLresult method from library; GetProcAddress() for ObjectFromLresult returned NULL"; } } else { LOG(WARN) << "Window handle is invalid or OLEACC.DLL is not loaded properly"; } return false; }
IWebBrowser2* BrowserFactory::CreateBrowser() { LOG(TRACE) << "Entering BrowserFactory::CreateBrowser"; IWebBrowser2* browser = NULL; DWORD context = CLSCTX_LOCAL_SERVER; if (this->ie_major_version_ == 7 && this->windows_major_version_ >= 6) { // ONLY for IE 7 on Windows Vista. XP and below do not have Protected Mode; // Windows 7 shipped with IE8. context = context | CLSCTX_ENABLE_CLOAKING; } HRESULT hr = ::CoCreateInstance(CLSID_InternetExplorer, NULL, context, IID_IWebBrowser2, reinterpret_cast<void**>(&browser)); // When IWebBrowser2::Quit() is called, the wrapper process doesn't // exit right away. When that happens, CoCreateInstance can fail while // the abandoned iexplore.exe instance is still valid. The "right" way // to do this would be to call ::EnumProcesses before calling // CoCreateInstance, finding all of the iexplore.exe processes, waiting // for one to exit, and then proceed. However, there is no way to tell // if a process ID belongs to an Internet Explorer instance, particularly // when a 32-bit process tries to enumerate 64-bit processes on 64-bit // Windows. So, we'll take the brute force way out, just retrying the call // to CoCreateInstance until it succeeds (the old iexplore.exe process has // exited), or we get a different error code. We'll also set a 45-second // timeout, with 45 seconds being chosen because it's below the default // 60 second HTTP request timeout of most language bindings. if (FAILED(hr) && HRESULT_CODE(hr) == ERROR_SHUTDOWN_IS_SCHEDULED) { LOG(DEBUG) << "CoCreateInstance for IWebBrowser2 failed due to a " << "browser process that has not yet fully exited. Retrying " << "until the browser process exits and a new instance can " << "be successfully created."; } clock_t timeout = clock() + (45 * CLOCKS_PER_SEC); while (FAILED(hr) && HRESULT_CODE(hr) == ERROR_SHUTDOWN_IS_SCHEDULED && clock() < timeout) { ::Sleep(500); hr = ::CoCreateInstance(CLSID_InternetExplorer, NULL, context, IID_IWebBrowser2, reinterpret_cast<void**>(&browser)); } if (FAILED(hr) && HRESULT_CODE(hr) != ERROR_SHUTDOWN_IS_SCHEDULED) { // If we hit this branch, the CoCreateInstance failed due to an unexpected // error, either before we looped, or at some point during the loop. In // in either case, there's not much else we can do except log the failure. LOGHR(WARN, hr) << "CoCreateInstance for IWebBrowser2 failed."; } if (browser != NULL) { browser->put_Visible(VARIANT_TRUE); } return browser; }
bool Browser::GetDocumentFromWindow(IHTMLWindow2* window, IHTMLDocument2** doc) { LOG(TRACE) << "Entering Browser::GetDocumentFromWindow"; HRESULT hr = window->get_document(doc); if (SUCCEEDED(hr)) { return true; } if (hr == E_ACCESSDENIED) { // Cross-domain documents may throw Access Denied. If so, // get the document through the IWebBrowser2 interface. CComPtr<IServiceProvider> service_provider; hr = window->QueryInterface<IServiceProvider>(&service_provider); if (FAILED(hr)) { LOGHR(WARN, hr) << "Unable to get browser, call to IHTMLWindow2::QueryService failed for IServiceProvider"; return false; } CComPtr<IWebBrowser2> window_browser; hr = service_provider->QueryService(IID_IWebBrowserApp, &window_browser); if (FAILED(hr)) { LOGHR(WARN, hr) << "Unable to get browser, call to IServiceProvider::QueryService failed for IID_IWebBrowserApp"; return false; } CComPtr<IDispatch> document_dispatch; hr = window_browser->get_Document(&document_dispatch); if (FAILED(hr) || hr == S_FALSE) { LOGHR(WARN, hr) << "Unable to get document, call to IWebBrowser2::get_Document failed"; return false; } hr = document_dispatch->QueryInterface(doc); if (FAILED(hr)) { LOGHR(WARN, hr) << "Unable to query document, call to IDispatch::QueryInterface failed."; return false; } return true; } else { LOGHR(WARN, hr) << "Unable to get main document, IHTMLWindow2::get_document returned other than E_ACCESSDENIED"; } return false; }
IAccessible* Alert::GetChildWithRole(IAccessible* parent, long expected_role, int index) { LOG(TRACE) << "Entering Alert::GetChildWithRole"; IAccessible* child = NULL; long child_count; HRESULT hr = parent->get_accChildCount(&child_count); if (FAILED(hr)) { LOGHR(WARN, hr) << "Failed to get accChildCount property from Active Accessibility object"; return child; } long returned_children = 0; std::vector<CComVariant> child_array(child_count); hr = ::AccessibleChildren(parent, 0, child_count, &child_array[0], &returned_children); int found_index = 0; for (long i = 0; i < child_count; ++i) { if (child_array[i].vt == VT_DISPATCH) { CComPtr<IAccessible> child_object; hr = child_array[i].pdispVal->QueryInterface<IAccessible>(&child_object); if (FAILED(hr)) { LOGHR(WARN, hr) << "QueryInterface for IAccessible failed for child object with index " << i; } CComVariant child_id; child_id.vt = VT_I4; child_id.lVal = CHILDID_SELF; CComVariant actual_role; hr = child_object->get_accRole(child_id, &actual_role); if (FAILED(hr)) { LOGHR(WARN, hr) << "Failed to get accRole property from Active Accessibility object"; } if (expected_role == actual_role.lVal) { if (found_index == index) { child = child_object.Detach(); } else { ++found_index; } } LOG(DEBUG) << "accRole for child with index " << i << ": " << actual_role.lVal; } } return child; }
int Element::GetDocumentFromWindow(IHTMLWindow2* parent_window, IHTMLDocument2** parent_doc) { LOG(TRACE) << "Entering Element::GetParentDocument"; HRESULT hr = parent_window->get_document(parent_doc); if (FAILED(hr)) { if (hr == E_ACCESSDENIED) { // Cross-domain documents may throw Access Denied. If so, // get the document through the IWebBrowser2 interface. CComPtr<IServiceProvider> service_provider; hr = parent_window->QueryInterface<IServiceProvider>(&service_provider); if (FAILED(hr)) { LOGHR(WARN, hr) << "Unable to get browser, call to IHTMLWindow2::QueryInterface failed for IServiceProvider"; return ENOSUCHDOCUMENT; } CComPtr<IWebBrowser2> window_browser; hr = service_provider->QueryService(IID_IWebBrowserApp, &window_browser); if (FAILED(hr)) { LOGHR(WARN, hr) << "Unable to get browser, call to IServiceProvider::QueryService failed for IID_IWebBrowserApp"; return ENOSUCHDOCUMENT; } CComPtr<IDispatch> parent_doc_dispatch; hr = window_browser->get_Document(&parent_doc_dispatch); if (FAILED(hr)) { LOGHR(WARN, hr) << "Unable to get document, call to IWebBrowser2::get_Document failed"; return ENOSUCHDOCUMENT; } try { hr = parent_doc_dispatch->QueryInterface<IHTMLDocument2>(parent_doc); if (FAILED(hr)) { LOGHR(WARN, hr) << "Unable to get document, QueryInterface for IHTMLDocument2 failed"; return ENOSUCHDOCUMENT; } } catch(...) { LOG(WARN) << "Unable to get document, exception thrown attempting to QueryInterface for IHTMLDocument2"; return ENOSUCHDOCUMENT; } } else { LOGHR(WARN, hr) << "Unable to get document, IHTMLWindow2::get_document failed with error code other than E_ACCESSDENIED"; return ENOSUCHDOCUMENT; } } return WD_SUCCESS; }
void Browser::Close() { LOG(TRACE) << "Entering Browser::Close"; // Closing the browser, so having focus on a frame doesn't // make any sense. this->SetFocusedFrameByElement(NULL); HRESULT hr = this->browser_->Quit(); if (FAILED(hr)) { LOGHR(WARN, hr) << "Call to IWebBrowser2::Quit failed"; } }
int Element::GetContainingDocument(const bool use_dom_node, IHTMLDocument2** doc) { LOG(TRACE) << "Entering Element::GetContainingDocument"; HRESULT hr = S_OK; CComPtr<IDispatch> dispatch_doc; if (use_dom_node) { CComPtr<IHTMLDOMNode2> node; hr = this->element_->QueryInterface(&node); if (FAILED(hr)) { LOGHR(WARN, hr) << "Unable to cast element to IHTMLDomNode2"; return ENOSUCHDOCUMENT; } hr = node->get_ownerDocument(&dispatch_doc); if (FAILED(hr)) { LOGHR(WARN, hr) << "Unable to locate owning document, call to IHTMLDOMNode2::get_ownerDocument failed"; return ENOSUCHDOCUMENT; } } else { hr = this->element_->get_document(&dispatch_doc); if (FAILED(hr)) { LOGHR(WARN, hr) << "Unable to locate document property, call to IHTMLELement::get_document failed"; return ENOSUCHDOCUMENT; } } try { hr = dispatch_doc.QueryInterface<IHTMLDocument2>(doc); if (FAILED(hr)) { LOGHR(WARN, hr) << "Found document but it's not the expected type (IHTMLDocument2)"; return ENOSUCHDOCUMENT; } } catch(...) { LOG(WARN) << "Found document but it's not the expected type (IHTMLDocument2)"; return ENOSUCHDOCUMENT; } return WD_SUCCESS; }
int Browser::Refresh() { LOG(TRACE) << "Entering Browser::Refresh"; HRESULT hr = this->browser_->Refresh(); if (FAILED(hr)) { LOGHR(WARN, hr) << "Call to IWebBrowser2::Refresh failed"; } this->set_wait_required(true); return WD_SUCCESS; }
HWND Browser::GetTopLevelWindowHandle() { LOG(TRACE) << "Entering Browser::GetTopLevelWindowHandle"; HWND top_level_window_handle = NULL; HRESULT hr = this->browser_->get_HWND(reinterpret_cast<SHANDLE_PTR*>(&top_level_window_handle)); if (FAILED(hr)) { LOGHR(WARN, hr) << "Getting HWND property of IWebBrowser2 object failed"; } return top_level_window_handle; }
void HtmlDialog::GetDocument(IHTMLDocument2** doc) { HRESULT hr = S_OK; if (this->focused_frame_window() == NULL) { hr = this->window_->get_document(doc); } else { hr = this->focused_frame_window()->get_document(doc); } if (FAILED(hr)) { LOGHR(DEBUG, hr) << "Unable to get document"; } }
std::string HtmlDialog::GetTitle() { CComPtr<IHTMLDocument2> doc; this->GetDocument(&doc); CComBSTR title; HRESULT hr = doc->get_title(&title); if (FAILED(hr)) { LOGHR(WARN, hr) << "Unable to get document title"; return ""; } std::string title_string = CW2A(title, CP_UTF8); return title_string; }