Conventions for passing the arguments to a process

A process's main() function gets an array of strings for the command line args. This is string[]  in C#, or {int argc, char** argv} in C/C++.  But there are some different conventions for how the parent app passes those strings in.

If you execute a program on the command line like:
myapp.exe myfile.txt second.txt

The CLR invokes the main method like main(new string[] { "myfile.txt", "second.txt"} ). That's generally what the user expects.

However, the C/C++ convention is that the first argument is actually the application's name. So a C main function would be invoked as main(3 /* number of args */, {"myapp.exe", "myfile.txt", "second.txt"}).

The key OS API is to create a process is kernel32!CreateProcess and the other mechanisms (eg: ICorDebug::CreateProcess, Process.Start) boil down to this.  The parent process is supposed to pass the application name as the first command line arg to CreateProcess to honor the C convention. When a managed app spins up, the CLR will do extra work to compensate for this convention by stripping off the first arg from the arg[] array it passes to Main().
 

What's the problem?
A common problem is calling CreateProcess (either in kernel32 or at ICorDebug) directly and forgetting to pass in the application name for the first argument. The System.Diagnostics.Process makes this easier to avoid by explicitly exposing properties for the command line.

A walkthrough: Suppose you want to execute application "myapp.exe" with args "myfile.txt" and "second.txt":

1) At the command prompt:
Enter:
    myapp.exe myfile.txt second.txt

2) with kernel32!CreateProcess:
Calling CreateProcess (ICorDebug::CreateProcess has the same semantics)
Let applicationName = "myapp.exe", commandline = "myapp.exe myfile.txt second.txt", so you'd call:

    CreateProcess("myapp.exe", "myapp.exe myfile.txt second.txt", ...)

In C++, argv[] = {"myapp.exe", "myfile.txt", "second.txt" }. In C#, args[] = { "myfile.txt", "second."txt"}. The equivalent of argv[0] can be retrieved by reflection.
 

Now if you forgot to add myapp.exe in the command line and called  CreateProcess("myapp.exe", "myfile.txt second.txt", ...), then in C#, args[] = {"second.txt"}, and you effectively lost your command line.

3) System.Diagnostics.Process 
With the managed Process object, it would look like:

ProcessStartInfo s = new ProcessStartInfo("myapp.exe";
s.Arguments = "myfile.txt second.txt"
Process.Start(s);

or

    Process.Start("myapp.exe", "myfile.txt second.txt");

I think it's very misleading that Process.Start() overload that takes an {application name, command line string}like CreateProcess in fact has very different semantics about handling the command line. You can use reflector on Process.Start() to see exactly how it boils down to ultimately CreateProcess.

See more examples of Process.Start here.