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();
+ }
}
}