Pregunta

Actualmente estoy escribiendo un pequeño programa de copia de seguridad de C #. Estoy usando un formulario de Windows estándar para la interfaz, y estoy llamando a cmd.exe como un nuevo proceso, y luego uso XCOPY desde este nuevo proceso. Todo funciona bien, excepto por esta última función que quiero agregar, que es la capacidad de interrumpir la operación.

Desde un indicador de comando nativo, puedo hacer esto de manera limpia con ctrl + c, pero, por más que lo intente, no puedo replicar esta funcionalidad utilizando las formas de proceso y el método de proceso. He intentado redireccionar la entrada estándar y usarla para enviar consolespecialkeys.ControlC al proceso, también he intentado enviar 0x03 y " / x03 " ;, ambos de los cuales he leído en otros mensajes del foro son código hexadecimal para ctrl + do. Sin embargo, nada de lo que estoy enviando está registrado y salir del proceso mata la interfaz de usuario, pero deja el xcopy.exe funcionando en segundo plano. Al eliminar xcopy.exe manualmente, se deja el archivo que se estaba copiando a la mitad y se corrompió, no es algo que ocurra al usar ctrl + c en un símbolo del sistema.

¿Me estoy perdiendo algo cegadoramente? Soy nuevo en C #, así que levanto las manos y admito que es muy probable que sea lento o que no entienda cómo funciona el proceso con cmd.exe. Sin embargo, dado que los procesos admiten la redirección de entrada estándar, parece algo que debería funcionar ... al menos para mí. A continuación, coloco el esquema básico de mi código, en caso de que ayude a identificar dónde me estoy equivocando.

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

Muchas gracias de antemano por cualquier ayuda que alguien pueda ofrecer.

¿Fue útil?

Solución

No quiero ser un Besserwisser, pero creo que estarías mucho mejor haciendo la copia dentro de tu programa. Usar Archivo, Directorio y las otras clases en el espacio de nombres de System.IO, es realmente simple y lo deja en control total para informar el progreso, cancelar operaciones, etc.

Otros consejos

Sí, hacer la operación en .NET sería más fácil. PERO, necesito enviar ctrl-c a un proceso también y no tengo esa opción.

Entonces, ¿podemos obtener una respuesta a esta pregunta?

EDITAR: ¿Tengo que publicar un duplicado para obtener una respuesta? Y no, @ j0rd4n no respondió la pregunta.

Como dijeron los demás, hay mejores formas de lograr esa tarea en particular. Sin embargo, eso no responde a tu pregunta. Utilizo una técnica similar a la que has mostrado aquí para automatizar varias tareas y me resulta bastante útil. Sin embargo, a veces las cosas van muy mal y desea que el proceso se resuelva antes de que las cosas empeoren. ; p

Aquí está el problema con su ejemplo:

XCopyStartInfo.CreateNoWindow = true;

Configúrelo en falso y luego procesará XCopyProcess.CloseMainWindow () y XCopyProcess.Close (). Mucho más limpio que usar Kill ().

Requeriría menos líneas de código para recorrer los subdirectorios y los archivos, copiarlos uno por uno y luego no tendría que preocuparse por controlar otro proceso ...

Lo siento, está en 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

He enviado con éxito una combinación CTRL-C a un proceso cmd.exe creado con SW_HIDE, es decir, una ventana oculta de cmd.exe.

La técnica fue utilizar EnumWindows para identificar el proceso y obtener su identificador de ventana (todavía tiene un identificador para procesar mensajes, incluso si no está visible).

Luego, utilicé PostMessage para publicar una combinación ctrl-c en el proceso. Esto tuvo el mismo efecto que si un usuario hubiera presionado 'ctrl-c' mientras la ventana estaba activa.

Para hacer esto desde C #, es probable que desee visitar http://pinvoke.net/ : un salvavidas cuando se trata de escribir prototipos de funciones de API Win32 en C #.

Tendrás que terminar el proceso manualmente si quieres manejar la copia de esta manera. En su código anterior, está llamando a XCopyProcess.WaitForExit (...). Esta es una llamada de bloqueo, por lo que el proceso de C # principal se detendrá en ese punto hasta que el proceso secundario haya finalizado o haya transcurrido el intervalo de tiempo.

Lo que podrías hacer es, en lugar de bloquear, puedes dormir en un bucle de forma rutinaria, verificando si el usuario ha solicitado finalizar el proceso a través de tu C # UI. Si recibe este evento, mata explícitamente el proceso. De lo contrario, esperas otro intervalo hasta que finalice el proceso.

EDITAR: estoy de acuerdo con los otros comentarios, sin embargo. Copie directamente desde el marco .NET en lugar de usar xcopy.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top