Как я отправляю ctrl+c в процесс в c#?

Я пишу класс обертки для исполняемого файла командной строки. Этот exe принимает вход от stdin пока я не совершил нападки Ctrl+C в оболочке командной строки, в этом случае это печатает вывод к stdout на основе входа. Я хочу моделировать это Ctrl+C нажмите в коде C#, отправив команду уничтожения в.NET Process объект. Я попытался звонить Process.Kill(), но это, кажется, ничего не дает мне в процессе StandardOutput StreamReader. Могло бы быть что-нибудь, что я не делаю правильно? Вот код, который я пытаюсь использовать:

ProcessStartInfo info = new ProcessStartInfo(exe, args);
info.RedirectStandardError = true;
info.RedirectStandardInput = true;
info.RedirectStandardOutput = true;
info.UseShellExecute = false;
Process p = Process.Start(info);

p.StandardInput.AutoFlush = true;
p.StandardInput.WriteLine(scriptcode);

p.Kill();

string error = p.StandardError.ReadToEnd();
if (!String.IsNullOrEmpty(error)) 
{
    throw new Exception(error);
}
string output = p.StandardOutput.ReadToEnd();

Вывод всегда пуст, даже при том, что я возвращаю данные из stdout когда я выполняю exe вручную.

Править: Это - C# 2.0 между прочим.

28
задан CarenRose 19 November 2019 в 18:40
поделиться

4 ответа

Я на самом деле только что выяснил ответ. Спасибо вам обоим за Ваши ответы, но оказывается, что все, что я должен был сделать, было этим:

p.StandardInput.Close()

, который вызывает программу, которую я породил, чтобы закончить читать из stdin и производить то, в чем я нуждаюсь.

30
ответ дан Kevlar 28 November 2019 в 02:34
поделиться

@alonl: пользователь пытается обернуть программу командной строки. Программы командной строки не имеют насосов сообщения, если они конкретно не создаются, и даже если это имело место, Ctrl+C не имеет той же семантики в приложении среды Windows (копия, по умолчанию), как это делает в среде командной строки (Повреждение).

я бросил это вместе. CtrlCClient.exe просто называет Консоль. ReadLine () и ожидает:


        static void Main(string[] args)
        {
            ProcessStartInfo psi = new ProcessStartInfo("CtrlCClient.exe");
            psi.RedirectStandardInput = true;
            psi.RedirectStandardOutput = true;
            psi.RedirectStandardError = true;
            psi.UseShellExecute = false;
            Process proc = Process.Start(psi);
            Console.WriteLine("{0} is active: {1}", proc.Id, !proc.HasExited);
            proc.StandardInput.WriteLine("\x3");
            Console.WriteLine(proc.StandardOutput.ReadToEnd());
            Console.WriteLine("{0} is active: {1}", proc.Id, !proc.HasExited);
            Console.ReadLine();
        }

Мой вывод, кажется, делает то, что Вы хотите:

4080 is active: True

4080 is active: False

Hope, которая помогает!

(Для разъяснения: \x3 является шестнадцатеричной escape-последовательностью для шестнадцатеричного символа 3, который является ctrl+c. Это не просто магическое число.;))

21
ответ дан CarenRose 28 November 2019 в 02:34
поделиться

Попытка, на самом деле отправляющая Сочетание клавиш Ctrl+C, вместо того, чтобы непосредственно завершить процесс:

 [DllImport("user32.dll")]
        public static extern int SendMessage(
              int hWnd,      // handle to destination window
              uint Msg,       // message
              long wParam,  // first message parameter
              long lParam   // second message parameter
              );

Ищут его на MSDN, необходимо найти то, в чем Вы нуждаетесь там для отправки комбинации Ctrl+Key... Я знаю, что сообщение, в котором Вы нуждаетесь для отправки Alt+Key, является WM_SYSTEMKEYDOWN и WM_SYSTEMKEYUP, не может сказать Вам о Ctrl...

-7
ответ дан Alon L 28 November 2019 в 02:34
поделиться

FWIW, в моем случае, что я хотел, от консольного процесса, создайте дочерний консольный процесс (ffmpeg.exe в этом отношении) и поддерживайте чистую обработку CTRL-C в моем процессе и в дочернем процессе (ffmpreg выходы обычно, когда CTRL-C нажимается, который является хорошей функцией, я хотел продолжать работать)

Ни одно из решения, которое я нашел, здесь работали, таким образом, я просто interop'd функция CreateProcess Windows и это просто работает w/o любое усилие, CTRL-C автоматически получен дочерним приложением и родительским приложением, входные и выходные потоки совместно используются и т.д. Я не смог воспроизвести такой код с помощью стандартного класса Процесса.NET:

    static void RunFFMpeg(string arguments)
    {
        var startup = new STARTUPINFO();
        startup.cb = Marshal.SizeOf<STARTUPINFO>();
        if (!CreateProcess(null, "ffmpeg.exe " + arguments, IntPtr.Zero, IntPtr.Zero, false, 0, IntPtr.Zero, null, ref startup, out var info))
            throw new Win32Exception(Marshal.GetLastWin32Error());

        CloseHandle(info.hProcess);
        CloseHandle(info.hThread);

        var process = Process.GetProcessById(info.dwProcessId);
        Console.CancelKeyPress += (s, e) =>
        {
            process.WaitForExit();
            Console.WriteLine("Abort.");
            // end of program is here
        };

        process.WaitForExit();
        Console.WriteLine("Exit.");
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct PROCESS_INFORMATION
    {
        public IntPtr hProcess;
        public IntPtr hThread;
        public int dwProcessId;
        public int dwThreadId;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    private struct STARTUPINFO
    {
        public int cb;
        public string lpReserved;
        public string lpDesktop;
        public string lpTitle;
        public int dwX;
        public int dwY;
        public int dwXSize;
        public int dwYSize;
        public int dwXCountChars;
        public int dwYCountChars;
        public int dwFillAttribute;
        public int dwFlags;
        public short wShowWindow;
        public short cbReserved2;
        public IntPtr lpReserved2;
        public IntPtr hStdInput;
        public IntPtr hStdOutput;
        public IntPtr hStdError;
    }

    [DllImport("kernel32")]
    private static extern bool CloseHandle(IntPtr hObject);

    [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)]
    private static extern bool CreateProcess(
       string lpApplicationName,
       string lpCommandLine,
       IntPtr lpProcessAttributes,
       IntPtr lpThreadAttributes,
       bool bInheritHandles,
       int dwCreationFlags,
       IntPtr lpEnvironment,
       string lpCurrentDirectory,
       ref STARTUPINFO lpStartupInfo,
       out PROCESS_INFORMATION lpProcessInformation);
0
ответ дан 28 November 2019 в 02:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: