winform 内嵌控制台System.Console

127 阅读2分钟

winform 内嵌控制台System.Console


概要

  1. 新建一个Winfrom应用程序
  2. 把项目输出类型改为Exe
  3. 设置Console.Title为 Guid, Winform中通过Guid找到窗体, 嵌入到Winform中

项目代码

.csproj

重点

  <PropertyGroup>
    <TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
    <OutputType>Exe</OutputType>
  </PropertyGroup>

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace CollectFormJobApp
{
    internal static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Console.Title = "CollectFormJobApp - " + Guid.NewGuid().ToString("N");
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}

Form1.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static CollectFormJobApp.ShareDllImport;

namespace CollectFormJobApp
{
    public partial class Form1 : Form
    {
        private DebounceDispatcher resizeDebounce = new DebounceDispatcher();
        
        public Form1()
        {
            InitializeComponent();
            AddConsole();
        }

        private IntPtr console_handle;

        private void AddConsole()
        {
            console_handle = FindWindow(null, Console.Title);
            if (console_handle == IntPtr.Zero)
                return;
            
            // 设置容器
            SetParent(console_handle, consolePage.Handle);

            // 去掉边框, 最大化, 最小化, 大小调节
            SetWindowLongPtr(console_handle, GWL_STYLE,
                GetWindowLongPtr(console_handle, GWL_STYLE) - WS_CAPTION - WS_SIZEBOX - WS_MAXIMIZEBOX - WS_MINIMIZEBOX);

            Task.Factory.StartNew(async () =>
            {
                try
                {
                    await Task.Delay(1000);
                    ShowWindow(console_handle, 3);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                }
            }).ConfigureAwait(false);
        }


        private void mainboardTabControl_SizeChanged(object sender, EventArgs e)
        {
            resizeDebounce.Debounce(() =>
            {
                ShowWindow(console_handle, 0); // 隐藏
                ShowWindow(console_handle, 3); // 最大化显示

                Logger.Log4Net.AppLog.Info("Info");
                Logger.Log4Net.AppLog.Warn("Warn");
                Logger.Log4Net.AppLog.Error("Error");
            }, 200);
        }
    }
}

ShareDllImport.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CollectFormJobApp
{
    public static class ShareDllImport
    {
        /// <summary>
        /// 开启控制台
        /// </summary>
        /// <returns></returns>
        [System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError = true)]
        [return: System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bool)]
        public static extern bool AllocConsole();//开启

        /// <summary>
        /// 获取当前进程的控制台
        /// </summary>
        /// <returns></returns>
        [System.Runtime.InteropServices.DllImport("Kernel32")]
        public extern static IntPtr GetConsoleWindow();
        
        /// <summary>
        /// 释放控制台
        /// </summary>
        [System.Runtime.InteropServices.DllImport("Kernel32")]
        public static extern void FreeConsole();//关闭

        [System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "FindWindow")]
        public extern static IntPtr FindWindow(string lpClassName, string lpWindowName);//找出运行的窗口   

        [System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "FindWindow")]
        public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

        [System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "GetSystemMenu")]
        public extern static IntPtr GetSystemMenu(IntPtr hWnd, IntPtr bRevert); //取出窗口运行的菜单   

        [System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "RemoveMenu")]
        public extern static IntPtr RemoveMenu(IntPtr hMenu, uint uPosition, uint uFlags); //灰掉按钮

        [System.Runtime.InteropServices.DllImport("User32.dll ", EntryPoint = "SetParent")]
        public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);//设置父窗体

        [System.Runtime.InteropServices.DllImport("user32.dll ", EntryPoint = "ShowWindow")]
        public static extern int ShowWindow(IntPtr hwnd, int nCmdShow);//显示窗口

        [System.Runtime.InteropServices.DllImport("user32.dll ", EntryPoint = "SetWindowLong")]
        public static extern long SetWindowLongPtr(IntPtr hwnd, int index, long style);
        [System.Runtime.InteropServices.DllImport("user32.dll ", EntryPoint = "GetWindowLong")]
        public static extern long GetWindowLongPtr(IntPtr hwnd, int index);


        public const int GWL_EXSTYLE = -20;
        public const int GWLP_HINSTANCE = -6;
        public const int GWLP_HWNDPARENT = -8;
        public const int GWLP_ID = -12;
        public const int GWL_STYLE = -16;
        public const int GWLP_USERDATA = -21;
        public const int GWLP_WNDPROC = -4;
        
        /// <summary>
        /// WS_CAPTION<br/>
        /// https://learn.microsoft.com/zh-cn/windows/win32/winmsg/window-styles
        /// </summary>
        public const long WS_CAPTION = 0x00C00000L;
        public const long WS_SIZEBOX = 0x00040000L;
        public const long WS_MINIMIZEBOX = 0x00020000L;
        public const long WS_MAXIMIZEBOX = 0x00010000L;
        
        
    }
}

DebounceDispatcher.cs

using System;
using System.Threading;

namespace CollectFormJobApp
{
    /// <summary>
    /// 防抖调度器 确保函数在一定时间间隔内以固定的频率执行
    /// </summary>
    public class DebounceDispatcher
    {
        private Timer timer;

        /// <summary>
        /// 函数防抖
        /// </summary>
        /// <param name="action">需要执行的<see cref="Action"/></param>
        /// <param name="delay">时间间隔/毫秒</param>
        public void Debounce(Action action, int delay)
        {
            timer?.Dispose();
            timer = new Timer((_) =>
            {
                action?.Invoke();
            }, null, delay, Timeout.Infinite);
        }
    }

}