美文网首页
Unity+SLua的一些小零碎(2)

Unity+SLua的一些小零碎(2)

作者: 慢慢来比较快_ | 来源:发表于2020-04-08 22:16 被阅读0次

    增加调试控制台

    Unity版本:2019.3.4f1
    SLua版本:1.7.0
    .NET : 4.7.1

    前文已经把Unity和SLua搭建起来了。这次主要是希望为Unity增加一个单独的调试控制台,方便开发,也方便后面策划跑包过程中更容易定位问题(实时调试),原理则是调用了kernel32.dll里的AllocConsole()和FreeConsole()。

    控制台存在的意义:
    1. 根据Debug.Log、Debug.LogWarning和Debug.LogError区分输出,控制台输出不同颜色的字符,便于查看
    2. 打出PC包后,也能正常查看Log
    3. 当程序异常触发断点时,能通过控制台进行调试(具体可以参考网上各种debuger的实现)
    当前的问题:

    我之前项目是使用Unity 5.6,控制台是利用GetStdHandle进行操作的,也能正常调用kernel32.dll里的函数。但是到了2019.3,发现GetStdHandle行不通了,GetLastError也没返回任何错误,估计跟Unity一些底层实现有关。通过谷歌一些资料和尝试,结果是使用CreateFileW能正常操作,但是文字着色等操作依旧无效(跟GetStdHandle相关的操作都无效,即使GetLastError返回是0),所以下面代码只能保证控制台正常使用,而不能保证文字着色。

    using UnityEngine;
    using System;
    using System.IO;
    using System.Runtime.InteropServices;
    using SLua;
    using Microsoft.Win32.SafeHandles;
    
    namespace QGNB
    {
        internal class ConsoleWindow
        {
    #if UNITY_EDITOR_WIN || UNITY_STANDLONE_WIN
            static ConsoleWindow g_window;
    
            static void HandleLog(string message, string stackTrace, LogType type)
            {
                if (type == LogType.Warning)
                    g_window.SetForegroundColor(0x0e);
                else if (type == LogType.Error)
                    g_window.SetForegroundColor(0x0c);
                else
                    g_window.SetForegroundColor(0x0c);
    
                Console.WriteLine(message);
            }
            static public void DestroyWindow()
            {
                g_window.Shutdown();
            }
    
            static public void CreateWindow()
            {
                g_window = new ConsoleWindow();
                g_window.Initialize();
                g_window.SetTitle("QGNB");
    
                Application.logMessageReceived += HandleLog;
            }
    
            TextWriter oldOutput;
            TextReader oldInput;
    
            IntPtr stdOutHandler;
            IntPtr stdInHandler;
    
            public void SetForegroundColor(uint color)
            {
                //SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color);
                //Debug.Log(">> SetConsoleTextAttribute " + GetLastError());
            }
    
            private FileStream CreateFileStream(string name, uint win32DesiredAccess, uint win32ShareMode,
                                    FileAccess dotNetFileAccess)
            {
                var file = new SafeFileHandle(CreateFileW(name, win32DesiredAccess, win32ShareMode, IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, IntPtr.Zero), true);
                if (!file.IsInvalid)
                {
                    var fs = new FileStream(file, dotNetFileAccess);
                    return fs;
                }
                return null;
            }
    
            public StreamReader standardInput;
            public StreamWriter standardOutput;
    
            public void Initialize()
            {
                AllocConsole();
    
                oldOutput = Console.Out;
                oldInput = Console.In;
    
                try
                {
    
                    var fs = CreateFileStream("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE, FileAccess.Write);
                    if (fs != null)
                    {
                        standardOutput = new StreamWriter(fs) { AutoFlush = true };
                        Console.SetOut(standardOutput);
                    }
    
                    fs = CreateFileStream("CONIN$", GENERIC_READ, FILE_SHARE_READ, FileAccess.Read);
                    if (fs != null)
                    {
                        standardInput = new StreamReader(fs);
                        Console.SetIn(standardInput);
                    }
    
                    SetConsoleOutputCP(65001);
                }
                catch (System.Exception e)
                {
                    Debug.Log("Couldn't redirect output: " + e.Message);
                }
            }
    
            public void Shutdown()
            {
                standardOutput.Close();
                standardInput.Close();
                Console.SetOut(oldOutput);
                Console.SetIn(oldInput);
                FreeConsole();
            }
    
            public void SetTitle(string strName)
            {
                SetConsoleTitle(strName);
            }
    
            static public string ReadConsoleString()
            {
                while (true)
                {
                    string str = g_window.standardInput.ReadLine();
                    if(str != null)
                    {
                        return str;
                    }
                }
            }
    
            #region Win API Functions and Constants
            [DllImport("kernel32.dll",
                EntryPoint = "AllocConsole",
                SetLastError = true,
                CharSet = CharSet.Auto,
                CallingConvention = CallingConvention.StdCall)]
            private static extern int AllocConsole();
    
            [DllImport("kernel32.dll",
               EntryPoint = "FreeConsole",
               SetLastError = true,
               CharSet = CharSet.Auto,
               CallingConvention = CallingConvention.StdCall)]
            private static extern int FreeConsole();
    
            [DllImport("kernel32.dll",
                EntryPoint = "AttachConsole",
                SetLastError = true,
                CharSet = CharSet.Auto,
                CallingConvention = CallingConvention.StdCall)]
            private static extern UInt32 AttachConsole(UInt32 dwProcessId);
    
            [DllImport("kernel32.dll",
                EntryPoint = "GetStdHandle",
                SetLastError = true,
                CharSet = CharSet.Auto,
                CallingConvention = CallingConvention.StdCall)]
            private static extern IntPtr GetStdHandle(Int32 nStdHandle);
    
            [DllImport("kernel32.dll",
                EntryPoint = "SetConsoleTextAttribute",
                SetLastError = true,
                CharSet = CharSet.Auto,
                CallingConvention = CallingConvention.StdCall)]
            private static extern bool SetConsoleTextAttribute(IntPtr handle, uint color);
    
            [DllImport("kernel32.dll",
                EntryPoint = "SetConsoleTitle",
                SetLastError = true,
                CharSet = CharSet.Auto,
                CallingConvention = CallingConvention.StdCall)]
            private static extern bool SetConsoleTitle(string title);
    
            [DllImport("kernel32.dll",
                EntryPoint = "SetConsoleOutputCP",
                SetLastError = true,
                CharSet = CharSet.Auto,
                CallingConvention = CallingConvention.StdCall)]
            private static extern bool SetConsoleOutputCP(uint mode);
    
            [DllImport("kernel32.dll",
                EntryPoint = "SetConsoleScreenBufferSize",
                SetLastError = true,
                CharSet = CharSet.Auto,
                CallingConvention = CallingConvention.StdCall)]
            private static extern bool SetConsoleScreenBufferSize(IntPtr handle, _coord coord);
    
            [DllImport("kernel32.dll",
                EntryPoint = "GetLastError",
                SetLastError = true,
                CharSet = CharSet.Auto,
                CallingConvention = CallingConvention.StdCall)]
            private static extern int GetLastError();
    
            [DllImport("kernel32.dll",
                EntryPoint = "CreateFileW",
                SetLastError = true,
                CharSet = CharSet.Auto,
                CallingConvention = CallingConvention.StdCall)]
            private static extern IntPtr CreateFileW(
                  string lpFileName,
                  UInt32 dwDesiredAccess,
                  UInt32 dwShareMode,
                  IntPtr lpSecurityAttributes,
                  UInt32 dwCreationDisposition,
                  UInt32 dwFlagsAndAttributes,
                  IntPtr hTemplateFile
                );
    
            private const Int32 STD_OUTPUT_HANDLE = -11;
            private const Int32 STD_INPUT_HANDLE = -10;
    
            private const UInt32 GENERIC_WRITE = 0x40000000;
            private const UInt32 GENERIC_READ = 0x80000000;
            private const UInt32 FILE_SHARE_READ = 0x00000001;
            private const UInt32 FILE_SHARE_WRITE = 0x00000002;
            private const UInt32 OPEN_EXISTING = 0x00000003;
            private const UInt32 FILE_ATTRIBUTE_NORMAL = 0x80;
            private const UInt32 ERROR_ACCESS_DENIED = 5;
            private const UInt32 ATTACH_PARRENT = 0xFFFFFFFF;
    
            #endregion
    #else
             static public void ReadConsoleString() { return ""; }
             static public void DestroyWindow() {}
             static public void CreateWindow() {}
    #endif
        }
    
    
        [CustomLuaClass]
        public class ConsoleServer : MonoBehaviour
        {
            static public string ReadConsoleString()
            {
                return ConsoleWindow.ReadConsoleString();
            }
    #if UNITY_EDITOR_WIN || UNITY_STANDLONE_WIN
            void Awake()
            {
                DontDestroyOnLoad(gameObject);
                ConsoleWindow.CreateWindow();
            }
    
            void OnDestroy()
            {
                ConsoleWindow.DestroyWindow();
            }
    #endif
        }
    }
    

    相关文章

      网友评论

          本文标题:Unity+SLua的一些小零碎(2)

          本文链接:https://www.haomeiwen.com/subject/bjaxmhtx.html