简体   繁体   中英

C# Process.Start and Process.StartInfo errors

I was trying to open an application (.exe) with a button click on a form using:

System.Diagnostics.Process.Start("C:\\Games\\GameDir\\Game.exe");

and the application executed and displayed the error message "can't find background.jpg, application will now quit."

The .jpg in question was located outside the .exe in a folder called "data" (same directory, ie, C:/Games/GameDir/data). So, I tried using:

System.Diagnostics.ProcessStartInfo pInfo = new System.Diagnostics.ProcessStartInfo();
pInfo.WorkingDirectory = "C:\\Games\\GameDir\\";

//Also tried pInfo.WorkingDirectory = "C:\\Games\\GameDir"; without ending slashes
pInfo.FileName = "Game.exe";
pInfo.UseShellExecute = false;
System.Diagnostics.Process.Start(pInfo);

and the project wouldn't build, because "the system can't find the file specified" (error on Process.Start(pInfo)).

I had to create a shortcut to the executable, and Start that:

System.Diagnostics.Process.Start("C:\\Games\\GameDir\\Game.exe - Shortcut");

And that finally worked.

My question is - why in the world pInfo.WorkingDirectory didn't work? What is so different about the shortcut's "Start in" property of "C:/Games/GameDir" than pInfo.WorkingDirectory = "C:/Games/GameDir"? Are they not the same thing?

WorkingDirectory is only used when UseShellExecute = true . Otherwise, the property is ignored all together and the Filename full path is used. From Microsoft's documentation :

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

To get it working, just delete the working directory assignment and use the path in your filename.

System.Diagnostics.ProcessStartInfo pInfo = new System.Diagnostics.ProcessStartInfo();
pInfo.FileName = "C:\\Games\\GameDir\\Game.exe";
pInfo.UseShellExecute = false;
System.Diagnostics.Process.Start(pInfo);

Many programs suffer from the exact same bug your program died on. They'll have a statement similar to this one in their code:

  var backImage = Image.FromFile(@"data\background.jpg");

That's a relative path name. As opposed to a full path name, like @"c:\\games\\gamedir\\data\\background.jpg. When the operating system is forced to deal with a relative path name then it must use the default drive and the default directory to find a file. Environment.CurrentDirectory in a .NET program.

So when you used "Game.exe", the operating system was forced to used your default directory to create a full path name. To come up with something like "c:\\users\\margot\\documents\\visual studio 2013\\projects\\gamestarter\\bin\\debug\\game.exe". Kaboom, it isn't located there.

The notion of the default working directory is very, very evil and has crashed many a program. It is the worst global variable you can imagine. And has all the problems associated with a global variable, it can change without you noticing and crash your app when you rely on it. Just calling a chunk of code that you didn't write can get it changed. The most notorious example in .NET is the OpenFileDialog class. Forgetting to set its RestoreDirectory property to true is a standard bug.

The notion of a default directory comes from the 1970s, back in the days when everybody started programs by typing their name in a command line interface shell program. Which made it very clear where the default directory was located. You can still see this when you run Cmd.exe, you see the "DOS prompt". But it is pretty evil in a GUI operating system, you can't see it anymore.

There probably isn't anything you can do to get that game fixed. You found the proper workaround, setting ProcessStartInfo.WorkingDirectory is required to keep it happy.

In your own code, just keep the golden rule in mind: never use relative paths when you refer to files in your code. In your program, that should be a configuration setting since you cannot assume that the game will always be installed to c:\\games\\gamedir. Sooner or later, somebody is going to recognize that it belongs in c:\\program files :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM