Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/cpp/iedriver/HtmlDialog.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 "HtmlDialog.h"
18
19
#include "errorcodes.h"
20
#include "logging.h"
21
22
#include "BrowserFactory.h"
23
#include "StringUtilities.h"
24
#include "WebDriverConstants.h"
25
26
#define HIDDEN_PARENT_WINDOW_CLASS "Internet Explorer_Hidden"
27
28
namespace webdriver {
29
30
HtmlDialog::HtmlDialog(IHTMLWindow2* window, HWND hwnd, HWND session_handle) : DocumentHost(hwnd, session_handle) {
31
LOG(TRACE) << "Entering HtmlDialog::HtmlDialog";
32
this->is_navigating_ = false;
33
this->window_ = window;
34
this->AttachEvents();
35
}
36
37
HtmlDialog::~HtmlDialog(void) {
38
}
39
40
void HtmlDialog::AttachEvents() {
41
CComPtr<IUnknown> unknown;
42
this->window_->QueryInterface<IUnknown>(&unknown);
43
HRESULT hr = this->DispEventAdvise(unknown);
44
}
45
46
void HtmlDialog::DetachEvents() {
47
LOG(TRACE) << "Entering HtmlDialog::DetachEvents";
48
CComPtr<IUnknown> unknown;
49
this->window_->QueryInterface<IUnknown>(&unknown);
50
HRESULT hr = this->DispEventUnadvise(unknown);
51
}
52
53
void __stdcall HtmlDialog::OnBeforeUnload(IHTMLEventObj *pEvtObj) {
54
LOG(TRACE) << "Entering HtmlDialog::OnBeforeUnload";
55
this->is_navigating_ = true;
56
}
57
58
void __stdcall HtmlDialog::OnLoad(IHTMLEventObj *pEvtObj) {
59
LOG(TRACE) << "Entering HtmlDialog::OnLoad";
60
this->is_navigating_ = false;
61
}
62
63
void HtmlDialog::GetDocument(IHTMLDocument2** doc) {
64
this->GetDocument(false, doc);
65
}
66
67
void HtmlDialog::GetDocument(const bool force_top_level_document,
68
IHTMLDocument2** doc) {
69
LOG(TRACE) << "Entering HtmlDialog::GetDocument";
70
HRESULT hr = S_OK;
71
if (this->focused_frame_window() == NULL || force_top_level_document) {
72
hr = this->window_->get_document(doc);
73
} else {
74
hr = this->focused_frame_window()->get_document(doc);
75
}
76
77
if (FAILED(hr)) {
78
LOGHR(DEBUG, hr) << "Unable to get document";
79
}
80
}
81
82
void HtmlDialog::Close() {
83
LOG(TRACE) << "Entering HtmlDialog::Close";
84
if (!this->is_closing()) {
85
this->is_navigating_ = false;
86
this->set_is_closing(true);
87
// Closing the browser, so having focus on a frame doesn't
88
// make any sense.
89
this->SetFocusedFrameByElement(NULL);
90
this->DetachEvents();
91
this->window_->close();
92
93
// Must manually release the CComPtr<IHTMLWindow> so that the
94
// destructor will not try to release a no-longer-valid object.
95
this->window_.Release();
96
this->window_ = NULL;
97
98
this->PostQuitMessage();
99
}
100
}
101
102
bool HtmlDialog::IsValidWindow() {
103
LOG(TRACE) << "Entering HtmlDialog::IsValidWindow";
104
// If the window handle is no longer valid, the window is closing,
105
// and we must post the quit message.
106
if (!::IsWindow(this->GetTopLevelWindowHandle())) {
107
this->is_navigating_ = false;
108
this->DetachEvents();
109
this->PostQuitMessage();
110
return false;
111
}
112
return true;
113
}
114
115
bool HtmlDialog::SetFullScreen(bool is_full_screen) {
116
return false;
117
}
118
119
bool HtmlDialog::IsFullScreen() {
120
return false;
121
}
122
123
bool HtmlDialog::IsBusy() {
124
LOG(TRACE) << "Entering HtmlDialog::IsBusy";
125
return false;
126
}
127
128
bool HtmlDialog::Wait(const std::string& page_load_strategy) {
129
LOG(TRACE) << "Entering HtmlDialog::Wait";
130
// If the window is no longer valid, the window is closing,
131
// and the wait is completed.
132
if (!this->is_closing() && !this->IsValidWindow()) {
133
return true;
134
}
135
136
// Check to see if a new dialog has opened up on top of this one.
137
// If so, the wait is completed, no matter whether the OnUnload
138
// event has fired signaling navigation started, nor whether the
139
// OnLoad event has fired signaling navigation complete. Set the
140
// flag so that the Wait method is no longer called.
141
HWND child_dialog_handle = this->GetActiveDialogWindowHandle();
142
if (child_dialog_handle != NULL) {
143
this->is_navigating_ = false;
144
this->set_wait_required(false);
145
return true;
146
}
147
148
// Otherwise, we wait a short amount and see if navigation is complete
149
// (signaled by the OnLoad event firing).
150
::Sleep(250);
151
return !this->is_navigating_;
152
}
153
154
HWND HtmlDialog::GetContentWindowHandle() {
155
LOG(TRACE) << "Entering HtmlDialog::GetContentWindowHandle";
156
return this->window_handle();
157
}
158
159
HWND HtmlDialog::GetBrowserWindowHandle() {
160
LOG(TRACE) << "Entering HtmlDialog::GetBrowserWindowHandle";
161
return this->window_handle();
162
}
163
164
std::string HtmlDialog::GetWindowName() {
165
LOG(TRACE) << "Entering HtmlDialog::GetWindowName";
166
return "";
167
}
168
169
std::string HtmlDialog::GetBrowserUrl() {
170
LOG(TRACE) << "Entering HtmlDialog::GetBrowserUrl";
171
return "";
172
}
173
174
std::string HtmlDialog::GetTitle() {
175
LOG(TRACE) << "Entering HtmlDialog::GetTitle";
176
CComPtr<IHTMLDocument2> doc;
177
this->GetDocument(&doc);
178
CComBSTR title;
179
HRESULT hr = doc->get_title(&title);
180
if (FAILED(hr)) {
181
LOGHR(WARN, hr) << "Unable to get document title";
182
return "";
183
}
184
185
std::wstring converted_title = title;
186
std::string title_string = StringUtilities::ToString(converted_title);
187
return title_string;
188
}
189
190
HWND HtmlDialog::GetTopLevelWindowHandle(void) {
191
LOG(TRACE) << "Entering HtmlDialog::GetTopLevelWindowHandle";
192
HWND parent_handle = ::GetParent(this->window_handle());
193
194
// "Internet Explorer_Hidden\0" == 25
195
std::vector<char> parent_class_buffer(25);
196
if (::GetClassNameA(parent_handle, &parent_class_buffer[0], 25)) {
197
if (strcmp(HIDDEN_PARENT_WINDOW_CLASS, &parent_class_buffer[0]) == 0) {
198
// Some versions of Internet Explorer re-parent a closing showModalDialog
199
// window to a hidden parent window. If that is what we see happening
200
// here, that will be equivalent to the parent window no longer being
201
// valid, and we can return an invalid handle, indicating the window is
202
// "closed."
203
return NULL;
204
}
205
}
206
return parent_handle;
207
}
208
209
HWND HtmlDialog::GetActiveDialogWindowHandle() {
210
LOG(TRACE) << "Entering HtmlDialog::GetActiveDialogWindowHandle";
211
DialogWindowInfo info;
212
info.hwndOwner = this->GetTopLevelWindowHandle();
213
info.hwndDialog = NULL;
214
if (info.hwndOwner != NULL) {
215
::EnumWindows(&HtmlDialog::FindChildDialogWindow, reinterpret_cast<LPARAM>(&info));
216
}
217
if (info.hwndDialog != NULL) {
218
std::vector<char> window_class_name(34);
219
if (::GetClassNameA(info.hwndDialog, &window_class_name[0], 34)) {
220
if (strcmp(HTML_DIALOG_WINDOW_CLASS, &window_class_name[0]) == 0) {
221
HWND content_window_handle = this->FindContentWindowHandle(info.hwndDialog);
222
if (content_window_handle != NULL) {
223
// Must have a sleep here to give IE a chance to draw the window.
224
::Sleep(250);
225
::PostMessage(this->executor_handle(),
226
WD_NEW_HTML_DIALOG,
227
NULL,
228
reinterpret_cast<LPARAM>(content_window_handle));
229
}
230
}
231
}
232
}
233
return info.hwndDialog;
234
}
235
236
long HtmlDialog::GetWidth() {
237
LOG(TRACE) << "Entering HtmlDialog::GetWidth";
238
// TODO: calculate width
239
return 0L;
240
}
241
242
long HtmlDialog::GetHeight() {
243
LOG(TRACE) << "Entering HtmlDialog::GetHeight";
244
// TODO: calculate height
245
return 0L;
246
}
247
248
void HtmlDialog::SetWidth(long width) {
249
LOG(TRACE) << "Entering HtmlDialog::SetWidth";
250
}
251
252
void HtmlDialog::SetHeight(long height) {
253
LOG(TRACE) << "Entering HtmlDialog::SetHeight";
254
}
255
256
int HtmlDialog::NavigateToUrl(const std::string& url,
257
std::string* error_message) {
258
LOG(TRACE) << "Entering HtmlDialog::NavigateToUrl";
259
// Cannot force navigation on windows opened with showModalDialog();
260
return ENOTIMPLEMENTED;
261
}
262
263
int HtmlDialog::NavigateBack() {
264
LOG(TRACE) << "Entering HtmlDialog::NavigateBack";
265
// Cannot force navigation on windows opened with showModalDialog();
266
return ENOTIMPLEMENTED;
267
}
268
269
int HtmlDialog::NavigateForward() {
270
LOG(TRACE) << "Entering HtmlDialog::NavigateForward";
271
// Cannot force navigation on windows opened with showModalDialog();
272
return ENOTIMPLEMENTED;
273
}
274
275
int HtmlDialog::Refresh() {
276
LOG(TRACE) << "Entering HtmlDialog::Refresh";
277
// Cannot force navigation on windows opened with showModalDialog();
278
return ENOTIMPLEMENTED;
279
}
280
281
BOOL CALLBACK HtmlDialog::FindChildDialogWindow(HWND hwnd, LPARAM arg) {
282
DialogWindowInfo* window_info = reinterpret_cast<DialogWindowInfo*>(arg);
283
if (::GetWindow(hwnd, GW_OWNER) != window_info->hwndOwner) {
284
return TRUE;
285
}
286
std::vector<char> window_class_name(34);
287
if (::GetClassNameA(hwnd, &window_class_name[0], 34) == 0) {
288
// No match found. Skip
289
return TRUE;
290
}
291
if (strcmp(ALERT_WINDOW_CLASS, &window_class_name[0]) != 0 &&
292
strcmp(HTML_DIALOG_WINDOW_CLASS, &window_class_name[0]) != 0) {
293
return TRUE;
294
} else {
295
// If the window style has the WS_DISABLED bit set or the
296
// WS_VISIBLE bit unset, it can't be handled via the UI,
297
// and must not be a visible dialog.
298
if ((::GetWindowLong(hwnd, GWL_STYLE) & WS_DISABLED) != 0 ||
299
(::GetWindowLong(hwnd, GWL_STYLE) & WS_VISIBLE) == 0) {
300
return TRUE;
301
}
302
}
303
window_info->hwndDialog = hwnd;
304
return FALSE;
305
}
306
307
} // namespace webdriver
308
309