| // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef REMOTING_HOST_WIN_RDP_HOST_WINDOW_H_ |
| #define REMOTING_HOST_WIN_RDP_HOST_WINDOW_H_ |
| |
| #include <atlbase.h> |
| #include <atlcom.h> |
| #include <atlcrack.h> |
| #include <atlctl.h> |
| #include <wrl/client.h> |
| |
| #include "base/memory/ref_counted.h" |
| #include "base/timer/timer.h" |
| #include "net/base/ip_endpoint.h" |
| #include "remoting/host/screen_resolution.h" |
| // The following header was generated by Visual Studio. We had to check it in |
| // due to a bug in VS2013. See crbug.com/318952 for details. |
| #include "remoting/host/win/com_imported_mstscax.tlh" |
| #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h" |
| |
| namespace remoting { |
| |
| // RdpClientWindow is used to establish a connection to the given RDP endpoint. |
| // It is a GUI window class that hosts Microsoft RDP ActiveX control, which |
| // takes care of handling RDP properly. RdpClientWindow must be used only on |
| // a UI thread. |
| class RdpClientWindow |
| : public CWindowImpl<RdpClientWindow, CWindow, CFrameWinTraits>, |
| public IDispEventImpl<1, RdpClientWindow, |
| &__uuidof(mstsc::IMsTscAxEvents), |
| &__uuidof(mstsc::__MSTSCLib), 1, 0> { |
| public: |
| // Receives connect/disconnect notifications. The notifications can be |
| // delivered after RdpClientWindow::Connect() returned success. |
| // |
| // RdpClientWindow guarantees that OnDisconnected() is the last notification |
| // the event handler receives. OnDisconnected() is guaranteed to be called |
| // only once. |
| class EventHandler { |
| public: |
| virtual ~EventHandler() {} |
| |
| // Invoked when the RDP control has established a connection. |
| virtual void OnConnected() = 0; |
| |
| // Invoked when the RDP control has been disconnected from the RDP server. |
| // This includes both graceful shutdown and any fatal error condition. |
| // |
| // Once RdpClientWindow::Connect() returns success the owner of the |
| // |RdpClientWindow| object must keep it alive until OnDisconnected() is |
| // called. |
| // |
| // OnDisconnected() should not delete |RdpClientWindow| object directly. |
| // Instead it should post a task to delete the object. The ActiveX code |
| // expects the window be alive until the currently handled window message is |
| // completely processed. |
| virtual void OnDisconnected() = 0; |
| }; |
| |
| DECLARE_WND_CLASS(L"RdpClientWindow") |
| |
| // Specifies the endpoint to connect to and passes the event handler pointer |
| // to be notified about connection events. |
| RdpClientWindow(const net::IPEndPoint& server_endpoint, |
| const std::string& terminal_id, |
| EventHandler* event_handler); |
| ~RdpClientWindow() override; |
| |
| // Creates the window along with the ActiveX control and initiates the |
| // connection. |resolution| specifies resolution of the screen. Returns false |
| // if an error occurs. |
| bool Connect(const ScreenResolution& resolution); |
| |
| // Initiates shutdown of the connection. The caller must not delete |this| |
| // until it receives OnDisconnected() notification. |
| void Disconnect(); |
| |
| // Emulates pressing Ctrl+Alt+End combination that is translated to Secure |
| // Attention Sequence by the ActiveX control. |
| void InjectSas(); |
| |
| // Change the resolution of the desktop. |
| void ChangeResolution(const ScreenResolution& resolution); |
| |
| private: |
| typedef IDispEventImpl<1, RdpClientWindow, |
| &__uuidof(mstsc::IMsTscAxEvents), |
| &__uuidof(mstsc::__MSTSCLib), 1, 0> RdpEventsSink; |
| |
| // Handled window messages. |
| BEGIN_MSG_MAP_EX(RdpClientWindow) |
| MSG_WM_CLOSE(OnClose) |
| MSG_WM_CREATE(OnCreate) |
| MSG_WM_DESTROY(OnDestroy) |
| END_MSG_MAP() |
| |
| // Requests the RDP ActiveX control to close the connection gracefully. |
| void OnClose(); |
| |
| // Creates the RDP ActiveX control, configures it, and initiates an RDP |
| // connection to |server_endpoint_|. |
| LRESULT OnCreate(CREATESTRUCT* create_struct); |
| |
| // Releases the RDP ActiveX control interfaces. |
| void OnDestroy(); |
| |
| BEGIN_SINK_MAP(RdpClientWindow) |
| SINK_ENTRY_EX(1, __uuidof(mstsc::IMsTscAxEvents), 2, |
| &RdpClientWindow::OnConnected) |
| SINK_ENTRY_EX(1, __uuidof(mstsc::IMsTscAxEvents), 3, |
| &RdpClientWindow::OnLoginComplete) |
| SINK_ENTRY_EX(1, __uuidof(mstsc::IMsTscAxEvents), 4, |
| &RdpClientWindow::OnDisconnected) |
| SINK_ENTRY_EX(1, __uuidof(mstsc::IMsTscAxEvents), 10, |
| &RdpClientWindow::OnFatalError) |
| SINK_ENTRY_EX(1, __uuidof(mstsc::IMsTscAxEvents), 15, |
| &RdpClientWindow::OnConfirmClose) |
| SINK_ENTRY_EX(1, __uuidof(mstsc::IMsTscAxEvents), 18, |
| &RdpClientWindow::OnAuthenticationWarningDisplayed) |
| SINK_ENTRY_EX(1, __uuidof(mstsc::IMsTscAxEvents), 19, |
| &RdpClientWindow::OnAuthenticationWarningDismissed) |
| END_SINK_MAP() |
| |
| // mstsc::IMsTscAxEvents notifications. |
| STDMETHOD(OnAuthenticationWarningDisplayed)(); |
| STDMETHOD(OnAuthenticationWarningDismissed)(); |
| STDMETHOD(OnConnected)(); |
| STDMETHOD(OnLoginComplete)(); |
| STDMETHOD(OnDisconnected)(long reason); |
| STDMETHOD(OnFatalError)(long error_code); |
| STDMETHOD(OnConfirmClose)(VARIANT_BOOL* allow_close); |
| |
| int LogOnCreateError(HRESULT error); |
| |
| // Wrappers for the event handler's methods that make sure that |
| // OnDisconnected() is the last notification delivered and is delivered |
| // only once. |
| void NotifyConnected(); |
| void NotifyDisconnected(); |
| |
| // Updates the desktop using |screen_resolution_| if resizing is supported. |
| HRESULT UpdateDesktopResolution(); |
| |
| // Attempts to reapply the requested screen resolution. This method is used |
| // to workaround the inconsistent behavior seen by the RDP API which can fail |
| // for an indeterminate amount of time (i.e. a few seconds) after the user has |
| // logged into the session. In practice retrying after ~100ms will succeed, |
| // but we will use |apply_resolution_timer_| to try a few times if the machine |
| // is under load. |
| void ReapplyDesktopResolution(); |
| |
| // Invoked to report connect/disconnect events. |
| EventHandler* event_handler_; |
| |
| // Contains the requested dimensions of the screen. |
| remoting::ScreenResolution screen_resolution_; |
| |
| // Used for applying resolution changes after a timeout. |
| base::RepeatingTimer apply_resolution_timer_; |
| |
| // Tracks the number of resolution change retries. |
| int apply_resolution_attempts_ = 0; |
| |
| // The endpoint to connect to. |
| net::IPEndPoint server_endpoint_; |
| |
| // The terminal ID assigned to this connection. |
| std::string terminal_id_; |
| |
| // Our RDP session always starts logged out (i.e. at the logon screen), some |
| // functions do not work until the user has logged in so we want to track that |
| // event. We don't support logging out so this value should never revert from |
| // true to false. |
| bool user_logged_in_ = false; |
| |
| // Interfaces exposed by the RDP ActiveX control. |
| Microsoft::WRL::ComPtr<mstsc::IMsRdpClient> client_; |
| Microsoft::WRL::ComPtr<mstsc::IMsRdpClient9> client_9_; |
| Microsoft::WRL::ComPtr<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 |
| |
| #endif // REMOTING_HOST_WIN_RDP_HOST_WINDOW_H_ |