From: misomosi Date: Mon, 18 May 2026 18:28:35 +0000 (-0400) Subject: Restart for both .NET 4.x and .NET 5.0+ X-Git-Url: http://git.misomosispi.com/?a=commitdiff_plain;h=a776c909d640e1c9848ca963fc1c20c1aae325d1;p=gists.git Restart for both .NET 4.x and .NET 5.0+ --- diff --git a/DotnetProcessRestart/.gitignore b/DotnetProcessRestart/.gitignore index ca5b692..431fe7c 100644 --- a/DotnetProcessRestart/.gitignore +++ b/DotnetProcessRestart/.gitignore @@ -5,3 +5,6 @@ obj/ bin/ lib/ + +# Test-specific ignores +restart.txt diff --git a/DotnetProcessRestart/ProcessRestart.cs b/DotnetProcessRestart/ProcessRestart.cs index 85af26a..72f7bfb 100644 --- a/DotnetProcessRestart/ProcessRestart.cs +++ b/DotnetProcessRestart/ProcessRestart.cs @@ -1,36 +1,87 @@ using System; +using System.IO; using System.Runtime.InteropServices; +using System.Text; + class RestartExample { #if NET5_0_OR_GREATER + // Simpler restart for .NET Core public static void Restart() { - System.Console.WriteLine("Core!"); - // Use ProcessStartInfo.ArgumentList to pass args + string[] args = Environment.GetCommandLineArgs(); + System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo(args[0]); + for (int i = 1; i < args.Length; i++) + psi.ArgumentList.Add(args[i]); + psi.UseShellExecute = false; + System.Diagnostics.Process.Start(psi); Environment.Exit(0); } #else - // Technically an unsafe API but we keep it private + // ArgumentList in ProcessStartInfo isn't always present before .NET 5.0 + // Restart using KERNEL32's CreateProcessW and Environment.CommandLine + // We have a lot of unsafe structs and imports, so + // keep them private and just use them for the restart + [StructLayout(LayoutKind.Sequential)] + private struct STARTUPINFOW + { + public uint cb; + public IntPtr lpReserved; // char * + public IntPtr lpDesktop; // char * + public IntPtr lpTitle; // char * + public uint dwX; + public uint dwY; + public uint dwXSize; + public uint dwYSize; + public uint dwXCountChars; + public uint dwYCountChars; + public uint dwFillAttribute; + public uint dwFlags; + public ushort uShowWindow; + public ushort cbReserved2; + public IntPtr lpReserved2; // void * + public IntPtr hStdInput; // HANDLE + public IntPtr hStdOutput; // HANDLE + public IntPtr hStdError; // HANDLE + } + [StructLayout(LayoutKind.Sequential)] + private struct PROCESS_INFORMATION + { + IntPtr hProcess; // HANDLE + IntPtr hThread; // HANDLE + uint dwProcessId; + uint dwThreadId; + } + // SECURITY_ATTRIBUTES not needed, so not defined [DllImport("KERNEL32.dll", ExactSpelling=true, SetLastError=true)] private static extern int CreateProcessW( - string lpApplicationName, - char[] lpCommandLine, - IntPtr lpProcesAttributes, - IntPtr lpThreadAttributes, + [MarshalAs(UnmanagedType.LPWStr)] string lpApplicationName, + [MarshalAs(UnmanagedType.LPWStr)] StringBuilder lpCommandLine, + IntPtr lpProcesAttributes, // SECURITY_ATTRIBUTES * + IntPtr lpThreadAttributes, // SECURITY_ATTRIBUTES * int bInheritHandles, uint dwCreationFlags, - IntPtr lpEnvironment, - string lpCurrentDirectory, - IntPtr lpStartupInfo, - IntPtr lpProcessInformation + IntPtr lpEnvironment, // void * + [MarshalAs(UnmanagedType.LPWStr)] string lpCurrentDirectory, + ref STARTUPINFOW lpStartupInfo, + out PROCESS_INFORMATION lpProcessInformation ); public static void Restart() { - Console.WriteLine("Windows!"); - char[] lpCommandLine = Environment.CommandLine.ToCharArray(); - // Use CreateProcessW with lpCommandLine to relaunch process + StringBuilder lpCommandLine = new StringBuilder(Environment.CommandLine); + STARTUPINFOW si = new STARTUPINFOW(); + PROCESS_INFORMATION pi = new PROCESS_INFORMATION(); + si.cb = (uint)Marshal.SizeOf(si); + CreateProcessW(null, lpCommandLine, IntPtr.Zero, IntPtr.Zero, 0, 0, IntPtr.Zero, null, ref si, out pi); Environment.Exit(0); } #endif public static void Main(string[] args) { - Restart(); + string fname = "restart.txt"; + if (File.Exists(fname)) { + Console.WriteLine("Restarted!"); + } else { + Console.WriteLine("Restarting!"); + File.WriteAllText(fname, ""); + Restart(); + } } }