summaryrefslogtreecommitdiffstats
path: root/remoting
diff options
context:
space:
mode:
authoralexeypa@chromium.org <alexeypa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-16 17:03:26 +0000
committeralexeypa@chromium.org <alexeypa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-16 17:03:26 +0000
commitbfe06bc74b95f3c1ca8e41afcf9bed115b12679b (patch)
treea68fe5dded573175bf81ba93a37fce9e4ae5f767 /remoting
parent069f9c90db338324cb4e0683e6452f0f21f34475 (diff)
downloadchromium_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.cc104
-rw-r--r--remoting/host/win/rdp_client_window.h8
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