Process.Start() of xcopy only works under the debugger?

Answered Process.Start() of xcopy only works under the debugger?

  • Thursday, October 06, 2005 4:54 PM
     
     

    I am trying to run a child process to xcopy files into another directory.  xcopy is regular old Windows system xcopy.  I am creating a new System.Diagnostics.Process, filling out some start info, then kicking it off with Process.Start().  When I run this code under the .NET debugger it works fine.

    However, if I run my app outside the debugger, the xcopy child process fails to do anything.  I've attached a debugger after I started my app outside the .NET IDE and although the child process appears to run, I get nothing from its stdout and the files I intend to xcopy are never copied.  This child process (xcopy) does not hang... I do a Process.WaitForExit() after the Start() and the thread that kicks off the child process does not hang.  Its almost as if the p.Start() call doesn't actually do anything.  Any ideas?

    I'd post code but I don't have it here at the moment.  The code is pretty much standard 'set start info and kick off child process' kinda stuff.  Thanks!

All Replies

  • Thursday, October 06, 2005 7:42 PM
    Moderator
     
     

    Perhaps the directories are not right?  And perhaps the error message is written to stderr?

     

  • Thursday, October 06, 2005 10:56 PM
     
     
    Try seting the working directory and checking the exit code. 



    ProcessStartInfo s = new ProcessStartInfo(ExecutablePath);
    s.Arguments = args;
    s.CreateNoWindow = true;
    s.RedirectStandardOutput = true;
    s.RedirectStandardError = true;
    s.UseShellExecute = false;
    s.WindowStyle = ProcessWindowStyle.Hidden;
    s.WorkingDirectory = Path.GetDirectoryName(ExecutablePath);

    using (Process p = Process.Start(s))
    {
        string standardOutput = p.StandardOutput.ReadToEnd();
        string errorOutput = p.StandardError.ReadToEnd();
        p.WaitForExit(30 * 1000);
       
        int exitCode = p.ExitCode;
        log.DebugFormat("ExitCode: {0}", exitCode);
       
        log.DebugFormat("Standard Output: {0}", standardOutput);
        log.DebugFormat("Standard Error Output: {0}", errorOutput);
    }

     


  • Monday, October 10, 2005 4:20 PM
     
     
    Thanks for the suggestions.  I'm still having the same problem.

    xcopy returns 0 and nothing is sent to stdout or stderr when I run it outside the debugger.  It returns 0 when run inside the debugger, along with the usual stdout and stderr messages one would expenct after an xcopy run.

    The code I have creating the child process is a general method that starts other process.  The method works just fine starting other processes throughout the execution of my app.  I only see this issue with xcopy.  I wonder if other system commands would behave similarly...

    I've heard of Win32 apps calling a different CreateProcess() when run in the debugger, does the .NET framework do something like this?  Maybe the issue lies in what version of Process.Start() is actually called at runtime (?).  Thanks for the help!
  • Tuesday, October 11, 2005 1:54 PM
    Moderator
     
     
    are you using cmd.exe as your executable and '/c xcopy  [src] [optional dest]' as your arguments?
  • Tuesday, October 11, 2005 2:45 PM
    Moderator
     
     
    thats the damndest thing. . . does the same thing here. the move comand works though.

    heres what I used:


    ProcessStartInfo s = new ProcessStartInfo("cmd.exe");
    s.Arguments = @"/c xcopy D:\foobar f:\foobar /e /y";
    s.CreateNoWindow = true;
    s.RedirectStandardOutput = true;
    s.RedirectStandardError = true;
    s.UseShellExecute = false;
    s.WindowStyle = ProcessWindowStyle.Hidden;
    int exitCode;
    string standardOutput;
    string errorOutput;
    using (Process p = Process.Start(s))
    {
     standardOutput= p.StandardOutput.ReadToEnd();
     errorOutput = p.StandardError.ReadToEnd();
     p.WaitForExit(30*1000);
        exitCode = p.ExitCode;
    }
    MessageBox.Show(this, string.Format("ExitCode: {0}\r"+
        "Standard Output: \n\t{1}\r"+
        "Standard Error Output:\n\t{2}\r",
        exitCode,
        standardOutput.Replace("\n","\n\t"),
        errorOutput.Replace("\n","\n\t")));
    }

     


    in debug, results:
    ---------------------------
    ExitCode: 0
    Standard Output:
     D:\foobar\foobar.txt

     D:\foobar\foobas\foobas.txt

     2 File(s) copied

    Standard Error Output:
     
    ---------------------------
    OK  
    ---------------------------

    in runtime:
    ---------------------------
    ExitCode: 0
    Standard Output:
     
    Standard Error Output:
     
    ---------------------------
    OK   
    ---------------------------

  • Tuesday, October 11, 2005 8:26 PM
     
     
    no I'm starting xcopy directly, no cmd shell involved.

    you said Move works.  Does Move 'move' whole directories?  That might be a good alternative.  This is my first foray into the windows world (and after this silly bug maybe my last Smile) so I'm not too familiar with the system commands.

    I'm glad someone was able to duplicate the issue... at least I'm not crazy.  My code is almost identical to what you have, thanks for posting what you wrote.  Could this be some bug in .NET, or worse yet, Win32?
  • Wednesday, October 12, 2005 1:24 AM
    Moderator
     
     Answered

    Seems to be a bug with .net as Executing CreateProcess on xcopy using win32 api works in both debug and runtime.

    Move renames a foleder - doesn't work across volumes.

    I didn't know xcopy was an exe - thought it was a shell command like dir and move therefore needing to be executed cia cmd.exe.

    here's a class to copy System.IO.FileSystemInfo objects:

    use it to copy directories and files (I guess its not necessary for Files as File already has a copy method.)


    namespace FileSystemUtilities
    {
     public enum FileSystemItemType{ File , Folder }

     public class FileSystemItem
     {
      System.IO.FileSystemInfo _obj;
      public FileSystemItem(System.IO.FileSystemInfo obj)
      {
       _obj = obj;
      }
     
      public FileSystemItemType ItemType
      {
       get
       {
        return _obj is System.IO.FileInfo ?
         FileSystemItemType.File :
         FileSystemItemType.Folder;
       }
      }

      public System.IO.FileSystemInfo Item
      {
       get
       {
        return this._obj;
       }
      }
     
      public void Copy(string location)
      {
       if(!System.IO.Directory.Exists(location))
        System.IO.Directory.CreateDirectory(location);
       if (this.ItemType==FileSystemItemType.File)
       {
        if (System.IO.File.Exists(location + _obj.Name))
         System.IO.File.Delete(location + _obj.Name);
        System.IO.File.Copy( _obj.FullName, location + _obj.Name);
       }
       else
       {
        if (!System.IO.Directory.Exists(location + _obj.Name))
         System.IO.Directory.CreateDirectory(location + _obj.Name);
        System.IO.DirectoryInfo curr = _obj as System.IO.DirectoryInfo;
        location+= _obj.Name + "\\";
        foreach(System.IO.DirectoryInfo di in curr.GetDirectories())
        {
         FileSystemItem fi = new FileSystemItem(di);
         fi.Copy(location);
        }
        foreach(System.IO.FileInfo fiCurr in curr.GetFiles())
        {
         FileSystemItem fi = new FileSystemItem(fiCurr);
         fi.Copy(location);
        }
       }
      }
     }
    }

     

  • Wednesday, October 12, 2005 5:17 PM
     
     
    Thanks for looking into it, your class will work nicely.  Looks like if you run xcopy from a System.Process.Start("xcopy") [syntax may be slightly wrong but you get the idea] it'll work but then you can't redirect output and you get a window that pops up.  Oh well.  I feel like someone from M$ should look at this.  Thanks for the help!
  • Thursday, October 13, 2005 1:36 PM
     
     Answered
    ok, I think I fixed my issue... But in doing so, opened a whole new can of worms.

    Adding the /I switch to xcopy fixes the issue.  But...

    1)  Why did this work when run in the context of the .NET IDE debugger
    without the /I switch?

    2)  Why did the debugger, when attached to this process running outside of
    the IDE, step past the p.WaitForExit()?

    Both of these things should not have happened because xcopy was in the process of asking "is the destination a file or directory"... and was expecting input from the user.

  • Friday, October 14, 2005 4:57 PM
     
     

    As I recall, putting a "/" at the end of the destination path will force xcopy to treat it as a directory.

  • Tuesday, October 25, 2005 9:30 PM
     
     

    Xcopy is evil. It's a great command line utility, but calling it from programs is asking for trouble.

    The URT has built in classes for handling all sorts of file operations.

    The URT version of xcopy is this. 

    System.IO.File.Copy(source, destination);

    You can't pass it things like *.*, so it's a little more work but wrapping in in a method and calling it in a loop isn't much trouble.

    Source and destinations are strings. MSDN online has everything you need to know about the File and Directory class.
    http://msdn.microsoft.com/library/en-us/cpref/html/frlrfsystemiofileclasstopic.asp

    or Google "System.IO.File class" if you forget/lose the URL.

    -Dustin Andrews

  • Tuesday, May 22, 2007 8:37 PM
     
     
    This is an old thread...but I'm still using .NET 1.1 and just ran into this same problem, so I thought I'd see if anyone ever found out more about this apparent xcopy/.NET1.1 bug.

    User awm129 reported that adding a "/I" option made xcopy start working, even though "it should not have".  I suspect that this was "randomness" instead.  My own failure mode appears to be "random".    I am calling xcopy from a .NET program and as I have run an identical test case over and over, it has worked about 20% of the time.  There appears to be not pattern, except that it works two or three times in a row, then fails dozens of times in a row.

    M. Bearden
  • Tuesday, May 22, 2007 9:35 PM
     
     
    This was reminding me of other cases I've had in the past where something like "cmd /c COMMAND" would not run, but "cmd /c start /b COMMAND" or something like that would.

    I just hammered on this for a while, and I discovered a way of spawing xcopy with Process.Start() that works consistently. Will document below, in case this ever helps anyone else who is stung by this.

    I should also point out a few details:
    My symptoms are EXACTLY those reported by awm129 above. I'm on Windows Xp, and I have written a generic routine that calls Process.Start() using executable "cmd" and arguments "/c COMMAND" where I am passing in various things for COMMAND, including xcopy. Everything that I pass in except for xcopy works 100% of the time. I got xcopy to work, as I said, about 20% of the time.

    These cases do not work for xcopy:

    cmd /c xcopy ...
    cmd /c start /b xcopy ...
    cmd /c start /b cmd /c xcopy ...
    cmd /c start /b /i cmd /c xcopy ...
    cmd /c start /b /i xcopy ...

    However, in same test case, I found that these next combinations, when passed
    through Process.Start(), DO work 100% of the time for me:

    cmd /c start /i xcopy ...
    cmd /c start /i cmd /c xcopy ...
    cmd /c start /i /min xcopy ...


    I am going to try using the last one because it at least only opens the
    annoying shell window on my toolbar, not on the desktop.

    Go figure! This is a nasty and complex bug, and like I said, this is bringing back
    memories of various other occasions where "chaining" various combinations of
    cmd.exe / start / cmd.exe / start has seemed necessary to get a command to run.
    I seem to recall that most of those cases involved batch files, and some of the time
    the error mode was a shell or batch file that would never exit, even if you called
    'exit'...

    What I'll take away from this: Process.Start() and cmd.exe are BAD NEWS
    when used together.

    M. Bearden
  • Wednesday, May 23, 2007 8:35 AM
    Moderator
     
     Answered
    This is a quirk of xcopy.exe.  If you redirect the output, you have to redirect the input as well.
  • Tuesday, June 19, 2007 6:20 PM
     
     Proposed Answer
    Hans, THANK YOU.   Your tip about redirecting standard input worked and solves my own problems with calling xcopy.exe from .NET code.  

    For anyone else reading, here is the fix.  I was using System.Diagnostics.Process to run
    xcopy in a shell.    My original call, that had repeated intermittent failures, used these options:

                proc.StartInfo.CreateNoWindow = true;
                proc.StartInfo.UseShellExecute = false;
                proc.StartInfo.RedirectStandardOutput = true;
                proc.StartInfo.RedirectStandardError = true;
                proc.Start();

    After I added this line to my setup:

                proc.StartInfo.RedirectStandardInput = true;

    I'm now experiencing a 100% success rate with my xcopy invocations.

    Mark Bearden
    • Proposed As Answer by Mario Hebert Tuesday, September 20, 2011 2:32 PM
    •  
  • Thursday, October 11, 2012 3:40 PM
     
     

    For what it's worth, I'm running XCopy from an ASP.NET web service and while it works on my dev machine, it just opens and closes on the Windows 2008 server.

    Even with redirection all switched off I cannot get XCopy to do anything. It exits with a 0 success code, too.

    A test doing a simple Dir (with redirection etc.) works and returns the output to my client, its just XCopy that's got a bug or some kind of whacky nanny-state Microsoft security thing preventing it from running.

    I'm now going to use Robocopy and see if that works.

  • Thursday, October 11, 2012 5:32 PM
     
     
    Robocopy was all good with /E /Z /EFSRAW /DCOPY:T /PURGE /XO /COPY:DATSO