tags:

views:

864

answers:

4

I have an MSBuild task that executes (among other things) a call to xcopy. What I have found is that this call to xcopy executes correctly when I run my MSBuild task from a batch file, and fails to execute or produce any output that would allow me any idea what is going on when that same batch file is called from another C# application with a System.Diagnostics.Process.

Both processes are launched with more or less the same structure:

waitProc.StartInfo.Arguments = "/C [executable]";
waitProc.StartInfo.FileName = "cmd.exe";
waitProc.StartInfo.UseShellExecute = false;

Furthermore by changing the "UseShellExecute" from false to true on the xcopy command I can make this succeed in both use cases, however the command fails to run in a third use case. The third use case being our automated build system which is a windows service calling msbuild directly. In the case of the failure on our build machine the copy command hangs indefinitely which is, I believe, because the System.Diagnostics.Process tries to display a window, and services do not have a Windows desktop session associated with them, so they cannot display windows.

I have tried using the "CreateNoWindow" property, and I've tried setting the "WindowStyle" to "ProcessWindowStyle.Hidden," but that does not change the behavior on the build machine.

All of this said, what I really want to know is what exactly the UseShellExecute property does, because it seems to do a whole lot more than the MSDN documentation suggests.

Thanks.

A: 

From the Documentation:

Setting this property to false enables you to redirect input, output, and error streams.

Note: UseShellExecute must be false if the UserName property is not a null reference (Nothing in Visual Basic) or an empty string, or an InvalidOperationException will be thrown when the Process.Start(ProcessStartInfo) method is called. When you use the operating system shell to start processes, you can start any document (which is any registered file type associated with an executable that has a default open action) and perform operations on the file, such as printing, with the Process component. When UseShellExecute is false, you can start only executables with the Process component.

Note: UseShellExecute must be true if you set the ErrorDialog property to true. The WorkingDirectory property behaves differently when UseShellExecute is true than when UseShellExecute is false. When UseShellExecute is true, the WorkingDirectory property specifies the location of the executable. If WorkingDirectory is an empty string, the current directory is understood to contain the executable.

When UseShellExecute is false, the WorkingDirectory property is not used to find the executable. Instead, it is used by the process that is started and has meaning only within the context of the new process.

Nick
+5  A: 

ProcessStartInfo.UseShellExecute tells the Process to use the Windows Shell to execute the specified application.

Without this set, you can only execute an EXE file directly. By setting this, you allow the Windows Shell to be used, which allows things such as specifying a .doc file and having the associated program open the file.

However, using the Windows Shell requires a valid desktop context, which is why your third use case fails.

In general, using cmd.exe is problematic unless you're using the Windows Shell. You may want to just write the code to handle your "batch" operation directly - ie: use the methods from types in the System.IO namespace to do your copying. This would avoid this issue entirely.

Reed Copsey
Do you have any idea why it needs a valid desktop context? I kinda assumed that was the case when it was hanging on the build machine, but I really don't understand why the windows shell would need the ability to draw to the screen.
Chris
@Chris: The "windows shell" is basically explorer, and is launched when you actually login. Unfortunately, this is a common issue with batch files on build machines - I've seen a lot of people struggle with it, and I've switched to just writing my "scripts" in C# directly to avoid the issue ;)
Reed Copsey
A: 

The use of 'UseShellExecute' IIRC, is to allow explorer (the main shell) to execute the process and not the .NET runtime....unless somebody corrects me that I'm wrong...

tommieb75
this property tells operating system to execute this app by console or by shell.
Andrey
@Michael - Why did you remove the signature? Surely I thought I was being polite there by saying 'best regards' instead of having none at all which is deemed rude....what's your logic? FYI - I have answered over 800 questions and not one complaint...I get a nice 'Thank you Tom' when I answered someone's question correctly or has Political Correctness gone mad! sigh
tommieb75
A: 

did you specify WorkingDirectory correctly? You can see actual output of your command by adding >c:\log.txt 2>c:\err.txt run it wil this addition and check those files

Andrey