C# How to enable exit event on a running javaw app - c#

I am trying to create an external launcher for an app, which I recently noticed is running in Java..
I did not immediately noticed because the program has an .exe extension and I assumed it was an executable directly running the software. Instead, it appears that this is an initial container than then open Java and run the software in Java.
The launcher I wrote works for apps like Notepad, but the structure I have does not work with the situation I have found myself in.
Here the (simplified) code I am using.
Button on a form launch the exe using this
MyProcess = Process.Start(processPath);
MyProcess.EnableRaisingEvents = true;
MyProcess is a process class with a private class associated to it. I got the code from another answer here.
private Process withEventsField_MyProcess;
Process MyProcess
{
get { return withEventsField_MyProcess; }
set
{
if (withEventsField_MyProcess != null)
{
withEventsField_MyProcess.Exited -= MyProcess_Exited;
}
withEventsField_MyProcess = value;
if (withEventsField_MyProcess != null)
{
withEventsField_MyProcess.Exited += MyProcess_Exited;
}
}
}
Whenever the event is triggered, I run my event code
private void MyProcess_Exited(object sender, System.EventArgs e)
{
//do stuff here
Application.Exit();
}
The problem with this is that I was planning to monitor an executable, and instead I find myself with an exe that stats java and then exits, and my events detects that as the exit event for the whole system.
I am trying to find a simple solution that allows me to detect when the specific Java app is closed so I can execute the rest of the program.
While I am writing this as a generic question for future users, I have the hint of an idea, but no clear view about how to implement it (assuming the idea is good at all).
I found out that via cmd I can get processes with also the command line executed to call them.
In the case of the Java program I want to monitor, the command line would work as a unique identifier. Therefore, I should be able to hook up into that to determine which process I want to monitor for the exited event.
And this is where I hit the wall.
Any help would be much appreciated.

Apparently, I did not google enough.
This is quite easy o achieve with WMI queries.
This code shows how one can isolate all the instances of the process javaw.exe and check any WMI parameter (e.g. the CommandLine)
public static void Main()
{
SelectQuery query = new SelectQuery("Select * from Win32_Process WHERE Name = 'javaw.exe'" );
ManagementScope scope = new System.Management.ManagementScope(#"\\.\root\CIMV2");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
try
{
foreach (ManagementObject processes in searcher.Get())
{
Console.WriteLine(processes["CommandLine"].ToString() + Environment.NewLine);
}
}
catch (Exception e)
{
Console.WriteLine("Exception: " + e);
}
Console.Read();
}
Here a guide that shows how to create an event watcher base don WMI query
https://www.codeproject.com/Articles/12138/Process-Information-and-Notifications-using-WMI
It is an old post, and you will need to update part of the code.

Related

How to check a Window already opened when button is clicked?

I am Working in Visual Studio 2008 Winforms Application project in Windows 7 (32 bit).I am doing the project in C#.
I have placed some buttons in a tab and added actions for that once it is clicked. While clicking the button am just running a .exe file in its action part.
My problem is that, i opened a window by clicking one button(so the .exe file is running), now while am clicking the button again it is opening same window again irrespective of checking that it is open or not. I want to solve this issue,as when a window is opened it must not open again on another click on same button. How to solve this issue. ?
Please help....
Thanks in advance..
You could check if the process is already running, when re-clicking the button:
private void btnStartExecutable_Click(object sender, EventArgs e)
{
Process[] processName = Process.GetProcessesByName("InsertProcessNameHere");
if (pname.Length == 0)
{
MessageBox.Show("Application isn't running yet.");
//Start application here
Process.Start("InsertProcessNameHere");
}
else
{
MessageBox.Show("Application is already running.");
//Don't start application, since it has been started already
}
}
You can try this:
bool processExited = true;
private void button1_Click(object sender, EventArgs e)
{
if (processExited)
{
Process process = new Process();
process.EnableRaisingEvents = true;
process.Exited += MyProcessExited;
process.StartInfo = new ProcessStartInfo();
process.StartInfo.FileName = "notepad.exe";
process.Start();
processExited = false;
}
else
{
MessageBox.Show("Still running");
}
}
void MyProcessExited(object sender, EventArgs e)
{
processExited = true;
}
The right answer here IMHO is that unless the two application shares a common resource or can talk to each other through some channel, there is no safe and efficient way to achieve what you want. Since the process is external, it could already be running before your calling app starts, or even while it's already running. You won't be able to tell if the process has been started from your app or not.
By the time I'm writing this your question does not yet state if you are in liberty to modify the external app you are calling. If you are however, using a Mutex would be a quick and easy way to solve your problem.
In your external app, whenever you want to make the other app aware of whatever condition you want (be it that the process is running or that a specific window is opened), have a Mutex instance created like this:
var mutex = new Threading.Mutex(true, "mutex unique identifier");
And in your calling app, try to create a Mutex instance with the same identifier:
bool alreadyExists;
var mutex = new Threading.Mutex(false, "mutex unique identifier", out alreadyExists);
Here the alreadyExists variable will tell you whether or not the external process is running or not. This is much safer than trying to identify it via its name, as other processes could have the same or a new version could be of a different name. Of course, the mutex identifier must be as unique as possible (like a Guid), otherwise you may encounter the same problem. ;)
Whenever you feel like the mutex must be released (at external app level), release it:
mutex.ReleaseMutex();
Note that if the process ends the mutex will be automatically released by the OS.
If the external app isn't a .NET based app, you can still create a mutex with Win32 API functions.
Thanks for the support.. I got the answer like this..
1) Creating an event'Exit' for the process in function button click
2) Define a function for the exit event where you set a flag
3) Check the flag is set or not everytime while opening the process in the function button click
Event for Exit: 'P' is the name of process:
p.Exited += new EventHandler(p_Exited);
p_Exited will be the function name where we will set the flag.
Thanks all...
If you know the name of the process that gets started or the path the .exe is run from you can use the Process class to check to see if it is currently running.
http://msdn.microsoft.com/en-us/library/system.diagnostics.process(v=vs.110).aspx

Closing the client application using a Singleton class implementation

I have a .net application written in c#. This application is called from a parent application written in c++. When the parent application crashes or accidently closes the .net application still runs. But I want to close the client application too when the parent application crashes or stops.
One of my colleague said we can easily implement this using a singleton class. How can I do that?
You are going to have to poll to see if the parent application is still running.
One way to do this is setting up when an application was run by configuring audit process tracking in Windows. The following links might get you started:
Audit process tracking
How can I track what programs come and go on my machine?
The process tracking will create entries in the Windows event log which you can then access using C++, C# &/or VB.Net. You can use these logs to see if the Parent application is running.
Edit:
If you have access to the C++ codebase you could try to catch the exception when the parent app crashes or closes, eg:
Application.ThreadException += new ThreadExceptionEventHandler(ApplicationThreadException);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(ApplicationUnhandledException);
private void ApplicationThreadException(object sender, ThreadExceptionEventArgs e)
{
//Write to a File, Registry, Database flagging the application has crashed
}
private void ApplicationUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
//Write to a File, Registry, Database flagging the application has crashed
}
private void frmMain_FormClosed(object sender, FormClosedEventArgs e)
{
//Write to a File, Registry, Database flagging the application has closed
}
Otherwise you will have to poll to see if the Parent application is listed in the Process Manager, eg:
StringBuilder sb = new StringBuilder();
ManagementClass MgmtClass = new ManagementClass("Win32_Process");
foreach (ManagementObject mo in MgmtClass.GetInstances())
{
sb.Append("Name:\t" + mo["Name"] + Environment.NewLine);
sb.Append("ID:\t" + mo["ProcessId"] + Environment.NewLine);
sb.Append(Environment.NewLine);
}
If its not listed, close the child application.
Firstly, you have to catch event when the parent windows raise exception or closing.
Secondly, you will send to close message to process which already launched by parent window.
For your information about send close message you can take reference here:
Send message to a Windows process (not its main window)
Or
how to close a window from a different process

How do I programatically open an application and check when it's closed?

I've been able to use a winforms application to open another winforms application using:
Rhino4.Application oRhino = (Rhino4.Application)Activator.CreateInstance(Type.GetTypeFromProgID("Rhino4.Application"));
But how do I check if it gets closed? Is it possible to create an event that will get fired when the user closes the application?
EDIT
Process[] pr = Process.GetProcessesByName("Rhino4");
for (int i = 0; i < pr.Length; i++)
{
if (pr[i].MainWindowTitle != null)
{
if (pr[i].MainWindowTitle.Length > 4)
{
if (pr[i].MainWindowTitle.Substring(0, 4) == "wall")
{
pr[i].Exited += new EventHandler(caseInfoMenu_Exited);
}
}
}
}
void caseInfoMenu_Exited(object sender, EventArgs e)
{
MessageBox.Show("Window closed");
}
I've managed to identify the process using this code. But the Exited-event doesn't fire when I close the program.
Its maybe not the most elegant solution but indirectly you could do this by checking if the process exist or not and then do this repeatable. This is of course if you do not already have a handle to the process.
void checkProcess()
{
Process[] processes = Process.GetProcessesByName("NameOfProcess");
if (processes.Length == 0)
{
// No such process
}
else
{
foreach (Process proc in processes)
{
// do something with proc
}
}
}
Edit: Some thoughts on this after reading the posts in Abdul's answer plus your own question. This is by no means an answer, but maybe it can help you on your quest.
Firstly, Activator.CreateInstance calls the best fitting constructor on the object type that you give to it and returns a handle to that object. It does create the threads/processes itself and thus it has not knowledge about them. The (9) processes you'll see in your list are probably created by the Rheno4 class itself. There is a discussion about this here.
Secondly, according to msdn the EnableRaisingEvents property should be set to true when the process is created for the Exited event to function correctly. This leaves me wondering what happens when you attach the event after the process is already created?
You could of course iterate over all matching processess before and after calling CreateInstance to extract all new instances of Rheno4 that has been created. But this is far from a bulletproof solution and the risk is that you are fetching processes that are created by someone else or that not all processes are retreived (in case there is a delay in creating the other object). Depending on your needs, however, this maybe is appliable.
Another thought. The processes returned from the GetProcessesByName has a rich set of properties. Maybe you can look though these and find a common denominator for the processes returned. The ones I would start to investigate are: Threads, StartInfo, MainModule.
What about catching Exited event
myProcess.Exited += new EventHandler(myProcess_Exited);
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);
}
Source msdn.
If you want to start the application again after closing then :-
I think you need to crearte a Windows Service which will keep checking the process running and if it is closed then start the application again
As far as events are concern then "Closing" and "Close" events are there in Windows App which fires when user shutdowns the app.

Kill process tree programmatically in C#

I am starting Internet Explorer programmatically with code that looks like this:
ProcessStartInfo startInfo = new ProcessStartInfo("iexplore.exe");
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.Arguments = "http://www.google.com";
Process ieProcess = Process.Start(startInfo);
This generates 2 processes visible in the Windows Task Manager. Then, I attempt to kill the process with:
ieProcess.Kill();
This results in one of the processes in Task Manager being shut down, and the other remains. I tried checking for any properties that would have children processes, but found none. How can I kill the other process also? More generally, how do you kill all the processes associated with a process that you start with Process.Start?
This worked very nicely for me:
/// <summary>
/// Kill a process, and all of its children, grandchildren, etc.
/// </summary>
/// <param name="pid">Process ID.</param>
private static void KillProcessAndChildren(int pid)
{
// Cannot close 'system idle process'.
if (pid == 0)
{
return;
}
ManagementObjectSearcher searcher = new ManagementObjectSearcher
("Select * From Win32_Process Where ParentProcessID=" + pid);
ManagementObjectCollection moc = searcher.Get();
foreach (ManagementObject mo in moc)
{
KillProcessAndChildren(Convert.ToInt32(mo["ProcessID"]));
}
try
{
Process proc = Process.GetProcessById(pid);
proc.Kill();
}
catch (ArgumentException)
{
// Process already exited.
}
}
Update 2016-04-26
Tested on Visual Studio 2015 Update 2 on Win7 x64. Still works as well now as it did 3 years ago.
Update 2017-11-14
Added check for system idle process if (pid == 0)
Update 2018-03-02
Need to add a reference to the System.Management namespace, see comment from #MinimalTech below. If you have ReSharper installed, it will offer to do this for you automatically.
Update 2018-10-10
The most common use case for this is killing any child processes that our own C# process has started.
In this case, a better solution is to use Win32 calls within C# to make any spawned process a child process. This means that when the parent process exits, any child processes are automatically closed by Windows, which eliminates the need for the code above. Please let me know if you want me to post the code.
If anyone needs a dotnet core solution,
Dotnet core 3.0
process.Kill(true);
See official documentation
Dotnet core 2.0
For .Net 2.0 dotnet cli came up with an implementation based on taskill as mentioned above and recursive pgrep/kill for unix based systems. Full implementation can be found on github. Sadly, the class is internal so you'll have to copy it into your code base.
List Child processes (has to be done recursively):
$"pgrep -P {parentId}"
Kill on process:
$"kill -TERM {processId}"
I'm not a fan of any of the solutions presented here.
Here's what I came up with:
private static void EndProcessTree(string imageName)
{
Process.Start(new ProcessStartInfo
{
FileName = "taskkill",
Arguments = $"/im {imageName} /f /t",
CreateNoWindow = true,
UseShellExecute = false
}).WaitForExit();
}
How to use:
EndProcessTree("chrome.exe");
Process Class (System.Diagnostics)
ProcessStartInfo Class (System.Diagnostics)
Taskkill
You should call Process.CloseMainWindow() which will send a message to the main window of the process. Think of it as having the user click the "X" close button or File | Exit menu item.
It is safer to send a message to Internet Explorer to close itself down, than go and kill all its processes. Those processes could be doing anything and you need to let IE do its thing and finish before just killing it in the middle of doing something that may be important for future runs. This goes true for any program you kill.
If anyone is interested, I took one of the answers from the other page and modified it slightly. It is a self contained class now with static methods. It does not have proper error handling or logging. Modify to use for your own needs. Providing your root Process to KillProcessTree will do it.
class ProcessUtilities
{
public static void KillProcessTree(Process root)
{
if (root != null)
{
var list = new List<Process>();
GetProcessAndChildren(Process.GetProcesses(), root, list, 1);
foreach (Process p in list)
{
try
{
p.Kill();
}
catch (Exception ex)
{
//Log error?
}
}
}
}
private static int GetParentProcessId(Process p)
{
int parentId = 0;
try
{
ManagementObject mo = new ManagementObject("win32_process.handle='" + p.Id + "'");
mo.Get();
parentId = Convert.ToInt32(mo["ParentProcessId"]);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
parentId = 0;
}
return parentId;
}
private static void GetProcessAndChildren(Process[] plist, Process parent, List<Process> output, int indent)
{
foreach (Process p in plist)
{
if (GetParentProcessId(p) == parent.Id)
{
GetProcessAndChildren(plist, p, output, indent + 1);
}
}
output.Add(parent);
}
}
Another solution is to use the taskill command. I use the next code in my applications:
public static void Kill()
{
try
{
ProcessStartInfo processStartInfo = new ProcessStartInfo("taskkill", "/F /T /IM your_parent_process_to_kill.exe")
{
WindowStyle = ProcessWindowStyle.Hidden,
CreateNoWindow = true,
UseShellExecute = false,
WorkingDirectory = System.AppDomain.CurrentDomain.BaseDirectory,
RedirectStandardOutput = true,
RedirectStandardError = true
};
Process.Start(processStartInfo);
}
catch { }
}
Are you using IE8 or IE9? That would absolutely start more than one process due to its new multi-process architecture. Anyway, have a look at this other answer for getting a process tree and killing it.
Another approach that can be very useful is using the Windows API for Job Objects. A process can be assigned to a job object. The child processes of such a process are automatically assigned to the same job object.
All processes assigned to a job object can be killed at once e.g. with TerminateJobObject which:
Terminates all processes currently associated with the job.
The C# example in this answer (based on this answer) uses the JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE flag instead, which:
Causes all processes associated with the job to terminate when the last handle to the job is closed.
With .NET Core 3.0 there is a method just for that, namely new overload of the already existing Process.Kill() method. IOW, doing process.Kill(true) on the variable process of type Process kills the process with all its descendants. This is cross-platform, naturally.
As per documentation
The Kill method executes asynchronously. After calling the Kill method, call the WaitForExit method to wait for the process to exit, or check the HasExited property to determine if the process has exited.
ProcessStartInfo startInfo = new ProcessStartInfo("iexplore.exe");
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.Arguments = "http://www.google.com";
Process ieProcess = Process.Start(startInfo);
ieProcess.Kill();
ieProcess.WaitForExit();
How to properly close Internet Explorer when launched from PowerShell?
Several of those commented in the above thread that this is caused by a bug in Win7 (as it does not seem to occur for users that are using other versions of windows). Many pages on the internet, including microsoft's page claim user error, and tell you to simply use the available quit method on the IE object which is SUPPOSED to close all child processes as well (and reportedly does in Win8/XP etc)
I must admit, for my part, it WAS user error. I am in win7 and the reason the quit method was not working for me was because of an error in coding. Namely I was creating the IE object at declaration, and then creating another (attached to the same object) later on in the code... I had almost finished hacking the parent-child killing routine to work for me when I realized the issue.
Because of how IE functions, the processID you spawned as the parent could be attached to other windows/subprocesses that you did NOT create. Use quit, and keep in mind that depending on user settings (like empty cache on exit) it could take a few minutes for the processes to finish their tasks and close.

programmatically kill a process in vista/windows 7 in C#

I want to kill a process programmatically in vista/windows 7 (I'm not sure if there's significant problems in the implementation of the UAC between the two to make a difference).
Right now, my code looks like:
if(killProcess){
System.Diagnostics.Process[] process = System.Diagnostics.Process.GetProcessesByName("MyProcessName");
// Before starting the new process make sure no other MyProcessName is running.
foreach (System.Diagnostics.Process p in process)
{
p.Kill();
}
myProcess = System.Diagnostics.Process.Start(psi);
}
I have to do this because I need to make sure that if the user crashes the program or exits abruptly, this secondary process is restarted when the application is restarted, or if the user wants to change the parameters for this secondary process.
The code works fine in XP, but fails in Windows 7 (and I assume in Vista) with an 'access is denied' message. From what the Almighty Google has told me, I need to run my killing program as administrator to get around this problem, but that's just weak sauce. The other potential answer is to use LinkDemand, but I don't understand the msdn page for LinkDemand as it pertains to processes.
I could move the code into a thread, but that has a whole host of other difficulties inherent to it that I really don't want to discover.
You are correct in that it's because you don't have administrative priveleges. You can solve this by installing a service under the local system user and running a custom command against it as needed.
In your windows form app:
private enum SimpleServiceCustomCommands { KillProcess = 128 };
ServiceControllerPermission scp = new ServiceControllerPermission(ServiceControllerPermissionAccess.Control, Environment.MachineName, "SERVICE_NAME");
scp.Assert();
System.ServiceProcess.ServiceController serviceCon = new System.ServiceProcess.ServiceController("SERVICE_NAME", Environment.MachineName);
serviceCon.ExecuteCommand((int)SimpleServiceCustomCommands.KillProcess);
myProcess = System.Diagnostics.Process.Start(psi);
In your service:
private enum SimpleServiceCustomCommands { KillProcess = 128 };
protected override void OnCustomCommand(int command)
{
switch (command)
{
case (int)SimpleServiceCustomCommands.KillProcess:
if(killProcess)
{
System.Diagnostics.Process[] process = System.Diagnostics.Process.GetProcessesByName("MyProcessName");
// Before starting the new process make sure no other MyProcessName is running.
foreach (System.Diagnostics.Process p in process)
{
p.Kill();
}
}
break;
default:
break;
}
}
I'll add the code for Simon Buchan's suggestion. It makes sense and should work as well, assuming your windows form is what launched the process in the first place.
Here's where you create the process. Notice the variable myProc. That's your handle on it:
System.Diagnostics.Process myProc = new System.Diagnostics.Process();
myProc.EnableRaisingEvents=false;
myProc.StartInfo.FileName="PATH_TO_EXE";
myProc.Start();
Later, just kill it with:
myProc.Kill();

Categories

Resources