C# WPF 控制台管理器调试断言崩溃

Posted

技术标签:

【中文标题】C# WPF 控制台管理器调试断言崩溃【英文标题】:C# WPF Console Manager Debug Assert Crash 【发布时间】:2021-10-05 11:00:24 【问题描述】:

我目前正在 dotNet 中从事一个项目,我正处于一个有趣的困境中。目前,我的项目是一个 WPF 应用程序,它为控制台应用程序配置设置,然后启动应用程序的主要功能(一个无限循环的 API Hook,用于更新地图上的对象)。以前,我一直在使用在No output to console from a WPF application? 找到的解决方案,并且作为解决方案提供的 ConsoleManager 类运行良好。我最近遇到了解决方案停止工作的问题,在Debug.Assert(_out!=NULL) 的调试或发布版本中总是失败,向我吐出以下错误消息。

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& 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& handled)
   at System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& 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& msg)
   at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& 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()

ConsoleManager 的第 82 行是Debug.Assert(_out != NULL)

当前从 JetBrains Rider IDE 2021.1.5 运行 dotNet 5.0.302。

我发现让 WPF 应用程序启动控制台有点少见,但为了正确配置设置,它使它最方便。

非常感谢任何帮助!

编辑:这是我用于 ConsoleManager 的具体代码

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 = "kernel32.dll";

        [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; 
        

        /// <summary>
        /// Creates a new console instance if the process is not attached to a console already.
        /// </summary>
        public static void Show()
        
            //#if DEBUG
            if (!HasConsole)
            
                AllocConsole();
                InvalidateOutAndError();
            
            //#endif
        

        /// <summary>
        /// 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.
        /// </summary>
        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("_out",
                System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);

            System.Reflection.FieldInfo _error = type.GetField("_error",
                System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);

            System.Reflection.MethodInfo _InitializeStdOutError = type.GetMethod("InitializeStdOutError",
                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);
        
    

【问题讨论】:

【参考方案1】:

从 .NET Framework 4x 迁移到 .NET Core,System.Console 中包含对 StdOut 文本编写器的引用的字段名称已从 .NET Framework 中的 _out 更改为 .NET Core 中的 s_out

所以你需要调整你的反射代码...

#if NET_CORE 
    System.Reflection.FieldInfo _out = type.GetField("s_out", ...);
#else
    System.Reflection.FieldInfo _out = type.GetField("_out", ...);
#endif

源码System.Console.NET Core https://source.dot.net/#System.Console/System/Console.cs,f907d79481da6ba4

源码System.Console.NET Framework 4.6 https://github.com/microsoft/referencesource/blob/master/mscorlib/system/console.cs

【讨论】:

这正是我所需要的。像魅力一样工作。非常感谢!

以上是关于C# WPF 控制台管理器调试断言崩溃的主要内容,如果未能解决你的问题,请参考以下文章

vs2017远程调试linux配置连接管理器时蓝屏

python.exe 崩溃(使用了所有系统允许的窗口管理器对象句柄)

将大型虚拟文件从 C# 拖放到 Windows 资源管理器

我在哪里可以找到包管理器窗口中执行的代码的控制台或调试输出?

Process.Start 打开资源管理器

商务管理器