Get running process given process handle - c#

can someone tell me how i can capture a running process in c# using the process class if i already know the handle?
Id rather not have not have to enumerate the getrunning processes method either. pInvoke is ok if possible.

In plain C#, it looks like you have to loop through them all:
// IntPtr myHandle = ...
Process myProcess = Process.GetProcesses().Single(
p => p.Id != 0 && p.Handle == myHandle);
The above example intentionally fails if the handle isn't found. Otherwise, you could of course use SingleOrDefault. Apparently, it doesn't like you requesting the handle of process ID 0, hence the extra condition.
Using the WINAPI, you can use GetProcessId. I couldn't find it on pinvoke.net, but this should do:
[DllImport("kernel32.dll")]
static extern int GetProcessId(IntPtr handle);
(signature uses a DWORD, but process IDs are represented by ints in the .NET BCL)
It seems a bit odd that you'd have a handle, but not a process ID however. Process handles are acquired by calling OpenProcess, which takes a process ID.

using System.Diagnostics;
class ProcessHandler {
public static Process FindProcess( IntPtr yourHandle ) {
foreach (Process p in Process.GetProcesses()) {
if (p.Handle == yourHandle) {
return p;
}
}
return null;
}
}

There seems to be no simple way to do this by the .Net API. The question is, where you got that handle from? If by the same way you can get access to the processes ID, you could use:
Process.GetProcessById (int iD)

I'm using these methods for long time:
public static Process FindProcess(IntPtr handle) => FindProcess(p => p.Handle == handle);
public static Process FindProcess(int id) => FindProcess(p => p.Id == id);
public static Process FindProcess(string title) => FindProcess(p=> p.MainWindowTitle == title);
public static Process FindProcess(Func<Process,bool> comparer)
{
foreach (Process p in Process.GetProcesses())
if (comparer(p))
return p;
return null;
}
Enjoy...

You could use the GetWindowThreadProcessId WinAPI call
http://www.pinvoke.net/default.aspx/user32/GetWindowThreadProcessId.html
To get the Process Id - then get a Process object using that.....
But why don't you want to enumerate the ids of the running processes?

Related

CheckProcess application close

how can I make my application not open if AnyDesk and TeamViewer are open? Example: If AnyDesk and TeamViewer are running, my application will not open, but if AnyDesk and TeamViewer are closed, it will open normally.
Process[] runningProcs = Process.GetProcesses("Anydesk.exe");
foreach(Process process in runningProcs)
{
Application.Exit();
}
I don't know if this is right, but that's what I was trying
The idea you have is right but you don't have to get all processes twice and you don't have to use a foreach to exit. If you use a foreach on processes with only the name "Anydesk.exe," you'll exit when even only one of the apps is running and not both. You can use LINQ's convenient features to do this:
public static void Main()
{
var processNames = Process
.GetProcesses()
.Select(p => p.ProcessName);
if (processNames.Any(name => name is "name1" or "name2"))
{
Console.WriteLine("Found forbidden process");
Environment.Exit(exitCode: 1);
}
Console.WriteLine("No forbidden processes found");
}
The downside to this code is that only one of the applications needs to be running in order for the app to exit. Instead, you can use .Contains to ensure both are in the enumerable like this:
public static void Main()
{
var processNames = Process
.GetProcesses()
.Select(p => p.ProcessName)
.ToArray(); // Avoid multiple enumeration
if (processNames.Contains("name1") && processNames.Contains("name2"))
{
Console.WriteLine("Found forbidden process");
Environment.Exit(exitCode: 1);
}
Console.WriteLine("No forbidden processes found");
}
If the convenience of LINQ is too slow for your likings, you can use regular for loops and do the same things

How to terminate every process with the current process name except for the current process

Im trying to terminate every process with the same name as my process without killing my process.
This might be a bit confusing, maybe this code will help you understand what i meant:
private static void KillExistingProcesses()
{
Process[] p = Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName);
foreach (var pro in p)
{
if (...) // if pro != Process.GetCurrentProcess()
pro.Kill();
}
}
I tried doing this:
if (!pro.Equals(Process.GetCurrentProcess())
&& pro != Process.GetCurrentProcess())
But i still end up terminating my own process.
Can you guys help me with this? I just need to terminate every process with the same name of my process excpet for the current process.
Thank you :)
You can estimate your own Process-ID and then, in the loop, compare it to element:
private static void KillExistingProcesses()
{
Process myProc = Process.GetCurrentProcess();
;
Process[] p = Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName);
foreach (var pro in p)
{
if (pro.Id != myProc.Id)
{
pro.Kill();
}
}
}
You can use Linq to filter out the processes with the same Id
Process current = Process.GetCurrentProcess();
var processes = Process.GetProcessesByName(current.ProcessName)
.Where(p => p.Id != current.Id);
foreach(var process in processes)
{
process.Kill();
}
You are comparing Process objects which have no meaningful equality relation defined.
Compare the process IDs.

Starting and stopping a process in C# .NET

I am trying towrite a simple program that has two methods, one that starts a process and one that takes down the same process.
as in:
public Process StartProc(string procname)
{
Process proc = new Process();
proc.StartInfo.FileName = procname;
proc.Start();
return proc;
}
public void StopProc(Process proc)
{
proc.Close();
}
Is it possible to do this like that?
Yes, the method you are after is called Kill, not Close:
public void StopProc(Process proc)
{
proc.Kill();
}
This will forcibly close the process - when possible it is preferable to signal the application to close such as by requesting that the application close the main window:
public void StopProc(Process proc)
{
proc.CloseMainWindow();
}
This allows the application to perform clean-up logic (such as saving files), however may allow the process to continue running if it chooses to ignore the request and will do nothing if the process does not have a main window (for example with a console application).
For more information see the documentation on the Process.CloseMainWindow method.
I think you are looking for Process.Kill().
You don't really need a StopProc() method, you can just write proc.Kill() directly.
However, it is not generally recommended that you terminate processes in such a brutal way. Doing so can leave shared objects in an undefined state. If you can find a way to co-operatively close the process that is to be preferred.
By starting the process, you can get the unique Id of that process and then you can kill it like this:
public static int Start(string processName)
{
var process =
Process.Start(processName);
return
process.Id;
}
public static void Stop(int processId)
{
var process =
Process.GetProcessById(processId);
process.Kill();
}

Detecting if another instance of the application is already running

My application needs to behave slightly differently when it loads if there is already an instance running.
I understand how to use a mutex to prevent additional instances loading, but that doesn't quite solve my problem.
For example:
Instance 1 loads, gets the mutex.
Instance 2 loads, can't get the mutex, knows there's another instance. So far, so good.
Instance 1 closes, releases the mutex.
Instance 3 loads, gets the mutex, doesn't know that Instance 2 is still running.
Any ideas? Thankfully it doesn't need to deal with multiple user accounts or anything like that.
(C#, desktop application)
Edit: To clarify, the application doesn't need to be restricted to a single instance, just perform a slightly different start-up action if there's another instance already running. Multiple instances are fine (and expected).
This will probably do just what you want. It has the nice additional feature of bringing the already running instance forward.
EDIT: updated the code to determine the application title automatically.
using System;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
static void Main()
{
if (!EnsureSingleInstance())
{
return;
}
//...
}
static bool EnsureSingleInstance()
{
Process currentProcess = Process.GetCurrentProcess();
var runningProcess = (from process in Process.GetProcesses()
where
process.Id != currentProcess.Id &&
process.ProcessName.Equals(
currentProcess.ProcessName,
StringComparison.Ordinal)
select process).FirstOrDefault();
if (runningProcess != null)
{
ShowWindow(runningProcess.MainWindowHandle, SW_SHOWMAXIMIZED);
SetForegroundWindow(runningProcess.MainWindowHandle);
return false;
}
return true;
}
[DllImport("user32.dll", EntryPoint = "SetForegroundWindow")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern Boolean ShowWindow(IntPtr hWnd, Int32 nCmdShow);
private const int SW_SHOWMAXIMIZED = 3;
Another approach is to detect the running instance as detailed in Scott Hanselman's blog
His example activates the first instance when the second tries.
However, it wouldn't be hard to get the second instance to just stop if that's what you wanted.
Try using a Semaphore instead of a Mutex
Could you simply check GetLastError() after creating the mutex with CreateMutex()? If it returns ERROR_ALREADY_EXISTS, then there is another running instance of your application.
According to http://msdn.microsoft.com/en-us/library/ms682411%28VS.85%29.aspx,
If the mutex is a named mutex and the
object existed before this function
call, the return value is a handle to
the existing object, GetLastError
returns ERROR_ALREADY_EXISTS,
bInitialOwner is ignored, and the
calling thread is not granted
ownership. However, if the caller has
limited access rights, the function
will fail with ERROR_ACCESS_DENIED and
the caller should use the OpenMutex
function.
EDIT: Just realized this was a C#/.Net question, sorry.
In .Net, use the Mutex constructor that returns the createdNew flag, http://msdn.microsoft.com/en-us/library/bwe34f1k%28VS.80%29.aspx:
public Mutex (
bool initiallyOwned,
string name,
out bool createdNew
)
a good approach is to use the Sandor solution but use WMI to obtain the processes list, described here: C#: How to get the full path of running process? (Jeff's solution). that way, you can also check if the other running instances match by path and remote terminal session id:
static bool EnsureSingleInstance()
{
Process currentProcess = Process.GetCurrentProcess();
var wmiQueryString = "SELECT ProcessId, ExecutablePath, CommandLine FROM Win32_Process";
using (var searcher = new ManagementObjectSearcher(wmiQueryString))
using (var results = searcher.Get())
{
var query = from p in Process.GetProcesses()
join mo in results.Cast<ManagementObject>()
on p.Id equals (int)(uint)mo["ProcessId"]
select new
{
Process = p,
Path = (string)mo["ExecutablePath"],
CommandLine = (string)mo["CommandLine"],
};
var runningProcess = (from process in query
where
process.Process.Id != currentProcess.Id &&
process.Process.ProcessName.Equals(
currentProcess.ProcessName,
StringComparison.Ordinal) &&
process.Path == currentProcess.MainModule.FileName &&
process.Process.SessionId == currentProcess.SessionId
select process).FirstOrDefault();
return runningProcess == null;
}
}

How terminate child processes when parent process terminated in C#

Task: Auto kill all child processes if parent process terminate. Parent procees can be terminated not only in correct way, but also by killing in ProcessExplorer, for example.
How can I do it?
Similar question in ะก topic advice to use Job objects. How to use it in C# without exporting external DLL?
I tried to use Job Objects. But this code doesn't work properly:
var job = PInvoke.CreateJobObject(null, null);
var jobli = new PInvoke.JOBOBJECT_BASIC_LIMIT_INFORMATION();
jobli.LimitFlags = PInvoke.LimitFlags.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
| PInvoke.LimitFlags.JOB_OBJECT_LIMIT_PRIORITY_CLASS
| PInvoke.LimitFlags.JOB_OBJECT_LIMIT_JOB_TIME
| PInvoke.LimitFlags.JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION
| PInvoke.LimitFlags.JOB_OBJECT_LIMIT_JOB_MEMORY;
var res = PInvoke.SetInformationJobObject(job, PInvoke.JOBOBJECTINFOCLASS.JobObjectBasicLimitInformation, jobli, 48);
if (!res)
{
int b = PInvoke.GetLastError();
Console.WriteLine("Error " + b);
}
var Prc = Process.Start(...);
PInvoke.AssignProcessToJobObject(job, Prc.Handle);
PInvoke.SetInformationJobObject returns with error. GetLastError returns error 24.
However, PInvoke.AssignProcessToJobObject works and child process added to Job Queue (I can see it in ProcessExplorer). But, because PInvoke.SetInformationJobObject don't work - spawned process stay alive when I kill parent one.
What do I have incorrect in this code?
To kill a process tree on windows, given only the parent process or process id, you'll need to walk the process tree.
For that, you'll need a way to get the parent process id for a given process.
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Diagnostics;
using System.Management;
namespace KillProcessTree
{
public static class MyExtensions
{
public static int GetParentProcessId(this 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;
}
}
Once you have that, actually killing the tree is not hard.
class Program
{
/// <summary>
/// Kill specified process and all child processes
/// </summary>
static void Main(string[] args)
{
if (args.Length < 1)
{
Console.WriteLine("Usage: KillProcessTree <pid>");
return;
}
int pid = int.Parse(args[0]);
Process root = Process.GetProcessById(pid);
if (root != null)
{
Console.WriteLine("KillProcessTree " + pid);
var list = new List<Process>();
GetProcessAndChildren(Process.GetProcesses(), root, list, 1);
// kill each process
foreach (Process p in list)
{
try
{
p.Kill();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
else
{
Console.WriteLine("Unknown process id: " + root);
}
}
/// <summary>
/// Get process and children
/// We use postorder (bottom up) traversal; good as any when you kill a process tree </summary>
/// </summary>
/// <param name="plist">Array of all processes</param>
/// <param name="parent">Parent process</param>
/// <param name="output">Output list</param>
/// <param name="indent">Indent level</param>
private static void GetProcessAndChildren(Process[] plist, Process parent, List<Process> output, int indent)
{
foreach (Process p in plist)
{
if (p.GetParentProcessId() == parent.Id)
{
GetProcessAndChildren(plist, p, output, indent + 1);
}
}
output.Add(parent);
Console.WriteLine(String.Format("{0," + indent*4 + "} {1}", parent.Id, parent.MainModule.ModuleName));
}
}
} // namespace
I tried the code above and indeed, it does not work, complaining of a bad size. The reason for this is that the structure used changes size depending on the host platform; the original code fragment (seen on a dozen websites) assumes a 32 bit application.
Switch the structure to this (note the IntPtr resizing members) and it will work. At least it did for me.
[StructLayout(LayoutKind.Sequential)]
struct JOBOBJECT_BASIC_LIMIT_INFORMATION
{
public Int64 PerProcessUserTimeLimit;
public Int64 PerJobUserTimeLimit;
public Int16 LimitFlags;
public UIntPtr MinimumWorkingSetSize;
public UIntPtr MaximumWorkingSetSize;
public Int16 ActiveProcessLimit;
public Int64 Affinity;
public Int16 PriorityClass;
public Int16 SchedulingClass;
}
You can pass ProcessID of the parent process as an argument to the child process. And then child processes will be responsible for checking from time to time whether the parent process still running. (By calling Process.GetProcessById.)
Another way to track existence of the parent process is to use Mutex synchronization primitive.
Parent application will initially create a global mutex with the name known by children. Children can check from time to time whether the mutex still exists and terminate if not. (Once the parent process is closed the mutex will be destroyed by the system automatically, regardless of the way it way closed.)
Did you pay attention to the error code? Error 24 is ERROR_BAD_LENGTH, which probably means that 48 isn't the right length of the structure. I think it's 44, but you should do a sizeof to be sure.
Windows does not force child processes to close when a parent process closes. When you select "Kill Tree" in a tool like Task Manager or Process explorer, the tool actually finds all child processes and kill them one by one.
If you want to ensure that child processes are cleaned when your application terminates, you can create a ProcessManager class that implements IDisposable that actually creates the processes, keeps track of their instances and calls Kill on each one of them on Dispose, e.g.
public class ProcessManager:IDisposable
{
List<Process> processes=new List<Process>();
public Process Start(ProcessStartInfo info)
{
var newProcess = Process.Start(info);
newProcess.EnableRaisingEvents = true
processes.Add(newProcess);
newProcess.Exited += (sender, e) => processes.Remove(newProcess);
return newProcess;
}
~ProcessManager()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
foreach (var process in processes)
{
try
{
if (!process.HasExited)
process.Kill();
}
catch{}
}
}
}

Categories

Resources