diff options
author | alexeypa@chromium.org <alexeypa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-04-16 17:03:26 +0000 |
---|---|---|
committer | alexeypa@chromium.org <alexeypa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-04-16 17:03:26 +0000 |
commit | bfe06bc74b95f3c1ca8e41afcf9bed115b12679b (patch) | |
tree | a68fe5dded573175bf81ba93a37fce9e4ae5f767 /remoting | |
parent | 069f9c90db338324cb4e0683e6452f0f21f34475 (diff) | |
download | chromium_src-bfe06bc74b95f3c1ca8e41afcf9bed115b12679b.zip chromium_src-bfe06bc74b95f3c1ca8e41afcf9bed115b12679b.tar.gz chromium_src-bfe06bc74b95f3c1ca8e41afcf9bed115b12679b.tar.bz2 |
Cancel any modal UI shown by the RDP control.
|RdpClientWindow| now installs WH_CBT hook to listen to window activations and closes any windows activated on the UI thread. This allows |RdpClientWindow| to cancel modal UI dialogs popped up by the RDP control.
BUG=137696
Review URL: https://codereview.chromium.org/14261008
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@194376 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting')
-rw-r--r-- | remoting/host/win/rdp_client_window.cc | 104 | ||||
-rw-r--r-- | remoting/host/win/rdp_client_window.h | 8 |
2 files changed, 106 insertions, 6 deletions
diff --git a/remoting/host/win/rdp_client_window.cc b/remoting/host/win/rdp_client_window.cc index fa02a80..1f81538 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 activation hook handle. +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 +// 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 of other instances of the RDP control on this + // 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 diff --git a/remoting/host/win/rdp_client_window.h b/remoting/host/win/rdp_client_window.h index 33de1d3..c4b71d2 100644 --- a/remoting/host/win/rdp_client_window.h +++ b/remoting/host/win/rdp_client_window.h @@ -11,6 +11,7 @@ #include <atlctl.h> #include "base/basictypes.h" +#include "base/memory/ref_counted.h" #include "base/message_loop.h" #include "base/win/scoped_comptr.h" #include "net/base/ip_endpoint.h" @@ -105,10 +106,13 @@ class RdpClientWindow SINK_ENTRY_EX(1, __uuidof(mstsc::IMsTscAxEvents), 15, OnConfirmClose) SINK_ENTRY_EX(1, __uuidof(mstsc::IMsTscAxEvents), 18, OnAuthenticationWarningDisplayed) + SINK_ENTRY_EX(1, __uuidof(mstsc::IMsTscAxEvents), 19, + OnAuthenticationWarningDismissed) END_SINK_MAP() // mstsc::IMsTscAxEvents notifications. STDMETHOD(OnAuthenticationWarningDisplayed)(); + STDMETHOD(OnAuthenticationWarningDismissed)(); STDMETHOD(OnConnected)(); STDMETHOD(OnDisconnected)(long reason); STDMETHOD(OnFatalError)(long error_code); @@ -132,6 +136,10 @@ class RdpClientWindow // Interfaces exposed by the RDP ActiveX control. base::win::ScopedComPtr<mstsc::IMsRdpClient> client_; base::win::ScopedComPtr<mstsc::IMsRdpClientAdvancedSettings> client_settings_; + + // Used to cancel modal dialog boxes shown by the RDP control. + class WindowHook; + scoped_refptr<WindowHook> window_activate_hook_; }; } // namespace remoting |