c#打开cmd然后输入claude

csharp 复制代码
using EA;
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;

namespace EA_CodeEngineer_64.Template.TabUserControl
{
    public partial class UserControlCmdHandle : UserControl
    {
        // Windows API 函数声明
        [DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

        [DllImport("user32.dll", SetLastError = true)]
        private static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);

        [DllImport("user32.dll", SetLastError = true)]
        private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

        [DllImport("user32.dll", SetLastError = true)]
        private static extern int GetWindowLong(IntPtr hWnd, int nIndex);

        [DllImport("user32.dll")]
        private static extern IntPtr SetFocus(IntPtr hWnd);

        [DllImport("user32.dll")]
        private static extern IntPtr SetActiveWindow(IntPtr hWnd);

        [DllImport("user32.dll")]
        private static extern bool BringWindowToTop(IntPtr hWnd);

        [DllImport("user32.dll")]
        private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

        [DllImport("user32.dll")]
        private static extern bool SetForegroundWindow(IntPtr hWnd);

        [DllImport("user32.dll")]
        private static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);

        [DllImport("kernel32.dll")]
        private static extern IntPtr GetStdHandle(int nStdHandle);

        [DllImport("kernel32.dll")]
        private static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode);

        [DllImport("kernel32.dll")]
        private static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode);

        [DllImport("user32.dll")]
        private static extern IntPtr PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

        [DllImport("kernel32.dll")]
        private static extern bool AttachConsole(uint dwProcessId);

        [DllImport("kernel32.dll")]
        private static extern bool FreeConsole();

        private const uint WM_KEYDOWN = 0x0100;
        private const uint WM_KEYUP = 0x0101;
        private const uint WM_CHAR = 0x0102;
        private const byte VK_DOWN = 0x28;
        private const byte VK_RETURN = 0x0D;

        private const int STD_INPUT_HANDLE = -10;
        private const uint ENABLE_EXTENDED_FLAGS = 0x0080;
        private const uint ENABLE_QUICK_EDIT_MODE = 0x0040;
        private const int SW_SHOW = 5;

        // 窗口样式常量
        private const int GWL_STYLE = -16;
        private const int WS_CHILD = 0x40000000;
        private const int WS_VISIBLE = 0x10000000;
        private const int WS_CAPTION = 0x00C00000;
        private const int WS_BORDER = 0x00800000;

        private Process cmdProcess;
        private Panel cmdPanel;
        private bool _isEmbedded = false;
        private bool _isProcessStarted = false;

        /// <summary>
        /// 工作目录(CMD 启动后的初始目录)。如果不设置,将使用 Model.GetCodePath()
        /// </summary>
        public string WorkingDirectory { get; set; }

        /// <summary>
        /// 是否自动执行 claude 并发送按键(需要 claude 已安装)
        /// </summary>
        public bool AutoExecute { get; set; } = true;

        public UserControlCmdHandle()
        {
            InitializeComponent();
            SetStyle(ControlStyles.Selectable, true);
            this.TabStop = true;
        }

        private void UserControlCmdHandle_Load(object sender, EventArgs e)
        {
            InitializeEmbedding();
            // 延迟一下再选择控件,确保嵌入完成后再尝试激活
            this.BeginInvoke(new Action(() => this.Select()));
        }

        private void InitializeEmbedding()
        {
            cmdPanel = new Panel
            {
                Dock = DockStyle.Fill,
                BackColor = System.Drawing.Color.Black
            };
            // 让 Panel 不处理鼠标点击(直接传递给子窗口)
            cmdPanel.MouseDown += (s, e) => ActivateCmdWindow();
            this.Controls.Add(cmdPanel);

            Thread thread = new Thread(StartCmdAndEmbed);
            thread.IsBackground = true;
            thread.Start();
        }

        protected override void WndProc(ref Message m)
        {
            const int WM_MOUSEACTIVATE = 0x0021;
            if (m.Msg == WM_MOUSEACTIVATE)
            {
                // 当鼠标点击 UserControl 时,立即激活 CMD 窗口
                ActivateCmdWindow();
                // 返回 MA_ACTIVATE 让系统继续处理
                m.Result = (IntPtr)1; // MA_ACTIVATE
                return;
            }
            base.WndProc(ref m);
        }

        public void ShowList(EA.Repository repository, string title) { }

        private void SendKeyToWindow(IntPtr hWnd, byte vkCode, bool keyDown)
        {
            uint msg = keyDown ? WM_KEYDOWN : WM_KEYUP;
            PostMessage(hWnd, msg, (IntPtr)vkCode, IntPtr.Zero);
        }

        private void SendKeyPressToWindow(IntPtr hWnd, byte vkCode)
        {
            SendKeyToWindow(hWnd, vkCode, true);
            Thread.Sleep(20);
            SendKeyToWindow(hWnd, vkCode, false);
        }

        private void SendString(IntPtr hWnd, string text)
        {
            foreach (char c in text)
            {
                PostMessage(hWnd, WM_CHAR, (IntPtr)c, IntPtr.Zero);
                Thread.Sleep(5);
            }
        }

        private void DisableQuickEditForProcess(Process process)
        {
            if (process == null || process.HasExited) return;
            if (!AttachConsole((uint)process.Id)) return;
            IntPtr consoleInput = GetStdHandle(STD_INPUT_HANDLE);
            if (GetConsoleMode(consoleInput, out uint mode))
            {
                mode &= ~ENABLE_QUICK_EDIT_MODE;
                mode |= ENABLE_EXTENDED_FLAGS;
                SetConsoleMode(consoleInput, mode);
            }
            FreeConsole();
        }

        private bool IsClaudeInstalled()
        {
            try
            {
                Process whereProcess = new Process();
                whereProcess.StartInfo.FileName = "where";
                whereProcess.StartInfo.Arguments = "claude";
                whereProcess.StartInfo.UseShellExecute = false;
                whereProcess.StartInfo.RedirectStandardOutput = true;
                whereProcess.StartInfo.CreateNoWindow = true;
                whereProcess.Start();
                string output = whereProcess.StandardOutput.ReadToEnd();
                whereProcess.WaitForExit(1000);
                return !string.IsNullOrEmpty(output.Trim());
            }
            catch
            {
                return false;
            }
        }

        private void StartCmdAndEmbed()
        {
            try
            {
                bool hasClaude = IsClaudeInstalled();
                string arguments = hasClaude ? "/k claude --dangerously-skip-permissions" : "/k";

                cmdProcess = new Process();
                cmdProcess.StartInfo.FileName = "cmd.exe";
                cmdProcess.StartInfo.Arguments = arguments;
                cmdProcess.StartInfo.UseShellExecute = true;
                cmdProcess.StartInfo.CreateNoWindow = false;
                cmdProcess.StartInfo.WindowStyle = ProcessWindowStyle.Normal;

                // 设置工作目录:优先使用用户指定的 WorkingDirectory,其次使用 Model.GetCodePath()
                string workDir = !string.IsNullOrEmpty(WorkingDirectory) ? WorkingDirectory : Model.GetCodePath();
                cmdProcess.StartInfo.WorkingDirectory = workDir;

                cmdProcess.Start();
                _isProcessStarted = true;

                IntPtr cmdHandle = IntPtr.Zero;
                for (int i = 0; i < 50; i++)
                {
                    Thread.Sleep(100);
                    cmdProcess.Refresh();
                    cmdHandle = cmdProcess.MainWindowHandle;
                    if (cmdHandle != IntPtr.Zero)
                        break;
                }

                if (cmdHandle == IntPtr.Zero)
                    throw new Exception("未能在规定时间内获取 CMD 窗口句柄");

                this.Invoke(new Action(() =>
                {
                    int style = GetWindowLong(cmdHandle, GWL_STYLE);
                    style = (style & ~WS_CAPTION & ~WS_BORDER) | WS_CHILD | WS_VISIBLE;
                    SetWindowLong(cmdHandle, GWL_STYLE, style);
                    SetParent(cmdHandle, cmdPanel.Handle);
                    MoveWindow(cmdHandle, 0, 0, cmdPanel.Width, cmdPanel.Height, true);

                    ShowWindow(cmdHandle, SW_SHOW);
                    SetActiveWindow(cmdHandle);
                    BringWindowToTop(cmdHandle);
                    SetForegroundWindow(cmdHandle);
                    SetFocus(cmdHandle);
                    _isEmbedded = true;
                    DisableQuickEditForProcess(cmdProcess);

                    if (hasClaude && AutoExecute)
                    {
                        System.Windows.Forms.Timer autoTimer = new System.Windows.Forms.Timer();
                        int step = 0;
                        autoTimer.Interval = 2000;
                        autoTimer.Tick += (s, args) =>
                        {
                            if (!_isProcessStarted || cmdProcess == null || cmdProcess.HasExited)
                            {
                                autoTimer.Stop();
                                autoTimer.Dispose();
                                return;
                            }
                            IntPtr h = cmdProcess.MainWindowHandle;
                            if (h == IntPtr.Zero) return;

                            SetActiveWindow(h);
                            BringWindowToTop(h);
                            SetForegroundWindow(h);
                            SetFocus(h);
                            Thread.Sleep(50);

                            if (step == 0)
                            {
                                SendKeyPressToWindow(h, VK_DOWN);
                                SendKeyPressToWindow(h, VK_RETURN);
                                step++;
                                autoTimer.Interval = 1500;
                            }
                            else if (step == 1)
                            {
                                SendString(h, "!pwd");
                                SendKeyPressToWindow(h, VK_RETURN);
                                autoTimer.Stop();
                                autoTimer.Dispose();
                            }
                        };
                        autoTimer.Start();
                    }
                }));
            }
            catch (Exception ex)
            {
                this.Invoke(new Action(() =>
                {
                    MessageBox.Show($"启动嵌入式 CMD 失败:{ex.Message}", "错误",
                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                }));
                Debug.WriteLine(ex.ToString());
            }
        }

        private void UserControlCmdHandle_Resize(object sender, EventArgs e)
        {
            if (!_isEmbedded || cmdPanel == null || cmdProcess == null)
                return;
            if (!_isProcessStarted || cmdProcess.HasExited)
                return;

            IntPtr cmdHandle;
            try
            {
                cmdHandle = cmdProcess.MainWindowHandle;
            }
            catch (InvalidOperationException)
            {
                return;
            }

            if (cmdHandle != IntPtr.Zero)
            {
                MoveWindow(cmdHandle, 0, 0, cmdPanel.Width, cmdPanel.Height, true);
            }
        }

        private void UserControlCmdHandle_Enter(object sender, EventArgs e)
        {
            ActivateCmdWindow();
        }

        private void UserControlCmdHandle_MouseDown(object sender, MouseEventArgs e)
        {
            // 直接激活 CMD 窗口,而不只是让 UserControl 获得焦点
            ActivateCmdWindow();
        }

        private void ActivateCmdWindow()
        {
            if (!_isEmbedded || cmdProcess == null || !_isProcessStarted || cmdProcess.HasExited)
                return;

            IntPtr hWnd;
            try
            {
                hWnd = cmdProcess.MainWindowHandle;
            }
            catch (InvalidOperationException)
            {
                return;
            }

            if (hWnd == IntPtr.Zero) return;

            // 1. 先暂时移除子窗口样式,恢复为顶级窗口(但父窗口仍为 Panel 时不可见,所以仅瞬间) 
            int style = GetWindowLong(hWnd, GWL_STYLE);
            SetWindowLong(hWnd, GWL_STYLE, style & ~WS_CHILD);

            // 2. 重新设置为子窗口并重新嵌入
            style = GetWindowLong(hWnd, GWL_STYLE);
            style = (style & ~WS_CAPTION & ~WS_BORDER) | WS_CHILD | WS_VISIBLE;
            SetWindowLong(hWnd, GWL_STYLE, style);
            SetParent(hWnd, cmdPanel.Handle);
            MoveWindow(hWnd, 0, 0, cmdPanel.Width, cmdPanel.Height, true);

            // 3. 强制激活窗口
            ShowWindow(hWnd, SW_SHOW);
            SwitchToThisWindow(hWnd, true);
            SetForegroundWindow(hWnd);
            SetActiveWindow(hWnd);
            BringWindowToTop(hWnd);
            SetFocus(hWnd);

            // 4. 刷新消息队列
            Application.DoEvents();
        }
    }
}
相关推荐
雪豹阿伟1 小时前
1.C# —— 项目结构、变量、数据类型与枚举
c#·上位机
雪豹阿伟1 小时前
C# —— Visual Studio 2026 安装教程
c#·上位机
时空自由民.2 小时前
无刷电机反电动势和过零点介绍
单片机·嵌入式硬件
LCG元2 小时前
STM32实战:基于STM32F103的智能晾衣架(光控+雨控)
stm32·单片机·嵌入式硬件
FuckPatience2 小时前
C# 引用dll没用,显示没有对应的类名称
c#
Sean_VIP2 小时前
Bootloader+APP调试技巧
stm32
西城微科方案开发2 小时前
华润微CS98P171(SOP8):高性价比8位通用MCU
单片机·嵌入式硬件
LingLong_roar2 小时前
普冉单片机PY32F002AF15P6TU + 0.96寸TFT ST7735s 80*160显示屏,使用软件SPI显示字符串“Hello World!”
单片机·嵌入式硬件
加号33 小时前
【C#】 实现程序最小化后重新拉起并强制置顶显示的技术指南
开发语言·c#