Question

J'écris moi-même un petit programme de sauvegarde C #. J'utilise un formulaire Windows standard pour l'interface et j'appelle cmd.exe en tant que nouveau processus, puis j'utilise XCOPY à partir de ce nouveau processus. Tout fonctionne très bien, à l'exception de la dernière fonctionnalité que je souhaite ajouter, à savoir la possibilité d'interrompre l'opération.

À partir d'une invite de commande native, je peux le faire proprement avec ctrl + c, mais autant que je puisse le faire, je ne peux pas répliquer cette fonctionnalité à l'aide de la méthode winforms and process. J'ai essayé de rediriger l'entrée standard et de l'utiliser pour envoyer des consolespecialkeys.ControlC au processus. J'ai également essayé d'envoyer 0x03 et "/ x03", les deux que j'ai lus dans d'autres messages de forum étant du code hexadécimal pour ctrl + c. Toutefois, rien de ce que j'envoie n'est enregistré, et quitter le processus tue l'interface utilisateur, mais laisse le fichier xcopy.exe fonctionner en arrière-plan. Si vous supprimez manuellement xcopy.exe, le fichier à copier est copié et corrompu, ce qui ne se produit pas à l’aide de la combinaison de touches ctrl + c dans une invite de commande.

Est-ce que je manque quelque chose d'aveuglement évident? Je suis nouveau en C #, je vais donc lever la main et admettre que c'est probablement parce que je suis lent ou mal à comprendre comment le processus fonctionne avec cmd.exe. Cependant, étant donné que les processus prennent en charge la redirection des entrées standard, il semble que quelque chose devrait fonctionner ... du moins pour moi. J'ai mis le schéma de base de mon code ci-dessous, au cas où cela aiderait à identifier où je me trompe.

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

Un grand merci d’avance pour toute aide apportée.

Était-ce utile?

La solution

Je ne veux pas être un besserwisser, mais je pense que vous feriez bien mieux de copier dans votre programme. Utiliser File, Directory et les autres classes de l’espace de noms System.IO est très simple et vous permet de contrôler totalement l’état de la progression, l’annulation des opérations, etc.

Autres conseils

Oui, effectuer l'opération dans .NET serait plus facile. MAIS, je dois aussi envoyer ctrl-c à un processus et je n'ai pas cette option.

Pouvons-nous donc obtenir une réponse à cette question?

MODIFIER: Dois-je envoyer un duplicata pour obtenir une réponse? Et non, @ j0rd4n n'a pas répondu à la question.

Comme l’ont dit les autres, il existe de meilleurs moyens d’accomplir cette tâche particulière. Cependant, cela ne répond pas à votre question. J'utilise une technique similaire à celle que vous avez montrée ici pour automatiser diverses tâches et que je trouve très utile. Parfois, les choses vont très mal et vous voulez que le processus soit renfloué avant que les choses n'empirent. ; p

Voici le problème de votre exemple:

XCopyStartInfo.CreateNoWindow = true;

Définissez-le sur false et il traitera ensuite XCopyProcess.CloseMainWindow () et XCopyProcess.Close (). Beaucoup plus propre que d'utiliser Kill ().

Il faudrait moins de lignes de code pour parcourir les sous-répertoires et les fichiers et les copier un par un, sans que vous ayez à vous soucier de contrôler un autre processus ...

Désolé, c'est dans 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

J'ai envoyé avec succès une combinaison CTRL-C à un processus cmd.exe créé avec SW_HIDE - i.e, une fenêtre masquée cmd.exe.

La technique consistait à utiliser EnumWindows pour identifier le processus et obtenir son handle de fenêtre (il a toujours un handle pour traiter les messages même s'il n'est pas visible).

Ensuite, j'ai utilisé PostMessage pour publier une combinaison ctrl-c dans le processus. Cela a le même effet que si un utilisateur appuyait sur 'ctrl-c' alors que la fenêtre était active.

Pour ce faire, vous voudrez probablement visiter http://pinvoke.net/ - une bouée de sauvetage. lorsqu'il s'agit d'écrire des prototypes de fonctions d'API Win32 en C #.

Vous devrez arrêter manuellement le processus si vous souhaitez gérer la copie de cette façon. Dans votre code ci-dessus, vous appelez XCopyProcess.WaitForExit (...). Il s’agit d’un appel bloquant. Le processus C # parent s’arrête à ce stade jusqu’à ce que le processus enfant soit terminé ou que l’intervalle de temps s’écoule.

Au lieu de bloquer, vous pouvez dormir dans une boucle en vérifiant régulièrement si l'utilisateur a demandé de supprimer le processus via votre interface utilisateur C #. Si vous recevez cet événement, vous tuez explicitement le processus. Sinon, vous attendez un autre intervalle jusqu'à la fin du processus.

MODIFIER: Je suis cependant d'accord avec les autres commentaires. Copiez directement à partir du framework .NET au lieu d'utiliser xcopy.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top