Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/cpp/iedriver/Alert.cpp
2867 views
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
666
667