I have buggy code and I don't know where or what is the fault.
I am writing an application for a customer. During the splash screen the app checks if Mysql is running to be able to connect to it later. If mysql is on, the app continues booting. If mysql is not running I start it and re-check again.
Initially, I was finding the mysql pid, but for some reason I can't get it without using unmanaged code.
So I found another way in xampp source code and I decided to use it.
Running the app under vstudio debugger stepping or stopping in a breakpoint works perfectly, but if run without stepping, the app boots mysql server but can´t detect it and eventually the application stop (I don't want the app continue loading if database fails).
This behavior has led me to think that one or more variables are disposed at runtime before I can use it again.
I don't know how solve this issue and need a hand.
EDIT: The issue was mysql was not started yet running the app without interruption
As Jan & SWEKO said. Adding some delay works perfectly
The splash screen Load code.
// App booting tasks
void Load()
{
// License validation ok
Boolean licensecheck = BootChecks.LicenseCheck();
if (! licensecheck)
{
MessageBox.Show("License Error Conta ct Technical Support","Error",MessageBoxButtons.OK,MessageBoxIcon.Stop);
Application.Exit();
}
bar.Width += 10; // feed progress bar ( it's a custom drawn label )
this.Refresh(); // update form to paint it
Application.DoEvents(); // process all pooled messages
// Mysql check
Boolean dbcheck = BootChecks.DbCheck();
// THE ISSUE IT'S HERE RUNNING WITHOUT STEPPING , ALWAYS FIRES THE ERROR
if ( ! dbcheck )
{
MessageBox.Show("Can't init Mysql. Contact Technical Support", "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop);
Application.Exit();
}
bar.Width += 10;
this.Refresh();
Application.DoEvents();
// more stuff
}
Database check code
public static bool DbCheck()
{
Boolean norun = MysqlController.CheckMysqlIsRunning(Constants.dbpidfile);
// check if running
if ( norun ) return true;
// if not running, I start it
MysqlController.StartMysql(Constants.dbexe,Constants.dbopts);
Boolean rerun = MysqlController.CheckMysqlIsRunning(Constants.dbpidfile);
// if really running all it's ok
if ( rerun ) return true;
// really a fault
return false;
}
Real mysql check
comment: this way was found on xampp package. To know if mysql it's running find mysql pid file, and open a named event. if right definitively mysql it's running.
public static Boolean CheckMysqlIsRunning(String pathtopidfile)
{
try
{
Int32 pid;
using ( StreamReader sr = new StreamReader(pathtopidfile) )
{
pid = int.Parse(sr.ReadToEnd());
}
IntPtr chk = OpenEvent(SyncObjectAccess.EVENT_MODIFY_STATE, false,
String.Format("MySQLShutdown{0}", pid.ToString()));
if ( chk != null ) return true;
return false;
}
catch (Exception) { return false;}
}
public static void StartMysql(String path, String aargs)
{
// All ok. Simply spawn a process
}
You have to code some kind of loop. You start the mysql process and when you check immediately after is, the process is still not there and you return false.
Try something like this:
// if not running, I start it
MysqlController.StartMysql(Constants.dbexe,Constants.dbopts);
// wait 10 seconds max.
int timeout = 10;
bool mySqlIsRunning = false;
while(!MysqlController.CheckMysqlIsRunning(Constants.dbpidfile)) {
// wait a while
Thread.Sleep(1000);
if (timeout-- == 0) {
// timeout error
// show message to user ...
}
}
// here mysql is running or your timeout is expired.
I think the problem might be that you spawn a background process that is not finished when you run the check.
When you are debugging, MySQL has enough time to start in the time it takes you to go from
MysqlController.StartMysql(Constants.dbexe,Constants.dbopts);
to
Boolean rerun = MysqlController.CheckMysqlIsRunning(Constants.dbpidfile);
However, that might not be the case when you are running the app for real. As a simple test, try adding a simple Thread.Sleep(2000) to wait a couple of seconds before the running the check again.
IMHO its bad form to have a method say it will do a check, then also do an initialization. Break out the code of the check into two. Then do the initialization in the main code after the check. Hold on to the references to the database by having them held as properties on the form.
Related
I'm trying to make a console app in c# that will confirm that another application is always running. The other application periodically crashes, and I need to check every few minutes and relaunch it if it has stopped working.
There are many questions on SO that address making sure than no more than one instance of the application is running. I'm trying to confirm that one (no more or less) is running at all times.
Does anybody know how to even begin approaching this?
I would suggest using System.Diagnostics.Process.GetProcessesByName to see if your process is running and then, if not, using System.Diagnostics.Process.Start to start the process.
var processes = Process.GetProcessesByName("yourProcessName");
if(processes.Length == 0)
{
Process.Start(#"C:\Path\To\Your\Process.exe");
}
// Kill the extras
for(int i = 1; i < process.Length; i++)
{
processes[i].Kill();
}
These commands are useful to control processes:
// check for processes
Process[] processes = Process.GetProcessesByName("nameOfExecutable");
foreach (Process proc in processes)
{
// do stuff
}
// start process (need path)
Process.Start("pathToExecutable");
// close gui process gently (if needed)
bool status = proc.CloseMainWindow();
// wait for process to close gently
bool status = proc.WaitForExit(killTimeMS);
// force close (kill) process
proc.Kill();
If you implement a "no more than one" rule (which is well-documented, as you point out) and then implement the periodic crash-checker, that should be sufficient to ensure that one and only one copy is running.
In fact, the periodic process doesn't even have to check for a crash. It can just fire up an instance, which will immediately exit if another instance is already running, thanks to whatever "no more than one" mechanism you implement. This has the added benefit of avoiding a possible race-condition between detecting a dead process and starting a new one.
You have a few options. The first is checking for a running process using the Process class. I got this from a Microsoft site, but it looks like it works:
public bool IsProcessRunning(string name)
{
//here we're going to get a list of all running processes on
//the computer
foreach (Process clsProcess in Process.GetProcesses())
{
if (clsProcess.ProcessName.StartsWith(name))
{
//process found so it's running so return true
return true;
}
}
//process not found, return false
return false;
}
You could also use interprocess communications. This is something we do in house. We have a watcher application that sends a message to a service being monitored. If the service doesn't return an ACK in a timeout period, we attempt to restart it.
I suggest you to check if your application is in the list of running processes:
System.Diagnostics.Process.GetProcesses();
I have a program where I have to get a SHDocVw.InternetExplorer instance from a running IE8 process. To get the instance the example code below runs. For some reason it won't work without the Thread.Sleep.
The Browser.HWND throws InvalidCastException for all instances in the m_IEFoundBrowsers if the Thread.Sleep is removed. When using the Thread.Sleep it works for the IE8 windows.
Does anyone know how to do this in a way not using Thread.Sleep? (I don't like to use the sleep function, usually it just pushes the problems into the future...)
Example code:
InternetExplorer m_IEBrowser = null;
ShellWindows m_IEFoundBrowsers = new ShellWindowsClass();
Thread.Sleep(10);
foreach (InternetExplorer Browser in m_IEFoundBrowsers)
{
try
{
if (Browser.HWND == (int)m_Proc.MainWindowHandle)
{
m_IEBrowser = Browser;
break;
}
}
catch(InvalidCastException ice)
{
//Do nothing. Browser.HWND could not execute for this item.
}
}
I came across the following link which seems to back up Hans's comment: http://weblogs.asp.net/joberg/archive/2005/05/03/405283.aspx
The article states:
The Internet Controls Library contains
the “ShellWindowsClass” which is
basically a collection of all the
shell windows (e.g.: IE) spawned
across the desktop. That component
provides an event handler called
“Windows Registered” that we are going
to hook up to. Once the process has
been launched, we will wait until the
corresponding window is registered
then we are going to connect our
Internet Explorer control to the shell
window found. To determine if the
window is found, we iterate through
the registered windows and we try to
find a handle that matches the handle
of the process we previously launched.
We will use the “ManualResetEvent”
synchronization primitive to wait a
certain amount of time for the window
to be registered.
I expect you'd be able to map these ideas across to your problem relatively easily.
The article posted by David solved the problem. The first time the code runs in my program it works as described in the article. But if I exit the program, leave the opened IE8 open, open my program again then the the windows_WindowRegistered method got problems with InvalidCastExceptions. Handling these exceptions as shown below made it work as needed.
EXAMPLE CODE:
private void windows_WindowRegistered(int lCookie)
{
if (process == null)
return; // This wasn't our window for sure
for (int i = 0; i < windows.Count; i++)
{
try
{
InternetExplorerLibrary.InternetExplorer ShellWindow = windows.Item(i) as InternetExplorerLibrary.InternetExplorer;
if (ShellWindow != null)
{
IntPtr tmpHWND = (IntPtr)ShellWindow.HWND;
if (tmpHWND == process.MainWindowHandle)
{
IE = ShellWindow;
waitForRegister.Set(); // Signal the constructor that it is safe to go on now.
return;
}
}
}
catch (InvalidCastException ice)
{
//Do nothing. Browser.HWND could not execute for this item.
}
}
}
I'm making an application that will monitor the state of another process and restart it when it stops responding, exits, or throws an error.
However, I'm having trouble to make it reliably check if the process (Being a C++ Console window) has stopped responding.
My code looks like this:
public void monitorserver()
{
while (true)
{
server.StartInfo = new ProcessStartInfo(textbox_srcdsexe.Text, startstring);
server.Start();
log("server started");
log("Monitor started.");
while (server.Responding)
{
if (server.HasExited)
{
log("server exitted, Restarting.");
break;
}
log("server is running: " + server.Responding.ToString());
Thread.Sleep(1000);
}
log("Server stopped responding, terminating..");
try
{ server.Kill(); }
catch (Exception) { }
}
}
The application I'm monitoring is Valve's Source Dedicated Server, running Garry's Mod, and I'm over stressing the physics engine to simulate it stopping responding.
However, this never triggers the process class recognizing it as 'stopped responding'.
I know there are ways to directly query the source server using their own protocol, but i'd like to keep it simple and universal (So that i can maybe use it for different applications in the future).
Any help appreciated
The Responding property indicates whether the process is running a Windows message loop which isn't hung.
As the documentation states,
If the process does not have a MainWindowHandle, this property returns true.
It is not possible to check whether an arbitrary process is doing an arbitrary thing, as you're trying to.
Or not!
I have a fairly simple application timer program. The program will launch a user selected (from file dialog) executable and then terminate the process after the user specified number of minutes. During testing I found that a crash occurs when I call the Process.Kill() method and the application is minimized to the system tray.
The executable in question is Frap.exe which I use frequently and is the reason I wrote the app timer in the first place. I always minimize fraps to the tray, and this is when the crash occurs.
My use of Kill() is straight forward enough...
while (true)
{
//keep checking if timer expired or app closed externally (ie. by user)
if (dtEndTime <= DateTime.Now || p.HasExited)
{
if (!p.HasExited)
p.Kill();
break;
}
System.Threading.Thread.Sleep(500);
}
In searching for alternatives methods to close an external application programmatically, I found only Close() and Kill() (CloseMainWindow is not helpful to me at all). I tried using Close(), which works providing the application is minimized the tray. If the app is minimized, Close() doesn't cause a crash but the app remains open and active.
One thing I noticed in a few posts posts regarding closing external applications was the comment: "Personally I'd try to find a more graceful way of shutting it down though." made in THIS thread found here at stack flow (no offense to John). Thing is, I ran across comments like that on a few sites, with no attempt at what a graceful or elegant (or crash-free!!) method might be.
Any suggestions?
The crash experienced is not consistant and I've little to offer as to details. I am unable to debug using VS2008 as I get message - cant debug crashing application (or something similar), and depending on what other programs I have running at the time, when the Kill() is called some of them also crash (also programs only running in the tray) so I'm thinking this is some sort of problem specifically related to the system tray.
Is it possible that your code is being executed in a way such that the Kill() statement could sometimes be called twice? In the docs for Process.Kill(), it says that the Kill executes asynchronously. So, when you call Kill(), execution continues on your main thread. Further, the docs state that Kill will throw a Win32Exception if you call it on an app that is already in the process of closing. The docs state that you can use WaitForExit() to wait for the process to exit. What happens if you put a call to WaitForExit() immediately following the call to Kill(). The loop looks ok (with the break statement). Is it possible that you have code entering that loop twice?
If that's not the problem, maybe there is another way to catch that exception:
Try hooking the AppDomain.CurrentDomain.UnhandledException event
(currentDomain is a static member)
The problem is that Kill runs asynchronously, so if it's throwing an exception, it's occurring on a different thread. That's why your exception handler doesn't catch it. Further (I think) that an unhandled async exception (which is what I believe you have) will cause an immediate unload of your application (which is what is happening).
Edit: Example code for hooking the UnhandledExceptionEvent
Here is a simple console application that demonstrates the use of AppDomain.UnhandledException:
using System;
public class MyClass
{
public static void Main()
{
System.AppDomain.CurrentDomain.UnhandledException += MyExceptionHandler;
System.Threading.ThreadPool.QueueUserWorkItem(DoWork);
Console.ReadLine();
}
private static void DoWork(object state)
{
throw new ApplicationException("Test");
}
private static void MyExceptionHandler(object sender, System.UnhandledExceptionEventArgs e)
{
// get the message
System.Exception exception = e.ExceptionObject as System.Exception;
Console.WriteLine("Unhandled Exception Detected");
if(exception != null)
Console.WriteLine("Message: {0}", exception.Message);
// for this console app, hold the window open until I press enter
Console.ReadLine();
}
}
My first thought is to put a try/catch block around the Kill() call and log the exception you get, if there is one. It might give you a clue what's wrong. Something like:
try
{
if(!p.HasExited)
{
p.Kill();
}
break;
}
catch(Exception ex)
{
System.Diagnostics.Trace.WriteLine(String.Format("Could not kill process {0}, exception {1}", p.ToString(), ex.ToString()));
}
I dont think I should claim this to be "THE ANSWER" but its a decent 'work around'. Adding the following to lines of code...
p.WaitForInputIdle(10000);
am.hWnd = p.MainWindowHandle;
...stopped the crashing issue. These lines were placed immediately after the Process.Start() statement. Both lines are required and in using them I opened the door to a few other questions that I will be investigating over the next few days. The first line is just an up-to 10 second wait for the started process to go 'idle' (ie. finish starting). am.hWnd is a property in my AppManagement class of type IntPtr and this is the only usage of both sides of the assignment. For lack of better explaination, these two lines are analguous to a debouncing method.
I modified the while loop only slightly to allow for a call to CloseMainWindow() which seems to be the better route to take - though if it fails I then Kill() the app:
while (true)
{
//keep checking if timer expired or app closed externally (ie. by user)
if (dtEndTime <= DateTime.Now || p.HasExited) {
try {
if (!p.HasExited) // if the app hasn't already exitted...
{
if (!p.CloseMainWindow()) // did message get sent?
{
if (!p.HasExited) //has app closed yet?
{
p.Kill(); // force app to exit
p.WaitForExit(2000); // a few moments for app to shut down
}
}
p.Close(); // free resources
}
}
catch { // blah blah }
break;
}
System.Threading.Thread.Sleep(500);
}
My initial intention for getting the MainWindowHandle was to maximize/restore an app if minimized and I might implement that in the near future. I decided to see if other programs that run like Fraps (ie, a UI but mostly run in the system tray (like messanger services such as Yahoo et al.)). I tested with XFire and nothing I could do would return a value for the MainWindowHandle. Anyways, this is a serperate issue but one I found interesting.
PS. A bit of credit to JMarsch as it was his suggestion RE: Win32Exception that actually lead me to finding this work around - as unlikely as it seems it true.
I have an application that has been getting strange errors when canceling out of a dialog box. The application can't continue if the box is cancelled out of, so it exits, but it is not working for some reason, and thus it keeps running and crashes.
I debugged this problem, and somehow the application runs right past the Application.Exit call. I'm running in Debug mode, and this is relevant because of a small amount of code that depends on the RELEASE variable being defined. Here is my app exit code. I have traced the code and it entered the ExitApp method, and keeps on going, returning control to the caller and eventually crashing.
This is an application which provides reports over a remote desktop connection, so that's why the exit code is a bit weird. Its trying to terminate the remote session, but only when running under release because I don't want to shut down my dev machine for every test run.
private void ExitApp()
{
HardTerminalExit();
Application.Exit();
}
// When in Debug mode running on a development computer, this will not run to avoid shutting down the dev computer
// When in release mode the Remote Connection or other computer this is run on will be shut down.
[Conditional("RELEASE")]
private void HardTerminalExit()
{
WTSLogoffSession(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, false);
}
I've run a debugger right past the Application.Exit line and nothing happens, then control returns to the caller after I step past that line.
What's going on? This is a Windows Forms application.
This is an article which expands on the same train of thought you are going through: http://www.dev102.com/2008/06/24/how-do-you-exit-your-net-application/
Basically:
Environment.Exit - From MSDN: Terminates this process and gives the
underlying operating system the
specified exit code. This is the code
to call when you are using console
application.
Application.Exit - From MSDN: Informs all message pumps that they
must terminate, and then closes all
application windows after the messages
have been processed. This is the code
to use if you are have called
Application.Run (WinForms
applications), this method stops all
running message loops on all threads
and closes all windows of the
application. There are some more
issues about this method, read about
it in the MSDN page.
Another discussion of this: Link
This article points out a good tip:
You can determine if System.Windows.Forms.Application.Run has been called by checking the System.Windows.Forms.Application.MessageLoop property. If true, then Run has been called and you can assume that a WinForms application is executing as follows.
if (System.Windows.Forms.Application.MessageLoop)
{
// Use this since we are a WinForms app
System.Windows.Forms.Application.Exit();
}
else
{
// Use this since we are a console app
System.Environment.Exit(1);
}
Having had this problem recently (that Application.Exit was failing to correctly terminate message pumps for win-forms with Application.Run(new Form())), I discovered that if you are spawning new threads or starting background workers within the constructor, this will prevent Application.Exit from running.
Move all 'RunWorkerAsync' calls from the constructor to a form Load method:
public Form()
{
this.Worker.RunWorkerAsync();
}
Move to:
public void Form_Load(object sender, EventArgs e)
{
this.Worker.RunWorkerAsync();
}
Try Environment.Exit(exitCode).
I have went though this situation in many cases I use Thread.CurrentThread.Abort()
and the process is closed. It seems that Application.Exit isn't hooking up properly with current thread.
Also ensure any threads running in your application have the IsBackground property set to true. Non-background threads will easily block the application from exiting.
Make sure you have no Console.ReadLine(); in your app and Environment.Exit(1); will work and close your app.
I created the following that will exit the app anywhere. You don't have to worry if the Form is running or not, the test determines that and calls appropriate Exit.
public void exit(int exitCode)
{
if (System.Windows.Forms.Application.MessageLoop)
{
// Use this since we are a WinForms app
System.Windows.Forms.Application.Exit()
}
else
{
// Use this since we are a console app
System.Environment.Exit(exitCode);
}
} //* end exit()
Is this application run (in the Main method) using Application.Run()? Otherwise, Application.Exit() won't work.
If you wrote your own Main method and you want to stop the application, you can only stop by returning from the Main method (or killing the process).
Try this :
in Program.cs file :
after Application.Run(new form());
add Application.Exit();
private void frmLogin_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
DialogResult result = MessageBox.Show("Do you really want to exit?", "Dialog Title", MessageBoxButtons.YesNo);
if (result == DialogResult.Yes)
{
Environment.Exit(0);
}
else
{
e.Cancel = true;
}
}
else
{
e.Cancel = true;
}
}