11using System ;
22using System . Collections . Generic ;
3+ using System . ComponentModel ;
34using System . Diagnostics ;
45using System . Drawing ;
56using System . IO ;
7+ using System . Linq ;
8+ using System . Security . Principal ;
9+ using System . Text ;
610using System . Threading ;
711using System . Windows . Forms ;
812
913namespace TopMostFriend {
1014 public static class Program {
1115 private static NotifyIcon SysIcon ;
1216 private static HotKeyWindow HotKeys ;
13- private static readonly Process OwnProcess = Process . GetCurrentProcess ( ) ;
1417 private static int InitialItems = 0 ;
1518
1619 private const string GUID =
@@ -30,21 +33,38 @@ public static class Program {
3033 public const string SHOW_EXPLORER_SETTING = @"ShowExplorerMisc" ;
3134 public const string LIST_BACKGROUND_PATH_SETTING = @"ListBackgroundPath" ;
3235 public const string LIST_BACKGROUND_LAYOUT_SETTING = @"ListBackgroundLayout" ;
36+ public const string ALWAYS_ADMIN_SETTING = @"RunAsAdministrator" ;
3337
3438 [ STAThread ]
35- public static void Main ( ) {
39+ public static void Main ( string [ ] args ) {
3640 if ( Environment . OSVersion . Version . Major >= 6 )
3741 Win32 . SetProcessDPIAware ( ) ;
3842
3943 Application . EnableVisualStyles ( ) ;
4044 Application . SetCompatibleTextRenderingDefault ( false ) ;
4145
46+ if ( args . Contains ( @"--reset-admin" ) )
47+ Settings . Remove ( ALWAYS_ADMIN_SETTING ) ;
48+
49+ string cliToggle = args . FirstOrDefault ( x => x . StartsWith ( @"--hwnd=" ) ) ;
50+ if ( ! string . IsNullOrEmpty ( cliToggle ) && int . TryParse ( cliToggle . Substring ( 7 ) , out int cliToggleHWnd ) )
51+ ToggleWindow ( new IntPtr ( cliToggleHWnd ) ) ;
52+
53+ if ( args . Contains ( @"--stop" ) )
54+ return ;
55+
4256 if ( ! GlobalMutex . WaitOne ( 0 , true ) ) {
4357 MessageBox . Show ( @"An instance of Top Most Friend is already running." , @"Top Most Friend" ) ;
4458 return ;
4559 }
4660
47- Settings . SetDefault ( FOREGROUND_HOTKEY_SETTING , ( ( int ) Keys . F << 16 ) | ( int ) ( Win32ModKeys . MOD_CONTROL | Win32ModKeys . MOD_ALT ) ) ;
61+ Settings . SetDefault ( FOREGROUND_HOTKEY_SETTING , 0 ) ;
62+ Settings . SetDefault ( ALWAYS_ADMIN_SETTING , false ) ;
63+
64+ if ( Settings . Get < bool > ( ALWAYS_ADMIN_SETTING ) && ! IsElevated ( ) ) {
65+ Elevate ( ) ;
66+ return ;
67+ }
4868
4969 string backgroundPath = Settings . Get ( LIST_BACKGROUND_PATH_SETTING , string . Empty ) ;
5070 Image backgroundImage = null ;
@@ -76,26 +96,67 @@ public static void Main() {
7696 InitialItems = SysIcon . ContextMenuStrip . Items . Count ;
7797
7898 HotKeys = new HotKeyWindow ( ) ;
79- SetForegroundHotKey ( Settings . Get < int > ( FOREGROUND_HOTKEY_SETTING ) ) ;
99+
100+ try {
101+ SetForegroundHotKey ( Settings . Get < int > ( FOREGROUND_HOTKEY_SETTING ) ) ;
102+ } catch ( Win32Exception ex ) {
103+ Console . WriteLine ( @"Hotkey registration failed:" ) ;
104+ Console . WriteLine ( ex ) ;
105+ }
80106
81107 Application . Run ( ) ;
82108
83- HotKeys . Dispose ( ) ;
84- SysIcon . Dispose ( ) ;
109+ Shutdown ( ) ;
110+ }
85111
112+ public static void Shutdown ( ) {
113+ HotKeys ? . Dispose ( ) ;
114+ SysIcon ? . Dispose ( ) ;
86115 GlobalMutex . ReleaseMutex ( ) ;
87116 }
88117
118+ private static bool ? IsElevatedValue ;
119+
120+ public static bool IsElevated ( ) {
121+ if ( ! IsElevatedValue . HasValue ) {
122+ using ( WindowsIdentity identity = WindowsIdentity . GetCurrent ( ) )
123+ IsElevatedValue = identity != null && new WindowsPrincipal ( identity ) . IsInRole ( WindowsBuiltInRole . Administrator ) ;
124+ }
125+
126+ return IsElevatedValue . Value ;
127+ }
128+
129+ public static void Elevate ( string args = null ) {
130+ if ( IsElevated ( ) )
131+ return ;
132+
133+ Shutdown ( ) ;
134+
135+ Process . Start ( new ProcessStartInfo {
136+ UseShellExecute = true ,
137+ FileName = Application . ExecutablePath ,
138+ WorkingDirectory = Environment . CurrentDirectory ,
139+ Arguments = args ?? string . Empty ,
140+ Verb = @"runas" ,
141+ } ) ;
142+ Application . Exit ( ) ;
143+ }
144+
89145 public static void SetForegroundHotKey ( int keyCode ) {
90146 SetForegroundHotKey ( ( Win32ModKeys ) ( keyCode & 0xFFFF ) , ( Keys ) ( ( keyCode & 0xFFFF0000 ) >> 16 ) ) ;
91147 }
92148
93149 public static void SetForegroundHotKey ( Win32ModKeys mods , Keys key ) {
94- Settings . Set ( FOREGROUND_HOTKEY_SETTING , ( ( int ) key << 16 ) | ( int ) mods ) ;
95- HotKeys . Unregister ( FOREGROUND_HOTKEY_ATOM ) ;
96-
97- if ( mods != 0 && key != 0 )
98- HotKeys . Register ( FOREGROUND_HOTKEY_ATOM , mods , key , ToggleForegroundWindow ) ;
150+ try {
151+ Settings . Set ( FOREGROUND_HOTKEY_SETTING , ( ( int ) key << 16 ) | ( int ) mods ) ;
152+ HotKeys . Unregister ( FOREGROUND_HOTKEY_ATOM ) ;
153+
154+ if ( mods != 0 && key != 0 )
155+ HotKeys . Register ( FOREGROUND_HOTKEY_ATOM , mods , key , ToggleForegroundWindow ) ;
156+ } catch ( Win32Exception ex ) {
157+ Debug . WriteLine ( @"Hotkey registration failed:" ) ;
158+ Debug . WriteLine ( ex ) ;
159+ }
99160 }
100161
101162 private static void RefreshWindowList ( ) {
@@ -150,12 +211,32 @@ public static void SetTopMost(IntPtr hWnd, bool state) {
150211 0 , 0 , 0 , 0 , Win32 . SWP_NOMOVE | Win32 . SWP_NOSIZE | Win32 . SWP_SHOWWINDOW
151212 ) ;
152213
214+ if ( IsTopMost ( hWnd ) != state ) {
215+ MessageBoxButtons buttons = MessageBoxButtons . OK ;
216+ StringBuilder sb = new StringBuilder ( ) ;
217+ sb . AppendLine ( @"Wasn't able to change topmost status on this window." ) ;
218+
219+ if ( ! IsElevated ( ) ) {
220+ sb . AppendLine ( @"Do you want to restart Top Most Friend as administrator and try again?" ) ;
221+ buttons = MessageBoxButtons . YesNo ;
222+ }
223+
224+ DialogResult result = MessageBox . Show ( sb . ToString ( ) , @"Top Most Friend" , buttons , MessageBoxIcon . Error ) ;
225+
226+ if ( result == DialogResult . Yes )
227+ Elevate ( $@ "--hwnd={ hWnd } ") ;
228+ return ;
229+ }
230+
153231 if ( state )
154232 Win32 . SwitchToThisWindow ( hWnd , false ) ;
155233 }
156234
157235 public static void ToggleForegroundWindow ( ) {
158- IntPtr hWnd = Win32 . GetForegroundWindow ( ) ;
236+ ToggleWindow ( Win32 . GetForegroundWindow ( ) ) ;
237+ }
238+
239+ public static void ToggleWindow ( IntPtr hWnd ) {
159240 SetTopMost ( hWnd , ! IsTopMost ( hWnd ) ) ;
160241 }
161242
@@ -182,9 +263,10 @@ private static Icon GetWindowIcon(IntPtr hWnd) {
182263
183264 private static IEnumerable < WindowEntry > GetWindowList ( ) {
184265 Process [ ] procs = Process . GetProcesses ( ) ;
266+ Process self = Process . GetCurrentProcess ( ) ;
185267
186268 foreach ( Process proc in procs ) {
187- if ( ! Settings . Get ( LIST_SELF_SETTING , Debugger . IsAttached ) && proc . Id == OwnProcess . Id )
269+ if ( ! Settings . Get ( LIST_SELF_SETTING , Debugger . IsAttached ) && proc == self )
188270 continue ;
189271
190272 IEnumerable < IntPtr > hwnds = proc . GetWindowHandles ( ) ;
0 commit comments