1- using System . Numerics ;
1+ using System . Diagnostics ;
2+ using System . Numerics ;
23using System . Reflection ;
34using System . Runtime . InteropServices ;
5+ using System . Security . Principal ;
46using Windows . Data . Xml . Dom ;
57using Windows . UI . Composition ;
68using Windows . UI . Composition . Desktop ;
1618using Avalonia . Media . Imaging ;
1719using Avalonia . Platform ;
1820using Avalonia . Threading ;
21+ using Everywhere . Extensions ;
1922using Everywhere . Interfaces ;
2023using Everywhere . Windows . Interop ;
2124using MicroCom . Runtime ;
@@ -27,13 +30,111 @@ namespace Everywhere.Windows.Services;
2730
2831public class Win32NativeHelper : INativeHelper
2932{
33+ private const string AppName = nameof ( Everywhere ) ;
34+ private const string RegistryRunKey = @"Software\Microsoft\Windows\CurrentVersion\Run" ;
35+ private static string AppPath => $ "\" { Environment . ProcessPath } \" --autorun";
36+
3037 // ReSharper disable InconsistentNaming
3138 // ReSharper disable IdentifierTypo
3239 private const uint EVENT_SYSTEM_FOREGROUND = 0x0003 ;
3340 private const uint WINEVENT_OUTOFCONTEXT = 0x0000 ;
3441 // ReSharper restore InconsistentNaming
3542 // ReSharper restore IdentifierTypo
3643
44+ public bool IsAdministrator
45+ {
46+ get
47+ {
48+ var identity = WindowsIdentity . GetCurrent ( ) ;
49+ var principal = new WindowsPrincipal ( identity ) ;
50+ return principal . IsInRole ( WindowsBuiltInRole . Administrator ) ;
51+ }
52+ }
53+
54+ public bool IsUserStartupEnabled
55+ {
56+ get
57+ {
58+ try
59+ {
60+ using var key = Registry . CurrentUser . OpenSubKey ( RegistryRunKey ) ;
61+ return key ? . GetValue ( AppName ) != null ;
62+ }
63+ catch
64+ {
65+ // If the registry key cannot be accessed, assume it is not enabled.
66+ return false ;
67+ }
68+ }
69+ set
70+ {
71+ if ( value )
72+ {
73+ using var key = Registry . CurrentUser . OpenSubKey ( RegistryRunKey , true ) ;
74+ key ? . SetValue ( AppName , AppPath ) ;
75+ }
76+ else
77+ {
78+ using var key = Registry . CurrentUser . OpenSubKey ( RegistryRunKey , true ) ;
79+ key ? . DeleteValue ( AppName , false ) ;
80+ }
81+ }
82+ }
83+
84+ public bool IsAdministratorStartupEnabled
85+ {
86+ get
87+ {
88+ try
89+ {
90+ return TaskSchedulerHelper . IsTaskScheduled ( AppName ) ;
91+ }
92+ catch
93+ {
94+ return false ;
95+ }
96+ }
97+ set
98+ {
99+ if ( ! IsAdministrator ) throw new UnauthorizedAccessException ( "The current user is not an administrator." ) ;
100+
101+ if ( value )
102+ {
103+ TaskSchedulerHelper . CreateScheduledTask ( AppName , AppPath ) ;
104+ }
105+ else
106+ {
107+ TaskSchedulerHelper . DeleteScheduledTask ( AppName ) ;
108+ }
109+ }
110+ }
111+
112+ public void RestartAsAdministrator ( )
113+ {
114+ if ( IsAdministrator )
115+ {
116+ throw new InvalidOperationException ( "The application is already running as an administrator." ) ;
117+ }
118+
119+ var startInfo = new ProcessStartInfo
120+ {
121+ FileName = Environment . ProcessPath . NotNull ( ) ,
122+ Arguments = "--autorun" ,
123+ UseShellExecute = true ,
124+ Verb = "runas" // This will prompt for elevation
125+ } ;
126+
127+ try
128+ {
129+ Process . Start ( startInfo ) ;
130+ Environment . Exit ( 0 ) ; // Exit the current process
131+ }
132+ catch ( Exception ex )
133+ {
134+ throw new InvalidOperationException ( "Failed to restart as administrator." , ex ) ;
135+ }
136+ }
137+
37138 public void SetWindowNoFocus ( Window window )
38139 {
39140 Win32Properties . AddWindowStylesCallback ( window , WindowStylesCallback ) ;
@@ -129,6 +230,7 @@ void WinEventProc(
129230 public void SetWindowHitTestInvisible ( Window window )
130231 {
131232 Win32Properties . AddWindowStylesCallback ( window , WindowStylesCallback ) ;
233+
132234 static ( uint style , uint exStyle ) WindowStylesCallback ( uint style , uint exStyle )
133235 {
134236 return ( style , exStyle |
@@ -166,8 +268,10 @@ public void SetWindowCornerRadius(Window window, CornerRadius cornerRadius)
166268 if ( ! _compositionContexts . TryGetValue ( hWnd , out var compositionContext ) )
167269 {
168270 // we will need lots of hacks, let's go
169- if ( window . PlatformImpl ? . GetType ( ) . GetField ( "_glSurface" , BindingFlags . Instance | BindingFlags . NonPublic ) is not { } glSurfaceField ) return ;
170- if ( glSurfaceField . GetValue ( window . PlatformImpl ) is not { } glSurface ) return ; // Avalonia.Win32.WinRT.Composition.WinUiCompositedWindowSurface
271+ if ( window . PlatformImpl ? . GetType ( ) . GetField ( "_glSurface" , BindingFlags . Instance | BindingFlags . NonPublic ) is not
272+ { } glSurfaceField ) return ;
273+ if ( glSurfaceField . GetValue ( window . PlatformImpl ) is not { } glSurface )
274+ return ; // Avalonia.Win32.WinRT.Composition.WinUiCompositedWindowSurface
171275 if ( glSurface . GetType ( ) . GetField ( "_window" , BindingFlags . Instance | BindingFlags . NonPublic ) is not { } windowField ) return ;
172276 if ( windowField . GetValue ( glSurface ) is not { } compositedWindow ) return ; // Avalonia.Win32.WinRT.Composition.WinUiCompositedWindow
173277 if ( glSurface . GetType ( ) . GetField ( "_shared" , BindingFlags . Instance | BindingFlags . NonPublic ) is not { } sharedField ) return ;
@@ -377,4 +481,4 @@ private record CompositionContext(Compositor Compositor, Visual RootVisual)
377481 {
378482 public CompositionClip ? Clip { get ; set ; }
379483 }
380- }
484+ }
0 commit comments