Используя AttachConsole, пользователь должен нажать Enter, чтобы получить обычную командную строку - PullRequest
21 голосов
/ 20 августа 2009

У меня есть прогарам, который можно запустить как в виде winform, так и из командной строки. Если он вызывается из командной строки, я вызываю AttachConsole (-1) для подключения к родительской консоли.

Однако после завершения моей программы пользователь должен нажать Enter, чтобы вернуться к стандартной командной строке ("c: \>"). Есть ли способ избежать этой необходимости?

Спасибо. Я мог бы обернуть его в файл cmd, чтобы избежать этой проблемы, но я хотел бы сделать это из моего exe.

Ответы [ 6 ]

18 голосов
/ 17 марта 2010

Попробуйте добавить эту строку перед выходом вашего exe ...

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

Немного хак, но лучшее, что я мог найти, когда столкнулся с этой проблемой.

3 голосов
/ 10 августа 2017

Вот самый безопасный способ взлома, который решает проблему с клавишей Enter независимо от того, находится ли окно консоли на переднем плане, в фоне или свернуто. Вы даже можете запустить его в нескольких окнах консоли.

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());
        }
    }
  }
}
3 голосов
/ 03 ноября 2015

Подход Роба Л несколько опасен, так как отправит 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;
    }

- чик -

            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);
            }

Это решение основано на коде, найденном здесь:

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

2 голосов
/ 25 августа 2010

Хорошо, у меня нет решения, но, похоже, дело в том, что cmd.exe не ожидает запущенного процесса, тогда как с обычным консольным приложением cmd.exe ждет, пока приложение не закроется. Я не знаю, что заставляет cmd.exe решать, ждать или нет в приложении, обычные приложения Windows Forms просто запускаются, и cmd.exe не ждет его завершения. Может быть, этот намек кого-то вызывает! Пока я буду копать немного глубже.

Wout

1 голос
/ 17 марта 2010

Попробуйте вызвать функцию FreeConsole до выхода из исполняемого файла.

0 голосов
/ 19 апреля 2019

Это было самое простое решение для меня:

myapp.exe [params] | ECHO.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...