I have this folder on my windows Path environment variable: C:\bin
I have a tool named 7z inside C:\bin\7z\7z.exe.
If I open any shell, like Powershell I can run the command "7z" and it works fine, the executable is found and it runs (And where.exe 7z prints out C:\bin\7z\7z.exe). The fact that the executable is inside a folder named after itself doesn't get in the way of the executable being found. The folder and the executable inside the folder seem to have to be named exactly as the program I am trying to run.
However, when running code in C# to run the executable, it is not found.
ProcessStartInfo startInfo = new ProcessStartInfo() {
UseShellExecute = false,
CreateNoWindow = true,
FileName = "7z",
Arguments = $"-h",
};
var p = Process.Start(startInfo); // Throws
I know that Process.Start supports Path environment variables here as I can successfully run this code for other executables that are not in inner folders.
My questions are:
Why isn't Process.Start able to find the executable?
Is having a directory named after the executable a supported and documented way to find executables with a Path directory? Where can I read this documentation?
If you set ProcessStartInfo.UseShellExecute to false, you must supply the full path to your executable. In this case Process.Start will call the CreateProcess function. From the documentation:
The string can specify the full path and file name of the module to execute or it can specify a partial name. In the case of a partial name, the function uses the current drive and current directory to complete the specification. The function will not use the search path. This parameter must include the file name extension; no default extension is assumed.
If you use ShellExecute true, the shell's best guest for 7z will be the directory, as you dont supply the .exe extension.
Related
If you save an email to a file on disk with an EML extension, you can open it in Outlook on Windows just by double-clicking the file. I'm hoping to do something similar as my application can encounter EML files that it needs to open.
I have some crude test code that has:
using System;
using System.Diagnostics;
using System.IO;
and then:
System.Diagnostics.Process.Start(#"C:\temp\test.eml");
When I run the code I get the following exception:
System.ComponentModel.Win32Exception: 'An error occurred trying to
start process 'C:\temp\test.eml' with working directory
'C:\Users\me\source\repos\TestProj\TestProj\bin\Release\net6.0-windows'.
The specified executable is not a valid application for this OS
platform.'
I have tried placing a simple text file in the same folder and named it 'test.txt' and checked that it opens in Notepad when I double-click it, but if I try to open it with:
System.Diagnostics.Process.Start(#"C:\temp\test.txt");
I get the same error. Where am I going wrong?
There was a breaking change in .NET Core compared to .NET Framework:
Change in default value of UseShellExecute
ProcessStartInfo.UseShellExecute has a default value of false on .NET Core. On .NET Framework, its default value is true.
Change description
Process.Start lets you launch an application directly, for example, with code such as Process.Start("mspaint.exe") that launches Paint. It also lets you indirectly launch an associated application if ProcessStartInfo.UseShellExecute is set to true. On .NET Framework, the default value for ProcessStartInfo.UseShellExecute is true, meaning that code such as Process.Start("mytextfile.txt") would launch Notepad, if you've associated .txt files with that editor. To prevent indirectly launching an app on .NET Framework, you must explicitly set ProcessStartInfo.UseShellExecute to false. On .NET Core, the default value for ProcessStartInfo.UseShellExecute is false. This means that, by default, associated applications are not launched when you call Process.Start.
Use Process.Start overload accepting ProcessStartInfo and set UseShellExecute to true:
var processStartInfo = new ProcessStartInfo
{
FileName = #"C:\temp\test.eml",
UseShellExecute = true
};
Process.Start(processStartInfo);
Otherwise provide path to executable and pass path to file as a parameter:
var pathToOutlook = #"C:\Program Files\Microsoft Office\root\Office16\OUTLOOK.EXE";
Process.Start(pathToOutlook, #"D:\Downloads\sample.eml");
I generate a ProcessStartInfo by referencing a filename-only executable, without giving the absolute path. I expect the operating system to resolve the concrete location by using the PATH environment variable.
However, on some installations, the PATH variable is not set correctly and upon starting the Process by calling Process.Start() it will throw a
System.ComponentModel.Win32Exception
The system cannot find the file specified
Are there programmatic options to check if the Process.Start will work beforehand?
I tried to use File.Exists(fileName), but this does only work for files located in the applications working directory.
In the command prompt you could use the following call to determine if it will work:
//example where a file is found
C:\>where calc.exe
C:\Windows\System32\calc.exe
//example where a file is not found
C:\>where foo.exe
INFO: Could not find files for the given pattern(s).
Is there something alike in .net to determine beforehand if the file path can be resolved so that Process.Start() will not throw?
I have implemeneted a method into my c# program to run a batch file, which runs a virus scan on any files uploaded;
public static Int32 ExecuteCommand(String filePath, Int32 Timeout){
Int32 ExitCode;
ProcessStartInfo ProcessInfo = new ProcessStartInfo();
ProcessInfo.CreateNoWindow = true;
ProcessInfo.UseShellExecute = true;
ProcessInfo.FileName = filePath;
Process proc = Process.Start(ProcessInfo);
proc.WaitForExit(Timeout);
ExitCode = proc.ExitCode;
proc.Close();
return ExitCode;
}
Ok now my batch file;
#ECHO OFF
c:
cd "..\AVG\AVG9\"
avgscana.exe /SCAN="..\learninglounge.com.solar.quarantine\" /REPORT="..\learninglounge.com.solar.antivirus\virusReports\report.txt"
EDIT : I do have fully qualified link to avg exe and directories but have replaced here with .. for purposes of posting to stackoverflow. Sorry if this caused confusion.
So my problem is the reporting side of my batch file. I can double click the batch file and it scans and creates the report no problem. When i run it through my c# i get an exit code of 2; command not recognised. It's fine if i remove the report part of my batch file. Now obviously this points to write permissions but I have checked that and the impersonated user has write access on the directory. Is there anything Im missing?
Thanks all
The error states that avgscana.exe isn't located in directory which is set as "current" when you execute command. When you click on your bat file in Windows Explorer current directory is set to directory where bat file is located. Probably your avgscana.exe is located in the same folder so it works fine.
When you execute the command from .Net application current directory remains the same (if you haven't changed it then it will be a folder where .Net app is located). If your .Net app is located not in the same folder as bat file then you will get an error which you're actually getting. You should either specify a full path in your bat file or set Environment.CurrentDirectory in .Net app before launching bat.
HAve You checked that all enviromental variables are set exactly the same as You run the batch file from cmd line. I am pretty sure that there might be some differences. Also what kind of operating system is it. If this requires elevation (vista windows 7) You might actually need to impersonate appropriate user in code.
luke
Ok well ive done a work around, id rather have saved the report there and then but instead i just catch the standard output from the process and then save to a file + any processing.
Weird one this.
In your batch file, you have:
c:
cd "..\AVG\AVG9\"
avgscana.exe
/SCAN="..\learninglounge.com.solar.quarantine\"
/REPORT="..\learninglounge.com.solar.antivirus\virusReports\report.txt"
When the command is executed, the 'current' directory on drive C: is ambiguous. You just move up the directory tree. Same with the avgscana.exe command, you make relative references instead of absolute.
Are you certain that the CD command has brought you to the correct directory? Change the CD command to an absolute reference ( cd "c:\wherever\avg\avg9\" ), and that way you can be sure your avgscana command's relative references are found.
Your CD command may be failing silently but your avgscana.exe may be in your path, so it does get executed, but since the relative /scan and /report locations are not found, it fails with a code 2.
Good luck!
I'm having problems running a process from my program.
When I start the process it says "Cannot find Tibia.dat!" ( it thinks the exe file is located in project directory, when it isn't ).
So when I start the process in my program ( from: C:\program\Tibia\Tibia.exe ) it says "Cannot find C:\user\marcus\my documents\visual studio 2009\blablalba\Tibia.dat".
Here's the code I'm using:
Process.Start(addressToFirstTibia + "\\Tibia.exe");
Grateful for help !!
You need to set the working directory. Tibia.exe probably expects it to be the same as the executable's directory, so try:
Process.Start(new ProcessStartInfo {
FileName = Path.Combine(addressToFirstTibia, "Tibia.exe"),
WorkingDirectory = addressToFirstTibia
});
Is Tibia.exe looking for Tibia.dat internally? It may be detecting somehow that the "current working directory" is the project directory, not its own executable directory.
There's a property called WorkingDirectory on ProcessStartInfo that may solve this issue for you. Info can be found here.
I am running my C# application from "D:\App\program.cs". My application needs to execute a file placed in "C:\Program Files\software\abc.exe".
How can I set the relative path in my program to execute the "abc.exe"?
To answer the question how to get a path that shows the relative location of pathB from pathA. You can use the Uri class to get the relative path.
string pathA = #"C:\App\program.cs";
string pathB = #"C:\program files\software\abc.exe";
System.Uri uriA = new Uri(pathA);
System.Uri uriB = new Uri(pathB);
Uri relativeUri = uriA.MakeRelativeUri(uriB);
string relativeToA = relativeUri.ToString();
Console.WriteLine(relativeToA);
This yields "../program%20files/software/abc.exe" for the relative path.
I have changed your example from D to C though because you can't have a relative path for two locations on different drive letters, although the above code still works, just yields the absolute.
OR if the c# bit is a red herring, and as I now understand you want to run a batch file:
in batch file put:
cd c:\program files\software\
abc.exe
abc.exe will then execute from software folder and not folder of the batch file.
You shouldn't be using relative path for referring something from Program Files. I would recommend to use Environment.GetFolderPath (and Environment.SpecialFolder) to get path to Program Files and then use some config setting to get reminder path to the program.
It's not clear what you mean by "set relative path", but if you're using Process and ProcessStartInfo to run the executable, I would suggest that you use an absolute path to specify the executable, and ProcessStartInfo.WorkingDirectory to tell the process where to run (so that relative paths will be evaluated appropriately within the new process).
EDIT: If you want the batch file to run c:\Program Files\Software\abc.exe then the contents of the batch file should be just:
"c:\Program Files\Software\abc.exe"
(Note the quotes to allow for space.)
I don't see what this has got to do with relative pathnames though.
If the application is in Program Files then you can create a batch file like
"%ProgramFiles%\software\abc.exe"