使用AttachConsole,用户必须按Enter键才能获得常规命令行

Cla*_*gon 21 c# console

我有一个progaram,既可以作为winform运行,也可以从命令行运行.如果从命令行调用它,我调用AttachConsole(-1)以附加到父控制台.

但是,在我的程序结束后,用户必须按Enter键才能返回标准命令提示符("c:\>").有没有办法避免这种需要?

谢谢.我可以将它包装在一个cmd文件中,以避免这个问题,但我想从我的exe中做到这一点.

小智 18

尝试在exe退出之前添加此行...

System.Windows.Forms.SendKeys.SendWait( "{} ENTER");

有点黑客,但是当我遇到这个问题时我能找到最好的.

  • 这看起来非常糟糕,但它似乎是唯一明显的方法.谢谢. (2认同)

小智 8

这是解决 Enter 键问题的最安全的 hack,无论控制台窗口是在前台、后台还是最小化。您甚至可以在多个控制台窗口中运行它。

using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;

namespace WindowsAndConsoleApp
{
  static class Program
  {
    const uint WM_CHAR = 0x0102;
    const int VK_ENTER = 0x0D;

    [DllImport("kernel32.dll")]
    static extern bool AttachConsole(int dwProcessId);
    private const int ATTACH_PARENT_PROCESS = -1;

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool FreeConsole();

    [DllImport("kernel32.dll")]
    static extern IntPtr GetConsoleWindow();

    [DllImport("user32.dll")]
    static extern int SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);

    [STAThread]
    static void Main(string[] args)
    {
        if (args.Length > 0)
        {
            // Do this first.
            AttachConsole(ATTACH_PARENT_PROCESS);

            Console.Title = "Console Window - Enter Key Test";
            Console.WriteLine("Getting the handle of the currently executing console window...");
            IntPtr cw = GetConsoleWindow();
            Console.WriteLine($"Console handle: {cw.ToInt32()}");
            Console.WriteLine("\nPut some windows in from of this one...");
            Thread.Sleep(5000);
            Console.WriteLine("Take your time...");
            Thread.Sleep(5000);
            Console.WriteLine("Sending the Enter key now...");

            // Send the Enter key to the console window no matter where it is.
            SendMessage(cw, WM_CHAR, (IntPtr)VK_ENTER, IntPtr.Zero);

            // Do this last.
            FreeConsole();
        }
        else
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new MainForm());
        }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)


inv*_*ame 5

Rob L 的方法有点危险,因为它会向活动窗口发送 Enter。更好的方法是将 Enter 实际发送到正确的进程(控制台)。

这是如何

    internal static class NativeMethods
    {
        [DllImport("kernel32.dll", SetLastError = true)]
        internal static extern bool AllocConsole();

        [DllImport("kernel32.dll", SetLastError = true)]
        internal static extern bool FreeConsole();

        [DllImport("kernel32", SetLastError = true)]
        internal static extern bool AttachConsole(int dwProcessId);

        [DllImport("user32.dll")]
        internal static extern IntPtr GetForegroundWindow();

        [DllImport("user32.dll", SetLastError = true)]
        internal static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);

        [DllImport("User32.Dll", EntryPoint = "PostMessageA")]
        internal static extern bool PostMessage(IntPtr hWnd, uint msg, int wParam, int lParam);

        internal const int VK_RETURN = 0x0D;
        internal const int WM_KEYDOWN = 0x100;
    }
Run Code Online (Sandbox Code Playgroud)

--剪断--

            bool attached = false;

            // Get uppermost window process
            IntPtr ptr = NativeMethods.GetForegroundWindow();
            int u;
            NativeMethods.GetWindowThreadProcessId(ptr, out u);
            Process process = Process.GetProcessById(u);

            if (string.Compare(process.ProcessName, "cmd", StringComparison.InvariantCultureIgnoreCase) == 0)
            {
                // attach to the current active console
                NativeMethods.AttachConsole(process.Id);
                attached = true;
            }
            else
            {
                // create new console
                NativeMethods.AllocConsole();
            }

            Console.Write("your output");

            NativeMethods.FreeConsole();

            if (attached)
            {
                var hWnd = process.MainWindowHandle;
                NativeMethods.PostMessage(hWnd, NativeMethods.WM_KEYDOWN, NativeMethods.VK_RETURN, 0);
            }
Run Code Online (Sandbox Code Playgroud)

此解决方案基于此处找到的代码:

http://www.jankowskimichal.pl/en/2011/12/wpf-hybrid-application-with-parameters/

  • 我同意 Rob 的解决方案是不安全的,但看来您的答案通过使用 GetForegroundWindow 也遇到了同样的问题。也许可以使用 API 来查看哪个进程启动了您的应用程序,或者使用 GetConsoleProcessList。 (2认同)