Вопрос

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

Из собственной командной строки я могу сделать это аккуратно с помощью ctrl + c, но, как ни старайся, я не могу воспроизвести эту функциональность, используя winforms и процессный подход. Я попытался перенаправить стандартный ввод и использовать его для отправки consolespecialkeys.ControlC процессу, я также попытался отправить 0x03 и "/ x03", оба из которых я читал в других сообщениях на форуме - это шестнадцатеричный код для ctrl + с. Ничто из того, что я отправляю, не зарегистрировано, и выход из процесса убивает пользовательский интерфейс, но оставляет 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();

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

Это было полезно?

Решение

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

Другие советы

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

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

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

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

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

XCopyStartInfo.CreateNoWindow = true;

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

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

Извините, это в 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

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top