Я пишу класс обертки для исполняемого файла командной строки. Этот 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 между прочим.
Я на самом деле только что выяснил ответ. Спасибо вам обоим за Ваши ответы, но оказывается, что все, что я должен был сделать, было этим:
p.StandardInput.Close()
, который вызывает программу, которую я породил, чтобы закончить читать из stdin и производить то, в чем я нуждаюсь.
@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. Это не просто магическое число.;))
Попытка, на самом деле отправляющая Сочетание клавиш 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...
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);