33using CollapseLauncher . Helper . Database ;
44using CollapseLauncher . Helper . Update ;
55using Hi3Helper ;
6+ using Hi3Helper . Data ;
67using Hi3Helper . EncTool ;
78using Hi3Helper . EncTool . Hashes ;
89using Hi3Helper . Http . Legacy ;
1920using PhotoSauce . NativeCodecs . Libjxl ;
2021using PhotoSauce . NativeCodecs . Libwebp ;
2122using System ;
23+ using System . Buffers ;
2224using System . Diagnostics ;
2325using System . Globalization ;
2426using System . IO ;
@@ -58,7 +60,8 @@ public static void Main(params string[] args)
5860 {
5961 try
6062 {
61- AppCurrentArgument = args . ToList ( ) ;
63+ args = KillParentPidIfRestartRequested ( args ) ;
64+ AppCurrentArgument = [ .. args ] ;
6265#if PREVIEW
6366 IsPreview = true ;
6467#endif
@@ -116,7 +119,6 @@ public static void Main(params string[] args)
116119 // Reason: These are methods that either has its own error handling and/or not that important,
117120 // so the execution could continue without anything to worry about **technically**
118121 CheckRuntimeFeatures ( ) ;
119- AppDomain . CurrentDomain . ProcessExit += OnProcessExit ;
120122
121123 Console . WriteLine ( Directory . GetCurrentDirectory ( ) ) ;
122124 Application . Start ( _ =>
@@ -419,22 +421,7 @@ public static void SpawnFatalErrorConsole(Exception ex)
419421
420422 if ( ConsoleKey . R == Console . ReadKey ( ) . Key )
421423 {
422- ProcessStartInfo startInfo = new ( )
423- {
424- FileName = AppExecutablePath ,
425- UseShellExecute = false
426- } ;
427-
428- foreach ( string arg in AppCurrentArgument )
429- {
430- startInfo . ArgumentList . Add ( arg ) ;
431- }
432-
433- Process process = new ( )
434- {
435- StartInfo = startInfo
436- } ;
437- process . Start ( ) ;
424+ ForceRestart ( ) ;
438425 }
439426
440427 tokenSource . Cancel ( ) ;
@@ -603,14 +590,6 @@ private static void HttpClientLogWatcher(object sender, DownloadLogEvent e)
603590 LogWriteLine ( e . Message , severity , true ) ;
604591 }
605592
606- private static void OnProcessExit ( object ? sender , EventArgs e )
607- {
608- // TODO: #671 This App.IsAppKilled will be replaced with cancellable-awaitable event
609- // to ensure no hot-exit being called before all background tasks
610- // hasn't being cancelled.
611- // App.IsAppKilled = true;
612- }
613-
614593 private static void CheckRuntimeFeatures ( )
615594 {
616595 try
@@ -664,19 +643,15 @@ private static void InitLocale()
664643
665644 private static void RunElevateUpdate ( )
666645 {
667- Process elevatedProc = new Process
646+ Process ? elevatedProc = Process . Start ( new ProcessStartInfo
668647 {
669- StartInfo = new ProcessStartInfo
670- {
671- FileName = UpdaterWindow . SourcePath ,
672- WorkingDirectory = UpdaterWindow . WorkingDir ,
673- Arguments =
674- $ "update --input \" { m_arguments . Updater . AppPath } \" --channel { m_arguments . Updater . UpdateChannel } ",
675- UseShellExecute = true ,
676- Verb = "runas"
677- }
678- } ;
679- elevatedProc . Start ( ) ;
648+ FileName = UpdaterWindow . SourcePath ,
649+ WorkingDirectory = UpdaterWindow . WorkingDir ,
650+ Arguments = $ "update --input \" { m_arguments . Updater . AppPath } \" --channel { m_arguments . Updater . UpdateChannel } ",
651+ UseShellExecute = true ,
652+ Verb = "runas"
653+ } ) ;
654+ elevatedProc ? . Start ( ) ;
680655 }
681656
682657 public static string GetVersionString ( )
@@ -693,24 +668,70 @@ public static string MD5Hash(string path)
693668 return "" ;
694669 }
695670
696- FileStream stream = File . OpenRead ( path ) ;
697- byte [ ] hash = CryptoHashUtility < MD5 > . Shared . GetHashFromStream ( stream ) ;
698- stream . Close ( ) ;
671+ using FileStream stream = File . OpenRead ( path ) ;
672+ byte [ ] hash = CryptoHashUtility < MD5 > . Shared . GetHashFromStream ( stream ) ;
699673 return Convert . ToHexStringLower ( hash ) ;
700674 }
701675
676+ private static string restartedFromPidArgKey = "restartedFromPid" ;
677+
702678 public static void ForceRestart ( )
703679 {
704680 // Workaround to artificially start new process and wait for the current one to be killed.
705- var cmdProc = Process . Start ( new ProcessStartInfo
681+ using Process ? cmdProc = Process . Start ( new ProcessStartInfo
706682 {
707- FileName = "cmd.exe" ,
708- Arguments = $ "/c timeout /T 1 && start \" \" \" { AppExecutablePath } \" ",
709- UseShellExecute = true ,
683+ FileName = AppExecutablePath ,
684+ WorkingDirectory = Environment . CurrentDirectory ,
685+ Arguments = $ "{ restartedFromPidArgKey } :{ Environment . ProcessId } { string . Join ( ' ' , AppCurrentArgument ) } ",
686+ UseShellExecute = true
710687 } ) ;
711688
712- cmdProc ? . WaitForExit ( ) ;
713689 Application . Current . Exit ( ) ;
714690 }
691+
692+ private static string [ ] KillParentPidIfRestartRequested ( params string [ ] args )
693+ {
694+ if ( args . Length == 0 )
695+ {
696+ return args ;
697+ }
698+
699+ int indexOfArg = - 1 ;
700+ string [ ] restArgs = args . Length == 1 ? [ ] : new string [ args . Length - 1 ] ;
701+
702+ // Copy other args and find restart arg
703+ for ( int i = 0 ; i < args . Length ; i ++ )
704+ {
705+ string currentArg = args [ i ] ;
706+ if ( currentArg . StartsWith ( restartedFromPidArgKey , StringComparison . OrdinalIgnoreCase ) )
707+ {
708+ indexOfArg = i ;
709+ continue ;
710+ }
711+ restArgs [ i < indexOfArg ? i : i - 1 ] = currentArg ;
712+ }
713+
714+ if ( indexOfArg < 0 )
715+ {
716+ return args ;
717+ }
718+
719+ ReadOnlySpan < char > restartParentPidArg = args [ indexOfArg ] ;
720+ ReadOnlySpan < char > restartParentPid = ConverterTool . GetSplit ( restartParentPidArg , 1 , ":,#$;" ) ;
721+
722+ // Check for PID. If exist, then kill.
723+ if ( ! int . TryParse ( restartParentPid , out int parentPid ) ||
724+ ! ProcessChecker . IsProcessExist ( parentPid ) )
725+ {
726+ return restArgs ;
727+ }
728+
729+ Console . WriteLine ( $ "Waiting to kill parent process: { parentPid } ") ;
730+ using Process parentProcess = Process . GetProcessById ( parentPid ) ;
731+ parentProcess . Kill ( ) ;
732+ parentProcess . WaitForExit ( ) ;
733+
734+ return restArgs ;
735+ }
715736 }
716737}
0 commit comments