Skip to content

Commit 0789093

Browse files
committed
Feature: Scale rdp session and use UpdateSessionDisplaySettings instead of reconnect
1 parent 72ef323 commit 0789093

File tree

2 files changed

+191
-41
lines changed

2 files changed

+191
-41
lines changed

Source/NETworkManager/Controls/RemoteDesktopControl.xaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
<Grid x:Name="RdpGrid" SizeChanged="RdpGrid_SizeChanged">
2121
<WindowsFormsHost MaxWidth="{Binding RdpClientWidth, Mode=OneWay}"
2222
MaxHeight="{Binding RdpClientHeight, Mode=OneWay}"
23-
Background="{DynamicResource ResourceKey=MahApps.Brushes.Window.Background}">
23+
Background="{DynamicResource ResourceKey=MahApps.Brushes.Window.Background}"
24+
DpiChanged="WindowsFormsHost_DpiChanged">
2425
<WindowsFormsHost.Style>
2526
<Style TargetType="{x:Type WindowsFormsHost}">
2627
<Style.Triggers>
@@ -38,7 +39,7 @@
3839
</Style.Triggers>
3940
</Style>
4041
</WindowsFormsHost.Style>
41-
<mstsc:AxMsRdpClient9NotSafeForScripting x:Name="RdpClient" />
42+
<mstsc:AxMsRdpClient10NotSafeForScripting x:Name="RdpClient" />
4243
</WindowsFormsHost>
4344
<Grid VerticalAlignment="Center" HorizontalAlignment="Center" TextBlock.TextAlignment="Center"
4445
Visibility="{Binding IsConnected, Converter={StaticResource BooleanReverseToVisibilityCollapsedConverter}}">

Source/NETworkManager/Controls/RemoteDesktopControl.xaml.cs

Lines changed: 188 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,33 @@
11
// Documenation: https://docs.microsoft.com/en-us/windows/desktop/termserv/remote-desktop-web-connection-reference
22

3-
using System;
4-
using System.Threading.Tasks;
5-
using System.Windows;
6-
using System.Windows.Input;
73
using AxMSTSCLib;
4+
using log4net;
85
using MSTSCLib;
96
using NETworkManager.Localization.Resources;
107
using NETworkManager.Models.RemoteDesktop;
118
using NETworkManager.Settings;
129
using NETworkManager.Utilities;
10+
using System;
11+
using System.Diagnostics;
12+
using System.Windows;
13+
using System.Windows.Input;
14+
using System.Windows.Threading;
1315

1416
namespace NETworkManager.Controls;
1517

1618
public partial class RemoteDesktopControl : UserControlBase, IDragablzTabItem
1719
{
1820
#region Variables
21+
private static readonly ILog Log = LogManager.GetLogger(typeof(RemoteDesktopControl));
1922

2023
private bool _initialized;
2124
private bool _closed;
2225

2326
private readonly Guid _tabId;
2427
private readonly RemoteDesktopSessionInfo _sessionInfo;
2528

29+
private DispatcherTimer _adjustScreenTimer;
30+
2631
// Fix WindowsFormsHost width
2732
private double _rdpClientWidth;
2833

@@ -132,6 +137,7 @@ public RemoteDesktopControl(Guid tabId, RemoteDesktopSessionInfo sessionInfo)
132137
Dispatcher.ShutdownStarted += Dispatcher_ShutdownStarted;
133138
}
134139

140+
135141
private void UserControl_Loaded(object sender, RoutedEventArgs e)
136142
{
137143
// Connect after the control is drawn and only on the first init
@@ -201,17 +207,31 @@ private void Connect()
201207
// Display
202208
RdpClient.ColorDepth = _sessionInfo.ColorDepth; // 8, 15, 16, 24
203209

210+
double desktopWidth, desktopHeight;
211+
204212
if (_sessionInfo.AdjustScreenAutomatically || _sessionInfo.UseCurrentViewSize)
205213
{
206-
RdpClient.DesktopWidth = (int)RdpGrid.ActualWidth;
207-
RdpClient.DesktopHeight = (int)RdpGrid.ActualHeight;
214+
desktopWidth = RdpGrid.ActualWidth;
215+
desktopHeight = RdpGrid.ActualHeight;
208216
}
209217
else
210218
{
211-
RdpClient.DesktopWidth = _sessionInfo.DesktopWidth;
212-
RdpClient.DesktopHeight = _sessionInfo.DesktopHeight;
219+
desktopWidth = _sessionInfo.DesktopWidth;
220+
desktopHeight = _sessionInfo.DesktopHeight;
213221
}
214222

223+
var scaleFactor = GetDpiScaleFactor();
224+
225+
desktopWidth = desktopWidth * scaleFactor / 100;
226+
desktopHeight = desktopHeight * scaleFactor / 100;
227+
228+
RdpClient.DesktopWidth = (int)desktopWidth;
229+
RdpClient.DesktopHeight = (int)desktopHeight;
230+
231+
// Initial scaling before connecting
232+
((IMsRdpExtendedSettings)RdpClient.GetOcx()).set_Property("DesktopScaleFactor", GetDesktopScaleFactor());
233+
((IMsRdpExtendedSettings)RdpClient.GetOcx()).set_Property("DeviceScaleFactor", GetDeviceScaleFactor());
234+
215235
// Authentication
216236
RdpClient.AdvancedSettings9.AuthenticationLevel = _sessionInfo.AuthenticationLevel;
217237
RdpClient.AdvancedSettings9.EnableCredSspSupport = _sessionInfo.EnableCredSspSupport;
@@ -307,7 +327,7 @@ private void Connect()
307327
// Connect
308328
RdpClient.Connect();
309329

310-
FixWindowsFormsHostSize();
330+
FixWindowsFormsHostSize(desktopWidth, desktopHeight);
311331
}
312332

313333
private void Reconnect()
@@ -317,16 +337,30 @@ private void Reconnect()
317337

318338
IsConnecting = true;
319339

320-
// Update screen size
340+
double desktopWidth, desktopHeight;
341+
321342
if (_sessionInfo.AdjustScreenAutomatically || _sessionInfo.UseCurrentViewSize)
322343
{
323-
RdpClient.DesktopWidth = (int)RdpGrid.ActualWidth;
324-
RdpClient.DesktopHeight = (int)RdpGrid.ActualHeight;
344+
desktopWidth = RdpGrid.ActualWidth;
345+
desktopHeight = RdpGrid.ActualHeight;
346+
}
347+
else
348+
{
349+
desktopWidth = _sessionInfo.DesktopWidth;
350+
desktopHeight = _sessionInfo.DesktopHeight;
325351
}
326352

353+
var scaleFactor = GetDpiScaleFactor();
354+
355+
desktopWidth = desktopWidth * scaleFactor / 100;
356+
desktopHeight = desktopHeight * scaleFactor / 100;
357+
358+
RdpClient.DesktopWidth = (int)desktopWidth;
359+
RdpClient.DesktopHeight = (int)desktopHeight;
360+
327361
RdpClient.Connect();
328362

329-
FixWindowsFormsHostSize();
363+
FixWindowsFormsHostSize(desktopWidth, desktopHeight);
330364
}
331365

332366
public void FullScreen()
@@ -337,22 +371,83 @@ public void FullScreen()
337371
RdpClient.FullScreen = true;
338372
}
339373

340-
public void AdjustScreen()
374+
public async void AdjustScreen()
341375
{
376+
if (IsConnecting)
377+
return;
378+
342379
if (!IsConnected)
343380
return;
344381

345-
// Adjust screen size
382+
if (IsReconnecting)
383+
return;
384+
385+
IsReconnecting = true;
386+
387+
double desktopWidth, desktopHeight;
388+
346389
if (_sessionInfo.AdjustScreenAutomatically || _sessionInfo.UseCurrentViewSize)
347-
RdpClient.Reconnect((uint)RdpGrid.ActualWidth, (uint)RdpGrid.ActualHeight);
390+
{
391+
desktopWidth = RdpGrid.ActualWidth;
392+
desktopHeight = RdpGrid.ActualHeight;
393+
}
394+
else
395+
{
396+
desktopWidth = _sessionInfo.DesktopWidth;
397+
desktopHeight = _sessionInfo.DesktopHeight;
398+
}
399+
400+
var scaleFactor = GetDpiScaleFactor();
401+
402+
desktopWidth = desktopWidth * scaleFactor / 100;
403+
desktopHeight = desktopHeight * scaleFactor / 100;
348404

349-
FixWindowsFormsHostSize();
405+
try
406+
{
407+
// This may fail if the RDP session was connected recently
408+
RdpClient.UpdateSessionDisplaySettings((uint)desktopWidth, (uint)desktopHeight, (uint)desktopWidth, (uint)desktopHeight, 0, GetDesktopScaleFactor(), GetDeviceScaleFactor());
409+
}
410+
catch (Exception ex)
411+
{
412+
Log.Error("Error while adjusting screen", ex);
413+
}
414+
415+
FixWindowsFormsHostSize(desktopWidth, desktopHeight);
416+
417+
IsReconnecting = false;
350418
}
351419

352-
private void FixWindowsFormsHostSize()
420+
/// <summary>
421+
/// Adjust the screen when the size of the control changes.
422+
/// Prevent multiple calls while resizing by using a timer.
423+
/// </summary>
424+
private void AdjustScreenOnSizeChanged()
353425
{
354-
RdpClientWidth = RdpClient.DesktopWidth;
355-
RdpClientHeight = RdpClient.DesktopHeight;
426+
if (_adjustScreenTimer == null)
427+
{
428+
_adjustScreenTimer = new DispatcherTimer
429+
{
430+
Interval = TimeSpan.FromMilliseconds(250)
431+
};
432+
433+
_adjustScreenTimer.Tick += (sender, args) =>
434+
{
435+
_adjustScreenTimer.Stop();
436+
437+
AdjustScreen();
438+
};
439+
}
440+
441+
_adjustScreenTimer.Start();
442+
}
443+
444+
private void FixWindowsFormsHostSize(double width, double height)
445+
{
446+
RdpClientWidth = width;
447+
RdpClientHeight = height;
448+
449+
Debug.WriteLine($"Values: {width} x {height}");
450+
Debug.WriteLine($"RDPClient: {RdpClient.DesktopWidth} x {RdpClient.DesktopHeight}");
356451
}
357452

358453
public void SendKey(Keystroke keystroke)
@@ -487,6 +582,73 @@ private static string GetDisconnectReason(int reason)
487582
};
488583
}
489584

585+
/// <summary>
586+
/// Get the desktop scale factor based on the DPI scale factor.
587+
/// Supported values are 100, 125, 150, 175, 200.
588+
/// See docs:
589+
/// https://learn.microsoft.com/en-us/windows/win32/termserv/imsrdpextendedsettings-property --> DesktopScaleFactor
590+
/// https://cdnweb.devolutions.net/blog/pdf/smart-resizing-and-high-dpi-issues-in-remote-desktop-manager.pdf
591+
/// </summary>
592+
/// <returns></returns>
593+
protected uint GetDesktopScaleFactor()
594+
{
595+
var scaleFactor = GetDpiScaleFactor();
596+
597+
switch (scaleFactor)
598+
{
599+
case 125:
600+
return 125;
601+
case 150:
602+
case 175:
603+
return 150;
604+
case 200:
605+
return 200;
606+
}
607+
608+
if (scaleFactor > 200)
609+
return 200;
610+
611+
return 100;
612+
}
613+
614+
/// <summary>
615+
/// Get the device scale factor based on the DPI scale factor.
616+
/// Supported values are 100, 140, 180.
617+
/// See docs:
618+
/// https://learn.microsoft.com/en-us/windows/win32/termserv/imsrdpextendedsettings-property --> DeviceScaleFactor
619+
/// https://cdnweb.devolutions.net/blog/pdf/smart-resizing-and-high-dpi-issues-in-remote-desktop-manager.pdf
620+
/// </summary>
621+
/// <returns>Device scale factor.</returns>
622+
protected uint GetDeviceScaleFactor()
623+
{
624+
var scaleFactor = GetDpiScaleFactor();
625+
626+
switch (scaleFactor)
627+
{
628+
case 125:
629+
case 150:
630+
case 175:
631+
return 140;
632+
case 200:
633+
return 180;
634+
}
635+
636+
if (scaleFactor > 200)
637+
return 180;
638+
639+
return 100;
640+
}
641+
642+
/// <summary>
643+
/// Get the current DPI scale factor like 100, 125, 150, 175, 200, 225, etc.
644+
/// </summary>
645+
/// <returns>Returns the DPI scale factor.</returns>
646+
public uint GetDpiScaleFactor()
647+
{
648+
var x = System.Windows.Media.VisualTreeHelper.GetDpi(this);
649+
650+
return (uint)(x.PixelsPerDip * 100);
651+
}
490652
#endregion
491653

492654
#region Events
@@ -508,26 +670,13 @@ private void RdpClient_OnDisconnected(object sender, IMsTscAxEvents_OnDisconnect
508670
private void RdpGrid_SizeChanged(object sender, SizeChangedEventArgs e)
509671
{
510672
// Resize the RDP screen size when the window size changes
511-
if (IsConnected && _sessionInfo.AdjustScreenAutomatically && !IsReconnecting)
512-
ReconnectOnSizeChanged().ConfigureAwait(false);
673+
if (_sessionInfo.AdjustScreenAutomatically)
674+
AdjustScreenOnSizeChanged();
513675
}
676+
#endregion
514677

515-
private async Task ReconnectOnSizeChanged()
678+
private void WindowsFormsHost_DpiChanged(object sender, DpiChangedEventArgs e)
516679
{
517-
IsReconnecting = true;
518-
519-
do // Prevent to many requests
520-
{
521-
await Task.Delay(250);
522-
} while (Mouse.LeftButton == MouseButtonState.Pressed);
523-
524-
// Reconnect with the new screen size
525-
RdpClient.Reconnect((uint)RdpGrid.ActualWidth, (uint)RdpGrid.ActualHeight);
526-
527-
FixWindowsFormsHostSize();
528-
529-
IsReconnecting = false;
680+
AdjustScreen();
530681
}
531-
532-
#endregion
533-
}
682+
}

0 commit comments

Comments
 (0)