11using System ;
2+ using System . Collections . Generic ;
23using System . Diagnostics ;
34using System . IO ;
5+ using System . Linq ;
46using System . Reflection ;
57using System . Runtime . InteropServices ;
68using FileLockedBy . Enums ;
@@ -14,72 +16,119 @@ namespace FileLockedBy
1416{
1517 class Program
1618 {
19+ private static bool SuppressUserInput = false ;
20+
1721 static void Main ( string [ ] args )
1822 {
1923 Console . Title = "Unlocker" ;
2024 Process currentProcess = Process . GetCurrentProcess ( ) ;
21- string fullPath = currentProcess . MainModule . FileName ;
22- string fileName = Path . GetFileName ( currentProcess . MainModule . FileName ) ;
25+ string fullPath = currentProcess . MainModule . FileName ;
26+ string fileName = Path . GetFileName ( currentProcess . MainModule . FileName ) ;
2327
24- bool suppressUserInput = false ;
2528 if ( args . Length == 2 )
2629 {
27- suppressUserInput = args [ 1 ] . ToLowerInvariant ( ) == "-s" ;
30+ SuppressUserInput = args [ 1 ] . ToLowerInvariant ( ) == "-s" ;
2831 }
2932 else if ( args . Length != 1 )
3033 {
31- Console . WriteLine ( $ "Usage: { fileName } <file_to_unlock> [-s] - unlocks the file") ;
34+ Console . WriteLine ( $ "Usage: { fileName } <file_to_unlock> [-s] - unlocks the file/directory ") ;
3235 Console . WriteLine ( $ "Usage: { fileName } register [-s] - integrate into Explorer") ;
3336 Console . WriteLine ( $ "Usage: { fileName } unregister [-s] - unintegrate from Explorer") ;
3437 Console . WriteLine ( $ "-s { new string ( ' ' , fileName . Length + 22 ) } - Optional parameter. Suppress user input") ;
3538 return ;
3639 }
3740
41+ AppDomain . CurrentDomain . UnhandledException += CurrentDomainOnUnhandledException ;
42+
3843 if ( args [ 0 ] . ToLowerInvariant ( ) == "register" )
3944 {
4045 ExplorerIntegration . RegisterMenuItem ( "Unlocker" , fullPath ) ;
4146 Console . WriteLine ( "Registered." ) ;
42- if ( ! suppressUserInput ) Console . ReadKey ( ) ;
47+ if ( ! SuppressUserInput ) Console . ReadKey ( ) ;
4348 return ;
4449 }
4550
4651 if ( args [ 0 ] . ToLowerInvariant ( ) == "unregister" )
4752 {
4853 ExplorerIntegration . UnregisterMenuItem ( "Unlocker" ) ;
4954 Console . WriteLine ( "Unregistered." ) ;
50- if ( ! suppressUserInput ) Console . ReadKey ( ) ;
55+ if ( ! SuppressUserInput ) Console . ReadKey ( ) ;
5156 return ;
5257 }
5358
59+ bool found ;
5460 Console . WriteLine ( "Unlocking begin..." ) ;
55- bool found = false ;
5661 string path = args [ 0 ] ;
57- var processes = Unlocker . FindLockerProcesses ( path ) ;
62+ if ( File . GetAttributes ( path ) . HasFlag ( FileAttributes . Directory ) )
63+ {
64+ if ( ! Path . EndsInDirectorySeparator ( path ) )
65+ {
66+ path += Path . DirectorySeparatorChar ;
67+ }
68+
69+ string [ ] files = Directory . GetFiles ( path , "*" , SearchOption . AllDirectories ) ;
70+ found = UnlockFiles ( files , currentProcess ) ;
71+ }
72+ else
73+ {
74+ found = UnlockFile ( path , currentProcess ) ;
75+ }
76+
77+ if ( ! found ) Console . WriteLine ( "Nothing found. Can't unlock or the file/directory is already unlocked." ) ;
78+ Console . WriteLine ( "End." ) ;
79+ if ( ! SuppressUserInput ) Console . ReadKey ( ) ;
80+ }
81+
82+ private static bool UnlockFile ( string file , Process currentProcess )
83+ {
84+ return UnlockFiles ( new [ ] { file } , currentProcess ) ;
85+ }
86+
87+ private static bool UnlockFiles ( string [ ] files , Process currentProcess )
88+ {
89+ bool found = false ;
90+ var processes = Unlocker . FindLockerProcesses ( files ) ;
91+
5892 foreach ( RM_PROCESS_INFO info in processes )
5993 {
6094 Console . WriteLine ( $ "Closing handle locked by { info . strAppName } ...") ;
6195 using ( SmartPtr sptr = SystemInformation . GetSystemHandleInformation ( ) )
6296 {
63- var information = ( SystemHandlesInformation ) Marshal . PtrToStructure ( sptr . Pointer , typeof ( SystemHandlesInformation ) ) ;
97+ var information = ( SystemHandlesInformation ) Marshal . PtrToStructure ( sptr . Pointer , typeof ( SystemHandlesInformation ) ) ;
6498 int handleCount = information . Count ;
6599 var process = Process . GetProcessById ( info . Process . dwProcessId ) ;
66100 var infoEnumerator = ProcessHelper . GetCurrentProcessOpenFilesEnumerator ( info . Process . dwProcessId , sptr , handleCount ) ;
67- bool skip = false ;
68- while ( infoEnumerator . MoveNext ( ) && ! skip )
101+ Dictionary < string , bool > skip = new Dictionary < string , bool > ( ) ;
102+ while ( infoEnumerator . MoveNext ( ) )
69103 {
70104 FileHandleInfo current = infoEnumerator . Current ;
71- if ( string . Compare ( path , current . FileSystemInfo . FullName , StringComparison . OrdinalIgnoreCase ) != 0 ) continue ;
72- Console . WriteLine ( $ "Found! { process . ProcessName } -> { process . MainModule . FileName } ") ;
73- found = true ;
74- skip = true ;
105+ skip . TryGetValue ( current . FileSystemInfo . FullName , out bool skipped ) ;
106+ if ( skipped
107+ || files . All ( file => string . Compare ( file , current . FileSystemInfo . FullName , StringComparison . OrdinalIgnoreCase ) != 0 ) )
108+ {
109+ continue ;
110+ }
111+
112+ Console . WriteLine (
113+ $ "Found locked file { current . FileSystemInfo . FullName } ! { process . ProcessName } -> { process . MainModule . FileName } ") ;
114+ found = true ;
115+ skip [ current . FileSystemInfo . FullName ] = true ;
75116 var result = ProcessHelper . CloseHandle ( process , current , currentProcess ) ;
76117 Console . WriteLine ( result == 0 ? "Success." : $ "Error: { Enum . GetName ( typeof ( Error ) , result ) } ") ;
77118 }
78119 }
79120 }
80- if ( ! found ) Console . WriteLine ( "Nothing found. Can't unlock or the file is already unlocked." ) ;
81- Console . WriteLine ( "End." ) ;
82- if ( ! suppressUserInput ) Console . ReadKey ( ) ;
121+
122+ return found ;
123+ }
124+
125+ private static void CurrentDomainOnUnhandledException ( object sender , UnhandledExceptionEventArgs e )
126+ {
127+ if ( e . IsTerminating && ! SuppressUserInput )
128+ {
129+ Console . WriteLine ( e . ExceptionObject . ToString ( ) ) ;
130+ Console . ReadKey ( ) ;
131+ }
83132 }
84133 }
85- }
134+ }
0 commit comments