Отправить ctrl + c процессу cmd.exe в c # - PullRequest
2 голосов
/ 05 мая 2009

Я сейчас пишу себе небольшую программу резервного копирования на C #. Я использую стандартную форму Windows для интерфейса и вызываю cmd.exe как новый процесс, а затем использую XCOPY из этого нового процесса. Все отлично работает, за исключением последней функции, которую я хочу добавить, - это возможность прервать операцию.

Из собственной командной строки я могу сделать это аккуратно с помощью ctrl + c, но, как ни старайся, я не могу воспроизвести эту функциональность, используя winforms и подход к процессу. Я попытался перенаправить стандартный ввод и использовать его для отправки consolespecialkeys.ControlC процессу, я также попытался отправить 0x03 и "/ x03", оба из которых я прочитал в других сообщениях на форуме, это шестнадцатеричный код для ctrl + c , Ничто из того, что я отправляю, не зарегистрировано, и выход из процесса убивает пользовательский интерфейс, но оставляет xcopy.exe работающим в фоновом режиме. Уничтожение xcopy.exe вручную приводит к тому, что файл, который он копировал, копируется и наполовину копируется, а не с помощью ctrl + c в командной строке.

Я упускаю что-то ослепительно очевидное? Я новичок в C #, поэтому я подниму руки и признаю, что, скорее всего, я медленный или неправильно понимаю, как этот процесс работает с cmd.exe. Однако, поскольку процессы поддерживают стандартное перенаправление ввода, похоже, что-то должно работать ... по крайней мере, мне. Ниже приведена основная схема моего кода, на случай, если он поможет определить, где я ошибаюсь.

string XCopyArguments = "\"" + dir.FullName + "\" \"" + destination + "\" /D /S /I /E";  
Process XCopyProcess = new Process();  
ProcessStartInfo XCopyStartInfo = new ProcessStartInfo(); 
XCopyStartInfo.FileName = "CMD.exe ";  
XCopyStartInfo.RedirectStandardError = true;
XCopyStartInfo.RedirectStandardOutput = true;
XCopyStartInfo.RedirectStandardInput = true;
XCopyStartInfo.UseShellExecute = false;
XCopyStartInfo.CreateNoWindow = true;
XCopyStartInfo.Arguments = " /D /c XCOPY " + XCopyArguments;
XCopyProcess.EnableRaisingEvents = true;
XCopyProcess.StartInfo = XCopyStartInfo;
XCopyProcess.Start();                
XCopyProcess.WaitForExit(15000);
int ExitCode = XCopyProcess.ExitCode;
if (ExitCode > 0 & !XCopyProcess.HasExited)
{
XCopyProcess.Kill();
}
XCopyProcess.Dispose();

Заранее большое спасибо за любую помощь, которую может предложить каждый.

Ответы [ 7 ]

13 голосов
/ 05 мая 2009

Я не хочу быть бессовестным, но я думаю, что вам было бы намного лучше делать копирование внутри вашей программы. Используя File, Directory и другие классы в пространстве имен System.IO, это действительно просто и дает вам полный контроль над отчетами о прогрессе, отменой операций и т. Д.

3 голосов
/ 05 мая 2009

Да, делать операции в .NET было бы проще. НО, мне также нужно отправить ctrl-c процессу, и у меня нет этой опции.

Итак, можем ли мы получить ответ на этот вопрос?

РЕДАКТИРОВАТЬ: Должен ли я опубликовать дубликат, чтобы получить ответ? И нет, @ j0rd4n не ответил на вопрос.

2 голосов
/ 09 декабря 2009

Как и другие говорили, есть лучшие способы для выполнения этой конкретной задачи. Однако это не отвечает на ваш вопрос. Я использую технику, аналогичную той, что вы показали здесь, для автоматизации различных задач и считаю ее весьма полезной. Иногда все идет очень плохо, и вы хотите, чтобы процесс выручил, прежде чем все станет хуже. ; Р * * тысяча одна

Вот проблема с вашим примером:

XCopyStartInfo.CreateNoWindow = true;

Установите значение false, и тогда он будет обрабатывать XCopyProcess.CloseMainWindow () и XCopyProcess.Close () Гораздо чище, чем при использовании Kill ().

1 голос
/ 24 января 2012

Я успешно отправил комбинацию CTRL-C процессу cmd.exe, созданному с помощью SW_HIDE, т.е. скрытому окну cmd.exe.

Техника заключалась в том, чтобы использовать EnumWindows для идентификации процесса и получения дескриптора его окна (он по-прежнему имеет дескриптор для обработки сообщений, даже если его не видно).

Далее я использовал PostMessage для публикации комбинации ctrl-c в процессе. Это имело тот же эффект, как если бы пользователь нажимал «ctrl-c», когда окно было активным.

Чтобы сделать это из C #, вы, вероятно, захотите посетить http://pinvoke.net/ - спасатель, когда дело доходит до написания прототипов функций Win32 API в C #.

1 голос
/ 19 мая 2009

Извините, это в VB.NET.

Declare Function GenerateConsoleCtrlEvent Lib "kernel32" ( _
                    ByVal dwCtrlEvent As Integer, _
                    ByVal dwProcessGroupId As Integer _
                    ) As Integer

Private Const CTRL_C_EVENT As Integer = 0

Private Sub SendCtrlC()
    GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0)

    ' send a Ctrl-C to this process
    GenerateConsoleCtrlEvent(CTRL_C_EVENT, currentpid)

    ' send a Ctrl-C to the cmd process
    GenerateConsoleCtrlEvent(CTRL_C_EVENT, cmdpid)
End Sub
1 голос
/ 05 мая 2009

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

0 голосов
/ 05 мая 2009

Вам придется вручную убить процесс, если вы хотите обработать копирование таким способом. В приведенном выше коде вы вызываете XCopyProcess.WaitForExit (...). Это блокирующий вызов, поэтому родительский процесс C # будет остановлен в этой точке до тех пор, пока дочерний процесс не завершится или не истечет временной интервал.

Что вы могли бы сделать, вместо того, чтобы блокировать, вы можете спать в цикле, регулярно проверяя, просил ли пользователь завершить процесс через ваш C # UI. Если вы получаете это событие, вы явно убиваете процесс. В противном случае вы ожидаете еще один интервал до завершения процесса.

РЕДАКТИРОВАТЬ: Я согласен с другими комментариями, хотя. Скопируйте прямо из .NET Framework вместо использования xcopy.

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