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 "base/lazy_instance.h" |
9 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/threading/thread_local.h" |
10 #include "base/utf_string_conversions.h" | 12 #include "base/utf_string_conversions.h" |
11 #include "base/win/scoped_bstr.h" | 13 #include "base/win/scoped_bstr.h" |
12 | 14 |
| 15 namespace remoting { |
| 16 |
| 17 namespace { |
| 18 |
13 // RDP connection disconnect reasons codes that should not be interpreted as | 19 // RDP connection disconnect reasons codes that should not be interpreted as |
14 // errors. | 20 // errors. |
15 const long kDisconnectReasonNoInfo = 0; | 21 const long kDisconnectReasonNoInfo = 0; |
16 const long kDisconnectReasonLocalNotError = 1; | 22 const long kDisconnectReasonLocalNotError = 1; |
17 const long kDisconnectReasonRemoteByUser = 2; | 23 const long kDisconnectReasonRemoteByUser = 2; |
18 const long kDisconnectReasonByServer = 3; | 24 const long kDisconnectReasonByServer = 3; |
19 | 25 |
20 namespace remoting { | 26 // Points to a per-thread instance of the window activation hook handle. |
| 27 base::LazyInstance<base::ThreadLocalPointer<RdpClientWindow::WindowHook> > |
| 28 g_window_hook = LAZY_INSTANCE_INITIALIZER; |
| 29 |
| 30 } // namespace |
| 31 |
| 32 // Used to close any windows activated on a particular thread. It installs |
| 33 // a WH_CBT window hook to track window activations and close all activated |
| 34 // windows. There should be only one instance of |WindowHook| per thread |
| 35 // at any given moment. |
| 36 class RdpClientWindow::WindowHook |
| 37 : public base::RefCounted<WindowHook> { |
| 38 public: |
| 39 static scoped_refptr<WindowHook> Create(); |
| 40 |
| 41 private: |
| 42 friend class base::RefCounted<WindowHook>; |
| 43 |
| 44 WindowHook(); |
| 45 virtual ~WindowHook(); |
| 46 |
| 47 static LRESULT CALLBACK CloseWindowOnActivation( |
| 48 int code, WPARAM wparam, LPARAM lparam); |
| 49 |
| 50 HHOOK hook_; |
| 51 |
| 52 DISALLOW_COPY_AND_ASSIGN(WindowHook); |
| 53 }; |
21 | 54 |
22 RdpClientWindow::RdpClientWindow(const net::IPEndPoint& server_endpoint, | 55 RdpClientWindow::RdpClientWindow(const net::IPEndPoint& server_endpoint, |
23 EventHandler* event_handler) | 56 EventHandler* event_handler) |
24 : event_handler_(event_handler), | 57 : event_handler_(event_handler), |
25 screen_size_(SkISize::Make(0, 0)), | 58 screen_size_(SkISize::Make(0, 0)), |
26 server_endpoint_(server_endpoint) { | 59 server_endpoint_(server_endpoint) { |
27 } | 60 } |
28 | 61 |
29 RdpClientWindow::~RdpClientWindow() { | 62 RdpClientWindow::~RdpClientWindow() { |
30 if (m_hWnd) | 63 if (m_hWnd) |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
193 | 226 |
194 return 0; | 227 return 0; |
195 } | 228 } |
196 | 229 |
197 void RdpClientWindow::OnDestroy() { | 230 void RdpClientWindow::OnDestroy() { |
198 client_.Release(); | 231 client_.Release(); |
199 client_settings_.Release(); | 232 client_settings_.Release(); |
200 } | 233 } |
201 | 234 |
202 HRESULT RdpClientWindow::OnAuthenticationWarningDisplayed() { | 235 HRESULT RdpClientWindow::OnAuthenticationWarningDisplayed() { |
203 LOG(ERROR) << "RDP: authentication warning is about to be shown. Closing " | 236 LOG(WARNING) << "RDP: authentication warning is about to be shown."; |
204 "the connection because the modal UI will block any further " | |
205 "progress"; | |
206 | 237 |
207 DestroyWindow(); | 238 // Hook window activation to cancel any modal UI shown by the RDP control. |
208 NotifyDisconnected(); | 239 // This does not affect creation of other instances of the RDP control on this |
| 240 // thread because the RDP control's window is hidden and is not activated. |
| 241 window_activate_hook_ = WindowHook::Create(); |
209 return S_OK; | 242 return S_OK; |
210 } | 243 } |
211 | 244 |
| 245 HRESULT RdpClientWindow::OnAuthenticationWarningDismissed() { |
| 246 LOG(WARNING) << "RDP: authentication warning has been dismissed."; |
| 247 |
| 248 window_activate_hook_ = NULL; |
| 249 return S_OK; |
| 250 } |
| 251 |
212 HRESULT RdpClientWindow::OnConnected() { | 252 HRESULT RdpClientWindow::OnConnected() { |
213 VLOG(1) << "RDP: successfully connected to " << server_endpoint_.ToString(); | 253 VLOG(1) << "RDP: successfully connected to " << server_endpoint_.ToString(); |
214 | 254 |
215 NotifyConnected(); | 255 NotifyConnected(); |
216 return S_OK; | 256 return S_OK; |
217 } | 257 } |
218 | 258 |
219 HRESULT RdpClientWindow::OnDisconnected(long reason) { | 259 HRESULT RdpClientWindow::OnDisconnected(long reason) { |
220 if (reason == kDisconnectReasonNoInfo || | 260 if (reason == kDisconnectReasonNoInfo || |
221 reason == kDisconnectReasonLocalNotError || | 261 reason == kDisconnectReasonLocalNotError || |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
273 } | 313 } |
274 | 314 |
275 void RdpClientWindow::NotifyDisconnected() { | 315 void RdpClientWindow::NotifyDisconnected() { |
276 if (event_handler_) { | 316 if (event_handler_) { |
277 EventHandler* event_handler = event_handler_; | 317 EventHandler* event_handler = event_handler_; |
278 event_handler_ = NULL; | 318 event_handler_ = NULL; |
279 event_handler->OnDisconnected(); | 319 event_handler->OnDisconnected(); |
280 } | 320 } |
281 } | 321 } |
282 | 322 |
| 323 scoped_refptr<RdpClientWindow::WindowHook> |
| 324 RdpClientWindow::WindowHook::Create() { |
| 325 scoped_refptr<WindowHook> window_hook = g_window_hook.Pointer()->Get(); |
| 326 |
| 327 if (!window_hook) |
| 328 window_hook = new WindowHook(); |
| 329 |
| 330 return window_hook; |
| 331 } |
| 332 |
| 333 RdpClientWindow::WindowHook::WindowHook() : hook_(NULL) { |
| 334 DCHECK(!g_window_hook.Pointer()->Get()); |
| 335 |
| 336 // Install a window hook to be called on window activation. |
| 337 hook_ = SetWindowsHookEx(WH_CBT, |
| 338 &WindowHook::CloseWindowOnActivation, |
| 339 NULL, |
| 340 GetCurrentThreadId()); |
| 341 // Without the hook installed, RdpClientWindow will not be able to cancel |
| 342 // modal UI windows. This will block the UI message loop so it is better to |
| 343 // terminate the process now. |
| 344 CHECK(hook_); |
| 345 |
| 346 // Let CloseWindowOnActivation() to access the hook handle. |
| 347 g_window_hook.Pointer()->Set(this); |
| 348 } |
| 349 |
| 350 RdpClientWindow::WindowHook::~WindowHook() { |
| 351 DCHECK(g_window_hook.Pointer()->Get() == this); |
| 352 |
| 353 g_window_hook.Pointer()->Set(NULL); |
| 354 |
| 355 BOOL result = UnhookWindowsHookEx(hook_); |
| 356 DCHECK(result); |
| 357 } |
| 358 |
| 359 // static |
| 360 LRESULT CALLBACK RdpClientWindow::WindowHook::CloseWindowOnActivation( |
| 361 int code, WPARAM wparam, LPARAM lparam) { |
| 362 // Get the hook handle. |
| 363 HHOOK hook = g_window_hook.Pointer()->Get()->hook_; |
| 364 |
| 365 if (code != HCBT_ACTIVATE) |
| 366 return CallNextHookEx(hook, code, wparam, lparam); |
| 367 |
| 368 // Close the window once all pending window messages are processed. |
| 369 HWND window = reinterpret_cast<HWND>(wparam); |
| 370 LOG(WARNING) << "RDP: closing a window: " << std::hex << window << std::dec; |
| 371 ::PostMessage(window, WM_CLOSE, 0, 0); |
| 372 return 0; |
| 373 } |
| 374 |
283 } // namespace remoting | 375 } // namespace remoting |
OLD | NEW |