title: C# WPF Console Manager Debug Assert Crash
body: <p>I am in an interesting predicament with a current project I am working on in dotNet. Currently, my project is a WPF application that configures settings for a console application, then launches the main function of the app (an infinitely looping API Hook that updates objects on a map). Previously, I have been using a solution I found at <a href="https://stackoverflow.com/questions/160587/no-output-to-console-from-a-wpf-application">No output to console from a WPF application?</a>, and the ConsoleManager class that was offered as a solution worked well. I've recently run into the issue where the solution has since stopped working, always failing in both Debug or Release builds at <code>Debug.Assert(_out!=NULL)</code>, spitting out the following error message to me.</p>
  <pre><code>Process terminated. Assertion failed.
     at CT_API_GUI.ConsoleManager.InvalidateOutAndError() in C:\Users\pixel\RiderProjects\AFMChronotrackAPI\ConsoleManager.cs:line 82
     at CT_API_GUI.ConsoleManager.Show() in C:\Users\pixel\RiderProjects\AFMChronotrackAPI\ConsoleManager.cs:line 38
     at CT_API_GUI.WinApi.Main() in C:\Users\pixel\RiderProjects\AFMChronotrackAPI\WinApi.cs:line 53
     at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine&amp; stateMachine)
     at CT_API_GUI.WinApi.Main()
     at CT_API_GUI.MainWindow.Run_OnClick(Object sender, RoutedEventArgs e) in C:\Users\pixel\RiderProjects\AFMChronotrackAPI\MainWindow.xaml.cs:line 41
     at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
     at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
     at System.Windows.Controls.Primitives.ButtonBase.OnClick()
     at System.Windows.Controls.Button.OnClick()
     at System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(MouseButtonEventArgs e)
     at System.Windows.UIElement.OnMouseLeftButtonUpThunk(Object sender, MouseButtonEventArgs e)
     at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
     at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
     at System.Windows.UIElement.ReRaiseEventAs(DependencyObject sender, RoutedEventArgs args, RoutedEvent newEvent)
     at System.Windows.UIElement.OnMouseUpThunk(Object sender, MouseButtonEventArgs e)
     at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
     at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
     at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
     at System.Windows.UIElement.RaiseTrustedEvent(RoutedEventArgs args)
     at System.Windows.Input.InputManager.ProcessStagingArea()
     at System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport)
     at System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawMouseActions actions, Int32 x, Int32 y, Int32 wheel)
     at System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr hwnd, WindowMessage msg, IntPtr wParam, IntPtr lParam, Boolean&amp; handled)
     at System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean&amp; handled)
     at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean&amp; handled)
     at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
     at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
     at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
     at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
     at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
     at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG&amp; msg)
     at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG&amp; msg)
     at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
     at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
     at System.Windows.Threading.Dispatcher.Run()
     at System.Windows.Application.RunDispatcher(Object ignore)
     at System.Windows.Application.RunInternal(Window window)
     at System.Windows.Application.Run()
     at CT_API_GUI.App.Main()
  </code></pre>
  <p>Where line 82 of ConsoleManager is <code>Debug.Assert(_out != NULL)</code></p>
  <p>Currently running dotNet 5.0.302 from the JetBrains Rider IDE 2021.1.5.</p>
  <p>I've found that it's a bit more rare to have the WPF application launch the console, but in order to configure the settings properly it makes it the most convenient.</p>
  <p>Any help is much appreciated!</p>
  <p><strong>Edit:</strong> Here is the specific code I am using for the ConsoleManager</p>
  <pre><code>using System;
  using System.Diagnostics;
  using System.IO;
  using System.Runtime.InteropServices;
  
  namespace CT_API_GUI
  {
      public static class ConsoleManager
      {
          private const string Kernel32_DllName = &quot;kernel32.dll&quot;;
  
          [DllImport(Kernel32_DllName)]
          private static extern bool AllocConsole();
  
          [DllImport(Kernel32_DllName)]
          private static extern bool FreeConsole();
  
          [DllImport(Kernel32_DllName)]
          private static extern IntPtr GetConsoleWindow();
  
          [DllImport(Kernel32_DllName)]
          private static extern int GetConsoleOutputCP();
  
          public static bool HasConsole
          {
              get { return GetConsoleWindow() != IntPtr.Zero; }
          }
  
          /// &lt;summary&gt;
          /// Creates a new console instance if the process is not attached to a console already.
          /// &lt;/summary&gt;
          public static void Show()
          {
              //#if DEBUG
              if (!HasConsole)
              {
                  AllocConsole();
                  InvalidateOutAndError();
              }
              //#endif
          }
  
          /// &lt;summary&gt;
          /// If the process has a console attached to it, it will be detached and no longer visible. Writing to the System.Console is still possible, but no output will be shown.
          /// &lt;/summary&gt;
          public static void Hide()
          {
              //#if DEBUG
              if (HasConsole)
              {
                  SetOutAndErrorNull();
                  FreeConsole();
              }
              //#endif
          }
  
          public static void Toggle()
          {
              if (HasConsole)
              {
                  Hide();
              }
              else
              {
                  Show();
              }
          }
  
          static void InvalidateOutAndError()
          {
              Type type = typeof(System.Console);
  
              System.Reflection.FieldInfo _out = type.GetField(&quot;_out&quot;,
                  System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
  
              System.Reflection.FieldInfo _error = type.GetField(&quot;_error&quot;,
                  System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
  
              System.Reflection.MethodInfo _InitializeStdOutError = type.GetMethod(&quot;InitializeStdOutError&quot;,
                  System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
  
              Debug.Assert(_out != null);
              Debug.Assert(_error != null);
  
              Debug.Assert(_InitializeStdOutError != null);
  
              _out.SetValue(null, null);
              _error.SetValue(null, null);
  
              _InitializeStdOutError.Invoke(null, new object[] {true});
          }
  
          static void SetOutAndErrorNull()
          {
              Console.SetOut(TextWriter.Null);
              Console.SetError(TextWriter.Null);
          }
      }
  }
  </code></pre>