c# calling process "cannot find the file specified" - c#

I'm a c# newbie so bear with me. I'm trying to call "pslist" from PsTools from a c# app, but I keep getting "The system cannot find the file specified". I thought I read somewhere on google that the exe should be in c:\windows\system32, so I tried that, still nothing. Even trying the full path to c:\windows\system32\PsList.exe is not working. I can open other things like notepad or regedit. Any ideas?
C:\WINDOWS\system32>dir C:\WINDOWS\SYSTEM32\PsList.exe
Volume in drive C has no label.
Volume Serial Number is ECC0-70AA
Directory of C:\WINDOWS\SYSTEM32
04/27/2010 11:04 AM 231,288 PsList.exe
1 File(s) 231,288 bytes
0 Dir(s) 8,425,492,480 bytes free
try
{
// Start the child process.
Process p = new Process();
// Redirect the output stream of the child process.
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
//This works
//p.StartInfo.FileName = #"C:\WINDOWS\regedit.EXE";
//This doesn't
p.StartInfo.FileName = #"C:\WINDOWS\system32\PsList.exe";
p.Start();
// Do not wait for the child process to exit before
// reading to the end of its redirected stream.
p.WaitForExit();
// Read the output stream first and then wait.
s1 = p.StandardOutput.ReadToEnd();
p.WaitForExit();
}
catch (Exception ex)
{
Console.WriteLine("Exception Occurred :{0},{1}",
ex.Message, ex.StackTrace.ToString());
Console.ReadLine();
}

You shouldn't do this in the first place unless you really need to.
Instead, use the Process class.
You can get all of the currently executing processes by calling Process.GetProcesses
To get the memory use of a single process, check the WorkingSet64 property of the Process object.
To get the CPU usage of a single process, use Performance Counters.

Related

Run C# Console application in WinForms Application and Wait till it completes

I have a C# Console application which I am trying to execute from another WinForm application just like batch runner by giving the console application's .exe file like below.
Process.Start("Path of Console application exe to execute")
However I need to wait and handle the output and display the output in WinForm's richtextbox from console application once it has completed the execution. How can I achieve this?
Update
I have changed the code to Start a Process and Read using StandardOutput and BeginOutputReadLine() to Read the output asynchronously, but not able to see output in console window, instead console window is getting closed. Not sure how to solve this.
p.StartInfo.UseShellExecute = false;
// p.StartInfo.CreateNoWindow = True
p.StartInfo.RedirectStandardOutput = true;
string #out = null;
p.StartInfo.RedirectStandardError = true;
p.OutputDataReceived += new DataReceivedEventHandler((sender, e) =>
{
#out += e.Data;
});
p.StartInfo.FileName = currentTest;
p.Start();
p.BeginOutputReadLine();
// string output = p.StandardError.ReadToEnd();
// p.WaitForExit()
while (!p.HasExited)
Application.DoEvents();
//Console.WriteLine($#"Output \n'{output.Substring(output.Length - 50)}'");
Console.WriteLine($#"\n Error stream: {#out}");
Console.ReadLine();
You need to redirect stdout (and probably stderr) so that any output comes to you, instead of a console; you may also want to redirect stdin. All of these things are available via ProcessStartInfo, with an example on MSDN. Note that if you want to display updates while the exe is running, you may need a worker thread to read incrementally from StandardOutput and StandardError, rather than ReadToEnd() - which won't return anything at all until the associated output pipe is closed.
However! If the console exe is "yours", it may be simpler to just expose the functionality you want in a library, and invoke it directly in-process. There are times when out-of-process is actively preferred, such as when you need to allow that process to go catastrophically wrong in some scenarios - but usually in-process is preferable, given free rein.

Launch Console Application and read output asynchronously

I'm trying to launch a game server (Game: Ark Survival Evolved) via a C# application. (Some kind of wrapper).
This game server is a console application with some output about the current state of the server.
I want to read the output in order to react to it. That's why the reading must happen asynchronously. (I can't wait untill the server has stopped)
My current approach is the following:
public void RunServer()
{
if (Process.GetProcessesByName("ShooterGameServer").Length <= 0)
{
Process p = new Process();
// redirect output stream
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.EnableRaisingEvents = true;
p.OutputDataReceived += (sender, args) => Display(args.Data);
// set Server.exe path
p.StartInfo.FileName = path_server;
// run server
p.Start();
// reading the console
p.BeginOutputReadLine();
p.WaitForExit(); // I've tried it without this line but it doesn't really help
}
}
// Show the console output
void Display(string output)
{
Console.Out.WriteLine(output);
}
The server exe starts perfectly fine, but it stops writing to the console, as soon as the StdOut should appear. (there are some StdErr messages before the StdOut messages which are still shown in the console window).
This is understandable, because I've only enabled p.StartInfo.RedirectStandardOutput = true in my code, so the StdErr channel is not affected by it.
The problem is that the redirected Output never shows up in the Display function. It just vanishes into thin air.
If I put a breaking point into the Display function it never gets called untill I close the server.exe. After that it gets called, but the parameter is null.
Unfortunately I don't have any further knowledge about the game server exe.
What am I missing ?
Edit: Turns out that redirecting the output of other exe files (e.g. cmd exe) works just fine. Is there another way I could read the console in my C# application? Maybe just "copy" the output instead of redirecting it completely?

will a program deadlock if the error stream is not read from regularly?

I originally wanted to quickly check an error stream from a program right after it starts to make sure that it ran successfully.
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.RedirectStandardError = true;
string errortext = Process.StandardError.ReadToEnd();
However, I was wondering do I have to redirect the Process's standard error back to a file.
I would think that if nothing is reading from std error and the program writes many errors to the stream, then eventually the buffer will fill up. I don't know exactly how ProcessStartInfo.RedirectStandardError works, but I assume that the buffer won't automatically write to a file when full.
In order to avoid freezing up the program I'm reading from, should stderror be redirected to a file instead? and then just read that file into the string to check for errors at startup?

Reading StdOut after process has been abnormally terminated using Process.kill

i am invoking an exe via c# Diagnostics.Process class and read output from it's StdOut. The process is forcefully terminated in case it doesn't automatically terminates in a specified time, something like:
process.StartInfo.FileName = #"D:\t.exe";
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardInput = false;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = false;
process.WaitForExit(500);
if (!process.HasExited)
{
process.Kill();
process.WaitForExit();
}
string stdOutContents = process.StandardOutput.ReadToEnd();
Now the problem is the code works succesfully when the exe terminates normally. But in case it fails to terminate normally (usually the exe gets stuck in an infinite loop somewhere), stdOutContents is read as an empty string.
How can i read StdOut after the process is killed (without using process.OutputDataReceived event technique)? (It has been verified that the exe-in-question does always writes something onto StdOut even if it gets stuck somewhere).
Update 1
Details about Exe which is being invoked (refereed as 'native app' across this question)
It is a small utility implemented in c language and compiled using MS C++ compiler. It does its job while simultaneously outputting status information onto the StdOut (using putchar).
There are only two possible cases of operation:
It will run successfully while simultaneously printing some data onto the StdOut.
It will run normally to a certain point (simultaneously outputting data on StdOut) and then get stuck in an infinite loop. (This is an acceptable behavior).
Both scenarios have been verified using cmd.
Details about new attempts
i wrote a c# app (referred as dummy app) which mimics the native app behavior and this code works fine. However when run for the native app, i get nothing at all.
i don't understand why the code cant read the contents outputted by the native app?
i also tried using event handler for OutputDataReceived. It gets called only once with args.Data = null when the code tries to kill the process. Inspecting the behavior for dummy app revealed that when process.kill is called, the handler is invoked with args.Data = null. So this seems to be a standard behavior of sorts for both apps.
i also tried changing the newline characters for native app. Since it is implemented in c language, it uses \n for newline. i tried using both \r\n pair for newline but StdOut is still blank (for case 2).
I had the same interrogation and the doc of Process.Kill says
Data edited by the process or resources allocated to the process can be lost if you call Kill.
Which seems to indicate that you cannot rely on reading the StandardOutput of a process, although it is not clearly stated that the output / error streams are disposed.
I finally got inspired by this answer
How to spawn a process and capture its STDOUT in .NET?
and I use the following code :
var info = new ProcessStartInfo("some.exe");
info.CreateNoWindow = true;
info.RedirectStandardOutput = true;
info.UseShellExecute = false;
using (var p = new Process())
{
p.StartInfo = info;
var output = new StringBuilder();
p.OutputDataReceived += (sender, eventArgs) =>
{
output.AppendLine(eventArgs.Data);
};
p.Start();
p.BeginOutputReadLine();
if (!p.WaitForExit(5000))
{
Console.WriteLine("Taking too long...");
p.Kill();
Console.WriteLine("Process killed, output :\n" + output);
}
}
Same pattern can be used with the ErrorDataReceived
Note that one could miss some unflushed output from the child process, however in my case I don't expect much from a process that requires to be killed, at most some information for debugging purposes.

Is there any alternative other than Process to execute built-in shell commands in C#

Is there any alternative other than Process to execute built-in shell commands in C#? Currently I am using Process class to run those commands. But in the current scenario I want to run more than 200 such commands in parallel. So spawning more than 200 processes is not a good idea. Is there any other alternative?
"Running a dos command" is the equivalent to "Creating a process and running it" so even if there is an other api, there will still be 200 processes (which, by the way, is nothing to worry about unless you're on a really, really tiny system)
You could but, shouldn't do
using Microsoft.VisualBasic;
Interaction.Shell(...);
Note: You would have to add a reference to the the VisualBasic assembly.
This is a direct answer to your question but, not somthing you should do.
As Max Keller pointed out, System.Diagnostics.Process always starts a new system process.
If have to start processes/operations for more than just some seconds, I would prefer to save all commands in a temp file and execute this with System.Diagnostics.Process rather than ever single operation.
// Get a temp file
string tempFilepath = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "MyBatchFile.bat");
// Ensure the file dont exists yet
if (System.IO.File.Exists(tempFilepath)) {
System.IO.File.Delete(tempFilepath);
}
// Create some operations
string[] batchOperations = new string[]{
"START netstat -a",
"START systeminfo"
};
// Write the temp file
System.IO.File.WriteAllLines(tempFilepath, batchOperations);
// Create process
Process myProcess = new Process();
try {
// Full filepath to the temp file
myProcess.StartInfo.FileName = tempFilepath;
// Execute it
myProcess.Start();
// This code assumes the process you are starting will terminate itself!
} catch (Exception ex) {
// Output any error to the console
Console.WriteLine(ex.Message);
}
// Remove the temp file
System.IO.File.Delete(tempFilepath);

Categories

Resources