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 ;
73using AxMSTSCLib ;
4+ using log4net ;
85using MSTSCLib ;
96using NETworkManager . Localization . Resources ;
107using NETworkManager . Models . RemoteDesktop ;
118using NETworkManager . Settings ;
129using NETworkManager . Utilities ;
10+ using System ;
11+ using System . Diagnostics ;
12+ using System . Windows ;
13+ using System . Windows . Input ;
14+ using System . Windows . Threading ;
1315
1416namespace NETworkManager . Controls ;
1517
1618public 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