Error in Process.Start() -- The system cannot find the file specified - c#

I am using the following code to fire the iexplore process. This is done in a simple console app.
public static void StartIExplorer()
{
var info = new ProcessStartInfo("iexplore");
info.UseShellExecute = false;
info.RedirectStandardInput = true;
info.RedirectStandardOutput = true;
info.RedirectStandardError = true;
string password = "password";
SecureString securePassword = new SecureString();
for (int i = 0; i < password.Length; i++)
securePassword.AppendChar(Convert.ToChar(password[i]));
info.UserName = "userName";
info.Password = securePassword;
info.Domain = "domain";
try
{
Process.Start(info);
}
catch (System.ComponentModel.Win32Exception ex)
{
Console.WriteLine(ex.Message);
}
}
The above code is throwing the error The system cannot find the file specified. The same code when run without specifying the user credentials works fine. I am not sure why it is throwing this error.
Can someone please explain?

Try to replace your initialization code with:
ProcessStartInfo info
= new ProcessStartInfo(#"C:\Program Files\Internet Explorer\iexplore.exe");
Using non full filepath on Process.Start only works if the file is found in System32 folder.

You can't use a filename like iexplore by itself because the path to internet explorer isn't listed in the PATH environment variable for the system or user.
However any path entered into the PATH environment variable allows you to use just the file name to execute it.
System32 isn't special in this regard as any directory can be added to the PATH variable. Each path is simply delimited by a semi-colon.
For example I have c:\ffmpeg\bin\ and c:\nmap\bin\ in my path environment variable, so I can do things like new ProcessStartInfo("nmap", "-foo") or new ProcessStartInfo("ffplay", "-bar")
The actual PATH variable looks like this on my machine.
%SystemRoot%\system32;C:\FFPlay\bin;C:\nmap\bin;
As you can see you can use other system variables, such as %SystemRoot% to build and construct paths in the environment variable.
So - if you add a path like "%PROGRAMFILES%\Internet Explorer;" to your PATH variable you will be able to use ProcessStartInfo("iexplore");
If you don't want to alter your PATH then simply use a system variable such as %PROGRAMFILES% or %SystemRoot% and then expand it when needed in code. i.e.
string path = Environment.ExpandEnvironmentVariables(
#"%PROGRAMFILES%\Internet Explorer\iexplore.exe");
var info = new ProcessStartInfo(path);

Also, if your PATH's dir is enclosed in quotes, it will work from the command prompt but you'll get the same error message
I.e. this causes an issue with Process.Start() not finding your exe:
PATH="C:\my program\bin";c:\windows\system32
Maybe it helps someone.

I had the same problem, but none of the solutions worked for me, because the message The system cannot find the file specified can be misleading in some special cases.
In my case, I use Notepad++ in combination with the registry redirect for notepad.exe. Unfortunately my path to Notepad++ in the registry was wrong.
So in fact the message The system cannot find the file specified was telling me, that it cannot find the application (Notepad++) associated with the file type(*.txt), not the file itself.

I know it's a bit old and although this question have accepted an answer, but I think its not quite answer.
Assume we want to run a process here C:\Program Files\SomeWhere\SomeProcess.exe.
One way could be to hard code absolute path:
new ProcessStartInfo(#"C:\Program Files\SomeWhere\SomeProcess.exe")
Another way (recommended one) is to use only process name:
new ProcessStartInfo("SomeProcess.exe")
The second way needs the process directory to be registered in Environment Variable Path variable. Make sure to add it in System Variables instead of Current User Variables, this allows your app to access this variable.

You can use the folowing to get the full path to your program like this:
Environment.CurrentDirectory

Related

pyinstaller .exe works locally but fails when called by C#?

I have created a script using Python2.7 and compiled it using pyinstaller into an exe of the same name, in this case "GeneralStats.py" turns into "GeneralStats.exe" using --onefile and -w arguments.
When called with C# I use:
var pythonDirectory = (Directory.GetCurrentDirectory());
var filePathExe1 = Path.Combine(pythonDirectory + "\\Python\\GeneralStats.exe");
Process.Start(filePathExe1);
When called outside of C#, so in my local files I can run the .exe and the result is a text file with lots of values in (Running correctly).
However, when ran with C# in this format, I get an error that "GeneralStats returned -1!"
Which I have had issues with before, but it was a simple python error that when I returned to my code and ran it, I would receive an error that I overlooked.
This time my python code returns no errors and works outside of C#.
Any ideas of why this could be? I can provide any code or file directories necessary, please just ask if you feel it would help with debugging.
EDIT:
Solved by removing:
var filePathExe1 = Path.Combine(pythonDirectory + "\\Python\\GeneralStats.exe");
Process.Start(filePathExe1);
And replacing with:
ProcessStartInfo _processStartInfo = new ProcessStartInfo();
_processStartInfo.WorkingDirectory = Path.Combine(pythonDirectory + "\\Python");
_processStartInfo.FileName = #"GeneralStats.exe";
_processStartInfo.CreateNoWindow = true;
Process myProcess = Process.Start(_processStartInfo);
You need to set the working directory for the Process - it is probably trying to load files from its working directory but isn't finding them.
See, e.g. this:
Use the ProcessStartInfo.WorkingDirectory property to set it prior to starting the process. If the property is not set, the default working directory is %SYSTEMROOT%\system32.
Set it to the path where GeneralStats.exe is.

C# Environment variable value doesn't get added [duplicate]

This question already has an answer here:
How to set system environment variable in C#?
(1 answer)
Closed 7 years ago.
I'm trying to add a value to the Path environment variable, but I can't seem to get it to work. I've went through a couple of similar questions and I'm pretty sure I have exactly the same code, but still it won't add the variable or I can't see it. I've checked both the administrator and local user account for changes. I've checked both during and after the running (debugging) of the application. I've also close VS2013 completely and checked.
Here's the code I'm using
string path = #"C:\Users\bono\Documents\Visual Studio 2013\Projects\3D-Scanner\AddEnviromentToPath\bin\Debug\AddEnviromentToPath.exe";
ProcessStartInfo process_start_info = new ProcessStartInfo();
process_start_info.FileName = path;
process_start_info.Verb = "runas";
process_start_info.WindowStyle = ProcessWindowStyle.Normal;
process_start_info.UseShellExecute = true;
process_start_info.Arguments = PATH_TO_PCL;
Process.Start(process_start_info); //Process that handles the adding of the value
AddEnviromentToPath program:
class Program {
static void Main(string[] args) {
//Just to make sure we're adding both
AddToEnvironmentPath(args[0], EnvironmentVariableTarget.User);
AddToEnvironmentPath(args[0], EnvironmentVariableTarget.Machine);
}
static void AddToEnvironmentPath(string pathComponent, EnvironmentVariableTarget target) {
string targetPath = System.Environment.GetEnvironmentVariable("Path", target) ?? string.Empty;
if (!string.IsNullOrEmpty(targetPath) && !targetPath.EndsWith(";")) {
targetPath = targetPath + ';';
}
targetPath = targetPath + pathComponent;
Environment.SetEnvironmentVariable("Path", targetPath, target);
}
}
Note that I'm running VS2013 and the main application as a standard user. When the AddEnviromentToPath program runs I get an admin verification panel. I log in here with an admin account.
Edit:
Other people seem to get it working with basically the same code:
How do I get and set Environment variables in C#?
Environment is not being set in windows using c#. Where am I going wrong?
Assuming that Environment.SetEnvironmentVariable calls the Win32 SetEnvironmentVariable function behind the scenes, this note is probably applicable:
Sets the contents of the specified environment variable for the
current process
...
This function has no effect on the system
environment variables or the environment variables of other processes.
If you want to change a global environment variable and have existing processes notice it, you need to:
Save it to the registry under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment
Notify existing processes of the change with the WM_SETTINGCHANGE message.
See the MSDN Environment Variables documentation for more information.
ProcessStartInfo to the rescue!
You need to check this documentation out:
https://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.environmentvariables%28v=vs.110%29.aspx
The key text which addresses your concerns:
Although you cannot set the EnvironmentVariables property, you can
modify the StringDictionary returned by the property.

Process.Start for system32 applications - The System Cannot Find the File Specified

I have written a simple custom shell application for Windows 8.1 systems in WPF. It functions fine, but I need to start some of the applications in the Run section of the registry. Fine and good, however, no matter what I try, they don't launch, and I receive an error: "The system cannot find the file specified."
This is designed for 64 bit systems, so I've heard that using C:\Windows\Sysnative\ for the path rather than C:\Windows\System32\ is a fix, but it didn't work. My code is as follows:
Process processToStart = new Process
{
StartInfo =
{
FileName = #"C:\Windows\Sysnative\hkcmd.exe",
WorkingDirectory = #"C:\Windows\Sysnative\")
}
};
processToStart.Start();
The way I found to get this to work was to disable WOW64 file system redirection. Nothing else seemed to work.
From this link:
http://tcamilli.blogspot.co.uk/2005/07/disabling-wow64-file-system.html
[DllImport("Kernel32.Dll", EntryPoint="Wow64EnableWow64FsRedirection")]
public static extern bool EnableWow64FSRedirection(bool enable);
Wow64Interop.EnableWow64FSRedirection(false)
Process processToStart = new Process
{
StartInfo =
{
FileName = #"C:\Windows\Sysnative\hkcmd.exe",
WorkingDirectory = #"C:\Windows\Sysnative\")
}
};
processToStart.Start();
Wow64Interop.EnableWow64FSRedirection(true)
Not sure if these might be the cause of your issue but from your example posted in the question, note these few points:
StartInfo.FileName should only contain the fileName, not the path.
If you're trying to execute hkcmd.exe, you wrote it as hkcmnd.exe (extra N).
In the example above I believe it effectively looks like specifying the filename and workingdirectory repeatedly causes a file to not be found. See this link I used to check and this link as well
Sysnative was not present on my machine (Win 7 x64), it might be in Windows 8.
I couldn't get hkcmd.exe to execute, it threw an error you had as well, however, executing cmd.exe and notepad.exe is fine.
Sample code:
System.Diagnostics.Process processToStart = new System.Diagnostics.Process();
processToStart.StartInfo.FileName = "cmd.exe"; //or notepad.exe
processToStart.StartInfo.WorkingDirectory = #"C:\Windows\System32\";
processToStart.Start();

Unable to launch shortcut (lnk) files from 32-bit C# application when the full path resolves to a 64-bit directory

I'm trying to launch programs in the Start Menu from a C# application, and nearly all of the items in the Start Menu are shortcut (lnk) files. When using Process.Start to launch these files, I found that I was getting "The system cannot find the path specified" error if the full path of the lnk file pointed to the C:\Program Files directory. I did some research with File System Redirection in Windows, so I tried disabling it, but I'm still getting the same error:
// disable file system redirection:
IntPtr ptr = new IntPtr();
bool isWow64FsRedirectionDisabled = Wow64DisableWow64FsRedirection(ref ptr);
// run the file:
System.Diagnostics.Process.Start("c:\\splitter.lnk");
This returns "The system cannot find the path specified." However, if I launch c:\splitter.lnk from the Start > Run dialog box, the program runs just fine. You can reproduce this issue on any 64-bit machine by creating a shortcut for any 64-bit app, placing it on the C drive, and attempting to run it using the code above.
Is there a better way to launch .lnk files to avoid this problem? Or am I not disabling file redirection properly?
EDIT: I also tried setting UseShellExecute to true to have the operating system run the file, but that still fails, which is interesting because running the same path from the Start > Run dialog box works just fine:
Process process = new Process();
process.StartInfo.UseShellExecute = true;
process.StartInfo.FileName = "c:\\splitter.lnk";
process.Start();
EDIT 2: I figured that instead of trying to launch the LNK file directly, I would get the target for it, and then run the target. I tried using How to resolve a .lnk in c# and How to follow a .lnk file programmatically, but both methods return the full path as C:\Program Files (x86)\Splitter.exe instead of the actual path of C:\Program Files\Splitter.exe.
Perhaps I can use one of the above methods to get the target of the LNK file. Then I can see if the target contains Program Files (x86). If it does, replace it with Program Files and check if the file exists. If it exists in Program Files, run that. If not, run the file from the Program Files (x86) location. This would be a messy workaround, but I don't know what else to try at this point. Any suggestions would be appreciated.
I was able to provide a workaround for this issue by using Sam Saffron's example script at How to resolve a .lnk in c#. I modified the ResolveShortcut function to the following:
public static string ResolveShortcut(string filename)
{
// this gets the full path from a shortcut (.lnk file).
ShellLink link = new ShellLink();
((IPersistFile)link).Load(filename, STGM_READ);
StringBuilder sb = new StringBuilder(MAX_PATH);
WIN32_FIND_DATAW data = new WIN32_FIND_DATAW();
((IShellLinkW)link).GetPath(sb, sb.Capacity, out data, 0);
string final_string = sb.ToString();
if (final_string.Length == 0)
final_string = filename;
// If the the shortcut's target resolves to the Program Files or System32 directory, and the user is on a
// 64-bit machine, the final string may actually point to C:\Program Files (x86) or C:\Windows\SYSWOW64.
// This is due to File System Redirection in Windows -- http://msdn.microsoft.com/en-us/library/aa365743%28VS.85%29.aspx.
// Unfortunately the solution there doesn't appear to work for 32-bit apps on 64-bit machines.
// We will provide a workaround here:
string new_path = Validate_Shortcut_Path(final_string, "SysWOW64", "System32");
if (File.Exists(new_path) == true && File.Exists(final_string) == false)
{
// the file is actually stored in System32 instead of SysWOW64. Let's update it.
final_string = new_path;
}
new_path = Validate_Shortcut_Path(final_string, "Program Files (x86)", "Program Files");
if (File.Exists(new_path) == true && File.Exists(final_string) == false)
{
// the file is actually stored in Program Files instead of Program Files (x86). Let's update it.
final_string = new_path;
}
// the lnk may incorrectly resolve to the C:\Windows\Installer directory. Check for this.
if (final_string.ToLower().IndexOf("windows\\installer") > -1)
final_string = filename;
if (File.Exists(final_string))
return final_string;
else
return filename;
}
public static string Validate_Shortcut_Path(string final_string, string find_what, string replace_with)
{
string final_string_lower = final_string.ToLower();
string find_what_lower = find_what.ToLower();
int find_value = final_string_lower.IndexOf(find_what_lower);
if (find_value > -1)
{
// the shortcut resolved to the find_what directory, which can be SysWOW64 or Program Files (x86),
// but this may not be correct. Let's check by replacing it with another value.
string new_string = final_string.Substring(0, find_value) + replace_with + final_string.Substring(find_value + find_what.Length);
if (File.Exists(new_string) == true && File.Exists(final_string) == false)
{
// the file is actually stored at a different location. Let's update it.
final_string = new_string;
}
}
return final_string;
}
If anyone is aware of a better way to do this, I am open to ideas. Otherwise I will use this method and accept this workaround as the answer.

How to get the exact path of notepad.exe in order to associate a file extension

I need to associate a file extension I have created “.rulog” with notepad.exe as part of a setup project installation for a windows 7 machine (it’s here since we require admin privileges to write to the registry).
Basically I need to obtain programmatically the exact path of the notepad.exe. Now, I understand that it typically lives in C:\Windows\system32. This is part of PATH system environment variable, so I guess I could loop through all the PATH variables and test if “notepad.exe” exists by combining “notepad.exe” with the current path using File.Exists. However this feels very clumsy.
Essentially I need to add an entry to
Computer\HKEY_CLASSES_ROOT\.rulog\shell\open\command\
with the value of the path of notepad.
Incidentally I can see that .txt in:
Computer\HKEY_CLASSES_ROOT\.txt\ShellNew
has a value for ItemName of
“#%SystemRoot%\system32\notepad.exe,-470”
Perhaps I can just copy this value? Or is this dangerous?(e.g. does not exist).
You can use:
Environment.GetEnvironmentVariable("windir") + "\\system32\\notepad.exe";
Or even easier:
Environment.SystemDirectory + "\\notepad.exe";
That way it doesn't matter which drive the os is on.
Copying the value with %systemroot% should be just fine. If it works for the OS, it should work for you!
Fool-proof solution:
string NotepadPath = Environment.SystemDirectory + "\\notepad.exe";
if (System.IO.File.Exists(NotepadPath))
{
Microsoft.Win32.Registry.SetValue("HKEY_CLASSES_ROOT\\.rulog\\shell\\open\\command\\", "", NotepadPath + " %1");
}
else
{
//do something else or throw new ApplicationException("Notepad not found!");
}

Categories