public static void Open() { #if UNITY_STANDALONE_WIN #pragma warning disable 0618 if (realOut == null) { realOut = Console.Out; } var hasConsole = PInvoke.AttachConsole(0x0ffffffff); if (hasConsole == false) { PInvoke.AllocConsole(); } try { // grab handle ptr var outHandlePtr = PInvoke.GetStdHandle(PInvoke.STD_OUTPUT_HANDLE); // we can then create a filestream from this handle var fileStream = new FileStream(outHandlePtr, FileAccess.Write); // and then create a new stream writer (using ASCII) var stdOut = new StreamWriter(fileStream, Encoding.ASCII); stdOut.AutoFlush = true; // and force unity to use this Console.SetOut(stdOut); } catch (System.Exception e) { Debug.Log(e); } #pragma warning restore 0618 #endif }
public static void Main() { using var exitEvent = new ManualResetEvent(initialState: false); using var cts = new CancellationTokenSource(); // close console and attach to parent // if the app is started from a console the logs are shown directly in the parent console // and it is blocked until this app exits. // (Windows Application + AttachConsole does not block the parent console) if (PInvoke.AttachConsole(Constants.ATTACH_PARENT_PROCESS)) { PInvoke.FreeConsole(); } PInvoke.AttachConsole(Constants.ATTACH_PARENT_PROCESS); // handle exit events (probably overkill) PInvoke.SetConsoleCtrlHandler(new PHANDLER_ROUTINE(sig => { switch (sig) { case Constants.CTRL_C_EVENT: case Constants.CTRL_LOGOFF_EVENT: case Constants.CTRL_SHUTDOWN_EVENT: case Constants.CTRL_CLOSE_EVENT: Stop(); // wait for shutdown and cleanup exitEvent.WaitOne(TimeSpan.FromSeconds(5)); return(true); default: return(false); } }), true); AppDomain.CurrentDomain.ProcessExit += (_, __) => Stop(); Console.CancelKeyPress += (_, __) => Stop(); SetupLogging(); try { Log.Information("Starting up..."); using var mutex = new Mutex(initiallyOwned: true, SingletonMutexName, out var notAlreadyRunning); if (notAlreadyRunning) // we are the only one around :( { try { Execute(cts.Token); } finally { mutex.ReleaseMutex(); } } else // another instance is already running { Log.Information("Another instance is already running."); } } catch (Exception e) { Log.Error(e, "Unexpected error"); } Log.CloseAndFlush(); exitEvent.Set(); void Stop() { if (cts.IsCancellationRequested) { return; } Log.Information("Shutting down..."); try { cts.Cancel(); } catch (ObjectDisposedException) { // we dont care about the error as this just means that the cts wa // already canceled and disposed which we wanted to do anyway } } }