Question

I'm currently writing myself a little C# back up program. I'm using a standard windows form for the interface, and am calling cmd.exe as a new process, and then using XCOPY from within this new process. Every thing's working great, except for this last feature I want to add in, which is the ability to break the operation.

From a native command prompt, I can do this cleanly with ctrl+c, but try as I might, I can't replicate this functionality using the winforms and process approach. I've tried redirecting the standardinput and using that to send consolespecialkeys.ControlC to the process, I've also tried sending 0x03 and "/x03", both of which I've read on other forum posts are hex code for ctrl+c. Nothing I'm sending is registered though, and exiting the process kills the user interface, but leaves the xcopy.exe working in the background. Killing xcopy.exe manually results in it leaving the file it was copying half copied and corrupted, not something that happens using the ctrl+c in a command prompt.

Am I missing something blindingly obvious? I'm new-ish to C#, so I'll hold my hands up and admit this is most likely me being slow, or misunderstanding how the process is working with cmd.exe. However, since processes support standard input redirection, it seems like something that should work... to me at least. I've put the basic outline of my code below, in case it helps identify where I'm messing up.

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

Many thanks in advance for any help anyone can offer.

Was it helpful?

Solution

I don't want to be a besserwisser, but I think you'd be much better off doing the copying inside your program. Using File, Directory and the other classes in the System.IO namespace, it's really simple, and leaves you in full control to report progress, cancel operations etc.

OTHER TIPS

Yes, doing the operation in .NET would be easier. BUT, I need to send ctrl-c to a process also and I don't have that option.

So can we please get an answer to this question?

EDIT: Do I have to post a duplicate to get an answer? And no, @j0rd4n didn't answer the question.

Like the others said, there are better ways to accomplish that particular task. However, that doesn't answer your question. I use a similar technique to what you have shown here for automating various tasks and find it quite useful. Sometimes things go very badly though and you want the process to bail out before things get worse. ;p

Here is the problem with your example:

XCopyStartInfo.CreateNoWindow = true;

Set it to false and it will then process XCopyProcess.CloseMainWindow() and XCopyProcess.Close(). Much cleaner than using Kill().

It would require fewer code lines to just loop over the subdirectories and files and copy them one by one and then you wouldn't have to worry about controling another process...

Sorry it's in 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

I've successfully sent a CTRL-C combination to an cmd.exe process created with SW_HIDE--i.e, a hidden cmd.exe window.

The technique was to use EnumWindows to identify the process and get it's window handle (it still has a handle to process messages even if its not visible).

Next, I used PostMessage to post a ctrl-c combination to the process. This had the same effect as if a user had hit 'ctrl-c' while the window was active.

To do this from C#, you would want to probably visit http://pinvoke.net/ - a lifesaver when it comes to writing Win32 API function prototypes in C#.

You'll have to manually kill the process if you want to handle the copying this way. In your code above, you are calling XCopyProcess.WaitForExit(...). This is a blocking call so the parent C# process will halt at that point until the child process has finished or the time-interval has elapsed.

What you could do is instead of blocking, you can sleep in a loop routinely checking if the user has requested to kill the process via your C# UI. If you receive this event, you explicitly kill the process. Otherwise, you wait for another interval until the process is finished.

EDIT: I do agree with the other comments, though. Copy directly from the .NET framework instead of using xcopy.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top