I have the following function:
private void TakeOverAllScreens()
{
int i = 0;
foreach (Screen s in Screen.AllScreens)
{
if (s != Screen.PrimaryScreen)
{
i++;
Process.Start(Application.ExecutablePath, "Screen|" + s.Bounds.X + "|" + s.Bounds.Y + "|" + i);
}
}
}
As you can see it creates a separate instance of my application for each screen on the pc.
How can I create an exit function that closes all of them?
The function needs to work on any instance of the app, not just my "Main" instance.
You can terminate all processes with the same name:
var current = Process.GetCurrentProcess();
Process.GetProcessesByName(current.ProcessName)
.Where(t => t.Id != current.Id)
.ToList()
.ForEach(t => t.Kill());
current.Kill();
Just you have to keep track of opened processes:
List<Process> opened = new List<Process>();
private void TakeOverAllScreens()
{
int i = 0;
foreach (Screen s in Screen.AllScreens)
{
if (s != Screen.PrimaryScreen)
{
i++;
opened.Add(Process.Start(Application.ExecutablePath, "Screen|" + s.Bounds.X + "|" + s.Bounds.Y + "|" + i));
}
}
}
Then:
private void terminateAll()
{
foreach (var p in opened) p.Kill();
}
How can you close an application?
There are three general options:
Kill it outright
Assuming that it has a main window and that it behaves conventionally, send a WM_CLOSE message to that window by P/Invoking SendMessage
Assuming that it wants to cooperate, use a custom communication channel to tell it to terminate itself
How should you close an application?
Killing a process outright is heavy-handed and should never be attempted unless you know that the process won't be doing anything sensitive when it's terminated. Typically this is used as a last resort.
Telling it to close its main window requires that you first learn what that window's HWND is somehow; you can do that by walking the list of top-level windows or by having the spawned process somehow communicate it to you. It also assumes that the other process will decide to terminate itself when you ask that its main window be closed (in reality it could decide to do anything, including completely ignore the message). This approach is a reasonable first attempt and it usually works fine with processes which are not under your control -- although you have to find the window yourself.
Using a custom communication channel allows you to completely control what happens and how plus it can be implemented in lots of ways, but it's an approach that involves writing the most code and needs you to have source access to both applications.
Conclusion
It depends. If you are 1000% sure that killing the process won't disrupt anything then that would be a quick and dirty solution; otherwise you need to use one of the two "polite" approaches.
Put all opened process in list, so you can kill the process one by one. Look code bellow:
private void TakeOverAllScreens()
{
int i = 0;
List<Process> allProcesses = new List<Process>();
foreach (Screen s in Screen.AllScreens)
{
if (s != Screen.PrimaryScreen)
{
i++;
allProcesses.Add(Process.Start(Application.ExecutablePath, "Screen|" + s.Bounds.X + "|" + s.Bounds.Y + "|" + i));
}
}
foreach (Process proc in allProcesses)
{
proc.Kill();
}
}
I always execute command
tskill notepad // to kill all instances of notepad
From within App, it can be done like
Process.Start("cmd /k tskill " + Process.GetCurrentProcess().ProcessName)
Try this function:
void ExitAll(string processName)
{
foreach(Process p in Process.GetProcesses())
{
if (p.ProcessName.ToLower().Equals(processName.ToLower()))
p.Kill();
}
}
Related
From a C# service, how I can check whether another app is dead or not?
I tried to use Process.Responding, it returns true but the app is died.
This is the code:
private List<string> getListStringGAppPath()
{
List<string> listGAppPaths = new List<string>();
Process[] processes = Process.GetProcessesByName("MyApp");
if (processes.Length > 0)
{
for (int i = 0; i < processes.Length; i++) {
listGAppPaths.Add(processes[i].Responding.ToString() + "######" + processes[i].MainModule.FileName);
//processes[i].Responding.ToString() always return True
}
return listGAppPaths;
}
else
{
return null;
}
}
When process dies, windows seems to toggles its state to Suspended, you can try checking its state first. Also here: Detecting process crash in .NET
You can check if the process is responding:
foreach (var process in System.Diagnostics.Process.GetProcesses())
{
Console.WriteLine("Process Name: {0}, Responding: {1}", process.ProcessName, process.Responding);
}
Similar to this answer:
Check status of process
You can use the methods in System.Diagnostics.Process to get process information.
GetProcessesByName(String)
Creates an array of new Process components and associates them with all the process resources on the local computer that share the specified process name.
GetProcessById(Int32)
Returns a new Process component, given the identifier of a process on the local computer.
GetProcesses()
Creates a new Process component for each process resource on the local computer.
If the process does not exist, then it must have died?
I have been researching this issue pretty extensively and cannot seem to find an answer.
I know that the Only part of a ReadProcessMemory or WriteProcessMemory request was completed exception is thrown when a 32-bit process tries to access a 64-bit process and the same for a 64-bit modifying a 32-bit process.
The solution to that issue is to change the Platform Target to 'Any CPU'. I have tried this and unfortunately this does not solve my issue.
The next block of code is what keeps throwing the exception. The program that runs this code is used to open up applications on remote computers and keeps a list of all the processes that the program itself opened so that I don't have to loop through all the processes.
Process processToRemove = null;
lock (_runningProcesses)
{
foreach (Process p in _runningProcesses)
{
foreach (ProcessModule module in p.Modules)
{
string[] strs = text.Split('\\');
if (module.ModuleName.Equals(strs[strs.Length - 1]))
{
processToRemove = p;
break;
}
}
if (processToRemove != null)
{
break;
}
}
if (processToRemove != null)
{
processToRemove.Kill();
_runningProcesses.Remove(processToRemove);
}
}
These processes can and most likely will be 32-bit and 64-bit, mixed together.
Is there anything I am doing that I shouldn't be doing, or is there just a better way to do all of this?
As detailed in the comments of the MSDN page for Process.Modules and this thread there is a known issue in Process.Modules when enumerating 32 bit processes from a 64 bit process and visa-versa:
Internally .NET's Process.Modules is using function EnumProcessModules
from PSAPI.dll. This function has a known issue that it cannot work
across 32/64 bit process boundary. Therefore enumerating another
64-bit process from 32-bit process or vice versa doesn't work
correctly.
The solution seems to be to use the EnumProcessModulesEx function, (which must be called via P/Invoke), however this function is only available on later versions of Windows.
We fixed this issue by adding
a new function called EnumProcessModulesEx to PSAPI.dll
(http://msdn2.microsoft.com/en-us/library/ms682633.aspx), but we
currently cannot use it in this case:
it only works on Windows Vista or Windows Server 2008
currently .NET 2.0 Framework don't have a service pack or hotfix to make Process.Modules use this new API
There are only some issues regarding the handling of the processes and the locking that I would change:
object lockObject = new object();
List<Process> processesToRemove = new List<Process>();
foreach (Process p in _runningProcesses)
{
foreach (ProcessModule module in p.Modules)
{
string[] strs = text.Split('\\');
if (module.ModuleName.Equals(strs[strs.Length - 1]))
{
processesToRemove.Add(p);
break;
}
}
}
lock (lockObject)
{
foreach (Process p in processesToRemove)
{
p.Kill();
_runningProcesses.Remove(p);
}
}
I'm not answering for the bounty, just wanted to give some ideas. This code isn't tested because I don't exactly know what you are trying to do there.
Just consider not to lock the process-list and to keep the lock as short as possible.
I agree with #sprinter252 that _runningProcesses should not be used as your sync object here.
//Somewhere that is accessible to both the thread getting the process list and the thread the
//code below will be running, declare your sync, lock while adjusting _runningProcesses
public static readonly object Sync = new object();
IList<Process> runningProcesses;
lock(Sync)
{
runningProcesses = _runningProcesses.ToList();
}
Process processToRemove = null;
foreach (Process p in _runningProcesses)
{
foreach (ProcessModule module in p.Modules)
{
string[] strs = text.Split('\\');
if (module.ModuleName.Equals(strs[strs.Length - 1]))
{
processToRemove = p;
break;
}
}
if (processToRemove != null)
{
break;
}
}
if (processToRemove != null)
{
//If we've got a process that needs killing, re-lock on Sync so that we may
//safely modify the shared collection
lock(Sync)
{
processToRemove.Kill();
_runningProcesses.Remove(processToRemove);
}
}
If this code is wrapped in a loop to continue to check _runningProcesses for the process you wish to kill, consider changing processToRemove to processesToRemove and change it's type to a collection, iterate over that list in the bottom block after a check for a non-zero count and lock outside of that loop to decrease the overhead of obtaining and releasing locks per process to kill.
I want to build my application with the function to restart itself. I found on codeproject
ProcessStartInfo Info=new ProcessStartInfo();
Info.Arguments="/C choice /C Y /N /D Y /T 3 & Del "+
Application.ExecutablePath;
Info.WindowStyle=ProcessWindowStyle.Hidden;
Info.CreateNoWindow=true;
Info.FileName="cmd.exe";
Process.Start(Info);
Application.Exit();
This does not work at all...
And the other problem is, how to start it again like this?
Maybe there are also arguments to start applications.
Edit:
http://www.codeproject.com/script/Articles/ArticleVersion.aspx?aid=31454&av=58703
I use similar code to the code you tried when restarting apps. I send a timed cmd command to restart the app for me like this:
ProcessStartInfo Info = new ProcessStartInfo();
Info.Arguments = "/C ping 127.0.0.1 -n 2 && \"" + Application.ExecutablePath + "\"";
Info.WindowStyle = ProcessWindowStyle.Hidden;
Info.CreateNoWindow = true;
Info.FileName = "cmd.exe";
Process.Start(Info);
Application.Exit();
The command is sent to the OS, the ping pauses the script for 2-3 seconds, by which time the application has exited from Application.Exit(), then the next command after the ping starts it again.
Note: The \" puts quotes around the path, incase it has spaces, which cmd can't process without quotes.
Hope this helps!
Why not use
Application.Restart();
??
More on Restart
Why not just the following?
Process.Start(Application.ExecutablePath);
Application.Exit();
If you want to be sure the app does not run twice either use Environment.Exit(-1) which kills the process instantaneously (not really the nice way) or something like starting a second app, which checks for the process of the main app and starts it again as soon as the process is gone.
You have the initial application A, you want to restart.
So, When you want to kill A, a little application B is started, B kill A, then B start A, and kill B.
To start a process:
Process.Start("A.exe");
To kill a process, is something like this
Process[] procs = Process.GetProcessesByName("B");
foreach (Process proc in procs)
proc.Kill();
A lot of people are suggesting to use Application.Restart. In reality, this function rarely performs as expected. I have never had it shut down the application I am calling it from. I have always had to close the application through other methods such as closing the main form.
You have two ways of handling this. You either have an external program that closes the calling process and starts a new one,
or,
you have the start of your new software kill other instances of same application if an argument is passed as restart.
private void Application_Startup(object sender, StartupEventArgs e)
{
try
{
if (e.Args.Length > 0)
{
foreach (string arg in e.Args)
{
if (arg == "-restart")
{
// WaitForConnection.exe
foreach (Process p in Process.GetProcesses())
{
// In case we get Access Denied
try
{
if (p.MainModule.FileName.ToLower().EndsWith("yourapp.exe"))
{
p.Kill();
p.WaitForExit();
break;
}
}
catch
{ }
}
}
}
}
}
catch
{
}
}
Winforms has the Application.Restart() method, which does just that. If you're using WPF, you can simply add a reference to System.Windows.Forms and call it.
Another way of doing this which feels a little cleaner than these solutions is to run a batch file which includes a specific delay to wait for the current application to terminate. This has the added benefit of preventing the two application instances from being open at the same time.
Example windows batch file ("restart.bat"):
sleep 5
start "" "C:\Dev\MyApplication.exe"
In the application, add this code:
// Launch the restart batch file
Process.Start(#"C:\Dev\restart.bat");
// Close the current application (for WPF case)
Application.Current.MainWindow.Close();
// Close the current application (for WinForms case)
Application.Exit();
My solution:
private static bool _exiting;
private static readonly object SynchObj = new object();
public static void ApplicationRestart(params string[] commandLine)
{
lock (SynchObj)
{
if (Assembly.GetEntryAssembly() == null)
{
throw new NotSupportedException("RestartNotSupported");
}
if (_exiting)
{
return;
}
_exiting = true;
if (Environment.OSVersion.Version.Major < 6)
{
return;
}
bool cancelExit = true;
try
{
List<Form> openForms = Application.OpenForms.OfType<Form>().ToList();
for (int i = openForms.Count - 1; i >= 0; i--)
{
Form f = openForms[i];
if (f.InvokeRequired)
{
f.Invoke(new MethodInvoker(() =>
{
f.FormClosing += (sender, args) => cancelExit = args.Cancel;
f.Close();
}));
}
else
{
f.FormClosing += (sender, args) => cancelExit = args.Cancel;
f.Close();
}
if (cancelExit) break;
}
if (cancelExit) return;
Process.Start(new ProcessStartInfo
{
UseShellExecute = true,
WorkingDirectory = Environment.CurrentDirectory,
FileName = Application.ExecutablePath,
Arguments = commandLine.Length > 0 ? string.Join(" ", commandLine) : string.Empty
});
Application.Exit();
}
finally
{
_exiting = false;
}
}
}
This worked for me:
Process.Start(Process.GetCurrentProcess().MainModule.FileName);
Application.Current.Shutdown();
Some of the other answers have neat things like waiting for a ping to give the initial application time to wind down, but if you just need something simple, this is nice.
For .Net application solution looks like this:
System.Web.HttpRuntime.UnloadAppDomain()
I used this to restart my web application after changing AppSettings in myconfig file.
System.Configuration.Configuration configuration = WebConfigurationManager.OpenWebConfiguration("~");
configuration.AppSettings.Settings["SiteMode"].Value = model.SiteMode.ToString();
configuration.Save();
I posted about this a little while ago, but I resolved the other issue and ran into one more. I am about to deploy this program to 28 hosting machines so I want to make sure this is working before I do so.
I wrote a little c# NET application that is basically a wrapper for a Java application, when my app starts, the Java app starts, when my app closes, it closes, and so on.
Everything works properly except that when I close my application, the Java application continues to run. When I create the process, I store the Process var in a variable outside of the methods, and then use that when my application goes to shutdown. For whatever reason though it is not terminating the Java application.
class Program
{
private static Process minecraftProcess;
public static void LaunchMinecraft(String file, String memoryValue)
{
String memParams = "-Xmx" + memoryValue + "M" + " -Xms" + memoryValue + "M ";
String args = memParams + "-jar " + file + " nogui";
ProcessStartInfo processInfo = new ProcessStartInfo("java.exe", args);
processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = false;
try
{
//using (Process minecraftProcess = Process.Start(processInfo))
using (minecraftProcess = Process.Start(processInfo))
{
minecraftProcess.WaitForExit();
}
}
catch
{
// Log Error
}
}
static void Main(string[] args)
{
Arguments CommandLine = new Arguments(args);
// Hook ProcessExit Event
AppDomain.CurrentDomain.ProcessExit += new EventHandler(Current_ProcessExit);
if (CommandLine["file"] != null && CommandLine["memory"] != null)
{
// Launch the Application (Command Line Parameters)
LaunchMinecraft(CommandLine["file"], CommandLine["memory"]);
}
else
{
// Launch the Application (Default Parameters)
LaunchMinecraft("minecraft_server.jar", "1024");
}
}
static void Current_ProcessExit(object sender, EventArgs e)
{
System.Threading.Thread.Sleep(10000);
// If we have an active Minecraft Service, Shut it down
if (minecraftProcess != null)
{
minecraftProcess.Kill();
}
}
}
You can't Sleep in a ProcessExit handler.
The documentation states:
The total execution time of all
ProcessExit event handlers is limited,
just as the total execution time of
all finalizers is limited at process
shutdown. The default is two seconds.
An unmanaged host can change this
execution time by calling the
ICLRPolicyManager::SetTimeout method
with the OPR_ProcessExit enumeration
value.
Nevermind, I just realized the minecraftProcess variable is static.
Don't know if you did not solve this issue by yourself but:
You should be aware that there are Start methods for instances (returning bool) and static (returning a object).
You should not use using with something other than using-local variables!
Just this should work fine:
minecraftProcess = Process.Start(processInfo)
minecraftProcess.WaitForExit();
How can I kill some active processes by searching for their .exe filenames in C# .NET or C++?
Quick Answer:
foreach (var process in Process.GetProcessesByName("whatever"))
{
process.Kill();
}
(leave off .exe from process name)
My solution is to use Process.GetProcess() for listing all the processes.
By filtering them to contain the processes I want, I can then run Process.Kill() method to stop them:
var chromeDriverProcesses = Process.GetProcesses().
Where(pr => pr.ProcessName == "chromedriver"); // without '.exe'
foreach (var process in chromeDriverProcesses)
{
process.Kill();
}
Update:
In case if you want to do the same in an asynchronous way (using the C# 8 Async Enumerables), check this out:
const string processName = "chromedriver"; // without '.exe'
await Process.GetProcesses()
.Where(pr => pr.ProcessName == processName)
.ToAsyncEnumerable()
.ForEachAsync(p => p.Kill());
Note: using async methods doesn't always mean code will run faster.
The main benefit is that the foreground thread will be released while operating.
You can use Process.GetProcesses() to get the currently running processes, then Process.Kill() to kill a process.
If you have the process ID (PID) you can kill this process as follow:
Process processToKill = Process.GetProcessById(pid);
processToKill.Kill();
You can Kill a specific instance of MS Word.
foreach (var process in Process.GetProcessesByName("WINWORD"))
{
// Temp is a document which you need to kill.
if (process.MainWindowTitle.Contains("Temp"))
process.Kill();
}
Depending on how many processes there are to kill (e.g. when its hundreds like in my case), foreaching over all of them might take quite a while. (interesting sidenote: while Kill() was usually quite quick in .NET FW 4.8 , somehow in NET 6.0 Windows its a lot slower - seeing multiple Win32Exceptions in the debug/trace until the target process is finally done)
Anyway back to topic:
In case of an app shutdown, where u need to make sure every process is is gone, consider using the TAP library - particulary the Parallel shortcuts, hundreds of processes killed within a glimpse.
Usage example:
var procs = Process.GetProcessByName("mydirtyprocesses");
if (procs.Length == 0) return;
procs.AsParallel().ForAll(process =>
{
try
{
process.Kill();
// No process linked to the process comp (mostly because the process died in
// the short timespan between invoking GetProcess() and the effective
// initialization of the props/fields of the component. -OR- Process has
// already exited (when the exit happened after the process component has
// beenpopulated (difference is, in case 1 you cannot even get the Process
// ID from // the component, in case 2 you see data like Id and get the true
// for HasExited // - so always be prepared for that.
// catch (InvalidOperationException)
{
// Process is gone, no further action required
return;
}
// Ensuring process is gone (otherwise try again or fail or whatever)
if (!process.HasExited)
{
// Handle it
}
}
In this particular scenario just wrap it properly in try/catch , as with such a number of processes the probability for an exception is quite increased
static void Main()
{
string processName = Process.GetCurrentProcess().ProcessName;
int processId = Process.GetCurrentProcess().Id;
Process[] oProcesses = Process.GetProcessesByName(processName);
if (oProcesses.Length > 1)
{
if ((MessageBox.Show("Application is opened!", "",MessageBoxButtons.YesNo) == DialogResult.Yes)) ;
{
foreach (var process in Process.GetProcessesByName(processName))
{
if (process.Id != processId)
{
process.Kill();
}
}
}
}
else
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new frmLogin());
}
}
public void EndTask(string taskname)
{
string processName = taskname.Replace(".exe", "");
foreach (Process process in Process.GetProcessesByName(processName))
{
process.Kill();
}
}
//EndTask("notepad");
Summary: no matter if the name contains .exe, the process will end. You don't need to "leave off .exe from process name", It works 100%.