C# WPF 项目中无法使用Console输出时出现句柄无效的IO异常解决方法

如以下代码,重点看:ConsoleManager.Show()的位置注释即可;


using System;
using System.Collections.Generic;
using System.Windows;
using System.IO;
using System.Security;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace GameLanguagePicker
{
    /// <summary>
    /// 该类源于Stackoverflow 的一问题贴的回答:
    /// 问题:No output to console from a WPF application?
    /// 地址:http://stackoverflow.com/questions/160587/no-output-to-console-from-a-wpf-application/718505
    /// </summary>
    [SuppressUnmanagedCodeSecurity]
    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);
        }
    }

    /// <summary>
    /// @author Jave.Lin
    /// @date 2014-1-9
    /// </summary>
    public class Programs
    {
        [STAThread]
        public static void Main(string[] args)
        {
            try
            {
                var listArgs = new List<string>(args);
                //listArgs.Add("-h");
                listArgs.Add("-p");
                listArgs.Add(@"E:\myWork");

                if (listArgs.Count == 0 || !listArgs.Contains("-h")) // 可视化操作
                {
                    var win = new MainWindow();//你要启动的Window类;就是你继承自Window类的类,并加载了一些.xaml(不加也可以)的窗体类;
                    Application app = new Application();//自己去new一个,或使用当前这个App也可以(它也是继承Application)
                    app.MainWindow = win;
                    //来种方式启动;
                    //第一种:
                    //wb.Show();
                    //app.Run();//以MainWindow作为启动窗体
                    //第二种
                    var pIdx = listArgs.IndexOf("-p");
                    if (pIdx != -1)
                    {
                        win.pathTextBox.Text = win.Picker.Path = listArgs[pIdx + 1];
                        win.Start();
                    }
                    app.Run(win);//以指定的Window来启动
                }
                else // 控制台式操作
                {
                    // 如果这里不申请控制台,后台,所有用到:Console的API都会报:句柄无效的IO异常;
                    // 可能是WPF 项目配置,还是其它的,在启动时,将Console指定了输出流吧;这个希望有知道的朋友可以告知一下
                    ConsoleManager.Show();

                    if (listArgs.Contains("-?") || (listArgs.Count > 1 && listArgs[0].ToLower() == "help") || !listArgs.Contains("-h") || !listArgs.Contains("-p"))
                    {
                        ShowUsage();
                        Console.ReadLine();
                    }
                    else
                    {
                        var picker = new Picker();
                        var left = Console.CursorLeft;
                        var top = Console.CursorTop;

                        var pIdx = listArgs.IndexOf("-p");
                        picker.Path = listArgs[pIdx + 1];

                        picker.Start((value, max) => 
                        {
                            // progress
                            Console.SetCursorPosition(left, top);
                            Console.WriteLine(string.Format("提取进度:{0} / {1}", value, max));
                        }, () => 
                        {
                            // complete
                            //Console.SetCursorPosition(left, top);
                            Console.WriteLine(string.Format("提取完成:{0}, 耗时:{1}", picker.FileCount, picker.ElapsedTime));
                            Console.ReadLine();
                        }, (er) => 
                        {
                            // error
                            throw er;
                        });
                    }
                }
                //Console.SetCursorPosition
                Console.ReadLine();
                //Console.ReadKey();
            }
            catch (Exception er)
            {
                Console.WriteLine("Exception!");
                Console.WriteLine(er.ToString());
            }
        }

        private static void ShowUsage()
        {
            Console.WriteLine("usage : GameLanguagePicker.exe [-options]");
            Console.WriteLine("-options:");
            Console.WriteLine("\t[-h]\t加-h说明:控制台方式操作,否则为:可视化窗口操作;不加则默认是:可视化窗口操作");
            Console.WriteLine("\t[-p pathValue]\t指定要提取的路径,-p pathValue必须成对出现");

            //Console.ReadLine();
        }
    }
}


  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值