OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "remoting/host/win/rdp_client_window.h" | 5 #include "remoting/host/win/rdp_client_window.h" |
6 | 6 |
7 #include <wtsdefs.h> | 7 #include <wtsdefs.h> |
8 | 8 |
9 #include <list> | 9 #include <list> |
10 | 10 |
11 #include "base/lazy_instance.h" | 11 #include "base/lazy_instance.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/strings/string16.h" | 13 #include "base/strings/string16.h" |
14 #include "base/strings/utf_string_conversions.h" | 14 #include "base/strings/utf_string_conversions.h" |
15 #include "base/threading/thread_local.h" | 15 #include "base/threading/thread_local.h" |
16 #include "base/win/scoped_bstr.h" | 16 #include "base/win/scoped_bstr.h" |
17 | 17 |
18 namespace remoting { | 18 namespace remoting { |
19 | 19 |
20 namespace { | 20 namespace { |
21 | 21 |
22 // RDP connection disconnect reasons codes that should not be interpreted as | 22 // RDP connection disconnect reasons codes that should not be interpreted as |
23 // errors. | 23 // errors. |
24 const long kDisconnectReasonNoInfo = 0; | 24 const long kDisconnectReasonNoInfo = 0; |
25 const long kDisconnectReasonLocalNotError = 1; | 25 const long kDisconnectReasonLocalNotError = 1; |
26 const long kDisconnectReasonRemoteByUser = 2; | 26 const long kDisconnectReasonRemoteByUser = 2; |
27 const long kDisconnectReasonByServer = 3; | 27 const long kDisconnectReasonByServer = 3; |
28 | 28 |
29 // Maximum length of a window class name including the terminating NULL. | 29 // Maximum length of a window class name including the terminating nullptr. |
30 const int kMaxWindowClassLength = 256; | 30 const int kMaxWindowClassLength = 256; |
31 | 31 |
32 // Each member of the array returned by GetKeyboardState() contains status data | 32 // Each member of the array returned by GetKeyboardState() contains status data |
33 // for a virtual key. If the high-order bit is 1, the key is down; otherwise, it | 33 // for a virtual key. If the high-order bit is 1, the key is down; otherwise, it |
34 // is up. | 34 // is up. |
35 const BYTE kKeyPressedFlag = 0x80; | 35 const BYTE kKeyPressedFlag = 0x80; |
36 | 36 |
37 const int kKeyboardStateLength = 256; | 37 const int kKeyboardStateLength = 256; |
38 | 38 |
39 // The RDP control creates 'IHWindowClass' window to handle keyboard input. | 39 // The RDP control creates 'IHWindowClass' window to handle keyboard input. |
(...skipping 10 matching lines...) Expand all Loading... |
50 // Disable sound redirection; do not play sounds at the remote computer. | 50 // Disable sound redirection; do not play sounds at the remote computer. |
51 kRdpAudioModeNone = 2 | 51 kRdpAudioModeNone = 2 |
52 }; | 52 }; |
53 | 53 |
54 // Points to a per-thread instance of the window activation hook handle. | 54 // Points to a per-thread instance of the window activation hook handle. |
55 base::LazyInstance<base::ThreadLocalPointer<RdpClientWindow::WindowHook> > | 55 base::LazyInstance<base::ThreadLocalPointer<RdpClientWindow::WindowHook> > |
56 g_window_hook = LAZY_INSTANCE_INITIALIZER; | 56 g_window_hook = LAZY_INSTANCE_INITIALIZER; |
57 | 57 |
58 // Finds a child window with the class name matching |class_name|. Unlike | 58 // Finds a child window with the class name matching |class_name|. Unlike |
59 // FindWindowEx() this function walks the tree of windows recursively. The walk | 59 // FindWindowEx() this function walks the tree of windows recursively. The walk |
60 // is done in breadth-first order. The function returns NULL if the child window | 60 // is done in breadth-first order. The function returns nullptr if the child |
61 // could not be found. | 61 // window could not be found. |
62 HWND FindWindowRecursively(HWND parent, const base::string16& class_name) { | 62 HWND FindWindowRecursively(HWND parent, const base::string16& class_name) { |
63 std::list<HWND> windows; | 63 std::list<HWND> windows; |
64 windows.push_back(parent); | 64 windows.push_back(parent); |
65 | 65 |
66 while (!windows.empty()) { | 66 while (!windows.empty()) { |
67 HWND child = FindWindowEx(windows.front(), NULL, NULL, NULL); | 67 HWND child = FindWindowEx(windows.front(), nullptr, nullptr, nullptr); |
68 while (child != NULL) { | 68 while (child != nullptr) { |
69 // See if the window class name matches |class_name|. | 69 // See if the window class name matches |class_name|. |
70 WCHAR name[kMaxWindowClassLength]; | 70 WCHAR name[kMaxWindowClassLength]; |
71 int length = GetClassName(child, name, arraysize(name)); | 71 int length = GetClassName(child, name, arraysize(name)); |
72 if (base::string16(name, length) == class_name) | 72 if (base::string16(name, length) == class_name) |
73 return child; | 73 return child; |
74 | 74 |
75 // Remember the window to look through its children. | 75 // Remember the window to look through its children. |
76 windows.push_back(child); | 76 windows.push_back(child); |
77 | 77 |
78 // Go to the next child. | 78 // Go to the next child. |
79 child = FindWindowEx(windows.front(), child, NULL, NULL); | 79 child = FindWindowEx(windows.front(), child, nullptr, nullptr); |
80 } | 80 } |
81 | 81 |
82 windows.pop_front(); | 82 windows.pop_front(); |
83 } | 83 } |
84 | 84 |
85 return NULL; | 85 return nullptr; |
86 } | 86 } |
87 | 87 |
88 } // namespace | 88 } // namespace |
89 | 89 |
90 // Used to close any windows activated on a particular thread. It installs | 90 // Used to close any windows activated on a particular thread. It installs |
91 // a WH_CBT window hook to track window activations and close all activated | 91 // a WH_CBT window hook to track window activations and close all activated |
92 // windows. There should be only one instance of |WindowHook| per thread | 92 // windows. There should be only one instance of |WindowHook| per thread |
93 // at any given moment. | 93 // at any given moment. |
94 class RdpClientWindow::WindowHook | 94 class RdpClientWindow::WindowHook |
95 : public base::RefCounted<WindowHook> { | 95 : public base::RefCounted<WindowHook> { |
(...skipping 28 matching lines...) Expand all Loading... |
124 | 124 |
125 DCHECK(!client_.get()); | 125 DCHECK(!client_.get()); |
126 DCHECK(!client_settings_.get()); | 126 DCHECK(!client_settings_.get()); |
127 } | 127 } |
128 | 128 |
129 bool RdpClientWindow::Connect(const webrtc::DesktopSize& screen_size) { | 129 bool RdpClientWindow::Connect(const webrtc::DesktopSize& screen_size) { |
130 DCHECK(!m_hWnd); | 130 DCHECK(!m_hWnd); |
131 | 131 |
132 screen_size_ = screen_size; | 132 screen_size_ = screen_size; |
133 RECT rect = { 0, 0, screen_size_.width(), screen_size_.height() }; | 133 RECT rect = { 0, 0, screen_size_.width(), screen_size_.height() }; |
134 bool result = Create(NULL, rect, NULL) != NULL; | 134 bool result = Create(nullptr, rect, nullptr) != nullptr; |
135 | 135 |
136 // Hide the window since this class is about establishing a connection, not | 136 // Hide the window since this class is about establishing a connection, not |
137 // about showing a UI to the user. | 137 // about showing a UI to the user. |
138 if (result) | 138 if (result) |
139 ShowWindow(SW_HIDE); | 139 ShowWindow(SW_HIDE); |
140 | 140 |
141 return result; | 141 return result; |
142 } | 142 } |
143 | 143 |
144 void RdpClientWindow::Disconnect() { | 144 void RdpClientWindow::Disconnect() { |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
238 base::win::ScopedComPtr<IUnknown> control; | 238 base::win::ScopedComPtr<IUnknown> control; |
239 HRESULT result = E_FAIL; | 239 HRESULT result = E_FAIL; |
240 base::win::ScopedComPtr<mstsc::IMsTscSecuredSettings> secured_settings; | 240 base::win::ScopedComPtr<mstsc::IMsTscSecuredSettings> secured_settings; |
241 base::win::ScopedComPtr<mstsc::IMsRdpClientSecuredSettings> secured_settings2; | 241 base::win::ScopedComPtr<mstsc::IMsRdpClientSecuredSettings> secured_settings2; |
242 base::win::ScopedBstr server_name( | 242 base::win::ScopedBstr server_name( |
243 base::UTF8ToUTF16(server_endpoint_.ToStringWithoutPort()).c_str()); | 243 base::UTF8ToUTF16(server_endpoint_.ToStringWithoutPort()).c_str()); |
244 base::win::ScopedBstr terminal_id(base::UTF8ToUTF16(terminal_id_).c_str()); | 244 base::win::ScopedBstr terminal_id(base::UTF8ToUTF16(terminal_id_).c_str()); |
245 | 245 |
246 // Create the child window that actually hosts the ActiveX control. | 246 // Create the child window that actually hosts the ActiveX control. |
247 RECT rect = { 0, 0, screen_size_.width(), screen_size_.height() }; | 247 RECT rect = { 0, 0, screen_size_.width(), screen_size_.height() }; |
248 activex_window.Create(m_hWnd, rect, NULL, WS_CHILD | WS_VISIBLE | WS_BORDER); | 248 activex_window.Create(m_hWnd, rect, nullptr, |
249 if (activex_window.m_hWnd == NULL) { | 249 WS_CHILD | WS_VISIBLE | WS_BORDER); |
| 250 if (activex_window.m_hWnd == nullptr) { |
250 result = HRESULT_FROM_WIN32(GetLastError()); | 251 result = HRESULT_FROM_WIN32(GetLastError()); |
251 goto done; | 252 goto done; |
252 } | 253 } |
253 | 254 |
254 // Instantiate the RDP ActiveX control. | 255 // Instantiate the RDP ActiveX control. |
255 result = activex_window.CreateControlEx( | 256 result = activex_window.CreateControlEx( |
256 OLESTR("MsTscAx.MsTscAx"), | 257 OLESTR("MsTscAx.MsTscAx"), |
257 NULL, | 258 nullptr, |
258 NULL, | 259 nullptr, |
259 control.Receive(), | 260 control.Receive(), |
260 __uuidof(mstsc::IMsTscAxEvents), | 261 __uuidof(mstsc::IMsTscAxEvents), |
261 reinterpret_cast<IUnknown*>(static_cast<RdpEventsSink*>(this))); | 262 reinterpret_cast<IUnknown*>(static_cast<RdpEventsSink*>(this))); |
262 if (FAILED(result)) | 263 if (FAILED(result)) |
263 goto done; | 264 goto done; |
264 | 265 |
265 result = control.QueryInterface(client_.Receive()); | 266 result = control.QueryInterface(client_.Receive()); |
266 if (FAILED(result)) | 267 if (FAILED(result)) |
267 goto done; | 268 goto done; |
268 | 269 |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
392 // Hook window activation to cancel any modal UI shown by the RDP control. | 393 // Hook window activation to cancel any modal UI shown by the RDP control. |
393 // This does not affect creation of other instances of the RDP control on this | 394 // This does not affect creation of other instances of the RDP control on this |
394 // thread because the RDP control's window is hidden and is not activated. | 395 // thread because the RDP control's window is hidden and is not activated. |
395 window_activate_hook_ = WindowHook::Create(); | 396 window_activate_hook_ = WindowHook::Create(); |
396 return S_OK; | 397 return S_OK; |
397 } | 398 } |
398 | 399 |
399 HRESULT RdpClientWindow::OnAuthenticationWarningDismissed() { | 400 HRESULT RdpClientWindow::OnAuthenticationWarningDismissed() { |
400 LOG(WARNING) << "RDP: authentication warning has been dismissed."; | 401 LOG(WARNING) << "RDP: authentication warning has been dismissed."; |
401 | 402 |
402 window_activate_hook_ = NULL; | 403 window_activate_hook_ = nullptr; |
403 return S_OK; | 404 return S_OK; |
404 } | 405 } |
405 | 406 |
406 HRESULT RdpClientWindow::OnConnected() { | 407 HRESULT RdpClientWindow::OnConnected() { |
407 VLOG(1) << "RDP: successfully connected to " << server_endpoint_.ToString(); | 408 VLOG(1) << "RDP: successfully connected to " << server_endpoint_.ToString(); |
408 | 409 |
409 NotifyConnected(); | 410 NotifyConnected(); |
410 return S_OK; | 411 return S_OK; |
411 } | 412 } |
412 | 413 |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
462 } | 463 } |
463 | 464 |
464 void RdpClientWindow::NotifyConnected() { | 465 void RdpClientWindow::NotifyConnected() { |
465 if (event_handler_) | 466 if (event_handler_) |
466 event_handler_->OnConnected(); | 467 event_handler_->OnConnected(); |
467 } | 468 } |
468 | 469 |
469 void RdpClientWindow::NotifyDisconnected() { | 470 void RdpClientWindow::NotifyDisconnected() { |
470 if (event_handler_) { | 471 if (event_handler_) { |
471 EventHandler* event_handler = event_handler_; | 472 EventHandler* event_handler = event_handler_; |
472 event_handler_ = NULL; | 473 event_handler_ = nullptr; |
473 event_handler->OnDisconnected(); | 474 event_handler->OnDisconnected(); |
474 } | 475 } |
475 } | 476 } |
476 | 477 |
477 scoped_refptr<RdpClientWindow::WindowHook> | 478 scoped_refptr<RdpClientWindow::WindowHook> |
478 RdpClientWindow::WindowHook::Create() { | 479 RdpClientWindow::WindowHook::Create() { |
479 scoped_refptr<WindowHook> window_hook = g_window_hook.Pointer()->Get(); | 480 scoped_refptr<WindowHook> window_hook = g_window_hook.Pointer()->Get(); |
480 | 481 |
481 if (!window_hook.get()) | 482 if (!window_hook.get()) |
482 window_hook = new WindowHook(); | 483 window_hook = new WindowHook(); |
483 | 484 |
484 return window_hook; | 485 return window_hook; |
485 } | 486 } |
486 | 487 |
487 RdpClientWindow::WindowHook::WindowHook() : hook_(NULL) { | 488 RdpClientWindow::WindowHook::WindowHook() : hook_(nullptr) { |
488 DCHECK(!g_window_hook.Pointer()->Get()); | 489 DCHECK(!g_window_hook.Pointer()->Get()); |
489 | 490 |
490 // Install a window hook to be called on window activation. | 491 // Install a window hook to be called on window activation. |
491 hook_ = SetWindowsHookEx(WH_CBT, | 492 hook_ = SetWindowsHookEx(WH_CBT, |
492 &WindowHook::CloseWindowOnActivation, | 493 &WindowHook::CloseWindowOnActivation, |
493 NULL, | 494 nullptr, |
494 GetCurrentThreadId()); | 495 GetCurrentThreadId()); |
495 // Without the hook installed, RdpClientWindow will not be able to cancel | 496 // Without the hook installed, RdpClientWindow will not be able to cancel |
496 // modal UI windows. This will block the UI message loop so it is better to | 497 // modal UI windows. This will block the UI message loop so it is better to |
497 // terminate the process now. | 498 // terminate the process now. |
498 CHECK(hook_); | 499 CHECK(hook_); |
499 | 500 |
500 // Let CloseWindowOnActivation() to access the hook handle. | 501 // Let CloseWindowOnActivation() to access the hook handle. |
501 g_window_hook.Pointer()->Set(this); | 502 g_window_hook.Pointer()->Set(this); |
502 } | 503 } |
503 | 504 |
504 RdpClientWindow::WindowHook::~WindowHook() { | 505 RdpClientWindow::WindowHook::~WindowHook() { |
505 DCHECK(g_window_hook.Pointer()->Get() == this); | 506 DCHECK(g_window_hook.Pointer()->Get() == this); |
506 | 507 |
507 g_window_hook.Pointer()->Set(NULL); | 508 g_window_hook.Pointer()->Set(nullptr); |
508 | 509 |
509 BOOL result = UnhookWindowsHookEx(hook_); | 510 BOOL result = UnhookWindowsHookEx(hook_); |
510 DCHECK(result); | 511 DCHECK(result); |
511 } | 512 } |
512 | 513 |
513 // static | 514 // static |
514 LRESULT CALLBACK RdpClientWindow::WindowHook::CloseWindowOnActivation( | 515 LRESULT CALLBACK RdpClientWindow::WindowHook::CloseWindowOnActivation( |
515 int code, WPARAM wparam, LPARAM lparam) { | 516 int code, WPARAM wparam, LPARAM lparam) { |
516 // Get the hook handle. | 517 // Get the hook handle. |
517 HHOOK hook = g_window_hook.Pointer()->Get()->hook_; | 518 HHOOK hook = g_window_hook.Pointer()->Get()->hook_; |
518 | 519 |
519 if (code != HCBT_ACTIVATE) | 520 if (code != HCBT_ACTIVATE) |
520 return CallNextHookEx(hook, code, wparam, lparam); | 521 return CallNextHookEx(hook, code, wparam, lparam); |
521 | 522 |
522 // Close the window once all pending window messages are processed. | 523 // Close the window once all pending window messages are processed. |
523 HWND window = reinterpret_cast<HWND>(wparam); | 524 HWND window = reinterpret_cast<HWND>(wparam); |
524 LOG(WARNING) << "RDP: closing a window: " << std::hex << window << std::dec; | 525 LOG(WARNING) << "RDP: closing a window: " << std::hex << window << std::dec; |
525 ::PostMessage(window, WM_CLOSE, 0, 0); | 526 ::PostMessage(window, WM_CLOSE, 0, 0); |
526 return 0; | 527 return 0; |
527 } | 528 } |
528 | 529 |
529 } // namespace remoting | 530 } // namespace remoting |
OLD | NEW |