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