This is a silly and tricky issue that I am facing.
The below code works well (it launches Calculator):
ProcessStartInfo psStartInfo = new ProcessStartInfo();
psStartInfo.FileName = #"c:\windows\system32\calc.exe";
Process ps = Process.Start(psStartInfo);
However the below one for SoundRecorder does not work. It gives me "The system cannot find the file specified" error.
ProcessStartInfo psStartInfo = new ProcessStartInfo();
psStartInfo.FileName = #"c:\windows\system32\soundrecorder.exe";
Process ps = Process.Start(psStartInfo);
I am able to launch Sound Recorder by using Start -> Run -> "c:\windows\system32\soundrecorder.exe" command.
Any idea whats going wrong?
I am using C# in Visual Studio 2015 and using Windows 7 OS.
UPDATE 1: I tried a File.Exists check and it shows me MessageBox from the below code:
if (File.Exists(#"c:\windows\system32\soundrecorder.exe"))
{
ProcessStartInfo psStartInfo = new ProcessStartInfo();
psStartInfo.FileName = #"c:\windows\system32\soundrecorder.exe";
Process ps = Process.Start(psStartInfo);
}
else
{
MessageBox.Show("File not found");
}
Most likely your app is 32-bit, and in 64-bit Windows references to C:\Windows\System32 get transparently redirected to C:\Windows\SysWOW64 for 32-bit apps. calc.exe happens to exist in both places, while soundrecorder.exe exists in the true System32 only.
When you launch from Start / Run the parent process is the 64-bit explorer.exe so no redirection is done, and the 64-bit C:\Windows\System32\soundrecorder.exe is found and started.
From File System Redirector:
In most cases, whenever a 32-bit application attempts to access %windir%\System32, the access is redirected to %windir%\SysWOW64.
[ EDIT ] From the same page:
32-bit applications can access the native system directory by substituting %windir%\Sysnative for %windir%\System32.
So the following would work to start soundrecorder.exe from the (real) C:\Windows\System32.
psStartInfo.FileName = #"C:\Windows\Sysnative\soundrecorder.exe";
Old thread but providing one more possible case
In my case i was using arguments inside Process.Start
System.Diagnostics.Process.Start("C:\\MyAppFolder\\MyApp.exe -silent");
I changed it to
ProcessStartInfo info = new ProcessStartInfo("C:\\MyAppFolder\\MyApp.exe");
info.Arguments = "-silent";
Process.Start(info)
Then it worked.
One more case, similar to Ranadheer Reddy's answer, but different enough to trip me up for awhile.
I was making a simple mistake. I had this:
ProcessStartInfo info = new ProcessStartInfo("C:\\MyAppFolder\\MyApp.exe ");
info.Arguments = "-silent";
Process.Start(info);
See that space after the end of the path to the app? Yeah. It doesn't like that. It will not find your file if you include that.
The solution was to remove the extraneous space. Then it worked.
This is an easy enough mistake to make if you're converting an app from starting processes by launching "cmd.exe /c MyApp.exe -silent" to running "MyApp.exe" directly instead, which is what I was doing. I hope recording my misfortune here will help future developers.
Related
Our test and development team has been working to implement and test a new version of our software using .NET 6 that we will be releasing early next year. For test's part, we have had to upgrade all of our C# automated testing to be cross-platform compatible. One set of tests requires starting a new process and executing a console application we have as a supporting library. Below is the following code I am using:
#if (WINDOWS)
string strCmdText = "/C \" SAT.FCCHandling -l" + password + " -i" + ip + " -xDeleteFCC\"";
#endif
#if (LINUX)
string strCmdText = "-c \" .//SAT.FCCHandling -l" + password + " -i" + ip + " -xDeleteFCC\"";
#endif[![enter image description here](https://i.stack.imgur.com/6SYCA.png)](https://i.stack.imgur.com/6SYCA.png)
using (var proc = Process.Start(new ProcessStartInfo
{
#if (WINDOWS)
FileName = "cmd.exe",
#endif
#if (LINUX)
FileName = "/bin/bash",
#endif
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true,
Arguments = strCmdText,
WindowStyle = ProcessWindowStyle.Hidden
}))
{
proc.WaitForExit();
if (proc.ExitCode != 0)
{ Assert.Fail("There was an issue Inserting an invalid FCC."); }
}
I have been using VSCode in Linux to debug problems that arise. When the code above is executed in Linux (specifically in Ubuntu 20.04), in the developer console it's indicating that the location for .NET is not found:
We also use TShark for packet capture in some testing. The methodology of code is used in launching TShark as a new process. I bring this up not because TShark is written in C# with .NET 6, but merely to point out that this approach for launching an application does work.
The problem, as I perceive it, is this child process being launched has no knowledge of environment variables. If I launch the application directly from the terminal in the binary directory, the application runs just fine.
I have done some digging and research online before posing this question. I haven't found anything that is exactly similar to my problem. I have tried a couple avenues based upon what I have read online, but these don't seem to be the right solution:
Assigning all variables to the StartInfo of the new process.
Assigning specifically EnvironmentVariables["TEST_ENV"] = "From parent"; to the Process.StartInfo. I saw something online that seemed to indicate that passing environment variables down to the child process was a necessity as the variables are instances.
Using the StartInfo.Verb = “runas” to elevate the privileges of the process.
I know that the solution is probably an obvious one that I'm just not seeing. I am not a Linux expert by any stretch of the imagination and have been having to learn as I go through this release. Any guidance is much appreciated and I'm happy to provide further information if necessary. Thank you.
I spent some time during the holidays researching, debugging, and testing. I was able to find a solution to my problem. Several things:
In order to know exactly what was happening to my process on launch, I attached two threads to the standard output and standard error of the process I start.
This lead me to discover that the file location was unknown to bash when calling it.
With this resolved, I discovered that I needed to execute 'chmod +x ' before executing the console application.
It's worthy of note that by trying to debug my problem from a .NET 6 console app (launching another console app) was injecting a different kind of problem into my existing problem. Using my existing NUnit testing that calls the console app was what lead me to the discovery noted above.
Lesson learned: If trying to call a .exe in Linux from your .NET 6 application by starting a process, be sure to make the file executable before you try calling it with bash or another shell.
I've seen a very similar question asked before, here, however the answer thread fell apart. Basically, I installed Python (and checked the option to add to the Path variable), confirmed that it is indeed in the path variable (through the Environment Variables window like you would normally).
When opening a cmd window manually, I can type python -V and get the version back, and anything else really, and everything works fine, python is indeed exposed through the command prompt (when opened manually).
However, when I attempt to run a command through cmd.exe with a C# app I have, I get
'python' is not recognized as an internal or external command,
operable program or batch file.
The block of C# code I have
var proc = new Process();
var startInfo = new ProcessStartInfo
{
UseShellExecute = true,
FileName = "cmd.exe",
Arguments = "/K " + command
};
proc.StartInfo = startInfo;
proc.Start();
This has worked fine in the past. However I had my work machine upgraded to Windows 10 and have been struggling to get this working.
The command text hasn't changed since the application was working before my windows upgrade, and if I take it's text and run it through a manually opened command prompt it executes fine with no issues. So I'm hesitant to believe it's an issue with the command itself.
UPDATE: If I run echo %PATH% in a regular prompt I see python, if I run it in the command prompt my application opens, I do not. I tried using set PATH, but that didn't help. Why is it that the PATH variable is different between a command prompt I open manually and one my application opens?
I thought it might have something to do with User and System variables having their own path, but Python is in both of them when checked via System Properties, so I'm at a loss.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
.Net Process.Start default directory?
I have a C# application, mono to be specific. This application needs to launch another application on the users system. I know of Process.Start and how to use it, but theres something pecuilar about this instance which makes that not work correctly.
For some reason the program I am trying to launch via Process.Start needs to be called from the directory it resides in, otherwise it gives an error on opening.
What I mean by that is, if I open up a command prompt and type in:
C:\appFolder\app.exe
The application will then give me an error.
However if I open a prompt and go:
cd c:\appFolder
app.exe
It then launches just fine.
The problem I am having with process.start is it tries to open the application without first doing what is the equivalent of 'cd c:\appFolder', and so the application gives an error on opening.
So how can I do make Process.Start do what would be the equivalent of first navigating to the apps folder 'cd c:\appFolder' and then calling app.exe?
BTW, I have solved this problem by putting
cd C:\appFolder
app.exe
into a .bat file, and have Process.Start open the .bat file, which works just fine. But I am curious to know if there is a way to cut out the .bat file.
Using cd blah just changes your working directory. You can set the working directory of your process by setting the WorkingDirectory of your ProcessStartInfo. Perhaps something like this:
var procInfo = new ProcessStartInfo("app.exe");
procInfo.WorkingDirectory = #"C:\appFolder";
Process.Start(procInfo);
try changing the working directory before your call
Directory.SetCurrentDirectory(#"path");
http://msdn.microsoft.com/en-us/library/system.io.directory.setcurrentdirectory.aspx
var psi = new ProcessStartInfo("app.exe");
psi.WorkingDirectory = #"C:\appFolder";
Process.Start(psi);
Use a ProcessStartInfo object to start the application and set the WorkingDirectory property accordingly.
I’m trying to launch an application (Operating System, My Application and the application I want to launch are all 32 bits), from .NET 3.51.
The code that launches the Process is used for other applications, but there’s one that is giving us a headache. If we “double click” on the application’s icon, it works as expected, meaning that it works fine as an application in the computer. Double clicking the .exe directly, also works.
The operating system is Windows 7 32Bits (Home and/or Professional).
Our .NET application is compiled with x86 to avoid problems.
The code that launches “Processes” is located inside a DLL (also 32 bits) made by us, basically it’s a simple DLL that holds some “Common Code” across the board, common methods, functions and stuff we use throughout our code. One of those methods look like this:
public static bool FireUpProcess( Process process, string path, bool enableRaisingEvents,
ProcessWindowStyle windowStyle, string arguments )
{
if ( process != null )
{
try
{
process.StartInfo.FileName = #path;
if ( arguments != null )
{
if ( arguments != String.Empty )
{
process.StartInfo.Arguments = arguments;
}
}
process.StartInfo.WindowStyle = windowStyle;
process.EnableRaisingEvents = enableRaisingEvents;
process.Start();
}
catch
{
try
{
process.Kill();
}
catch ( InvalidOperationException )
{
} // The process is not even created
return false;
}
}
else
{
return false;
}
return true;
}
I don’t know who wrote this method, but it has been working for roughly six years with different applications, therefore I assume it’s “ok”. However, we have a customer with a piece of software that won’t launch when passed through that argument.
The arguments are:
process is a System.Diagnostics.Process created with a simple "new Process();”
path is a full path to the .exe “c:/path/to/my.exe”.
enableRaisingEvents is false
windowStyle is Maximized (but have tried others).
It gives a crappy MessageBox… which I have happily immortalized. It’s in spanish but the translation ought to be easy:
It says:
Application Error
An unexpected exception has occurred for the program (0x0eedfade) at …
Googling that 0x0eedfade gives strange results that look scary, but the truth is, if I go to the .exe that I’m trying to launch and double click it, it works perfectly.
For The Record: If I try to launch other things (I.e.: Notepad.exe, Adobe Acrobat Reader) it works, but Firefox doesn’t open and doesn’t show an error.
This “some work, some doesn’t” behavior leads me to believe that there might be a problem with a Windows 7 security mechanism or similar that I don’t know.
What am I missing or doing wrong?
UPDATE: Ok; I’ve gotten a copy of the software. It’s a messy software but it works. Now that I can debug, I see that the program gives an error when launched with my FireUpProcess method.
As suggested I added the WorkingDirectory code, but here’s the code:
public static bool FireUpProcess(Process process, string path, bool enableRaisingEvents, ProcessWindowStyle windowStyle)
{
if (process != null)
{
try
{
if ( !String.IsNullOrEmpty(#path) )
{
process.StartInfo.FileName = #path;
process.StartInfo.WorkingDirectory = System.IO.Path.GetDirectoryName(#path);
process.StartInfo.WindowStyle = windowStyle;
// Suscribe to the exit notification
process.EnableRaisingEvents = enableRaisingEvents;
// Disable to prevent multiple launchs
Framework.Check.LogWarning("LAUNCHING EXTERNAL DEVICE WITH PATH: " + path);
process.Start(); // HERE The program reports the following:
That means, “The program could not be started because ddip.dll is missing… try reinstalling bla bla”.
The thing is, if I execute the same #path from the command line, the program opens perfectly:
That opens the program. And the same happens if I click on the “shortcut” that it’s located in the “programs” menu. There aren’t any parameters in that shortcut, it’s a simple call to the executable file.
So the question is now: What is the difference between my code and the other methods?
There has got to be something different that causes my process not to start.
Any ideas?
UPDATE AND SOLUTION
I made it work by using one of the below provided answers. Turns out that none directly pointed me to the solution, but they all gave me good ideas here and there.
I added an app manifest to our application (should have had it since the age of vista, don’t know why it wasn’t there in the 1st place). The app manifest I added by using VStudio 2008 add file -> app manifest.
In it, I made sure we have this:
<requestedExecutionLevel level=“asInvoker” uiAccess=“false” />
We don’t need admin or anything like that, but apparently Vista/7 need to know it.
After that was added, the process is correctly launched.
note: UseShellExecute is true by default (as suggested by some), you have to explicitly turn it to false if that’s what you want.
You are not setting the process.StartInfo.WorkingDirectory property. There's plenty of poorly written software out there that assumes the working directory will be the directory in which the EXE is stored. At least add this line:
process.StartInfo.WorkingDirectory = System.IO.Path.GetDirectoryName(#path);
The exception is however rather strange. I'd definitely recommend you tell the customer to update their anti-malware tools.
If the exe has a manifest, you should set UseShellExecute to true on the process object before you call Start. It's not a bad idea in any case.
As Kate Gregory pointed out, if you want to "emulate" the user double clicking on the icon, you have to set UseShellExecute to true. Setting this flags make the code use a totally different path, using the underlying windows ShellExecute function.
Now, I will add to this, that if you're running on a UAC-equipped Windows (Vista, 7, 2008, ...) you maybe should also try to use the runas verb as explained here and here.
With .NET, that would be:
if (System.Environment.OSVersion.Version.Major >= 6) // UAC's around...
{
processStartInfo.Verb = "runas";
}
I've had similar problems in the past. I resolved it by executing the cmd app as follows:
public static bool FireUpProcess(Process process, string path, bool enableRaisingEvents, ProcessWindowStyle windowStyle)
{
//if path contains " ", surround it with quotes.
//add /c and the path as parameters to the cmd process.
//Any other parameters can be added after the path.
ProcessStartInfo psi = new ProcessStartInfo("cmd", "/c" + path ));
psi.WorkingDirectory = System.IO.Path.GetDirectoryName(#path);
psi.WindowStyle = windowStyle;
// Suscribe to the exit notification
process.EnableRaisingEvents = enableRaisingEvents;
// Disable to prevent multiple launchs
Framework.Check.LogWarning("LAUNCHING EXTERNAL DEVICE WITH PATH: " + path);
process.Start(); ...}
If it is possible I would try to use Process Monitor from Sysinternals. When you start it up you can deselect Registry and Network Activity on the toolbar (the 5 icons on the right side). Then you only see Process and Disk activity. Since it looks like a file not found problem you should use the Filter dialog (6. icon from the left) select Process Name from the Drop down list (Architecture is the default) and enter your failing executable name. This will greatly limit the captured output so you can see what is going on. Then start the exectuable and check in the Result Column for NAME NOT FOUND result. This are the locations where a file was searched but not found. If you know the offending dll name you can search for it with Ctrl+F as usual to dig it out. Then you can compare the different search paths from your working application and when it was started from your application.
Could it be that the environment variable PATH has a different value inside your process? It could be that adding . (the current directory) helps to fix the dll search path. Or is the application started from a different user account? It could also be the new feature that when an application is installing things into Programm Files but has no rights (only administrator can do this) Windows will redirect the writes into the user profile. This is a secure and transparent way to get more secure. But this could cause e.g. during first application startup some e.g. config file to be deployed into the Administrators Profile when he is running the application not with consent from the UAC dialog. Then other users might also start the application but fail because the additional config file is located in the Administrators profile and not in Program Files as expected for everyone.
I believe Hans Passant is on the right track. In addition to what he said, check to ensure that ddip.dll and the exe are in the same directory. This is not always the case as there are other ways to bind assemblies outside the bin. Namely, the GAC and AssemblyResolve event. Considering your situation I see no reason the GAC is involved. Check the exe's code that is launched for any hooks into the AssemblyResolve event. If it's hooked into you may need to update the implementation to allow another process to launch it.
Because you are getting an exception regarding a missing DLL, I have little confidence in the answers regarding path delimiter issues. Nonetheless, you have the application code, so verify that it references ddip.dll. This will give you a good deal of confidence that you are in fact referencing the correct .exe and therefore it's not just a path delimiter problem with the command prompt (E.G. misinterpreted spaces).
How do I programmatically self delete?
C# / .NET Compact Framework 2 / Windows Mobile 6
Please, I don't want to discuss WHY to do it, I just need to know HOW to do it!
Important:
The "second application" approach is NOT an option. (Unless that second application can be "extracted" from running app, but I don't know how to do it!).
No problem in forced reboot, if windows do the trick at startup. (Is it possible? Nice! Show me how!).
Code samples are welcome.
The only way I can think of offhand to delete yourself and leave no trace is to use something already present in the device- namely wceload (the CAB extractor). I'd create a simple CAB file with a custom installer DLL that does a wait and then the delete.
I'd then add the CAB to the app as an embedded resource. When you need to delete you
extract the CAB to the file system
execute wceload.exe with the CAB as a parameter and /noui (or /silent)
Quit your application
The CAB then deletes your file (a named mutex could sync this better than just a Sleep call in the DLL). wceload automatically deletes the CAB (well depending on WinMo version, but there is a switch to force delete if necessary).
It's certainly a hack, but it would provide a "leave no trace" delete. Of course the CAB would probably have to clean it's own installation registry entries as well. Maybe you could just have the install return "failure" to prevent them from being written in the first place.
I am using this code and it works fine
string AppPath = System.IO.Path.GetDirectoryName(Assembly.GetEntryAssembly().Location).ToString() + "\\Uninstaller.exe";
ProcessStartInfo Info = new ProcessStartInfo();
Info.Arguments = "/C choice /C Y /N /D Y /T 0 & Del " + AppPath;
Info.WindowStyle = ProcessWindowStyle.Hidden;
Info.CreateNoWindow = true;
Info.FileName = "cmd.exe";
Process.Start(Info);
I've done this in the past by simply writing a batch file to the file system that will wait a few seconds and then delete the program. You then use Process.Start() to kick off the batch file and immediately call Environment.Exit(). You need to make sure that the batch file waits long enough for your program to close, or it won't work.
Windows can delete files on startup. It can be done by calling MoveFileEx like:
MoveFileEx(szDstFile, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
I'm not sure if that API is available in Mobile 6 or not. However, what it actually does is create a registry entry in HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\PendingFileRenameOperations. The key is a REG_MULI_SZ and you just need to give it a value like "szDstFile\0\0". On reboot Windows deletes the file.
As for programmatically rebooting, have a look at this thread on SO.