| 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..1f81538e582fe8e8c19ca43408c79c3134923479 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
|
|
|