From 200756361cebd0cf3b215bf36559b380a0b8f9da Mon Sep 17 00:00:00 2001 From: BlueBlock Date: Tue, 21 Mar 2023 11:55:17 -0400 Subject: [PATCH 01/13] rename base class of RDP So it is consistent with other protocols, rename the RDP base class to not reflect a version. --- .../ConnectionSerializers/Xml/XmlConnectionsDeserializer.cs | 4 ++-- mRemoteNG/Connection/ConnectionInfo.cs | 2 +- mRemoteNG/Tools/ScanHost.cs | 2 +- mRemoteNG/UI/Window/ConnectionWindow.cs | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/mRemoteNG/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDeserializer.cs b/mRemoteNG/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDeserializer.cs index 717364fca..bee10b50b 100644 --- a/mRemoteNG/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDeserializer.cs +++ b/mRemoteNG/Config/Serializers/ConnectionSerializers/Xml/XmlConnectionsDeserializer.cs @@ -261,7 +261,7 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml } else { - connectionInfo.Port = (int)RdpProtocol6.Defaults.Port; + connectionInfo.Port = (int)RdpProtocol.Defaults.Port; connectionInfo.Protocol = ProtocolType.RDP; } @@ -283,7 +283,7 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml if (xmlnode.GetAttributeAsBool("UseVNC")) connectionInfo.Port = (int)ProtocolVNC.Defaults.Port; else - connectionInfo.Port = (int)RdpProtocol6.Defaults.Port; + connectionInfo.Port = (int)RdpProtocol.Defaults.Port; } connectionInfo.UseConsoleSession = false; diff --git a/mRemoteNG/Connection/ConnectionInfo.cs b/mRemoteNG/Connection/ConnectionInfo.cs index 8d09d4873..c93fbd39d 100644 --- a/mRemoteNG/Connection/ConnectionInfo.cs +++ b/mRemoteNG/Connection/ConnectionInfo.cs @@ -251,7 +251,7 @@ namespace mRemoteNG.Connection switch (protocol) { case ProtocolType.RDP: - return (int)RdpProtocol6.Defaults.Port; + return (int)RdpProtocol.Defaults.Port; case ProtocolType.VNC: return (int)ProtocolVNC.Defaults.Port; case ProtocolType.SSH1: diff --git a/mRemoteNG/Tools/ScanHost.cs b/mRemoteNG/Tools/ScanHost.cs index 00ee74ecb..6c77f0271 100644 --- a/mRemoteNG/Tools/ScanHost.cs +++ b/mRemoteNG/Tools/ScanHost.cs @@ -24,7 +24,7 @@ namespace mRemoteNG.Tools public static int HttpPort { get; set; } = (int)ProtocolHTTP.Defaults.Port; public static int HttpsPort { get; set; } = (int)ProtocolHTTPS.Defaults.Port; public static int RloginPort { get; set; } = (int)ProtocolRlogin.Defaults.Port; - public static int RdpPort { get; set; } = (int)RdpProtocol6.Defaults.Port; + public static int RdpPort { get; set; } = (int)RdpProtocol.Defaults.Port; public static int VncPort { get; set; } = (int)ProtocolVNC.Defaults.Port; public ArrayList OpenPorts { get; set; } public ArrayList ClosedPorts { get; set; } diff --git a/mRemoteNG/UI/Window/ConnectionWindow.cs b/mRemoteNG/UI/Window/ConnectionWindow.cs index 037e6b6b0..68ec2dfa4 100644 --- a/mRemoteNG/UI/Window/ConnectionWindow.cs +++ b/mRemoteNG/UI/Window/ConnectionWindow.cs @@ -375,7 +375,7 @@ namespace mRemoteNG.UI.Window if (interfaceControl.Info.Protocol == ProtocolType.RDP) { - var rdp = (RdpProtocol6)interfaceControl.Protocol; + var rdp = (RdpProtocol)interfaceControl.Protocol; cmenTabFullscreen.Visible = true; cmenTabFullscreen.Checked = rdp.Fullscreen; cmenTabSmartSize.Visible = true; @@ -433,7 +433,7 @@ namespace mRemoteNG.UI.Window switch (interfaceControl.Protocol) { - case RdpProtocol6 rdp: + case RdpProtocol rdp: rdp.ToggleSmartSize(); break; } @@ -562,7 +562,7 @@ namespace mRemoteNG.UI.Window try { var interfaceControl = GetInterfaceControl(); - var rdp = interfaceControl?.Protocol as RdpProtocol6; + var rdp = interfaceControl?.Protocol as RdpProtocol; rdp?.ToggleFullscreen(); } catch (Exception ex) From a46b2c9d98d0553af30095fa6c8a246c25f0f507 Mon Sep 17 00:00:00 2001 From: BlueBlock Date: Tue, 21 Mar 2023 11:57:34 -0400 Subject: [PATCH 02/13] Update ProtocolFactory.cs remove unused usings --- mRemoteNG/Connection/Protocol/ProtocolFactory.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/mRemoteNG/Connection/Protocol/ProtocolFactory.cs b/mRemoteNG/Connection/Protocol/ProtocolFactory.cs index a103d5cd4..165bef1c7 100644 --- a/mRemoteNG/Connection/Protocol/ProtocolFactory.cs +++ b/mRemoteNG/Connection/Protocol/ProtocolFactory.cs @@ -7,7 +7,6 @@ using mRemoteNG.Connection.Protocol.Telnet; using mRemoteNG.Connection.Protocol.VNC; using System; using mRemoteNG.Connection.Protocol.PowerShell; -using mRemoteNG.Properties; using mRemoteNG.Resources.Language; using System.Runtime.Versioning; From dc38df5389419938e0cfc7ff8e2c765ced16423f Mon Sep 17 00:00:00 2001 From: BlueBlock Date: Tue, 21 Mar 2023 12:00:54 -0400 Subject: [PATCH 03/13] Update ConnectionsService.cs use object initializer and remove unused using --- mRemoteNG/Connection/ConnectionsService.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mRemoteNG/Connection/ConnectionsService.cs b/mRemoteNG/Connection/ConnectionsService.cs index e4d92f90a..17dea44b6 100644 --- a/mRemoteNG/Connection/ConnectionsService.cs +++ b/mRemoteNG/Connection/ConnectionsService.cs @@ -12,7 +12,6 @@ using mRemoteNG.Config.Putty; using mRemoteNG.Config.Serializers.ConnectionSerializers.MsSql; using mRemoteNG.Connection.Protocol; using mRemoteNG.Messages; -using mRemoteNG.Properties; using mRemoteNG.Security; using mRemoteNG.Tools; using mRemoteNG.Tree; @@ -75,8 +74,10 @@ namespace mRemoteNG.Connection { try { - var uriBuilder = new UriBuilder(); - uriBuilder.Scheme = "dummyscheme"; + var uriBuilder = new UriBuilder + { + Scheme = "dummyscheme" + }; if (connectionString.Contains("@")) { From 50daf64025b2bd5f7000aea7824652ba9258b3bd Mon Sep 17 00:00:00 2001 From: BlueBlock Date: Tue, 21 Mar 2023 12:03:28 -0400 Subject: [PATCH 04/13] Update ProtocolBase.cs - add check for object _interfaceControl before using it - adjust methods to protected where appropriate - remove unused using --- mRemoteNG/Connection/Protocol/ProtocolBase.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/mRemoteNG/Connection/Protocol/ProtocolBase.cs b/mRemoteNG/Connection/Protocol/ProtocolBase.cs index 37ba0c97e..cf63bc0e3 100644 --- a/mRemoteNG/Connection/Protocol/ProtocolBase.cs +++ b/mRemoteNG/Connection/Protocol/ProtocolBase.cs @@ -5,7 +5,6 @@ using System.Threading; using System.Windows.Forms; using mRemoteNG.UI.Tabs; using System.Runtime.Versioning; -using mRemoteNG.UI.Forms; // ReSharper disable UnusedMember.Local @@ -63,7 +62,7 @@ namespace mRemoteNG.Connection.Protocol public ConnectionInfo.Force Force { get; set; } - public readonly System.Timers.Timer tmrReconnect = new System.Timers.Timer(5000); + protected readonly System.Timers.Timer tmrReconnect = new System.Timers.Timer(5000); protected ReconnectGroup ReconnectGroup; protected ProtocolBase(string name) @@ -93,15 +92,15 @@ namespace mRemoteNG.Connection.Protocol } } - public virtual void ResizeBegin(object sender, EventArgs e) + protected virtual void ResizeBegin(object sender, EventArgs e) { } - public virtual void Resize(object sender, EventArgs e) + protected virtual void Resize(object sender, EventArgs e) { } - public virtual void ResizeEnd(object sender, EventArgs e) + protected virtual void ResizeEnd(object sender, EventArgs e) { } @@ -222,6 +221,10 @@ namespace mRemoteNG.Connection.Protocol private void SetTagToNothing() { + if (!_interfaceControl.IsAccessible || _interfaceControl.IsDisposed || + !_interfaceControl.Parent.IsAccessible || _interfaceControl.Parent.IsDisposed) + { return; } + if (_interfaceControl.Parent.InvokeRequired) { var s = new SetTagToNothingCB(SetTagToNothing); @@ -238,10 +241,7 @@ namespace mRemoteNG.Connection.Protocol private void DisposeControl() { // do not attempt to dispose the control if the control is already closed, closing or disposed - if (Control == null || !Control.IsAccessible || Control.IsDisposed) - { - return; - } + if (Control == null || !Control.IsAccessible || Control.IsDisposed) { return; } if (Control.InvokeRequired) { From 7c7c7086ce373605e38c9ece916660382c224afa Mon Sep 17 00:00:00 2001 From: BlueBlock Date: Tue, 21 Mar 2023 12:04:03 -0400 Subject: [PATCH 05/13] Update RdpProtocolFactory.cs class RdpProtocol6 renamed to RdpProtocol --- mRemoteNG/Connection/Protocol/RDP/RdpProtocolFactory.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mRemoteNG/Connection/Protocol/RDP/RdpProtocolFactory.cs b/mRemoteNG/Connection/Protocol/RDP/RdpProtocolFactory.cs index d9a9ac45b..b9c3142a9 100644 --- a/mRemoteNG/Connection/Protocol/RDP/RdpProtocolFactory.cs +++ b/mRemoteNG/Connection/Protocol/RDP/RdpProtocolFactory.cs @@ -8,14 +8,14 @@ namespace mRemoteNG.Connection.Protocol.RDP [SupportedOSPlatform("windows")] public class RdpProtocolFactory { - public RdpProtocol6 Build(RdpVersion rdpVersion) + public RdpProtocol Build(RdpVersion rdpVersion) { switch (rdpVersion) { case RdpVersion.Highest: return BuildHighestSupportedVersion(); case RdpVersion.Rdc6: - return new RdpProtocol6(); + return new RdpProtocol(); case RdpVersion.Rdc7: return new RdpProtocol7(); case RdpVersion.Rdc8: @@ -31,7 +31,7 @@ namespace mRemoteNG.Connection.Protocol.RDP } } - private RdpProtocol6 BuildHighestSupportedVersion() + private RdpProtocol BuildHighestSupportedVersion() { var versions = Enum.GetValues(typeof(RdpVersion)) .OfType() From 38abc8a1677d5e91def0d08acdf919a7483b5f66 Mon Sep 17 00:00:00 2001 From: BlueBlock Date: Tue, 21 Mar 2023 12:04:52 -0400 Subject: [PATCH 06/13] Update NotificationPanelMessageWriter.cs check for object _messageWindow before using it to avoid an exception --- .../Messages/MessageWriters/NotificationPanelMessageWriter.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/mRemoteNG/Messages/MessageWriters/NotificationPanelMessageWriter.cs b/mRemoteNG/Messages/MessageWriters/NotificationPanelMessageWriter.cs index 4f51e8c1b..37773e722 100644 --- a/mRemoteNG/Messages/MessageWriters/NotificationPanelMessageWriter.cs +++ b/mRemoteNG/Messages/MessageWriters/NotificationPanelMessageWriter.cs @@ -27,6 +27,7 @@ namespace mRemoteNG.Messages.MessageWriters private void AddToList(ListViewItem lvItem) { + if (!_messageWindow.IsAccessible || _messageWindow.IsDisposed) { return; } if (_messageWindow.lvErrorCollector.InvokeRequired) _messageWindow.lvErrorCollector.Invoke((MethodInvoker)(() => AddToList(lvItem))); else From cdc3759c0432884d98705adb9c582bc40baf313d Mon Sep 17 00:00:00 2001 From: BlueBlock Date: Tue, 21 Mar 2023 12:06:38 -0400 Subject: [PATCH 07/13] Update Optional.cs - use more efficient empty assignments - use string interpolation - adjust method access to minimal needed --- mRemoteNG/Tools/Optional.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/mRemoteNG/Tools/Optional.cs b/mRemoteNG/Tools/Optional.cs index 2d0c83eb6..37080bb9f 100644 --- a/mRemoteNG/Tools/Optional.cs +++ b/mRemoteNG/Tools/Optional.cs @@ -19,7 +19,7 @@ namespace mRemoteNG.Tools /// public Optional() { - _optional = new T[0]; + _optional = Array.Empty(); } /// @@ -30,7 +30,7 @@ namespace mRemoteNG.Tools { _optional = value != null ? new[] {value} - : new T[0]; + : Array.Empty(); } public override string ToString() @@ -97,9 +97,7 @@ namespace mRemoteNG.Tools if (_optional[0] is IComparable) return ((IComparable)_optional[0]).CompareTo(other.First()); - throw new ArgumentException(string.Format( - "Cannot compare objects. Optional type {0} is not comparable to itself", - typeof(T).FullName)); + throw new ArgumentException($"Cannot compare objects. Optional type {typeof(T).FullName} is not comparable to itself"); } #endregion @@ -121,7 +119,7 @@ namespace mRemoteNG.Tools return false; } - public bool Equals(Optional other) + private bool Equals(Optional other) { var otherObj = other.FirstOrDefault(); var thisObj = _optional.FirstOrDefault(); From 22cde74db2bace5b77354b5bb433ab4d8158e8f4 Mon Sep 17 00:00:00 2001 From: BlueBlock Date: Tue, 21 Mar 2023 12:07:18 -0400 Subject: [PATCH 08/13] Delete RdpProtocol6.cs class renamed to RdpProtocol --- .../Connection/Protocol/RDP/RdpProtocol6.cs | 881 ------------------ 1 file changed, 881 deletions(-) delete mode 100644 mRemoteNG/Connection/Protocol/RDP/RdpProtocol6.cs diff --git a/mRemoteNG/Connection/Protocol/RDP/RdpProtocol6.cs b/mRemoteNG/Connection/Protocol/RDP/RdpProtocol6.cs deleted file mode 100644 index 90f8e0cfe..000000000 --- a/mRemoteNG/Connection/Protocol/RDP/RdpProtocol6.cs +++ /dev/null @@ -1,881 +0,0 @@ -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Threading; -using System.Timers; -using System.Windows.Forms; -using AxMSTSCLib; -using mRemoteNG.App; -using mRemoteNG.Messages; -using mRemoteNG.Properties; -using mRemoteNG.Security.SymmetricEncryption; -using mRemoteNG.Tools; -using mRemoteNG.UI; -using mRemoteNG.UI.Forms; -using mRemoteNG.UI.Tabs; -using MSTSCLib; -using mRemoteNG.Resources.Language; -using static System.Windows.Forms.VisualStyles.VisualStyleElement.StartPanel; -using System.DirectoryServices.ActiveDirectory; -using System.Runtime.Versioning; - -namespace mRemoteNG.Connection.Protocol.RDP -{ - [SupportedOSPlatform("windows")] - public class RdpProtocol6 : ProtocolBase, ISupportsViewOnly - { - /* RDP v8 requires Windows 7 with: - * https://support.microsoft.com/en-us/kb/2592687 - * OR - * https://support.microsoft.com/en-us/kb/2923545 - * - * Windows 8+ support RDP v8 out of the box. - */ - private MsRdpClient6NotSafeForScripting _rdpClient; - protected ConnectionInfo connectionInfo; - protected bool loginComplete; - private Version _rdpVersion; - private bool _redirectKeys; - private bool _alertOnIdleDisconnect; - private readonly DisplayProperties _displayProperties; - private readonly FrmMain _frmMain = FrmMain.Default; - protected virtual RdpVersion RdpProtocolVersion => RdpVersion.Rdc6; - private AxHost AxHost => (AxHost)Control; - - #region Properties - - public virtual bool SmartSize - { - get => _rdpClient.AdvancedSettings2.SmartSizing; - protected set => _rdpClient.AdvancedSettings2.SmartSizing = value; - } - - public virtual bool Fullscreen - { - get => _rdpClient.FullScreen; - protected set => _rdpClient.FullScreen = value; - } - - private bool RedirectKeys - { -/* - get - { - return _redirectKeys; - } -*/ - set - { - _redirectKeys = value; - try - { - if (!_redirectKeys) - { - return; - } - - Debug.Assert(Convert.ToBoolean(_rdpClient.SecuredSettingsEnabled)); - var msRdpClientSecuredSettings = _rdpClient.SecuredSettings2; - msRdpClientSecuredSettings.KeyboardHookMode = 1; // Apply key combinations at the remote server. - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.RdpSetRedirectKeysFailed, ex); - } - } - } - - public bool LoadBalanceInfoUseUtf8 { get; set; } - - public bool ViewOnly - { - get => !AxHost.Enabled; - set => AxHost.Enabled = !value; - } - - #endregion - - #region Constructors - - public RdpProtocol6() - { - _displayProperties = new DisplayProperties(); - tmrReconnect.Elapsed += tmrReconnect_Elapsed; - } - - #endregion - - #region Public Methods - protected virtual AxHost CreateActiveXRdpClientControl() - { - return new AxMsRdpClient6NotSafeForScripting(); - } - - - public override bool Initialize() - { - connectionInfo = InterfaceControl.Info; - Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, - $"Requesting RDP version: {connectionInfo.RdpVersion}. Using: {RdpProtocolVersion}"); - Control = CreateActiveXRdpClientControl(); - base.Initialize(); - - try - { - if (!InitializeActiveXControl()) - return false; - - _rdpVersion = new Version(_rdpClient.Version); - SetRdpClientProperties(); - return true; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.RdpSetPropsFailed, ex); - return false; - } - } - - private bool InitializeActiveXControl() - { - try - { - Control.GotFocus += RdpClient_GotFocus; - Control.CreateControl(); - while (!Control.Created) - { - Thread.Sleep(0); - Application.DoEvents(); - } - Control.Anchor = AnchorStyles.None; - - _rdpClient = (MsRdpClient6NotSafeForScripting)((AxHost)Control).GetOcx(); - return true; - } - catch (COMException ex) - { - if (ex.Message.Contains("CLASS_E_CLASSNOTAVAILABLE")) - { - Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, - string.Format(Language.RdpProtocolVersionNotSupported, connectionInfo.RdpVersion)); - } - else - { - Runtime.MessageCollector.AddExceptionMessage(Language.RdpControlCreationFailed, ex); - } - Control.Dispose(); - return false; - } - } - - public override bool Connect() - { - loginComplete = false; - SetEventHandlers(); - - try - { - _rdpClient.Connect(); - base.Connect(); - - return true; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.ConnectionOpenFailed, ex); - } - - return false; - } - - public override void Disconnect() - { - try - { - _rdpClient.Disconnect(); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.RdpDisconnectFailed, ex); - Close(); - } - } - - public void ToggleFullscreen() - { - try - { - Fullscreen = !Fullscreen; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.RdpToggleFullscreenFailed, ex); - } - } - - public void ToggleSmartSize() - { - try - { - SmartSize = !SmartSize; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.RdpToggleSmartSizeFailed, ex); - } - } - - /// - /// Toggles whether the RDP ActiveX control will capture and send input events to the remote host. - /// The local host will continue to receive data from the remote host regardless of this setting. - /// - public void ToggleViewOnly() - { - try - { - ViewOnly = !ViewOnly; - } - catch - { - Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, $"Could not toggle view only mode for host {connectionInfo.Hostname}"); - } - } - - public override void Focus() - { - try - { - if (Control.ContainsFocus == false) - { - Control.Focus(); - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.RdpFocusFailed, ex); - } - } - - /// - /// Determines if this version of the RDP client - /// is supported on this machine. - /// - /// - public bool RdpVersionSupported() - { - try - { - using (var control = CreateActiveXRdpClientControl()) - { - control.CreateControl(); - return true; - } - } - catch - { - return false; - } - } - #endregion - - #region Private Methods - - private void SetRdpClientProperties() - { - _rdpClient.Server = connectionInfo.Hostname; - - SetCredentials(); - SetResolution(); - _rdpClient.FullScreenTitle = connectionInfo.Name; - - _alertOnIdleDisconnect = connectionInfo.RDPAlertIdleTimeout; - _rdpClient.AdvancedSettings2.MinutesToIdleTimeout = connectionInfo.RDPMinutesToIdleTimeout; - - #region Remote Desktop Services - _rdpClient.SecuredSettings2.StartProgram = connectionInfo.RDPStartProgram; - _rdpClient.SecuredSettings2.WorkDir = connectionInfo.RDPStartProgramWorkDir; - #endregion - - //not user changeable - _rdpClient.AdvancedSettings2.GrabFocusOnConnect = true; - _rdpClient.AdvancedSettings3.EnableAutoReconnect = true; - _rdpClient.AdvancedSettings3.MaxReconnectAttempts = Settings.Default.RdpReconnectionCount; - _rdpClient.AdvancedSettings2.keepAliveInterval = 60000; //in milliseconds (10,000 = 10 seconds) - _rdpClient.AdvancedSettings5.AuthenticationLevel = 0; - _rdpClient.AdvancedSettings2.EncryptionEnabled = 1; - - _rdpClient.AdvancedSettings2.overallConnectionTimeout = Settings.Default.ConRDPOverallConnectionTimeout; - - _rdpClient.AdvancedSettings2.BitmapPeristence = Convert.ToInt32(connectionInfo.CacheBitmaps); - if (_rdpVersion >= Versions.RDC61) - { - _rdpClient.AdvancedSettings7.EnableCredSspSupport = connectionInfo.UseCredSsp; - } - if(_rdpVersion >= Versions.RDC81) - { - if (connectionInfo.UseRestrictedAdmin) - SetExtendedProperty("RestrictedLogon", true); - else if (connectionInfo.UseRCG) - { - SetExtendedProperty("DisableCredentialsDelegation", true); - SetExtendedProperty("RedirectedAuthentication", true); - } - } - - SetUseConsoleSession(); - SetPort(); - RedirectKeys = connectionInfo.RedirectKeys; - SetRedirection(); - SetAuthenticationLevel(); - SetLoadBalanceInfo(); - SetRdGateway(); - ViewOnly = Force.HasFlag(ConnectionInfo.Force.ViewOnly); - - _rdpClient.ColorDepth = (int)connectionInfo.Colors; - - SetPerformanceFlags(); - - _rdpClient.ConnectingText = Language.Connecting; - } - - protected object GetExtendedProperty(string property) - { - try - { - // ReSharper disable once UseIndexedProperty - return ((IMsRdpExtendedSettings)_rdpClient).get_Property(property); - } - catch (Exception e) - { - Runtime.MessageCollector.AddExceptionMessage($"Error getting extended RDP property '{property}'", - e, MessageClass.WarningMsg, false); - return null; - } - } - - protected void SetExtendedProperty(string property, object value) - { - try - { - // ReSharper disable once UseIndexedProperty - ((IMsRdpExtendedSettings)_rdpClient).set_Property(property, ref value); - } - catch (Exception e) - { - Runtime.MessageCollector.AddExceptionMessage($"Error setting extended RDP property '{property}'", - e, MessageClass.WarningMsg, false); - } - } - - private void SetRdGateway() - { - try - { - if (_rdpClient.TransportSettings.GatewayIsSupported == 0) - { - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.RdpGatewayNotSupported, - true); - return; - } - - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.RdpGatewayIsSupported, - true); - - if (connectionInfo.RDGatewayUsageMethod != RDGatewayUsageMethod.Never) - { - _rdpClient.TransportSettings.GatewayUsageMethod = (uint)connectionInfo.RDGatewayUsageMethod; - _rdpClient.TransportSettings.GatewayHostname = connectionInfo.RDGatewayHostname; - _rdpClient.TransportSettings.GatewayProfileUsageMethod = 1; // TSC_PROXY_PROFILE_MODE_EXPLICIT - if (connectionInfo.RDGatewayUseConnectionCredentials == RDGatewayUseConnectionCredentials.SmartCard) - { - _rdpClient.TransportSettings.GatewayCredsSource = 1; // TSC_PROXY_CREDS_MODE_SMARTCARD - } - - if (_rdpVersion >= Versions.RDC61 && !Force.HasFlag(ConnectionInfo.Force.NoCredentials)) - { - if (connectionInfo.RDGatewayUseConnectionCredentials == RDGatewayUseConnectionCredentials.Yes) - { - _rdpClient.TransportSettings2.GatewayUsername = connectionInfo.Username; - _rdpClient.TransportSettings2.GatewayPassword = connectionInfo.Password; - _rdpClient.TransportSettings2.GatewayDomain = connectionInfo?.Domain; - } - else if (connectionInfo.RDGatewayUseConnectionCredentials == RDGatewayUseConnectionCredentials.SmartCard) - { - _rdpClient.TransportSettings2.GatewayCredSharing = 0; - } - else - { - _rdpClient.TransportSettings2.GatewayCredSharing = 0; - - string gwu = connectionInfo.RDGatewayUsername; - string gwp = connectionInfo.RDGatewayPassword; - string gwd = connectionInfo.RDGatewayDomain; - string pkey = ""; - - // access secret server api if necessary - if (InterfaceControl.Info.RDGatewayExternalCredentialProvider == ExternalCredentialProvider.DelineaSecretServer) - { - try - { - string RDGUserViaAPI = InterfaceControl.Info.RDGatewayUserViaAPI; - ExternalConnectors.DSS.SecretServerInterface.FetchSecretFromServer($"{RDGUserViaAPI}", out gwu, out gwp, out gwd, out pkey); - } - catch (Exception ex) - { - Event_ErrorOccured(this, "Secret Server Interface Error: " + ex.Message, 0); - } - - } - _rdpClient.TransportSettings2.GatewayUsername = gwu; - _rdpClient.TransportSettings2.GatewayPassword = gwp; - _rdpClient.TransportSettings2.GatewayDomain = gwd; - } - } - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.RdpSetGatewayFailed, ex); - } - } - - private void SetUseConsoleSession() - { - try - { - bool value; - - if (Force.HasFlag(ConnectionInfo.Force.UseConsoleSession)) - { - value = true; - } - else if (Force.HasFlag(ConnectionInfo.Force.DontUseConsoleSession)) - { - value = false; - } - else - { - value = connectionInfo.UseConsoleSession; - } - - if (_rdpVersion >= Versions.RDC61) - { - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, - string.Format(Language.RdpSetConsoleSwitch, _rdpVersion), - true); - _rdpClient.AdvancedSettings7.ConnectToAdministerServer = value; - } - else - { - Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, - string.Format(Language.RdpSetConsoleSwitch, _rdpVersion) + - Environment.NewLine + - "No longer supported in this RDP version. Reference: https://msdn.microsoft.com/en-us/library/aa380863(v=vs.85).aspx", - true); - // ConnectToServerConsole is deprecated - //https://msdn.microsoft.com/en-us/library/aa380863(v=vs.85).aspx - //_rdpClient.AdvancedSettings2.ConnectToServerConsole = value; - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.RdpSetConsoleSessionFailed, ex); - } - } - - private void SetCredentials() - { - try - { - if (Force.HasFlag(ConnectionInfo.Force.NoCredentials)) - { - return; - } - - var userName = connectionInfo?.Username ?? ""; - var password = connectionInfo?.Password ?? ""; - var domain = connectionInfo?.Domain ?? ""; - var UserViaAPI = connectionInfo?.UserViaAPI ?? ""; - string pkey = ""; - - // access secret server api if necessary - if (InterfaceControl.Info.ExternalCredentialProvider == ExternalCredentialProvider.DelineaSecretServer) - { - try - { - ExternalConnectors.DSS.SecretServerInterface.FetchSecretFromServer($"{UserViaAPI}", out userName, out password, out domain, out pkey); - } - catch (Exception ex) - { - Event_ErrorOccured(this, "Secret Server Interface Error: " + ex.Message, 0); - } - - } - - if (string.IsNullOrEmpty(userName)) - { - switch (Properties.OptionsCredentialsPage.Default.EmptyCredentials) - { - case "windows": - _rdpClient.UserName = Environment.UserName; - break; - case "custom" when !string.IsNullOrEmpty(Properties.OptionsCredentialsPage.Default.DefaultUsername): - _rdpClient.UserName = Properties.OptionsCredentialsPage.Default.DefaultUsername; - break; - case "custom": - try - { - ExternalConnectors.DSS.SecretServerInterface.FetchSecretFromServer(Properties.OptionsCredentialsPage.Default.UserViaAPIDefault, out userName, out password, out domain, out pkey); - _rdpClient.UserName = userName; - } - catch (Exception ex) - { - Event_ErrorOccured(this, "Secret Server Interface Error: " + ex.Message, 0); - } - - break; - } - } - else - { - _rdpClient.UserName = userName; - } - - if (string.IsNullOrEmpty(password)) - { - if (Properties.OptionsCredentialsPage.Default.EmptyCredentials == "custom") - { - if (Properties.OptionsCredentialsPage.Default.DefaultPassword != "") - { - var cryptographyProvider = new LegacyRijndaelCryptographyProvider(); - _rdpClient.AdvancedSettings2.ClearTextPassword = cryptographyProvider.Decrypt(Properties.OptionsCredentialsPage.Default.DefaultPassword, Runtime.EncryptionKey); - } - } - } - else - { - _rdpClient.AdvancedSettings2.ClearTextPassword = password; - } - - if (string.IsNullOrEmpty(domain)) - { - _rdpClient.Domain = Properties.OptionsCredentialsPage.Default.EmptyCredentials switch - { - "windows" => Environment.UserDomainName, - "custom" => Properties.OptionsCredentialsPage.Default.DefaultDomain, - _ => _rdpClient.Domain - }; - } - else - { - _rdpClient.Domain = domain; - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.RdpSetCredentialsFailed, ex); - } - } - - private void SetResolution() - { - try - { - var scaleFactor = (uint)(_displayProperties.ResolutionScalingFactor.Width * 100); - SetExtendedProperty("DesktopScaleFactor", scaleFactor); - SetExtendedProperty("DeviceScaleFactor", (uint)100); - - if (Force.HasFlag(ConnectionInfo.Force.Fullscreen)) - { - _rdpClient.FullScreen = true; - _rdpClient.DesktopWidth = Screen.FromControl(_frmMain).Bounds.Width; - _rdpClient.DesktopHeight = Screen.FromControl(_frmMain).Bounds.Height; - - return; - } - - if (InterfaceControl.Info.Resolution == RDPResolutions.FitToWindow || - InterfaceControl.Info.Resolution == RDPResolutions.SmartSize) - { - _rdpClient.DesktopWidth = InterfaceControl.Size.Width; - _rdpClient.DesktopHeight = InterfaceControl.Size.Height; - - if (InterfaceControl.Info.Resolution == RDPResolutions.SmartSize) - { - _rdpClient.AdvancedSettings2.SmartSizing = true; - } - } - else if (InterfaceControl.Info.Resolution == RDPResolutions.Fullscreen) - { - _rdpClient.FullScreen = true; - _rdpClient.DesktopWidth = Screen.FromControl(_frmMain).Bounds.Width; - _rdpClient.DesktopHeight = Screen.FromControl(_frmMain).Bounds.Height; - } - else - { - var resolution = connectionInfo.Resolution.GetResolutionRectangle(); - _rdpClient.DesktopWidth = resolution.Width; - _rdpClient.DesktopHeight = resolution.Height; - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.RdpSetResolutionFailed, ex); - } - } - - private void SetPort() - { - try - { - if (connectionInfo.Port != (int)Defaults.Port) - { - _rdpClient.AdvancedSettings2.RDPPort = connectionInfo.Port; - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.RdpSetPortFailed, ex); - } - } - - private void SetRedirection() - { - try - { - _rdpClient.AdvancedSettings2.RedirectDrives = connectionInfo.RedirectDiskDrives; - _rdpClient.AdvancedSettings2.RedirectPorts = connectionInfo.RedirectPorts; - _rdpClient.AdvancedSettings2.RedirectPrinters = connectionInfo.RedirectPrinters; - _rdpClient.AdvancedSettings2.RedirectSmartCards = connectionInfo.RedirectSmartCards; - _rdpClient.SecuredSettings2.AudioRedirectionMode = (int)connectionInfo.RedirectSound; - _rdpClient.AdvancedSettings6.RedirectClipboard = connectionInfo.RedirectClipboard; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.RdpSetRedirectionFailed, ex); - } - } - - private void SetPerformanceFlags() - { - try - { - var pFlags = 0; - if (connectionInfo.DisplayThemes == false) - pFlags += (int)RDPPerformanceFlags.DisableThemes; - - if (connectionInfo.DisplayWallpaper == false) - pFlags += (int)RDPPerformanceFlags.DisableWallpaper; - - if (connectionInfo.EnableFontSmoothing) - pFlags += (int)RDPPerformanceFlags.EnableFontSmoothing; - - if (connectionInfo.EnableDesktopComposition) - pFlags += (int)RDPPerformanceFlags.EnableDesktopComposition; - - if (connectionInfo.DisableFullWindowDrag) - pFlags += (int)RDPPerformanceFlags.DisableFullWindowDrag; - - if (connectionInfo.DisableMenuAnimations) - pFlags += (int)RDPPerformanceFlags.DisableMenuAnimations; - - if (connectionInfo.DisableCursorShadow) - pFlags += (int)RDPPerformanceFlags.DisableCursorShadow; - - if (connectionInfo.DisableCursorBlinking) - pFlags += (int)RDPPerformanceFlags.DisableCursorBlinking; - - _rdpClient.AdvancedSettings2.PerformanceFlags = pFlags; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.RdpSetPerformanceFlagsFailed, ex); - } - } - - private void SetAuthenticationLevel() - { - try - { - _rdpClient.AdvancedSettings5.AuthenticationLevel = (uint)connectionInfo.RDPAuthenticationLevel; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.RdpSetAuthenticationLevelFailed, ex); - } - } - - private void SetLoadBalanceInfo() - { - if (string.IsNullOrEmpty(connectionInfo.LoadBalanceInfo)) - { - return; - } - - try - { - _rdpClient.AdvancedSettings2.LoadBalanceInfo = LoadBalanceInfoUseUtf8 - ? new AzureLoadBalanceInfoEncoder().Encode(connectionInfo.LoadBalanceInfo) - : connectionInfo.LoadBalanceInfo; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace("Unable to set load balance info.", ex); - } - } - - private void SetEventHandlers() - { - try - { - _rdpClient.OnConnecting += RDPEvent_OnConnecting; - _rdpClient.OnConnected += RDPEvent_OnConnected; - _rdpClient.OnLoginComplete += RDPEvent_OnLoginComplete; - _rdpClient.OnFatalError += RDPEvent_OnFatalError; - _rdpClient.OnDisconnected += RDPEvent_OnDisconnected; - _rdpClient.OnLeaveFullScreenMode += RDPEvent_OnLeaveFullscreenMode; - _rdpClient.OnIdleTimeoutNotification += RDPEvent_OnIdleTimeoutNotification; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionStackTrace(Language.RdpSetEventHandlersFailed, ex); - } - } - - #endregion - - #region Private Events & Handlers - - private void RDPEvent_OnIdleTimeoutNotification() - { - Close(); //Simply close the RDP Session if the idle timeout has been triggered. - - if (!_alertOnIdleDisconnect) return; - MessageBox.Show($"The {connectionInfo.Name} session was disconnected due to inactivity", - "Session Disconnected", MessageBoxButtons.OK, MessageBoxIcon.Information); - } - - - private void RDPEvent_OnFatalError(int errorCode) - { - var errorMsg = RdpErrorCodes.GetError(errorCode); - Event_ErrorOccured(this, errorMsg, errorCode); - } - - private void RDPEvent_OnDisconnected(int discReason) - { - const int UI_ERR_NORMAL_DISCONNECT = 0xB08; - if (discReason != UI_ERR_NORMAL_DISCONNECT) - { - var reason = - _rdpClient.GetErrorDescription((uint)discReason, (uint)_rdpClient.ExtendedDisconnectReason); - Event_Disconnected(this, reason, discReason); - } - - if (Properties.OptionsAdvancedPage.Default.ReconnectOnDisconnect) - { - ReconnectGroup = new ReconnectGroup(); - ReconnectGroup.CloseClicked += Event_ReconnectGroupCloseClicked; - ReconnectGroup.Left = (int)((double)Control.Width / 2 - (double)ReconnectGroup.Width / 2); - ReconnectGroup.Top = (int)((double)Control.Height / 2 - (double)ReconnectGroup.Height / 2); - ReconnectGroup.Parent = Control; - ReconnectGroup.Show(); - tmrReconnect.Enabled = true; - } - else - { - Close(); - } - } - - private void RDPEvent_OnConnecting() - { - Event_Connecting(this); - } - - private void RDPEvent_OnConnected() - { - Event_Connected(this); - } - - private void RDPEvent_OnLoginComplete() - { - loginComplete = true; - } - - private void RDPEvent_OnLeaveFullscreenMode() - { - Fullscreen = false; - _leaveFullscreenEvent?.Invoke(this, new EventArgs()); - } - - private void RdpClient_GotFocus(object sender, EventArgs e) - { - ((ConnectionTab)Control.Parent.Parent).Focus(); - } - #endregion - - #region Public Events & Handlers - - public delegate void LeaveFullscreenEventHandler(object sender, EventArgs e); - - private LeaveFullscreenEventHandler _leaveFullscreenEvent; - - public event LeaveFullscreenEventHandler LeaveFullscreen - { - add => _leaveFullscreenEvent = (LeaveFullscreenEventHandler)Delegate.Combine(_leaveFullscreenEvent, value); - remove => - _leaveFullscreenEvent = (LeaveFullscreenEventHandler)Delegate.Remove(_leaveFullscreenEvent, value); - } - - #endregion - - #region Enums - - public enum Defaults - { - Colors = RDPColors.Colors16Bit, - Sounds = RDPSounds.DoNotPlay, - Resolution = RDPResolutions.FitToWindow, - Port = 3389 - } - - #endregion - - public static class Versions - { - public static readonly Version RDC60 = new Version(6, 0, 6000); - public static readonly Version RDC61 = new Version(6, 0, 6001); - public static readonly Version RDC70 = new Version(6, 1, 7600); - public static readonly Version RDC80 = new Version(6, 2, 9200); - public static readonly Version RDC81 = new Version(6, 3, 9600); - public static readonly Version RDC100 = new Version(10, 0, 0); - } - - #region Reconnect Stuff - - public void tmrReconnect_Elapsed(object sender, ElapsedEventArgs e) - { - try - { - var srvReady = PortScanner.IsPortOpen(connectionInfo.Hostname, Convert.ToString(connectionInfo.Port)); - - ReconnectGroup.ServerReady = srvReady; - - if (!ReconnectGroup.ReconnectWhenReady || !srvReady) return; - tmrReconnect.Enabled = false; - ReconnectGroup.DisposeReconnectGroup(); - //SetProps() - _rdpClient.Connect(); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddExceptionMessage( - string.Format(Language.AutomaticReconnectError, connectionInfo.Hostname), - ex, MessageClass.WarningMsg, false); - } - } - - #endregion - } -} \ No newline at end of file From 5cbf1f15684556ad781bdff9a84da095a7e8f708 Mon Sep 17 00:00:00 2001 From: BlueBlock Date: Tue, 21 Mar 2023 12:22:20 -0400 Subject: [PATCH 09/13] adjust method access level of common protocol methods --- mRemoteNG/Connection/Protocol/IntegratedProgram.cs | 2 +- .../Protocol/PowerShell/Connection.Protocol.PowerShell.cs | 2 +- mRemoteNG/Connection/Protocol/PuttyBase.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mRemoteNG/Connection/Protocol/IntegratedProgram.cs b/mRemoteNG/Connection/Protocol/IntegratedProgram.cs index 816ab72c9..3a291408d 100644 --- a/mRemoteNG/Connection/Protocol/IntegratedProgram.cs +++ b/mRemoteNG/Connection/Protocol/IntegratedProgram.cs @@ -134,7 +134,7 @@ namespace mRemoteNG.Connection.Protocol } } - public override void Resize(object sender, EventArgs e) + protected override void Resize(object sender, EventArgs e) { try { diff --git a/mRemoteNG/Connection/Protocol/PowerShell/Connection.Protocol.PowerShell.cs b/mRemoteNG/Connection/Protocol/PowerShell/Connection.Protocol.PowerShell.cs index 51d7dd137..7fec7b5de 100644 --- a/mRemoteNG/Connection/Protocol/PowerShell/Connection.Protocol.PowerShell.cs +++ b/mRemoteNG/Connection/Protocol/PowerShell/Connection.Protocol.PowerShell.cs @@ -71,7 +71,7 @@ namespace mRemoteNG.Connection.Protocol.PowerShell } } - public override void Resize(object sender, EventArgs e) + protected override void Resize(object sender, EventArgs e) { try { diff --git a/mRemoteNG/Connection/Protocol/PuttyBase.cs b/mRemoteNG/Connection/Protocol/PuttyBase.cs index 18efa712c..302243efe 100644 --- a/mRemoteNG/Connection/Protocol/PuttyBase.cs +++ b/mRemoteNG/Connection/Protocol/PuttyBase.cs @@ -265,7 +265,7 @@ namespace mRemoteNG.Connection.Protocol } } - public override void Resize(object sender, EventArgs e) + protected override void Resize(object sender, EventArgs e) { try { From b0a8ccc5b66bd0b98d5185057c3679300d7ae87b Mon Sep 17 00:00:00 2001 From: BlueBlock Date: Tue, 21 Mar 2023 12:23:59 -0400 Subject: [PATCH 10/13] multiple RDP issues fixed - fix scale of RDP session when moving between 4k and 1080 monitors etc. - fix inefficient continuous RDP screen resizing while the window size is changed - add a RDP version check before attempting to use each RDP version and properties --- .../Connection/Protocol/RDP/RdpProtocol.cs | 867 ++++++++++++++++++ .../Connection/Protocol/RDP/RdpProtocol10.cs | 18 +- .../Connection/Protocol/RDP/RdpProtocol11.cs | 15 +- .../Connection/Protocol/RDP/RdpProtocol7.cs | 27 +- .../Connection/Protocol/RDP/RdpProtocol8.cs | 62 +- .../Connection/Protocol/RDP/RdpProtocol9.cs | 22 +- 6 files changed, 952 insertions(+), 59 deletions(-) create mode 100644 mRemoteNG/Connection/Protocol/RDP/RdpProtocol.cs diff --git a/mRemoteNG/Connection/Protocol/RDP/RdpProtocol.cs b/mRemoteNG/Connection/Protocol/RDP/RdpProtocol.cs new file mode 100644 index 000000000..3a6b80cf4 --- /dev/null +++ b/mRemoteNG/Connection/Protocol/RDP/RdpProtocol.cs @@ -0,0 +1,867 @@ +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Threading; +using System.Timers; +using System.Windows.Forms; +using AxMSTSCLib; +using mRemoteNG.App; +using mRemoteNG.Messages; +using mRemoteNG.Properties; +using mRemoteNG.Security.SymmetricEncryption; +using mRemoteNG.Tools; +using mRemoteNG.UI; +using mRemoteNG.UI.Forms; +using mRemoteNG.UI.Tabs; +using MSTSCLib; +using mRemoteNG.Resources.Language; +using System.Runtime.Versioning; +using FileDialog = Microsoft.Win32.FileDialog; + +namespace mRemoteNG.Connection.Protocol.RDP +{ + [SupportedOSPlatform("windows")] + public class RdpProtocol : ProtocolBase, ISupportsViewOnly + { + /* RDP v8 requires Windows 7 with: + * https://support.microsoft.com/en-us/kb/2592687 + * OR + * https://support.microsoft.com/en-us/kb/2923545 + * + * Windows 8+ support RDP v8 out of the box. + */ + + private MsRdpClient6NotSafeForScripting _rdpClient; // lowest version supported + protected virtual RdpVersion RdpProtocolVersion => RDP.RdpVersion.Rdc6; + protected ConnectionInfo connectionInfo; + protected Version RdpVersion; + private readonly DisplayProperties _displayProperties; + protected readonly FrmMain _frmMain = FrmMain.Default; + protected bool loginComplete; + private bool _redirectKeys; + private bool _alertOnIdleDisconnect; + protected uint DesktopScaleFactor => (uint)(_displayProperties.ResolutionScalingFactor.Width * 100); + protected readonly uint DeviceScaleFactor = 100; + protected readonly uint Orientation = 0; + private AxHost AxHost => (AxHost)Control; + + + #region Properties + + public virtual bool SmartSize + { + get => _rdpClient.AdvancedSettings2.SmartSizing; + protected set => _rdpClient.AdvancedSettings2.SmartSizing = value; + } + + public virtual bool Fullscreen + { + get => _rdpClient.FullScreen; + protected set => _rdpClient.FullScreen = value; + } + + private bool RedirectKeys + { + set + { + _redirectKeys = value; + try + { + if (!_redirectKeys) + { + return; + } + + Debug.Assert(Convert.ToBoolean(_rdpClient.SecuredSettingsEnabled)); + IMsRdpClientSecuredSettings msRdpClientSecuredSettings = _rdpClient.SecuredSettings2; + msRdpClientSecuredSettings.KeyboardHookMode = 1; // Apply key combinations at the remote server. + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.RdpSetRedirectKeysFailed, ex); + } + } + } + + public bool LoadBalanceInfoUseUtf8 { get; set; } + + public bool ViewOnly + { + get => !AxHost.Enabled; + set => AxHost.Enabled = !value; + } + + #endregion + + #region Constructors + + public RdpProtocol() + { + _displayProperties = new DisplayProperties(); + tmrReconnect.Elapsed += tmrReconnect_Elapsed; + } + + #endregion + + #region Public Methods + + protected virtual AxHost CreateActiveXRdpClientControl() + { + return new AxMsRdpClient6NotSafeForScripting(); + } + + public override bool Initialize() + { + connectionInfo = InterfaceControl.Info; + Runtime.MessageCollector.AddMessage(MessageClass.DebugMsg, $"Requesting RDP version: {connectionInfo.RdpVersion}. Using: {RdpProtocolVersion}"); + Control = CreateActiveXRdpClientControl(); + base.Initialize(); + + try + { + if (!InitializeActiveXControl()) return false; + + RdpVersion = new Version(_rdpClient.Version); + + if (RdpVersion < Versions.RDC61) return false; // only RDP versions 6.1 and greater are supported; minimum dll version checked, MSTSCLIB is not capable + + SetRdpClientProperties(); + + return true; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.RdpSetPropsFailed, ex); + return false; + } + } + + private bool InitializeActiveXControl() + { + try + { + Control.GotFocus += RdpClient_GotFocus; + + Control.CreateControl(); + + while (!Control.Created) + { + Thread.Sleep(50); + Application.DoEvents(); + } + Control.Anchor = AnchorStyles.None; + + _rdpClient = (MsRdpClient6NotSafeForScripting)((AxHost)Control).GetOcx(); + + return true; + } + catch (COMException ex) + { + if (ex.Message.Contains("CLASS_E_CLASSNOTAVAILABLE")) + { + Runtime.MessageCollector.AddMessage(MessageClass.ErrorMsg, string.Format(Language.RdpProtocolVersionNotSupported, connectionInfo.RdpVersion)); + } + else + { + Runtime.MessageCollector.AddExceptionMessage(Language.RdpControlCreationFailed, ex); + } + Control.Dispose(); + return false; + } + } + + public override bool Connect() + { + loginComplete = false; + SetEventHandlers(); + + try + { + _rdpClient.Connect(); + base.Connect(); + + return true; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.ConnectionOpenFailed, ex); + } + + return false; + } + + public override void Disconnect() + { + try + { + _rdpClient.Disconnect(); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.RdpDisconnectFailed, ex); + Close(); + } + } + + public void ToggleFullscreen() + { + try + { + Fullscreen = !Fullscreen; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.RdpToggleFullscreenFailed, ex); + } + } + + public void ToggleSmartSize() + { + try + { + SmartSize = !SmartSize; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.RdpToggleSmartSizeFailed, ex); + } + } + + /// + /// Toggles whether the RDP ActiveX control will capture and send input events to the remote host. + /// The local host will continue to receive data from the remote host regardless of this setting. + /// + public void ToggleViewOnly() + { + try + { + ViewOnly = !ViewOnly; + } + catch + { + Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, $"Could not toggle view only mode for host {connectionInfo.Hostname}"); + } + } + + public override void Focus() + { + try + { + if (Control.ContainsFocus == false) + { + Control.Focus(); + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.RdpFocusFailed, ex); + } + } + + /// + /// Determines if this version of the RDP client + /// is supported on this machine. + /// + /// + public bool RdpVersionSupported() + { + try + { + using var control = CreateActiveXRdpClientControl(); + control.CreateControl(); + return true; + } + catch + { + return false; + } + } + #endregion + + #region Private Methods + + protected static class Versions + { + // https://en.wikipedia.org/wiki/Remote_Desktop_Protocol + public static readonly Version RDC60 = new Version(6, 0, 6000); + public static readonly Version RDC61 = new Version(6, 0, 6001); + public static readonly Version RDC70 = new Version(6, 1, 7600); + public static readonly Version RDC80 = new Version(6, 2, 9200); + public static readonly Version RDC81 = new Version(6, 3, 9600); + public static readonly Version RDC100 = new Version(10, 0, 0); + } + + private void SetRdpClientProperties() + { + // https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/clients/rdp-files + + _rdpClient.Server = connectionInfo.Hostname; + + SetCredentials(); + SetResolution(); + _rdpClient.FullScreenTitle = connectionInfo.Name; + + _alertOnIdleDisconnect = connectionInfo.RDPAlertIdleTimeout; + _rdpClient.AdvancedSettings2.MinutesToIdleTimeout = connectionInfo.RDPMinutesToIdleTimeout; + + #region Remote Desktop Services + _rdpClient.SecuredSettings2.StartProgram = connectionInfo.RDPStartProgram; + _rdpClient.SecuredSettings2.WorkDir = connectionInfo.RDPStartProgramWorkDir; + #endregion + + //not user changeable + _rdpClient.AdvancedSettings2.GrabFocusOnConnect = true; + _rdpClient.AdvancedSettings3.EnableAutoReconnect = true; + _rdpClient.AdvancedSettings3.MaxReconnectAttempts = Settings.Default.RdpReconnectionCount; + _rdpClient.AdvancedSettings2.keepAliveInterval = 60000; //in milliseconds (10,000 = 10 seconds) + _rdpClient.AdvancedSettings5.AuthenticationLevel = 0; + _rdpClient.AdvancedSettings2.EncryptionEnabled = 1; + + _rdpClient.AdvancedSettings2.overallConnectionTimeout = Settings.Default.ConRDPOverallConnectionTimeout; + + _rdpClient.AdvancedSettings2.BitmapPeristence = Convert.ToInt32(connectionInfo.CacheBitmaps); + + if (RdpVersion >= Versions.RDC61) + { + _rdpClient.AdvancedSettings7.EnableCredSspSupport = connectionInfo.UseCredSsp; + } + + SetUseConsoleSession(); + SetPort(); + RedirectKeys = connectionInfo.RedirectKeys; + SetRedirection(); + SetAuthenticationLevel(); + SetLoadBalanceInfo(); + SetRdGateway(); + ViewOnly = Force.HasFlag(ConnectionInfo.Force.ViewOnly); + + _rdpClient.ColorDepth = (int)connectionInfo.Colors; + + SetPerformanceFlags(); + + _rdpClient.ConnectingText = Language.Connecting; + } + + protected object GetExtendedProperty(string property) + { + try + { + // ReSharper disable once UseIndexedProperty + return ((IMsRdpExtendedSettings)_rdpClient).get_Property(property); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage($"Error getting extended RDP property '{property}'", ex, MessageClass.WarningMsg, false); + return null; + } + } + + protected void SetExtendedProperty(string property, object value) + { + try + { + // ReSharper disable once UseIndexedProperty + ((IMsRdpExtendedSettings)_rdpClient).set_Property(property, ref value); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage($"Error setting extended RDP property '{property}'", ex, MessageClass.WarningMsg, false); + } + } + + private void SetRdGateway() + { + try + { + if (_rdpClient.TransportSettings.GatewayIsSupported == 0) + { + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.RdpGatewayNotSupported, true); + return; + } + + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.RdpGatewayIsSupported, true); + + if (connectionInfo.RDGatewayUsageMethod == RDGatewayUsageMethod.Never) return; + + // USE GATEWAY + _rdpClient.TransportSettings.GatewayUsageMethod = (uint)connectionInfo.RDGatewayUsageMethod; + _rdpClient.TransportSettings.GatewayHostname = connectionInfo.RDGatewayHostname; + _rdpClient.TransportSettings.GatewayProfileUsageMethod = 1; // TSC_PROXY_PROFILE_MODE_EXPLICIT + if (connectionInfo.RDGatewayUseConnectionCredentials == RDGatewayUseConnectionCredentials.SmartCard) + { + _rdpClient.TransportSettings.GatewayCredsSource = 1; // TSC_PROXY_CREDS_MODE_SMARTCARD + } + + if (RdpVersion < Versions.RDC61 || Force.HasFlag(ConnectionInfo.Force.NoCredentials)) return; + + switch (connectionInfo.RDGatewayUseConnectionCredentials) + { + case RDGatewayUseConnectionCredentials.Yes: + _rdpClient.TransportSettings2.GatewayUsername = connectionInfo.Username; + _rdpClient.TransportSettings2.GatewayPassword = connectionInfo.Password; + _rdpClient.TransportSettings2.GatewayDomain = connectionInfo?.Domain; + break; + case RDGatewayUseConnectionCredentials.SmartCard: + _rdpClient.TransportSettings2.GatewayCredSharing = 0; + break; + default: + { + _rdpClient.TransportSettings2.GatewayCredSharing = 0; + + var gwu = connectionInfo.RDGatewayUsername; + var gwp = connectionInfo.RDGatewayPassword; + var gwd = connectionInfo.RDGatewayDomain; + var pkey = ""; + + // access secret server api if necessary + if (InterfaceControl.Info.RDGatewayExternalCredentialProvider == ExternalCredentialProvider.DelineaSecretServer) + { + try + { + string RDGUserViaAPI = InterfaceControl.Info.RDGatewayUserViaAPI; + ExternalConnectors.DSS.SecretServerInterface.FetchSecretFromServer($"{RDGUserViaAPI}", out gwu, out gwp, out gwd, out pkey); + } + catch (Exception ex) + { + Event_ErrorOccured(this, "Secret Server Interface Error: " + ex.Message, 0); + } + + } + _rdpClient.TransportSettings2.GatewayUsername = gwu; + _rdpClient.TransportSettings2.GatewayPassword = gwp; + _rdpClient.TransportSettings2.GatewayDomain = gwd; + break; + } + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.RdpSetGatewayFailed, ex); + } + } + + private void SetUseConsoleSession() + { + try + { + bool value; + + if (Force.HasFlag(ConnectionInfo.Force.UseConsoleSession)) + { + value = true; + } + else if (Force.HasFlag(ConnectionInfo.Force.DontUseConsoleSession)) + { + value = false; + } + else + { + value = connectionInfo.UseConsoleSession; + } + + if (RdpVersion >= Versions.RDC61) + { + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, string.Format(Language.RdpSetConsoleSwitch, RdpVersion), true); + _rdpClient.AdvancedSettings7.ConnectToAdministerServer = value; + } + else + { + Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, $"{string.Format(Language.RdpSetConsoleSwitch, RdpVersion)}{Environment.NewLine}No longer supported in this RDP version. Reference: https://msdn.microsoft.com/en-us/library/aa380863(v=vs.85).aspx", true); + // ConnectToServerConsole is deprecated + //https://msdn.microsoft.com/en-us/library/aa380863(v=vs.85).aspx + //_rdpClient.AdvancedSettings2.ConnectToServerConsole = value; + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.RdpSetConsoleSessionFailed, ex); + } + } + + private void SetCredentials() + { + try + { + if (Force.HasFlag(ConnectionInfo.Force.NoCredentials)) + { + return; + } + + var userName = connectionInfo?.Username ?? ""; + var password = connectionInfo?.Password ?? ""; + var domain = connectionInfo?.Domain ?? ""; + var userViaApi = connectionInfo?.UserViaAPI ?? ""; + var pkey = ""; + + // access secret server api if necessary + if (InterfaceControl.Info.ExternalCredentialProvider == ExternalCredentialProvider.DelineaSecretServer) + { + try + { + ExternalConnectors.DSS.SecretServerInterface.FetchSecretFromServer($"{userViaApi}", out userName, out password, out domain, out pkey); + } + catch (Exception ex) + { + Event_ErrorOccured(this, "Secret Server Interface Error: " + ex.Message, 0); + } + + } + + if (string.IsNullOrEmpty(userName)) + { + switch (Properties.OptionsCredentialsPage.Default.EmptyCredentials) + { + case "windows": + _rdpClient.UserName = Environment.UserName; + break; + case "custom" when !string.IsNullOrEmpty(Properties.OptionsCredentialsPage.Default.DefaultUsername): + _rdpClient.UserName = Properties.OptionsCredentialsPage.Default.DefaultUsername; + break; + case "custom": + try + { + ExternalConnectors.DSS.SecretServerInterface.FetchSecretFromServer(Properties.OptionsCredentialsPage.Default.UserViaAPIDefault, out userName, out password, out domain, out pkey); + _rdpClient.UserName = userName; + } + catch (Exception ex) + { + Event_ErrorOccured(this, "Secret Server Interface Error: " + ex.Message, 0); + } + + break; + } + } + else + { + _rdpClient.UserName = userName; + } + + if (string.IsNullOrEmpty(password)) + { + if (Properties.OptionsCredentialsPage.Default.EmptyCredentials == "custom") + { + if (Properties.OptionsCredentialsPage.Default.DefaultPassword != "") + { + var cryptographyProvider = new LegacyRijndaelCryptographyProvider(); + _rdpClient.AdvancedSettings2.ClearTextPassword = cryptographyProvider.Decrypt(Properties.OptionsCredentialsPage.Default.DefaultPassword, Runtime.EncryptionKey); + } + } + } + else + { + _rdpClient.AdvancedSettings2.ClearTextPassword = password; + } + + if (string.IsNullOrEmpty(domain)) + { + _rdpClient.Domain = Properties.OptionsCredentialsPage.Default.EmptyCredentials switch + { + "windows" => Environment.UserDomainName, + "custom" => Properties.OptionsCredentialsPage.Default.DefaultDomain, + _ => _rdpClient.Domain + }; + } + else + { + _rdpClient.Domain = domain; + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.RdpSetCredentialsFailed, ex); + } + } + + private void SetResolution() + { + try + { + SetExtendedProperty("DesktopScaleFactor", DesktopScaleFactor); + SetExtendedProperty("DeviceScaleFactor", DeviceScaleFactor); + + if (Force.HasFlag(ConnectionInfo.Force.Fullscreen)) + { + _rdpClient.FullScreen = true; + _rdpClient.DesktopWidth = Screen.FromControl(_frmMain).Bounds.Width; + _rdpClient.DesktopHeight = Screen.FromControl(_frmMain).Bounds.Height; + + return; + } + + switch (InterfaceControl.Info.Resolution) + { + case RDPResolutions.FitToWindow: + case RDPResolutions.SmartSize: + { + _rdpClient.DesktopWidth = InterfaceControl.Size.Width; + _rdpClient.DesktopHeight = InterfaceControl.Size.Height; + + if (InterfaceControl.Info.Resolution == RDPResolutions.SmartSize) + { + _rdpClient.AdvancedSettings2.SmartSizing = true; + } + + break; + } + case RDPResolutions.Fullscreen: + _rdpClient.FullScreen = true; + _rdpClient.DesktopWidth = Screen.FromControl(_frmMain).Bounds.Width; + _rdpClient.DesktopHeight = Screen.FromControl(_frmMain).Bounds.Height; + break; + default: + { + var resolution = connectionInfo.Resolution.GetResolutionRectangle(); + _rdpClient.DesktopWidth = resolution.Width; + _rdpClient.DesktopHeight = resolution.Height; + break; + } + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.RdpSetResolutionFailed, ex); + } + } + + private void SetPort() + { + try + { + if (connectionInfo.Port != (int)Defaults.Port) + { + _rdpClient.AdvancedSettings2.RDPPort = connectionInfo.Port; + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.RdpSetPortFailed, ex); + } + } + + private void SetRedirection() + { + try + { + _rdpClient.AdvancedSettings2.RedirectDrives = connectionInfo.RedirectDiskDrives; + _rdpClient.AdvancedSettings2.RedirectPorts = connectionInfo.RedirectPorts; + _rdpClient.AdvancedSettings2.RedirectPrinters = connectionInfo.RedirectPrinters; + _rdpClient.AdvancedSettings2.RedirectSmartCards = connectionInfo.RedirectSmartCards; + _rdpClient.SecuredSettings2.AudioRedirectionMode = (int)connectionInfo.RedirectSound; + _rdpClient.AdvancedSettings6.RedirectClipboard = connectionInfo.RedirectClipboard; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.RdpSetRedirectionFailed, ex); + } + } + + private void SetPerformanceFlags() + { + try + { + var pFlags = 0; + if (connectionInfo.DisplayThemes == false) + pFlags += (int)RDPPerformanceFlags.DisableThemes; + + if (connectionInfo.DisplayWallpaper == false) + pFlags += (int)RDPPerformanceFlags.DisableWallpaper; + + if (connectionInfo.EnableFontSmoothing) + pFlags += (int)RDPPerformanceFlags.EnableFontSmoothing; + + if (connectionInfo.EnableDesktopComposition) + pFlags += (int)RDPPerformanceFlags.EnableDesktopComposition; + + if (connectionInfo.DisableFullWindowDrag) + pFlags += (int)RDPPerformanceFlags.DisableFullWindowDrag; + + if (connectionInfo.DisableMenuAnimations) + pFlags += (int)RDPPerformanceFlags.DisableMenuAnimations; + + if (connectionInfo.DisableCursorShadow) + pFlags += (int)RDPPerformanceFlags.DisableCursorShadow; + + if (connectionInfo.DisableCursorBlinking) + pFlags += (int)RDPPerformanceFlags.DisableCursorBlinking; + + _rdpClient.AdvancedSettings2.PerformanceFlags = pFlags; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.RdpSetPerformanceFlagsFailed, ex); + } + } + + private void SetAuthenticationLevel() + { + try + { + _rdpClient.AdvancedSettings5.AuthenticationLevel = (uint)connectionInfo.RDPAuthenticationLevel; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.RdpSetAuthenticationLevelFailed, ex); + } + } + + private void SetLoadBalanceInfo() + { + if (string.IsNullOrEmpty(connectionInfo.LoadBalanceInfo)) + { + return; + } + + try + { + _rdpClient.AdvancedSettings2.LoadBalanceInfo = LoadBalanceInfoUseUtf8 + ? new AzureLoadBalanceInfoEncoder().Encode(connectionInfo.LoadBalanceInfo) + : connectionInfo.LoadBalanceInfo; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace("Unable to set load balance info.", ex); + } + } + + protected virtual void SetEventHandlers() + { + try + { + _rdpClient.OnConnecting += RDPEvent_OnConnecting; + _rdpClient.OnConnected += RDPEvent_OnConnected; + _rdpClient.OnLoginComplete += RDPEvent_OnLoginComplete; + _rdpClient.OnFatalError += RDPEvent_OnFatalError; + _rdpClient.OnDisconnected += RDPEvent_OnDisconnected; + _rdpClient.OnIdleTimeoutNotification += RDPEvent_OnIdleTimeoutNotification; + _rdpClient.OnLeaveFullScreenMode += RDPEvent_OnLeaveFullscreenMode; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionStackTrace(Language.RdpSetEventHandlersFailed, ex); + } + } + + #endregion + + #region Private Events & Handlers + + private void RDPEvent_OnIdleTimeoutNotification() + { + Close(); //Simply close the RDP Session if the idle timeout has been triggered. + + if (!_alertOnIdleDisconnect) return; + MessageBox.Show($@"The {connectionInfo.Name} session was disconnected due to inactivity", @"Session Disconnected", MessageBoxButtons.OK, MessageBoxIcon.Information); + } + + private void RDPEvent_OnFatalError(int errorCode) + { + var errorMsg = RdpErrorCodes.GetError(errorCode); + Event_ErrorOccured(this, errorMsg, errorCode); + } + + private void RDPEvent_OnDisconnected(int discReason) + { + const int UI_ERR_NORMAL_DISCONNECT = 0xB08; + if (discReason != UI_ERR_NORMAL_DISCONNECT) + { + var reason = _rdpClient.GetErrorDescription((uint)discReason, (uint)_rdpClient.ExtendedDisconnectReason); + Event_Disconnected(this, reason, discReason); + } + + if (Properties.OptionsAdvancedPage.Default.ReconnectOnDisconnect) + { + ReconnectGroup = new ReconnectGroup(); + ReconnectGroup.CloseClicked += Event_ReconnectGroupCloseClicked; + ReconnectGroup.Left = (int)((double)Control.Width / 2 - (double)ReconnectGroup.Width / 2); + ReconnectGroup.Top = (int)((double)Control.Height / 2 - (double)ReconnectGroup.Height / 2); + ReconnectGroup.Parent = Control; + ReconnectGroup.Show(); + tmrReconnect.Enabled = true; + } + else + { + Close(); + } + } + + private void RDPEvent_OnConnecting() + { + Event_Connecting(this); + } + + private void RDPEvent_OnConnected() + { + Event_Connected(this); + } + + private void RDPEvent_OnLoginComplete() + { + loginComplete = true; + } + + private void RDPEvent_OnLeaveFullscreenMode() + { + Fullscreen = false; + _leaveFullscreenEvent?.Invoke(this, EventArgs.Empty); + } + + private void RdpClient_GotFocus(object sender, EventArgs e) + { + ((ConnectionTab)Control.Parent.Parent).Focus(); + } + #endregion + + #region Public Events & Handlers + + public delegate void LeaveFullscreenEventHandler(object sender, EventArgs e); + + private LeaveFullscreenEventHandler _leaveFullscreenEvent; + + public event LeaveFullscreenEventHandler LeaveFullscreen + { + add => _leaveFullscreenEvent = (LeaveFullscreenEventHandler)Delegate.Combine(_leaveFullscreenEvent, value); + remove => _leaveFullscreenEvent = (LeaveFullscreenEventHandler)Delegate.Remove(_leaveFullscreenEvent, value); + } + + #endregion + + #region Enums + + public enum Defaults + { + Colors = RDPColors.Colors16Bit, + Sounds = RDPSounds.DoNotPlay, + Resolution = RDPResolutions.FitToWindow, + Port = 3389 + } + + #endregion + + #region Reconnect Stuff + + private void tmrReconnect_Elapsed(object sender, ElapsedEventArgs e) + { + try + { + var srvReady = PortScanner.IsPortOpen(connectionInfo.Hostname, Convert.ToString(connectionInfo.Port)); + + ReconnectGroup.ServerReady = srvReady; + + if (!ReconnectGroup.ReconnectWhenReady || !srvReady) return; + tmrReconnect.Enabled = false; + ReconnectGroup.DisposeReconnectGroup(); + //SetProps() + _rdpClient.Connect(); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddExceptionMessage( + string.Format(Language.AutomaticReconnectError, connectionInfo.Hostname), + ex, MessageClass.WarningMsg, false); + } + } + + #endregion + + } +} \ No newline at end of file diff --git a/mRemoteNG/Connection/Protocol/RDP/RdpProtocol10.cs b/mRemoteNG/Connection/Protocol/RDP/RdpProtocol10.cs index 611f1ad05..cd277b5c7 100644 --- a/mRemoteNG/Connection/Protocol/RDP/RdpProtocol10.cs +++ b/mRemoteNG/Connection/Protocol/RDP/RdpProtocol10.cs @@ -1,25 +1,27 @@ using System.Runtime.Versioning; using System.Windows.Forms; using AxMSTSCLib; -using MSTSCLib; namespace mRemoteNG.Connection.Protocol.RDP { [SupportedOSPlatform("windows")] public class RdpProtocol10 : RdpProtocol9 { - private MsRdpClient10NotSafeForScripting RdpClient10 => (MsRdpClient10NotSafeForScripting)((AxHost)Control).GetOcx(); - - protected override RdpVersion RdpProtocolVersion => RdpVersion.Rdc10; - + protected override RdpVersion RdpProtocolVersion => RDP.RdpVersion.Rdc10; + protected override AxHost CreateActiveXRdpClientControl() { - return new AxMsRdpClient10NotSafeForScripting(); + return new AxMsRdpClient11NotSafeForScripting(); } - protected override void UpdateSessionDisplaySettings(uint width, uint height) + public override bool Initialize() { - RdpClient10.UpdateSessionDisplaySettings(width, height, width, height, 0, 1, 1); + if (!base.Initialize()) + return false; + + if (RdpVersion < Versions.RDC100) return false; // minimum dll version checked, loaded MSTSCLIB dll version is not capable + + return true; } } diff --git a/mRemoteNG/Connection/Protocol/RDP/RdpProtocol11.cs b/mRemoteNG/Connection/Protocol/RDP/RdpProtocol11.cs index 4db5465b1..769781a8a 100644 --- a/mRemoteNG/Connection/Protocol/RDP/RdpProtocol11.cs +++ b/mRemoteNG/Connection/Protocol/RDP/RdpProtocol11.cs @@ -1,25 +1,26 @@ using System.Runtime.Versioning; using System.Windows.Forms; using AxMSTSCLib; -using MSTSCLib; namespace mRemoteNG.Connection.Protocol.RDP { [SupportedOSPlatform("windows")] public class RdpProtocol11 : RdpProtocol10 { - private MsRdpClient11NotSafeForScripting RdpClient11 => (MsRdpClient11NotSafeForScripting)((AxHost)Control).GetOcx(); - - protected override RdpVersion RdpProtocolVersion => RdpVersion.Rdc11; + protected override RdpVersion RdpProtocolVersion => RDP.RdpVersion.Rdc11; protected override AxHost CreateActiveXRdpClientControl() { return new AxMsRdpClient11NotSafeForScripting(); } - - protected override void UpdateSessionDisplaySettings(uint width, uint height) + public override bool Initialize() { - RdpClient11.UpdateSessionDisplaySettings(width, height, width, height, 0, 1, 1); + if (!base.Initialize()) + return false; + + if (RdpVersion < Versions.RDC100) return false; // minimum dll version checked, loaded MSTSCLIB dll version is not capable + + return true; } } diff --git a/mRemoteNG/Connection/Protocol/RDP/RdpProtocol7.cs b/mRemoteNG/Connection/Protocol/RDP/RdpProtocol7.cs index 42b60990d..9ff0ba0ba 100644 --- a/mRemoteNG/Connection/Protocol/RDP/RdpProtocol7.cs +++ b/mRemoteNG/Connection/Protocol/RDP/RdpProtocol7.cs @@ -9,9 +9,10 @@ using System.Runtime.Versioning; namespace mRemoteNG.Connection.Protocol.RDP { [SupportedOSPlatform("windows")] - public class RdpProtocol7 : RdpProtocol6 + public class RdpProtocol7 : RdpProtocol { - protected override RdpVersion RdpProtocolVersion => RdpVersion.Rdc7; + private MsRdpClient7NotSafeForScripting RdpClient7 => (MsRdpClient7NotSafeForScripting)((AxHost)Control).GetOcx(); + protected override RdpVersion RdpProtocolVersion => RDP.RdpVersion.Rdc7; public override bool Initialize() { @@ -20,20 +21,21 @@ namespace mRemoteNG.Connection.Protocol.RDP try { - var rdpClient7 = (MsRdpClient7NotSafeForScripting)((AxHost) Control).GetOcx(); - rdpClient7.AdvancedSettings8.AudioQualityMode = (uint)connectionInfo.SoundQuality; - rdpClient7.AdvancedSettings8.AudioCaptureRedirectionMode = connectionInfo.RedirectAudioCapture; - rdpClient7.AdvancedSettings8.NetworkConnectionType = (int)RdpNetworkConnectionType.Modem; + if (RdpVersion < Versions.RDC70) return false; // loaded MSTSCLIB dll version is not capable + + RdpClient7.AdvancedSettings8.AudioQualityMode = (uint)connectionInfo.SoundQuality; + RdpClient7.AdvancedSettings8.AudioCaptureRedirectionMode = connectionInfo.RedirectAudioCapture; + RdpClient7.AdvancedSettings8.NetworkConnectionType = (int)RdpNetworkConnectionType.Modem; if (connectionInfo.UseVmId) { SetExtendedProperty("DisableCredentialsDelegation", true); - rdpClient7.AdvancedSettings7.AuthenticationServiceClass = "Microsoft Virtual Console Service"; - rdpClient7.AdvancedSettings8.EnableCredSspSupport = true; - rdpClient7.AdvancedSettings8.NegotiateSecurityLayer = false; - rdpClient7.AdvancedSettings7.PCB = $"{connectionInfo.VmId}"; + RdpClient7.AdvancedSettings7.AuthenticationServiceClass = "Microsoft Virtual Console Service"; + RdpClient7.AdvancedSettings8.EnableCredSspSupport = true; + RdpClient7.AdvancedSettings8.NegotiateSecurityLayer = false; + RdpClient7.AdvancedSettings7.PCB = $"{connectionInfo.VmId}"; if (connectionInfo.UseEnhancedMode) - rdpClient7.AdvancedSettings7.PCB += ";EnhancedMode=1"; + RdpClient7.AdvancedSettings7.PCB += ";EnhancedMode=1"; } } catch (Exception ex) @@ -47,7 +49,8 @@ namespace mRemoteNG.Connection.Protocol.RDP protected override AxHost CreateActiveXRdpClientControl() { - return new AxMsRdpClient7NotSafeForScripting(); + return new AxMsRdpClient11NotSafeForScripting(); } + } } diff --git a/mRemoteNG/Connection/Protocol/RDP/RdpProtocol8.cs b/mRemoteNG/Connection/Protocol/RDP/RdpProtocol8.cs index 6df68cedb..3cab74136 100644 --- a/mRemoteNG/Connection/Protocol/RDP/RdpProtocol8.cs +++ b/mRemoteNG/Connection/Protocol/RDP/RdpProtocol8.cs @@ -21,18 +21,28 @@ namespace mRemoteNG.Connection.Protocol.RDP public class RdpProtocol8 : RdpProtocol7 { private MsRdpClient8NotSafeForScripting RdpClient8 => (MsRdpClient8NotSafeForScripting)((AxHost)Control).GetOcx(); - private Size _controlBeginningSize; - protected override RdpVersion RdpProtocolVersion => RdpVersion.Rdc8; + protected override RdpVersion RdpProtocolVersion => RDP.RdpVersion.Rdc8; - public override bool SmartSize + public override bool Initialize() { - get => base.SmartSize; - protected set + if (!base.Initialize()) + return false; + + if (RdpVersion < Versions.RDC81) return false; // minimum dll version checked, loaded MSTSCLIB dll version is not capable + + // https://learn.microsoft.com/en-us/windows/win32/termserv/imsrdpextendedsettings-property + if (connectionInfo.UseRestrictedAdmin) { - base.SmartSize = value; - DoResizeClient(); + SetExtendedProperty("RestrictedLogon", true); } + else if (connectionInfo.UseRCG) + { + SetExtendedProperty("DisableCredentialsDelegation", true); + SetExtendedProperty("RedirectedAuthentication", true); + } + + return true; } public override bool Fullscreen @@ -45,28 +55,17 @@ namespace mRemoteNG.Connection.Protocol.RDP } } - public override void ResizeBegin(object sender, EventArgs e) + protected override void Resize(object sender, EventArgs e) { - _controlBeginningSize = Control.Size; + if (_frmMain.PreviousWindowState == _frmMain.WindowState) return; + DoResizeControl(); + DoResizeClient(); } - public override void Resize(object sender, EventArgs e) - { - if (DoResizeControl() && _controlBeginningSize.IsEmpty) - { - DoResizeClient(); - } - base.Resize(sender, e); - } - - public override void ResizeEnd(object sender, EventArgs e) + protected override void ResizeEnd(object sender, EventArgs e) { DoResizeControl(); - if (!(Control.Size == _controlBeginningSize)) - { - DoResizeClient(); - } - _controlBeginningSize = Size.Empty; + DoResizeClient(); } protected override AxHost CreateActiveXRdpClientControl() @@ -94,10 +93,19 @@ namespace mRemoteNG.Connection.Protocol.RDP try { + //var q1 = Screen.FromControl(Control).Bounds.Size; + //var q2 = Control.Size; + var size = Fullscreen ? Screen.FromControl(Control).Bounds.Size : Control.Size; + + //size = Screen.FromControl(Control).Bounds.Size; UpdateSessionDisplaySettings((uint)size.Width, (uint)size.Height); + + //size = Control.Size; + //UpdateSessionDisplaySettings((uint)size.Width, (uint)size.Height); + } catch (Exception ex) { @@ -117,10 +125,8 @@ namespace mRemoteNG.Connection.Protocol.RDP Control.Size = InterfaceControl.Size; return true; } - else - { - return false; - } + + return false; } protected virtual void UpdateSessionDisplaySettings(uint width, uint height) diff --git a/mRemoteNG/Connection/Protocol/RDP/RdpProtocol9.cs b/mRemoteNG/Connection/Protocol/RDP/RdpProtocol9.cs index 391125c80..b9c799aa9 100644 --- a/mRemoteNG/Connection/Protocol/RDP/RdpProtocol9.cs +++ b/mRemoteNG/Connection/Protocol/RDP/RdpProtocol9.cs @@ -1,5 +1,4 @@ -using System; -using System.Runtime.Versioning; +using System.Runtime.Versioning; using System.Windows.Forms; using AxMSTSCLib; using MSTSCLib; @@ -11,7 +10,22 @@ namespace mRemoteNG.Connection.Protocol.RDP { private MsRdpClient9NotSafeForScripting RdpClient9 => (MsRdpClient9NotSafeForScripting)((AxHost)Control).GetOcx(); - protected override RdpVersion RdpProtocolVersion => RdpVersion.Rdc9; + protected override RdpVersion RdpProtocolVersion => RDP.RdpVersion.Rdc9; + + public RdpProtocol9() + { + _frmMain.ResizeEnd += ResizeEnd; + } + + public override bool Initialize() + { + if (!base.Initialize()) + return false; + + if (RdpVersion < Versions.RDC81) return false; // minimum dll version checked, loaded MSTSCLIB dll version is not capable + + return true; + } protected override AxHost CreateActiveXRdpClientControl() { @@ -20,7 +34,7 @@ namespace mRemoteNG.Connection.Protocol.RDP protected override void UpdateSessionDisplaySettings(uint width, uint height) { - RdpClient9.UpdateSessionDisplaySettings(width, height, width, height, 0, 1, 1); + RdpClient9.UpdateSessionDisplaySettings(width, height, width, height, Orientation, DesktopScaleFactor, DeviceScaleFactor); } } From d94eab71da43bfcf853e954f521b39b838cf4ac5 Mon Sep 17 00:00:00 2001 From: BlueBlock Date: Tue, 21 Mar 2023 12:58:58 -0400 Subject: [PATCH 11/13] Update RdpProtocol8.cs remove test code --- .../Connection/Protocol/RDP/RdpProtocol8.cs | 22 +++++-------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/mRemoteNG/Connection/Protocol/RDP/RdpProtocol8.cs b/mRemoteNG/Connection/Protocol/RDP/RdpProtocol8.cs index 3cab74136..a635cb2ce 100644 --- a/mRemoteNG/Connection/Protocol/RDP/RdpProtocol8.cs +++ b/mRemoteNG/Connection/Protocol/RDP/RdpProtocol8.cs @@ -93,25 +93,16 @@ namespace mRemoteNG.Connection.Protocol.RDP try { - //var q1 = Screen.FromControl(Control).Bounds.Size; - //var q2 = Control.Size; - var size = Fullscreen ? Screen.FromControl(Control).Bounds.Size : Control.Size; - //size = Screen.FromControl(Control).Bounds.Size; UpdateSessionDisplaySettings((uint)size.Width, (uint)size.Height); - - //size = Control.Size; - //UpdateSessionDisplaySettings((uint)size.Width, (uint)size.Height); - } catch (Exception ex) { Runtime.MessageCollector.AddExceptionMessage( - string.Format(Language.ChangeConnectionResolutionError, - connectionInfo.Hostname), + string.Format(Language.ChangeConnectionResolutionError, connectionInfo.Hostname), ex, MessageClass.WarningMsg, false); } } @@ -120,18 +111,15 @@ namespace mRemoteNG.Connection.Protocol.RDP { Control.Location = InterfaceControl.Location; // kmscode - this doesn't look right to me. But I'm not aware of any functionality issues with this currently... - if (!(Control.Size == InterfaceControl.Size) && !(InterfaceControl.Size == Size.Empty)) - { - Control.Size = InterfaceControl.Size; - return true; - } - - return false; + if (Control.Size == InterfaceControl.Size || InterfaceControl.Size == Size.Empty) return false; + Control.Size = InterfaceControl.Size; + return true; } protected virtual void UpdateSessionDisplaySettings(uint width, uint height) { RdpClient8.Reconnect(width, height); } + } } From 7d0cbf423e0118f3a204b26b55d750e5a9f15bcc Mon Sep 17 00:00:00 2001 From: BlueBlock Date: Tue, 21 Mar 2023 13:03:21 -0400 Subject: [PATCH 12/13] add resize fallback Add resize fallback if the target OS fails to resize using the most current method. (for example, this occurs with Server2008R2) --- mRemoteNG/Connection/Protocol/RDP/RdpProtocol9.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/mRemoteNG/Connection/Protocol/RDP/RdpProtocol9.cs b/mRemoteNG/Connection/Protocol/RDP/RdpProtocol9.cs index b9c799aa9..bf678d51a 100644 --- a/mRemoteNG/Connection/Protocol/RDP/RdpProtocol9.cs +++ b/mRemoteNG/Connection/Protocol/RDP/RdpProtocol9.cs @@ -1,4 +1,5 @@ -using System.Runtime.Versioning; +using System; +using System.Runtime.Versioning; using System.Windows.Forms; using AxMSTSCLib; using MSTSCLib; @@ -34,7 +35,15 @@ namespace mRemoteNG.Connection.Protocol.RDP protected override void UpdateSessionDisplaySettings(uint width, uint height) { - RdpClient9.UpdateSessionDisplaySettings(width, height, width, height, Orientation, DesktopScaleFactor, DeviceScaleFactor); + try + { + RdpClient9.UpdateSessionDisplaySettings(width, height, width, height, Orientation, DesktopScaleFactor, DeviceScaleFactor); + } + catch (Exception) + { + // target OS does not support newer method, fallback to an older method + base.UpdateSessionDisplaySettings(width, height); + } } } From 43c2797a51e5f4facdf9664b108e15b9b001e9e8 Mon Sep 17 00:00:00 2001 From: BlueBlock Date: Tue, 21 Mar 2023 13:56:55 -0400 Subject: [PATCH 13/13] Update ProgramRoot.cs do not show splash on taskbar --- mRemoteNG/App/ProgramRoot.cs | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/mRemoteNG/App/ProgramRoot.cs b/mRemoteNG/App/ProgramRoot.cs index d04fddcba..3b4293e0a 100644 --- a/mRemoteNG/App/ProgramRoot.cs +++ b/mRemoteNG/App/ProgramRoot.cs @@ -14,6 +14,7 @@ namespace mRemoteNG.App public static class ProgramRoot { private static Mutex _mutex; + private static FrmSplashScreenNew _frmSplashScreen = null; /// /// The main entry point for the application. @@ -33,18 +34,19 @@ namespace mRemoteNG.App System.Windows.Forms.Application.EnableVisualStyles(); System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false); - var frmSplashScreen = FrmSplashScreenNew.GetInstance(); + _frmSplashScreen = FrmSplashScreenNew.GetInstance(); var targetScreen = Screen.PrimaryScreen; Rectangle viewport = targetScreen.WorkingArea; - frmSplashScreen.Top = viewport.Top; - frmSplashScreen.Left = viewport.Left; - // normaly it should be screens[1] however due DPI apply 1 size "same" as default with 100% - frmSplashScreen.Left = viewport.Left + (targetScreen.Bounds.Size.Width / 2) - (frmSplashScreen.Width / 2); - frmSplashScreen.Top = viewport.Top + (targetScreen.Bounds.Size.Height / 2) - (frmSplashScreen.Height / 2); - - frmSplashScreen.Show(); + _frmSplashScreen.Top = viewport.Top; + _frmSplashScreen.Left = viewport.Left; + // normally it should be screens[1] however due DPI apply 1 size "same" as default with 100% + _frmSplashScreen.Left = viewport.Left + (targetScreen.Bounds.Size.Width / 2) - (_frmSplashScreen.Width / 2); + _frmSplashScreen.Top = viewport.Top + (targetScreen.Bounds.Size.Height / 2) - (_frmSplashScreen.Height / 2); + _frmSplashScreen.ShowInTaskbar = false; + _frmSplashScreen.Show(); + throw new Exception(); System.Windows.Forms.Application.Run(FrmMain.Default); } @@ -101,14 +103,13 @@ namespace mRemoteNG.App private static void ApplicationOnThreadException(object sender, ThreadExceptionEventArgs e) { - // if (PresentationSource.FromVisual(FrmSplashScreenNew)) - FrmSplashScreenNew.GetInstance().Close(); + // if (PresentationSource.FromVisual(FrmSplashScreenNew)) + FrmSplashScreenNew.GetInstance().Close(); if (FrmMain.Default.IsDisposed) return; - + var window = new FrmUnhandledException(e.Exception, false); window.ShowDialog(FrmMain.Default); - } private static void CurrentDomainOnUnhandledException(object sender, UnhandledExceptionEventArgs e)