Chromium Code Reviews| Index: remoting/host/win/rdp_client_window.cc |
| diff --git a/remoting/host/win/rdp_client_window.cc b/remoting/host/win/rdp_client_window.cc |
| index fa02a80ca6a6d6ae74b34c516860b3e72d3b981e..595c8339865e18b9c2be6f755a1f6a105f71d880 100644 |
| --- a/remoting/host/win/rdp_client_window.cc |
| +++ b/remoting/host/win/rdp_client_window.cc |
| @@ -6,10 +6,16 @@ |
| #include <wtsdefs.h> |
| +#include "base/lazy_instance.h" |
| #include "base/logging.h" |
| +#include "base/threading/thread_local.h" |
| #include "base/utf_string_conversions.h" |
| #include "base/win/scoped_bstr.h" |
| +namespace remoting { |
| + |
| +namespace { |
| + |
| // RDP connection disconnect reasons codes that should not be interpreted as |
| // errors. |
| const long kDisconnectReasonNoInfo = 0; |
| @@ -17,7 +23,34 @@ const long kDisconnectReasonLocalNotError = 1; |
| const long kDisconnectReasonRemoteByUser = 2; |
| const long kDisconnectReasonByServer = 3; |
| -namespace remoting { |
| +// Points to a per-thread instance of the window actication hook handle. |
|
garykac
2013/04/15 18:23:49
activation
alexeypa (please no reviews)
2013/04/15 18:26:53
Done.
|
| +base::LazyInstance<base::ThreadLocalPointer<RdpClientWindow::WindowHook> > |
| + g_window_hook = LAZY_INSTANCE_INITIALIZER; |
| + |
| +} // namespace |
| + |
| +// Used to close any windows activated on a particular thread. It installs\ |
|
garykac
2013/04/15 18:23:49
'\'?
alexeypa (please no reviews)
2013/04/15 18:26:53
Done.
|
| +// a WH_CBT window hook to track window activations and close all activated |
| +// windows. There should be only one instance of |WindowHook| per thread |
| +// at any given moment. |
| +class RdpClientWindow::WindowHook |
| + : public base::RefCounted<WindowHook> { |
| + public: |
| + static scoped_refptr<WindowHook> Create(); |
| + |
| + private: |
| + friend class base::RefCounted<WindowHook>; |
| + |
| + WindowHook(); |
| + virtual ~WindowHook(); |
| + |
| + static LRESULT CALLBACK CloseWindowOnActivation( |
| + int code, WPARAM wparam, LPARAM lparam); |
| + |
| + HHOOK hook_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(WindowHook); |
| +}; |
| RdpClientWindow::RdpClientWindow(const net::IPEndPoint& server_endpoint, |
| EventHandler* event_handler) |
| @@ -200,12 +233,19 @@ void RdpClientWindow::OnDestroy() { |
| } |
| HRESULT RdpClientWindow::OnAuthenticationWarningDisplayed() { |
| - LOG(ERROR) << "RDP: authentication warning is about to be shown. Closing " |
| - "the connection because the modal UI will block any further " |
| - "progress"; |
| + LOG(WARNING) << "RDP: authentication warning is about to be shown."; |
| - DestroyWindow(); |
| - NotifyDisconnected(); |
| + // Hook window activation to cancel any modal UI shown by the RDP control. |
| + // This does not affect creation other instances of the RDP control on this |
|
garykac
2013/04/15 18:23:49
...affect the creation of other...
alexeypa (please no reviews)
2013/04/15 18:26:53
Done.
|
| + // thread because the RDP control's window is hidden and is not activated. |
| + window_activate_hook_ = WindowHook::Create(); |
| + return S_OK; |
| +} |
| + |
| +HRESULT RdpClientWindow::OnAuthenticationWarningDismissed() { |
| + LOG(WARNING) << "RDP: authentication warning has been dismissed."; |
| + |
| + window_activate_hook_ = NULL; |
| return S_OK; |
| } |
| @@ -280,4 +320,56 @@ void RdpClientWindow::NotifyDisconnected() { |
| } |
| } |
| +scoped_refptr<RdpClientWindow::WindowHook> |
| +RdpClientWindow::WindowHook::Create() { |
| + scoped_refptr<WindowHook> window_hook = g_window_hook.Pointer()->Get(); |
| + |
| + if (!window_hook) |
| + window_hook = new WindowHook(); |
| + |
| + return window_hook; |
| +} |
| + |
| +RdpClientWindow::WindowHook::WindowHook() : hook_(NULL) { |
| + DCHECK(!g_window_hook.Pointer()->Get()); |
| + |
| + // Install a window hook to be called on window activation. |
| + hook_ = SetWindowsHookEx(WH_CBT, |
| + &WindowHook::CloseWindowOnActivation, |
| + NULL, |
| + GetCurrentThreadId()); |
| + // Without the hook installed, RdpClientWindow will not be able to cancel |
| + // modal UI windows. This will block the UI message loop so it is better to |
| + // terminate the process now. |
| + CHECK(hook_); |
| + |
| + // Let CloseWindowOnActivation() to access the hook handle. |
| + g_window_hook.Pointer()->Set(this); |
| +} |
| + |
| +RdpClientWindow::WindowHook::~WindowHook() { |
| + DCHECK(g_window_hook.Pointer()->Get() == this); |
| + |
| + g_window_hook.Pointer()->Set(NULL); |
| + |
| + BOOL result = UnhookWindowsHookEx(hook_); |
| + DCHECK(result); |
| +} |
| + |
| +// static |
| +LRESULT CALLBACK RdpClientWindow::WindowHook::CloseWindowOnActivation( |
| + int code, WPARAM wparam, LPARAM lparam) { |
| + // Get the hook handle. |
| + HHOOK hook = g_window_hook.Pointer()->Get()->hook_; |
| + |
| + if (code != HCBT_ACTIVATE) |
| + return CallNextHookEx(hook, code, wparam, lparam); |
| + |
| + // Close the window once all pending window messages are processed. |
| + HWND window = reinterpret_cast<HWND>(wparam); |
| + LOG(WARNING) << "RDP: closing a window: " << std::hex << window << std::dec; |
| + ::PostMessage(window, WM_CLOSE, 0, 0); |
| + return 0; |
| +} |
| + |
| } // namespace remoting |