"Fossies" - the Fresh Open Source Software Archive

Member "selenium-selenium-4.8.1/cpp/iedriver/Alert.cpp" (17 Feb 2023, 23937 Bytes) of package /linux/www/selenium-selenium-4.8.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "Alert.cpp" see the Fossies "Dox" file reference documentation.

    1 // Licensed to the Software Freedom Conservancy (SFC) under one
    2 // or more contributor license agreements. See the NOTICE file
    3 // distributed with this work for additional information
    4 // regarding copyright ownership. The SFC licenses this file
    5 // to you under the Apache License, Version 2.0 (the "License");
    6 // you may not use this file except in compliance with the License.
    7 // You may obtain a copy of the License at
    8 //
    9 //     http://www.apache.org/licenses/LICENSE-2.0
   10 //
   11 // Unless required by applicable law or agreed to in writing, software
   12 // distributed under the License is distributed on an "AS IS" BASIS,
   13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14 // See the License for the specific language governing permissions and
   15 // limitations under the License.
   16 
   17 #include "Alert.h"
   18 
   19 #include <UIAutomation.h>
   20 
   21 #include "errorcodes.h"
   22 #include "logging.h"
   23 #include "DocumentHost.h"
   24 #include "StringUtilities.h"
   25 #include "WebDriverConstants.h"
   26 
   27 #define INVALID_CONTROL_ID -1
   28 
   29 namespace webdriver {
   30 
   31 Alert::Alert(std::shared_ptr<DocumentHost> browser, HWND handle) {
   32   LOG(TRACE) << "Entering Alert::Alert";
   33   this->browser_ = browser;
   34   this->alert_handle_ = handle;
   35 
   36   this->is_standard_alert_ = true;
   37   this->is_standard_control_alert_ = true;
   38   HWND direct_ui_child = this->GetDirectUIChild();
   39   if (direct_ui_child) {
   40     this->is_standard_control_alert_ = false;
   41     DialogButtonInfo cancel_button_info = this->GetDialogButton(CANCEL);
   42     if (cancel_button_info.button_exists) {
   43       this->is_standard_alert_ = !IsLinkButton(cancel_button_info.button_handle);
   44     } else {
   45       DialogButtonInfo ok_button_info = this->GetDialogButton(OK);
   46       if (ok_button_info.button_exists) {
   47         this->is_standard_alert_ = !IsLinkButton(ok_button_info.button_handle);
   48       } else {
   49         this->is_standard_alert_ = false;
   50       }
   51     }
   52   }
   53 
   54   std::vector<char> window_class(30);
   55   ::GetClassNameA(handle, &window_class[0], 30);
   56 
   57   if (strcmp(&window_class[0], SECURITY_DIALOG_WINDOW_CLASS) == 0) {
   58     this->is_standard_alert_ = false;
   59     this->is_standard_control_alert_ = false;
   60     this->is_security_alert_ = true;
   61   } else {
   62     std::vector<HWND> text_boxes;
   63     ::EnumChildWindows(this->alert_handle_,
   64                       &Alert::FindTextBoxes,
   65                       reinterpret_cast<LPARAM>(&text_boxes));
   66     this->is_security_alert_ = text_boxes.size() > 1;
   67   }
   68 }
   69 
   70 
   71 Alert::~Alert(void) {
   72 }
   73 
   74 int Alert::Accept() {
   75   LOG(TRACE) << "Entering Alert::Accept";
   76   DialogButtonInfo button_info = this->GetDialogButton(OK);
   77   if (!button_info.button_exists) {
   78     // No OK button on dialog. Look for a cancel button
   79     // (JavaScript alert() dialogs have a single button, but its ID
   80     // can be that of a "cancel" button.)
   81     LOG(INFO) << "OK button does not exist on dialog; looking for Cancel button";
   82     button_info = this->GetDialogButton(CANCEL);
   83   }
   84     
   85   if (!button_info.button_exists) {
   86     LOG(WARN) << "OK and Cancel button do not exist on alert";
   87     return EUNHANDLEDERROR;
   88   }
   89 
   90   LOG(DEBUG) << "Closing alert using SendMessage";
   91   int status_code = this->ClickAlertButton(button_info);
   92   return WD_SUCCESS;
   93 }
   94 
   95 int Alert::Dismiss() {
   96   LOG(TRACE) << "Entering Alert::Dismiss";
   97   DialogButtonInfo button_info = this->GetDialogButton(CANCEL);
   98   if (!button_info.button_exists) {
   99     if (!this->is_standard_control_alert_) {
  100       // If this is not a standard control alert (i.e., has the
  101       // "do not create any more dialogs check box"), the use of
  102       // dialog control IDs won't work, so we have to look explicitly
  103       // for the OK button.
  104       button_info = this->GetDialogButton(OK);
  105     }
  106   }
  107 
  108   if (!button_info.button_exists) {
  109     LOG(WARN) << "Cancel button does not exist on alert";
  110     return EUNHANDLEDERROR;
  111   }
  112 
  113   // TODO(JimEvans): Check return code and return an appropriate
  114   // error if the alert didn't get closed properly.
  115   LOG(DEBUG) << "Closing alert using SendMessage";
  116   int status_code = this->ClickAlertButton(button_info);
  117   return WD_SUCCESS;
  118 }
  119 
  120 int Alert::SendKeys(const std::string& keys) {
  121   LOG(TRACE) << "Entering Alert::SendKeys";
  122   TextBoxFindInfo text_box_find_info;
  123   text_box_find_info.textbox_handle = NULL;
  124   text_box_find_info.match_proc = &Alert::IsSimpleEdit;
  125   return this->SendKeysInternal(keys, &text_box_find_info);
  126 }
  127 
  128 int Alert::SetUserName(const std::string& username) {
  129   LOG(TRACE) << "Entering Alert::SetUserName";
  130   // If this isn't a security alert, return an error.
  131   if (!this->is_security_alert_) {
  132     return EUNEXPECTEDALERTOPEN;
  133   }
  134   return this->SendKeys(username);
  135 }
  136 
  137 int Alert::SetPassword(const std::string& password) {
  138   LOG(TRACE) << "Entering Alert::SetPassword";
  139   // If this isn't a security alert, return an error.
  140   if (!this->is_security_alert_) {
  141     return EUNEXPECTEDALERTOPEN;
  142   }
  143   TextBoxFindInfo text_box_find_info;
  144   text_box_find_info.textbox_handle = NULL;
  145   text_box_find_info.match_proc = &Alert::IsPasswordEdit;
  146   return this->SendKeysInternal(password, &text_box_find_info);
  147 }
  148 
  149 int Alert::SendKeysInternal(const std::string& keys,
  150                             TextBoxFindInfo* text_box_find_info) {
  151   LOG(TRACE) << "Entering Alert::SendKeysInternal";
  152   if (!this->is_standard_alert_) {
  153     return EUNSUPPORTEDOPERATION;
  154   }
  155   // Alert present, find the text box.
  156   // Retry up to 10 times to find the dialog.
  157   int max_wait = 10;
  158   while ((text_box_find_info->textbox_handle == NULL) && --max_wait) {
  159     ::EnumChildWindows(this->alert_handle_,
  160                        &Alert::FindTextBox,
  161                        reinterpret_cast<LPARAM>(text_box_find_info));
  162     if (text_box_find_info->textbox_handle == NULL) {
  163       ::Sleep(50);
  164     }
  165   }
  166 
  167   if (text_box_find_info->textbox_handle == NULL) {
  168     LOG(WARN) << "Text box not found on alert";
  169     return EELEMENTNOTDISPLAYED;
  170   } else {
  171     LOG(DEBUG) << "Sending keystrokes to alert using SendMessage";
  172     std::wstring text = StringUtilities::ToWString(keys);
  173     ::SendMessage(text_box_find_info->textbox_handle,
  174                   WM_SETTEXT,
  175                   NULL,
  176                   reinterpret_cast<LPARAM>(text.c_str()));
  177   }
  178   return WD_SUCCESS;
  179 }
  180 
  181 std::string Alert::GetText() {
  182   LOG(TRACE) << "Entering Alert::GetText";
  183   std::string alert_text_value = "";
  184   if (this->is_standard_control_alert_) {
  185     alert_text_value = this->GetStandardDialogText();
  186   } else {
  187     std::string alert_text = this->GetDirectUIDialogText();
  188     if (!this->is_security_alert_) {
  189       if (!this->is_standard_alert_) {
  190         // This means the alert is from onbeforeunload, and we need to
  191         // strip off everything up to and including the first CR-LF pair.
  192         size_t first_crlf = alert_text.find("\r\n\r\n");
  193         if (first_crlf != std::string::npos && first_crlf + 4 < alert_text.size()) {
  194           alert_text_value = alert_text.substr(first_crlf + 4);
  195         }
  196       } else {
  197         alert_text_value = alert_text;
  198       }
  199     }
  200   }
  201   return alert_text_value;
  202 }
  203 
  204 std::string Alert::GetStandardDialogText() {
  205   LOG(TRACE) << "Entering Alert::GetStandardDialogText";
  206   TextLabelFindInfo info;
  207   info.label_handle = NULL;
  208   info.control_id_found = 0;
  209   info.excluded_control_id = 0;
  210 
  211   // Alert present, find the OK button.
  212   // Retry up to 10 times to find the dialog.
  213   int max_wait = 10;
  214   while ((info.label_handle == NULL) && --max_wait) {
  215     ::EnumChildWindows(this->alert_handle_,
  216                        &Alert::FindTextLabel,
  217                        reinterpret_cast<LPARAM>(&info));
  218     if (info.label_handle == NULL) {
  219       ::Sleep(50);
  220     }
  221   }
  222 
  223   // BIG ASSUMPTION HERE! If we found the text label, assume that
  224   // all other controls on the alert are fully drawn too.
  225   TextBoxFindInfo textbox_find_info;
  226   textbox_find_info.textbox_handle = NULL;
  227   textbox_find_info.match_proc = &Alert::IsSimpleEdit;
  228   ::EnumChildWindows(this->alert_handle_,
  229                      &Alert::FindTextBox,
  230                      reinterpret_cast<LPARAM>(&textbox_find_info));
  231   if (textbox_find_info.textbox_handle) {
  232     // There's a text box on the alert. That means the first
  233     // label found is the system-provided label. Ignore that
  234     // one and return the next one.
  235     info.label_handle = NULL;
  236     info.excluded_control_id = info.control_id_found;
  237     info.control_id_found = 0;
  238     ::EnumChildWindows(this->alert_handle_,
  239                        &Alert::FindTextLabel,
  240                        reinterpret_cast<LPARAM>(&info));
  241   }
  242   
  243   std::string alert_text_value;
  244   if (info.label_handle == NULL) {
  245     alert_text_value = "";
  246   } else {
  247     int text_length = ::GetWindowTextLength(info.label_handle);
  248     std::vector<wchar_t> text_buffer(text_length + 1);
  249     ::GetWindowText(info.label_handle, &text_buffer[0], text_length + 1);
  250     std::wstring alert_text = &text_buffer[0];
  251     alert_text_value = StringUtilities::ToString(alert_text);
  252   }
  253   return alert_text_value;
  254 }
  255 
  256 std::string Alert::GetDirectUIDialogText() {
  257   LOG(TRACE) << "Entering Alert::GetDirectUIDialogText";
  258   std::string alert_text_value = "";
  259   HWND direct_ui_child_handle = this->GetDirectUIChild();
  260 
  261   CComPtr<IAccessible> window_object;
  262   HRESULT hr = ::AccessibleObjectFromWindow(
  263       direct_ui_child_handle,
  264       OBJID_WINDOW,
  265       IID_IAccessible,
  266       reinterpret_cast<void**>(&window_object));
  267   if (FAILED(hr)) {
  268     LOGHR(WARN, hr) << "Failed to get Active Accessibility window object from dialog";
  269     return alert_text_value;
  270   }
  271 
  272   // ASSUMPTION: There is an object with the role of "pane" as a child of
  273   // the window object.
  274   CComPtr<IAccessible> pane_object = this->GetChildWithRole(window_object,
  275                                                             ROLE_SYSTEM_PANE,
  276                                                             0);
  277   if (!pane_object) {
  278     LOG(WARN) << "Failed to get Active Accessibility pane child object from window";
  279     return alert_text_value;
  280   }
  281 
  282   int child_index = 0;
  283   if (!this->is_standard_alert_) {
  284     // ASSUMPTION: This means the alert is from onbeforeunload, and
  285     // the second "static text" accessibility object is the one
  286     // that contains the message.
  287     child_index = 1;
  288   }
  289 
  290   CComPtr<IAccessible> message_text_object = this->GetChildWithRole(
  291       pane_object,
  292       ROLE_SYSTEM_STATICTEXT,
  293       child_index);
  294   if (!message_text_object) {
  295     LOG(WARN) << "Failed to get Active Accessibility text child object from pane";
  296     return alert_text_value;
  297   }
  298 
  299   CComVariant child_id;
  300   child_id.vt = VT_I4;
  301   child_id.lVal = CHILDID_SELF;
  302 
  303   CComBSTR text_bstr;
  304   hr = message_text_object->get_accName(child_id, &text_bstr);
  305   if (FAILED(hr)) {
  306     LOGHR(WARN, hr) << "Failed to get accName property from text object";
  307     return alert_text_value;
  308   } else if (hr != S_OK) {
  309     // N.B., get_accName can return an error value without it being a
  310     // standard COM error.
  311     LOG(WARN) << "Getting accName property from text object returned an error "
  312               << "(value: " << hr << "). The text object may not have a name.";
  313     return alert_text_value;
  314   } else if (text_bstr == NULL) {
  315     LOG(WARN) << "Getting accName property from text object returned a null "
  316               << "value";
  317     return alert_text_value;
  318   }
  319 
  320   std::wstring text = text_bstr;
  321   alert_text_value = StringUtilities::ToString(text);
  322   return alert_text_value;
  323 }
  324 
  325 IAccessible* Alert::GetChildWithRole(IAccessible* parent, long expected_role, int index) {
  326   LOG(TRACE) << "Entering Alert::GetChildWithRole";
  327   IAccessible* child = NULL;
  328   long child_count;
  329   HRESULT hr = parent->get_accChildCount(&child_count);
  330   if (FAILED(hr)) {
  331     LOGHR(WARN, hr) << "Failed to get accChildCount property from Active Accessibility object";
  332     return child;
  333   }
  334 
  335   long returned_children = 0;
  336   std::vector<CComVariant> child_array(child_count);
  337   hr = ::AccessibleChildren(parent, 0, child_count, &child_array[0], &returned_children);
  338 
  339   int found_index = 0;
  340   for (long i = 0; i < child_count; ++i) {
  341     if (child_array[i].vt == VT_DISPATCH) {
  342       CComPtr<IAccessible> child_object;
  343       hr = child_array[i].pdispVal->QueryInterface<IAccessible>(&child_object);
  344       if (FAILED(hr)) {
  345         LOGHR(WARN, hr) << "QueryInterface for IAccessible failed for child object with index " << i;
  346       }
  347 
  348       CComVariant child_id;
  349       child_id.vt = VT_I4;
  350       child_id.lVal = CHILDID_SELF;
  351 
  352       CComVariant actual_role;
  353       hr = child_object->get_accRole(child_id, &actual_role);
  354       if (FAILED(hr)) {
  355         LOGHR(WARN, hr) << "Failed to get accRole property from Active Accessibility object";
  356       }
  357 
  358       if (expected_role == actual_role.lVal) {
  359         if (found_index == index) {
  360           child = child_object.Detach();
  361         } else {
  362           ++found_index;
  363         }
  364       }
  365       LOG(DEBUG) << "accRole for child with index " << i << ": " << actual_role.lVal;
  366     }
  367   }
  368   return child;
  369 }
  370 
  371 HWND Alert::GetDirectUIChild() {
  372   LOG(TRACE) << "Entering Alert::GetDirectUIChild";
  373   HWND direct_ui_child = NULL;
  374   ::EnumChildWindows(this->alert_handle_,
  375                      &Alert::FindDirectUIChild,
  376                      reinterpret_cast<LPARAM>(&direct_ui_child));
  377   return direct_ui_child;
  378 }
  379 
  380 int Alert::ClickAlertButton(DialogButtonInfo button_info) {
  381   LOG(TRACE) << "Entering Alert::ClickAlertButton";
  382   // Click on the appropriate button of the Alert
  383   if (this->is_standard_control_alert_) {
  384     ::SendMessage(this->alert_handle_,
  385                   WM_COMMAND,
  386                   button_info.button_control_id,
  387                   NULL);
  388   } else {
  389     if (button_info.use_accessibility) {
  390       int status_code = ClickAlertButtonUsingAccessibility(button_info.accessibility_id);
  391       if (status_code != WD_SUCCESS) {
  392         return status_code;
  393       }
  394     } else {
  395       // For non-standard alerts (that is, alerts that are not
  396       // created by alert(), confirm() or prompt() JavaScript
  397       // functions), we cheat. Sending the BN_CLICKED notification
  398       // via WM_COMMAND makes the dialog think that the proper
  399       // button was clicked, but it's not the same as sending the
  400       // click message to the button. N.B., sending the BM_CLICK
  401       // message to the button may fail if the dialog doesn't have
  402       // focus, so we do it this way. Also, we send the notification
  403       // to the immediate parent of the button, which, in turn,
  404       // notifies the top-level dialog.
  405       ::SendMessage(::GetParent(button_info.button_handle),
  406                     WM_COMMAND,
  407                     MAKEWPARAM(0, BN_CLICKED),
  408                     reinterpret_cast<LPARAM>(button_info.button_handle));
  409     }
  410   }
  411   // Hack to make sure alert is really closed, and browser
  412   // is ready for the next operation. This may be a flawed
  413   // algorithim, since the busy property of the browser may
  414   // not be the right thing to check here.
  415   int retry_count = 20;
  416   bool is_alert_handle_valid = (::IsWindow(this->alert_handle_) == TRUE);
  417   while ((is_alert_handle_valid || this->browser_->IsBusy()) && retry_count > 0) {
  418     ::Sleep(50);
  419     is_alert_handle_valid = (::IsWindow(this->alert_handle_) == TRUE);
  420     retry_count--;
  421   }
  422 
  423   // TODO(JimEvans): Check for the following error conditions:
  424   // 1. Alert window still present (::IsWindow(this->alert_handle_) == TRUE)
  425   // 2. Browser still busy (this->browser_->IsBusy() == true)
  426   // and return an appropriate non-WD_SUCCESS error code.
  427   LOG(DEBUG) << "IsWindow() for alert handle 0x" << this->alert_handle_ << ": "
  428              << is_alert_handle_valid ? "true" : "false";
  429   return WD_SUCCESS;
  430 }
  431 
  432 Alert::DialogButtonInfo Alert::GetDialogButton(BUTTON_TYPE button_type) {
  433   LOG(TRACE) << "Entering Alert::GetDialogButton";
  434   // Return the simple version of the struct so that subclasses do not
  435   // have to know anything about the function pointer definition.
  436   DialogButtonInfo button_info;
  437   if (this->is_standard_alert_ || !this->is_security_alert_) {
  438     DialogButtonFindInfo button_find_info;
  439     button_find_info.button_handle = NULL;
  440     button_find_info.button_control_id = this->is_standard_alert_ ? IDOK : INVALID_CONTROL_ID;
  441     if (button_type == OK) {
  442       button_find_info.match_proc = &Alert::IsOKButton;
  443     } else {
  444       button_find_info.match_proc = &Alert::IsCancelButton;
  445     }
  446 
  447     int max_wait = 10;
  448     // Retry up to 10 times to find the dialog.
  449     while ((button_find_info.button_handle == NULL) && --max_wait) {
  450       ::EnumChildWindows(this->alert_handle_,
  451                          &Alert::FindDialogButton,
  452                          reinterpret_cast<LPARAM>(&button_find_info));
  453       if (button_find_info.button_handle == NULL) {
  454         ::Sleep(50);
  455       } else {
  456         break;
  457       }
  458     }
  459     button_info.button_handle = button_find_info.button_handle;
  460     button_info.button_control_id = button_find_info.button_control_id;
  461     button_info.button_exists = button_find_info.button_handle != NULL;
  462     button_info.accessibility_id = "";
  463     button_info.use_accessibility = false;
  464   } else {
  465     button_info.button_handle = NULL;
  466     button_info.button_control_id = 0;
  467     button_info.button_exists = true;
  468     button_info.accessibility_id = button_type == OK ? "OKButton" : "CancelButton";
  469     button_info.use_accessibility = true;
  470   }
  471 
  472   return button_info;
  473 }
  474 
  475 int Alert::ClickAlertButtonUsingAccessibility(const std::string& automation_id) {
  476   CComPtr<IUIAutomation> ui_automation;
  477   HRESULT hr = ::CoCreateInstance(CLSID_CUIAutomation,
  478                                   NULL,
  479                                   CLSCTX_INPROC_SERVER,
  480                                   IID_IUIAutomation,
  481                                   reinterpret_cast<void**>(&ui_automation));
  482 
  483   if (FAILED(hr)) {
  484     LOGHR(WARN, hr) << "Unable to create global UI Automation object";
  485     return EUNHANDLEDERROR;
  486   }
  487 
  488   CComPtr<IUIAutomationElement> parent_window;
  489   hr = ui_automation->ElementFromHandle(this->alert_handle_,
  490                                         &parent_window);
  491   if (FAILED(hr)) {
  492     LOGHR(WARN, hr) << "Unable to get automation object from window handle";
  493     return EUNHANDLEDERROR;
  494   }
  495 
  496   CComVariant button_automation_id = automation_id.c_str();
  497   CComPtr<IUIAutomationCondition> button_condition;
  498   hr = ui_automation->CreatePropertyCondition(UIA_AutomationIdPropertyId,
  499                                               button_automation_id,
  500                                               &button_condition);
  501   if (FAILED(hr)) {
  502     LOGHR(WARN, hr) << "Unable to create button finding condition";
  503     return EUNHANDLEDERROR;
  504   }
  505 
  506   CComPtr<IUIAutomationElement> button;
  507   hr = parent_window->FindFirst(TreeScope::TreeScope_Children,
  508                                 button_condition,
  509                                 &button);
  510   if (FAILED(hr)) {
  511     LOGHR(WARN, hr) << "Unable to find button";
  512     return EUNHANDLEDERROR;
  513   }
  514 
  515   CComPtr<IUIAutomationInvokePattern> button_invoke_pattern;
  516   hr = button->GetCurrentPatternAs(UIA_InvokePatternId,
  517                                    IID_PPV_ARGS(&button_invoke_pattern));
  518   if (FAILED(hr)) {
  519     LOGHR(WARN, hr) << "Unable to get invoke pattern on button";
  520     return EUNHANDLEDERROR;
  521   }
  522 
  523   hr = button_invoke_pattern->Invoke();
  524   if (FAILED(hr)) {
  525     LOGHR(WARN, hr) << "Unable to invoke button";
  526     return EUNHANDLEDERROR;
  527   }
  528 
  529   return WD_SUCCESS;
  530 }
  531 
  532 bool Alert::IsOKButton(HWND button_handle) {
  533   int control_id = ::GetDlgCtrlID(button_handle);
  534   if (control_id != 0) {
  535     return control_id == IDOK || control_id == IDYES || control_id == IDRETRY;
  536   }
  537   std::vector<wchar_t> button_window_class(100);
  538   ::GetClassName(button_handle, &button_window_class[0], static_cast<int>(button_window_class.size()));
  539   if (wcscmp(&button_window_class[0], L"Button") == 0) {
  540     long window_long = ::GetWindowLong(button_handle, GWL_STYLE);
  541     long button_style = window_long & BS_TYPEMASK;
  542     return button_style == BS_DEFCOMMANDLINK || button_style == BS_DEFPUSHBUTTON;
  543   }
  544   return false;
  545 }
  546 
  547 bool Alert::IsCancelButton(HWND button_handle) {
  548   int control_id = ::GetDlgCtrlID(button_handle);
  549   if (control_id != 0) {
  550     return control_id == IDCANCEL || control_id == IDNO;
  551   }
  552   std::vector<wchar_t> button_window_class(100);
  553   ::GetClassName(button_handle, &button_window_class[0], static_cast<int>(button_window_class.size()));
  554   if (wcscmp(&button_window_class[0], L"Button") == 0) {
  555     long window_long = ::GetWindowLong(button_handle, GWL_STYLE);
  556     long button_style = window_long & BS_TYPEMASK;
  557     // The BS_DEFCOMMANDLINK mask includes BS_COMMANDLINK, but we
  558     // want only to match those without the default bits set.
  559     return button_style == BS_COMMANDLINK || button_style == BS_PUSHBUTTON;
  560   }
  561   return false;
  562 }
  563 
  564 bool Alert::IsLinkButton(HWND button_handle) {
  565   std::vector<wchar_t> button_window_class(100);
  566   ::GetClassName(button_handle, &button_window_class[0], static_cast<int>(button_window_class.size()));
  567   if (wcscmp(&button_window_class[0], L"Button") == 0) {
  568     long window_long = ::GetWindowLong(button_handle, GWL_STYLE);
  569     long button_style = window_long & BS_TYPEMASK;
  570     return button_style == BS_COMMANDLINK;
  571   }
  572   return false;
  573 }
  574 
  575 bool Alert::IsSimpleEdit(HWND edit_handle) {
  576   std::vector<wchar_t> child_window_class(100);
  577   ::GetClassName(edit_handle, &child_window_class[0], 100);
  578 
  579   if (wcscmp(&child_window_class[0], L"Edit") == 0) {
  580     long window_long = ::GetWindowLong(edit_handle, GWL_STYLE);
  581     bool is_read_only = (window_long & ES_READONLY) == ES_READONLY;
  582     bool is_password = (window_long & ES_PASSWORD) == ES_PASSWORD;
  583     return !is_read_only && !is_password;
  584   }
  585   return false;
  586 }
  587 
  588 bool Alert::IsPasswordEdit(HWND edit_handle) {
  589   std::vector<wchar_t> child_window_class(100);
  590   ::GetClassName(edit_handle, &child_window_class[0], 100);
  591 
  592   if (wcscmp(&child_window_class[0], L"Edit") == 0) {
  593     long window_long = ::GetWindowLong(edit_handle, GWL_STYLE);
  594     bool is_password = (window_long & ES_PASSWORD) == ES_PASSWORD;
  595     return is_password;
  596   }
  597   return false;
  598 }
  599 
  600 BOOL CALLBACK Alert::FindDialogButton(HWND hwnd, LPARAM arg) {
  601   Alert::DialogButtonFindInfo* button_info = reinterpret_cast<Alert::DialogButtonFindInfo*>(arg);
  602   int control_id = ::GetDlgCtrlID(hwnd);
  603   if (button_info->match_proc(hwnd)) {
  604     button_info->button_handle = hwnd;
  605     button_info->button_control_id = control_id;
  606     return FALSE;
  607   }
  608   return TRUE;
  609 }
  610 
  611 BOOL CALLBACK Alert::FindTextBox(HWND hwnd, LPARAM arg) {
  612   TextBoxFindInfo* find_info = reinterpret_cast<TextBoxFindInfo*>(arg);
  613   if (find_info->match_proc(hwnd)) {
  614     find_info->textbox_handle = hwnd;
  615     return FALSE;
  616   }
  617   return TRUE;
  618 }
  619 
  620 BOOL CALLBACK Alert::FindTextLabel(HWND hwnd, LPARAM arg) {
  621   TextLabelFindInfo* find_info = reinterpret_cast<TextLabelFindInfo*>(arg);
  622   std::vector<wchar_t> child_window_class(100);
  623   ::GetClassName(hwnd, &child_window_class[0], 100);
  624 
  625   if (wcscmp(&child_window_class[0], L"Static") != 0) {
  626     return TRUE;
  627   }
  628 
  629   int control_id = ::GetDlgCtrlID(hwnd);
  630   int text_length = ::GetWindowTextLength(hwnd);
  631   if (text_length > 0) {
  632     if (find_info->excluded_control_id == 0 ||
  633         control_id != find_info->excluded_control_id) {
  634       find_info->label_handle = hwnd;
  635       find_info->control_id_found = control_id;
  636       return FALSE;
  637     }
  638   }
  639   return TRUE;
  640 }
  641 
  642 BOOL CALLBACK Alert::FindDirectUIChild(HWND hwnd, LPARAM arg){
  643   HWND *dialog_handle = reinterpret_cast<HWND*>(arg);
  644   std::vector<wchar_t> child_window_class(100);
  645   ::GetClassName(hwnd, &child_window_class[0], 100);
  646 
  647   if (wcscmp(&child_window_class[0], L"DirectUIHWND") != 0) {
  648     return TRUE;
  649   }
  650   *dialog_handle = hwnd;
  651   return FALSE;
  652 }
  653 
  654 BOOL CALLBACK Alert::FindTextBoxes(HWND hwnd, LPARAM arg) {
  655   std::vector<HWND>* dialog_handles = reinterpret_cast<std::vector<HWND>*>(arg);
  656   std::vector<wchar_t> child_window_class(100);
  657   ::GetClassName(hwnd, &child_window_class[0], 100);
  658 
  659   if (wcscmp(&child_window_class[0], L"Edit") == 0) {
  660     dialog_handles->push_back(hwnd);
  661   }
  662   return TRUE;
  663 }
  664 
  665 } // namespace webdriver