I have a main application calling another console application through Process component. I have set a memory limit on the console app using through custom implementation of Job Objects(Class name as 'Job' in the code)
Whenever the memory limit is crossed OutofMemory exception is thrown or KERNELBASE.DLL faulting happens. But I am unable to catch this exception in the main app or in the console app.
What is the way to handle this ?
Handling through Global exception in console app did not work.
Main Application has following code
private void startProcess()
{
try
{
Process proc = new Process();
proc.StartInfo.FileName = #"E:\App\console.exe";
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.UseShellExecute = false;
proc.OutputDataReceived += Proc_OutputDataReceived;
proc.ErrorDataReceived += Proc_ErrorDataReceived;
proc.BeginOutputReadLine();
proc.BeginErrorReadLine();
proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
proc.Start();
Job job = new Job(_maxmemory);//memory limit set for child process
job.AddProcess(proc.Id);//for the above console
proc.WaitForExit();//this is called on a thread.
}
catch (Exception ex)
{
}
}
Console app has following code
static void Main(string[] args)
{
System.AppDomain.CurrentDomain.UnhandledException += CatchUnhandledException;
}
static void CatchUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Console.Error.WriteLine(e.ExceptionObject.ToString());
}
How to handle this memory limit exception either in main app or console ?
Your main app code clearly will not catch that error. Process.Start() starts the other process asynchonously, so the method will end before the other process really does something. You'll have to call proc.WaitForExit() if you want to wait for the child process to terminate. After that, you can use the ExitCode property to find out whether your child process had an error. The value will be non-zero if your process died due to an exception.
Code such as this one in the child process should actually work:
static void Main(string[] args)
{
try
{
AllocateALotOfMemory();
}
catch (OutOfMemoryException e)
{
// Handle error
}
}
Related
I have written a small programme to perform a quick configuration on a client machine and it needs to be able to run with a GUI and silently from the command line. If I run it with the GUI then it works perfectly, if however I try to run it without then it just hangs.
I have traced the problem to this section of code:
string arg = "/C:\"setup.exe /qn ADD_OPINSIGHTS_WORKSPACE=1 OPINSIGHTS_WORKSPACE_ID=" + workSpaceID + " OPINSIGHTS_WORKSPACE_KEY=" + workSpaceKey + " AcceptEndUserLicenseAgreement=1\"";
log.Info(arg);
// Use ProcessStartInfo class
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.CreateNoWindow = false;
startInfo.UseShellExecute = false;
startInfo.FileName = "MMASetup-AMD64.exe";
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.Arguments = arg;
try
{
log.Info("try entered");
// Start the process with the info we specified.
// Call WaitForExit and then the using statement will close.
using (Process exeProcess = Process.Start(startInfo))
{
log.Info("Install started");
exeProcess.WaitForExit(30000);
log.Info("Install exit code: " + (exeProcess.ExitCode).ToString());
return (exeProcess.ExitCode).ToString();
}
}
catch (Exception e)
{
log.Error("MMA install threw an error: ", e);
return e.Message;
}
This method is in a seperate class to the GUI and silent code and is run in exactly the same way yet only reaches "Install started" when run silently. I know that the exe does finish so I have tried using the code in this solution but had the same problem:
ProcessStartInfo hanging on "WaitForExit"? Why?
I had the same Problem.
I made a startup class:
public partial class Startup {
// WPF App
private App _app;
[STAThread]
public static void Main(string[] args) {
try {
//Do what you need
//Check the args
//Start your setup silent
//start the WPF App if need it
this._app = new App();
this._app.InitializeComponent();
this._app.Run();
} catch (Exception ex) {
//Logging ex
}
}
After that you must change your Application Startup Object to the Startup Class.
I was running all of my work asynchronously and because I was not loading the GUI thread Windows was treating the application like a console app. Whereas a GUI thread would call other asynchronous methods and wait for them to finish a console application calls the methods and then closes because it has nothing left to do. The solution was to explicitly make the main thread wait like this:
public static void Main(string[] args)
{
try
{
Install().Wait();
}
catch (Exception ex)
{
}
}
private static async Task Install()
{}
I'm trying to make a service, that every 1000milliseconds(1 Second) Kills any process with the name Skype. I'm 100% sure I have coded it all correctly, everything is working, logging etc. But killing the process is not.
private System.Timers.Timer _timer;
protected override void OnStart(string[] args)
{
try
{
_timer = new System.Timers.Timer(100);
_timer.Elapsed += _timer_Elapsed;
_timer.Enabled = true;
if (!EventLog.SourceExists("MYTESTSERVICE"))
EventLog.CreateEventSource("MYTESTSERVICE", "MYTESTSERVICE LOG");
//_timer.Start();
Process[] p = Process.GetProcessesByName("Skype");
foreach (Process proc in p)
{
proc.Kill();
proc.WaitForExit();
EventLog.WriteEntry("User Tried To Start Skype! Closed.", EventLogEntryType.Warning);
}
}
catch (Exception ex)
{
EventLog.WriteEntry(String.Format("WcfServiceHostTest \n Exception Message: {0}\nTrace: {1}", ex.Message, ex.StackTrace), EventLogEntryType.Error);
}
}
I am currently not using the timer, but instead testing it upon service startup. If Skype is running, the process is not killed. I even tried notepad, and it did not kill that either. I have done research on this, but have not found an answer.
Any help is appreciated!
- Seb
you can use the taskkill:
Process.Start(new ProcessStartInfo
{
FileName = "taskkill",
Arguments = $"/im skype.exe /f /t",
CreateNoWindow = true,
UseShellExecute = false
}).WaitForExit();
I've built Form App that I use for some time , Now I want to Catch the StandardError of my process as well as its standartOutput
I've looked at answers in SO and MSDN and yet and cant get it right
My code :
public void RunProcess(string FileName, string Arguments,, bool IsPrintOutput = true)
{
process = new Process();
process.ErrorDataReceived += new DataReceivedEventHandler(OnDataReceivedEvent);
if (IsPrintOutput) process.OutputDataReceived += new DataReceivedEventHandler(OnDataReceivedEvent);
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.FileName = FileName;
process.StartInfo.Arguments = Arguments;
if (EventWhenExit)
{
process.EnableRaisingEvents = true;
process.Exited += new EventHandler(myprocess_Exited);
}
process.Start();
process.BeginOutputReadLine();
//run polling on stored logs to print them to screen
PollingService();
}
I've check it with Iperf and I see that when I run it with correct argument I get correct output
but when I just send it with out any argumnet I see that with cmd I get
C:\>iperf.exe
Usage: iperf [-s|-c host] [options]
Try `iperf --help' for more information.
And my App I get Nothing !
what am I missing here ?
Thanks
You can stop reading here ! If you want to see the details of inner method continue below :
private void OnDataReceivedEvent(object sender, DataReceivedEventArgs e)
{
string ProcessOutput = e.Data;
ProcessLog.Add(e.Data);
}
private void PollingService()
{
var T = new Thread (()=>
{
while (true /* ProcessRunning*/)
{
if (ProcessLogIndex < ProcessLog.Count)
{
lock (this)
{
var tempList = ProcessLog.GetRange(ProcessLogIndex, ProcessLog.Count - ProcessLogIndex);
ProcessLogIndex = ProcessLog.Count;
foreach (var ToSend in tempList)
{
onDataOutputFromProcess(this, ToSend, sProcessNameID.ToString());
}
}
}
Thread.Sleep(400);
}
});
T.IsBackground = true;
T.Start();
}
I don't see a call to BeginErrorReadLine() anywhere in the code you posted. If you don't call that method, then the Process class won't actually redirect the stderr to your event handler.
I believe the above is the issue, but if you are actually calling that somewhere (and just didn't show it), then it is worth considering that there are some strange console programs out there that don't actually used stderr (or stdout) for error output. Instead, they write directly to the console window or some other non-standard mechanism. In those cases, you won't be able to receive the error output by redirecting stderr.
You can identify those programs by redirecting their output at the command like with e.g. iperf.exe 2> foo.txt. The stderr file handle is 2, and so that syntax redirects that file handle to a file named foo.txt. If the file is empty and you see errors on the screen, then the program is one of those strange programs.
But really, I think you probably just forgot to call BeginErrorReadLine(). :)
I'm writing an application to check the exit code of another application. The application I am monitoring may already be running so I'm checking for it with Process.GetProcessesByName. If it exists I'm checking the exit code after a call to WaitForExit but when I do I get an exception:
"Process was not started by this object, so requested information cannot be determined."
If I start the process (if it isn't already running) then it doesn't give me the exception.
(Windows 8.1)
So how do I find out what the ExitCode was when I haven't started the process? The only option I can think of is to write an output code to a text file on exit and read that in...
System.Diagnostics.Process exposes events that you can access after setting EnableRaisingEvents to true:
int processId = 0; // TODO: populate this variable
var proc = System.Diagnostics.Process.GetProcessById(processId);
proc.EnableRaisingEvents = true;
proc.Exited += ProcessEnded;
Event handler:
private void ProcessEnded(object sender, EventArgs e)
{
var process = sender as Process;
if (process != null)
{
var test = process.ExitCode;
}
}
variable test now contains the exit code.
Tested on Windows 8.1
I have a console application and in the Main method. I start a process like the code below, when process exists, the Exist event of the process is fired but it closed my console application too, I just want to start a process and then in exit event of that process start another process.
It is also wired that process output is reflecting in my main console application.
Process newCrawler = new Process();
newCrawler.StartInfo = new ProcessStartInfo();
newCrawler.StartInfo.FileName = configSection.CrawlerPath;
newCrawler.EnableRaisingEvents = true;
newCrawler.Exited += new EventHandler(newCrawler_Exited);
newCrawler.StartInfo.Arguments = "someArg";
newCrawler.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
newCrawler.StartInfo.UseShellExecute = false;
newCrawler.Start();
You have to call newCrawler.WaitForExit() in order to stay until the child process finish. Then you can use newCrawler.ExitCode to have the exit value.
Seems like the Process exit handling could have caused the application error. So the application could have terminated. Can you put a proper try..catch block and debugg to see what is going wrong. Or comment the
line
newCrawler.Exited += new EventHandler(newCrawler_Exited);
and see what happens.
Please try following code (This is from MSDN) , also don't forget to pass one argument (FileName)
using System;
using System.Diagnostics;
using System.ComponentModel;
using System.Threading;
using Microsoft.VisualBasic;
class PrintProcessClass
{
private Process myProcess = new Process();
private int elapsedTime;
private bool eventHandled;
// Print a file with any known extension.
public void PrintDoc(string fileName)
{
elapsedTime = 0;
eventHandled = false;
try
{
// Start a process to print a file and raise an event when done.
myProcess.StartInfo.FileName = fileName;
myProcess.StartInfo.Verb = "Print";
myProcess.StartInfo.CreateNoWindow = true;
myProcess.EnableRaisingEvents = true;
myProcess.Exited += new EventHandler(myProcess_Exited);
myProcess.Start();
}
catch (Exception ex)
{
Console.WriteLine("An error occurred trying to print \"{0}\":" + "\n" + ex.Message, fileName);
return;
}
// Wait for Exited event, but not more than 30 seconds.
const int SLEEP_AMOUNT = 100;
while (!eventHandled)
{
elapsedTime += SLEEP_AMOUNT;
if (elapsedTime > 30000)
{
break;
}
Thread.Sleep(SLEEP_AMOUNT);
}
}
// Handle Exited event and display process information.
private void myProcess_Exited(object sender, System.EventArgs e)
{
eventHandled = true;
Console.WriteLine("Exit time: {0}\r\n" +
"Exit code: {1}\r\nElapsed time: {2}", myProcess.ExitTime, myProcess.ExitCode, elapsedTime);
}
public static void Main(string[] args)
{
// Verify that an argument has been entered.
if (args.Length <= 0)
{
Console.WriteLine("Enter a file name.");
return;
}
// Create the process and print the document.
PrintProcessClass myPrintProcess = new PrintProcessClass();
myPrintProcess.PrintDoc(args[0]);
}
}
One thing I noticed is, if you are not passing the filename as parameter, that will lead the process to crash, but still the application is intact (Since the exception is handled inside the process).
If you are not passing the filename the above code will crash beacuse the
myPrintProcess.PrintDoc(args[0]);
will throw exception from main process itself.
I tried to create an exceptin inside the Exit handler, at that time the application (main process) also crashed.
can you try commenting the code inside Exit handler?