Skip to content

Commit

Permalink
Implementing retrival of alert text for onBeforeUnload dialogs.
Browse files Browse the repository at this point in the history
Fixes issue #7901.
  • Loading branch information
jimevans committed Sep 26, 2014
1 parent 9571395 commit 855c835
Show file tree
Hide file tree
Showing 7 changed files with 137 additions and 8 deletions.
128 changes: 124 additions & 4 deletions cpp/iedriver/Alert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,7 @@ Alert::Alert(BrowserHandle browser, HWND handle) {
this->browser_ = browser;
this->alert_handle_ = handle;

HWND direct_ui_child = NULL;
::EnumChildWindows(this->alert_handle_,
&Alert::FindDirectUIChild,
reinterpret_cast<LPARAM>(&direct_ui_child));
HWND direct_ui_child = this->GetDirectUIChild();
this->is_standard_alert_ = direct_ui_child == NULL;
}

Expand Down Expand Up @@ -99,6 +96,21 @@ int Alert::SendKeys(std::string keys) {

std::string Alert::GetText() {
LOG(TRACE) << "Entering Alert::GetText";
std::string alert_text_value = "";
if (this->is_standard_alert_) {
alert_text_value = this->GetStandardDialogText();
} else {
std::string alert_text = this->GetDirectUIDialogText();
size_t first_crlf = alert_text.find("\r\n\r\n");
if (first_crlf != std::string::npos && first_crlf + 4 < alert_text.size()) {
alert_text_value = alert_text.substr(first_crlf + 4);
}
}
return alert_text_value;
}

std::string Alert::GetStandardDialogText() {
LOG(TRACE) << "Entering Alert::GetStandardDialogText";
TextLabelFindInfo info;
info.label_handle = NULL;
info.control_id_found = 0;
Expand Down Expand Up @@ -147,6 +159,114 @@ std::string Alert::GetText() {
return alert_text_value;
}

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;
}

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;
}

HWND Alert::GetDirectUIChild() {
LOG(TRACE) << "Entering Alert::GetDirectUIChild";
HWND direct_ui_child = NULL;
::EnumChildWindows(this->alert_handle_,
&Alert::FindDirectUIChild,
reinterpret_cast<LPARAM>(&direct_ui_child));
return direct_ui_child;
}

int Alert::ClickAlertButton(DialogButtonInfo button_info) {
LOG(TRACE) << "Entering Alert::ClickAlertButton";
// Click on the appropriate button of the Alert
Expand Down
4 changes: 4 additions & 0 deletions cpp/iedriver/Alert.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ class Alert {

DialogButtonInfo GetDialogButton(BUTTON_TYPE button_type);
int ClickAlertButton(DialogButtonInfo button_info);
std::string GetStandardDialogText(void);
std::string GetDirectUIDialogText(void);
HWND GetDirectUIChild(void);
IAccessible* GetChildWithRole(IAccessible* parent, long expected_role, int index);

static bool IsOKButton(HWND button_handle);
static bool IsCancelButton(HWND button_handle);
Expand Down
8 changes: 4 additions & 4 deletions cpp/iedriver/IEDriver.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@
</DisableSpecificWarnings>
</ClCompile>
<Link>
<AdditionalDependencies>ws2_32.lib;Rpcrt4.lib;version.lib;iepmapi.lib;psapi.lib;comsuppw.lib;wininet.lib;urlmon.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ws2_32.lib;Rpcrt4.lib;version.lib;iepmapi.lib;psapi.lib;oleacc.lib;comsuppw.lib;wininet.lib;urlmon.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AssemblyDebug>true</AssemblyDebug>
<SubSystem>NotSet</SubSystem>
Expand Down Expand Up @@ -137,7 +137,7 @@
<ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles>
</ClCompile>
<Link>
<AdditionalDependencies>ws2_32.lib;Rpcrt4.lib;version.lib;iepmapi.lib;psapi.lib;comsuppw.lib;wininet.lib;urlmon.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ws2_32.lib;Rpcrt4.lib;version.lib;iepmapi.lib;psapi.lib;oleacc.lib;comsuppw.lib;wininet.lib;urlmon.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AssemblyDebug>true</AssemblyDebug>
<SubSystem>NotSet</SubSystem>
Expand All @@ -163,7 +163,7 @@
<ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles>
</ClCompile>
<Link>
<AdditionalDependencies>ws2_32.lib;Rpcrt4.lib;version.lib;iepmapi.lib;psapi.lib;comsuppw.lib;wininet.lib;urlmon.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ws2_32.lib;Rpcrt4.lib;version.lib;iepmapi.lib;psapi.lib;oleacc.lib;comsuppw.lib;wininet.lib;urlmon.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
Expand All @@ -190,7 +190,7 @@
<ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles>
</ClCompile>
<Link>
<AdditionalDependencies>ws2_32.lib;Rpcrt4.lib;version.lib;iepmapi.lib;psapi.lib;comsuppw.lib;wininet.lib;urlmon.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ws2_32.lib;Rpcrt4.lib;version.lib;iepmapi.lib;psapi.lib;oleacc.lib;comsuppw.lib;wininet.lib;urlmon.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
Expand Down
5 changes: 5 additions & 0 deletions cpp/iedriverserver/CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ available via the project downloads page. Changes in "revision" field indicate
private releases checked into the prebuilts directory of the source tree, but
not made generally available on the downloads page.

v2.43.0.2
=========
* Implemented retrival of alert text for onBeforeUnload dialogs. Fixes issue
#7901.

v2.43.0.1
=========
* Improved cross-platform compatibility of webdriver-server C++ code. This
Expand Down
Binary file modified cpp/iedriverserver/IEDriverServer.rc
Binary file not shown.
Binary file modified cpp/prebuilt/Win32/Release/IEDriverServer.exe
Binary file not shown.
Binary file modified cpp/prebuilt/x64/Release/IEDriverServer.exe
Binary file not shown.

0 comments on commit 855c835

Please sign in to comment.