Run more than 1 process in Process Class - c#

Well, it will be a bit hard to explain what i need to do here, but it goes like this:
I am building a program that will need to run .exe (From different folders).
How can i do this, that i will be able to do Process.start(), but i will be able to kill it as well?
I mean, if I do:
System.Diagnostics.Process process;
process = process.start();
Then I can do Process.Kill(); but what if I dont know how many processes I have? How can I do more and more processes with the ability to kill them?
Is this even possible?
I am hoping i explained it correctly. I am not sure how I can explain it better :O

You can store the created processes in a list to track them. Remove them from the list when you kill them:
var list = new List<Process>();
var p1 = Process.Start(...);
list.Add(p1);
// similarly for other processes, or run this in a loop
// later...
var p = list[0];
p.Kill();
list.Remove(p);
// ...
You can also use other specialized collections (like a queue) if that makes more sense.

Related

When killing a process in C#, how can I be sure I'm killing the right one?

Overall Goal
I'm attempting to kill all of the processes by a certain name (notepad.exe below) that I currently own. Generally speaking, it's along the lines of:
Get all of the applications with a certain name that I'm the owner of
In this case, "I" will usually be a service account
Kill all of them.
Questions
How likely is it that from the time I grab a PID to the time I kill it, another application could have spawned that uses that PID? If I grab a PID of ID 123, how likely is it that it could have closed and a different application now owns PID 123?
What is the best way I can reasonably pull this off while limiting the potential that I kill off the wrong PID?
What I have so Far
The below code is based on another SO answer and uses WMI to get all the processes by a certain name and list the users.
What's next: The next step is to kill the processes that are owned by me; however, how can I tell that the PIDs I have here will be the same PIDs I'm trying to kill?
static void Main(string[] args)
{
const string PROCESS_NAME = "notepad.exe";
var queryString = string.Format("Name = '{0}'", PROCESS_NAME);
var propertiesToSelect = new[] { "Handle", "ProcessId" };
var processQuery = new SelectQuery("Win32_Process", queryString, propertiesToSelect);
using (var searcher = new ManagementObjectSearcher(processQuery))
{
using (var processes = searcher.Get())
foreach (var aProcess in processes)
{
var process = (ManagementObject)aProcess;
var outParameters = new object[2];
var result = (uint)process.InvokeMethod("GetOwner", outParameters);
if (result == 0)
{
var user = (string)outParameters[0];
var domain = (string)outParameters[1];
var processId = (uint)process["ProcessId"];
Console.WriteLine("PID: {0} | User: {1}\\{2}", processId, domain, user);
// TODO: Use process data...
}
else
{
// TODO: Handle GetOwner() failure...
}
}
}
Console.ReadLine();
}
Yes, there is a risk of killing the wrong process. The reuse of PIDs probably is a history accident that has caused a lot of grief over the years.
Do it like this:
Find the PIDs you want to kill.
Obtain handles to those processes to stabilize the PIDs. Note, that this might obtain handles to wrong processes.
Re-find the PIDs you want to kill.
Kill those processes that you have stabilized and that are in the second find result set.
By inserting this lock-and-validate step you can be sure.
How likely is it that from the time I grab a PID to the time I kill it, another application could have spawned that uses that PID?
Another application wouldn't be assigned the same PID if it was spawned whilst the other one was alive. So this condition wouldn't happen as Windows' PIDs are unique decimal numbers to that specific process.
If I grab a PID of ID 123, how likely is it that it could have closed and a different application now owns PID 123?
This is technically feasible that the process could be closed between the time you gain your handle on the process and when you want to kill it. However, that would depend entirely on the lifespan of the process handling within your code. I guess there will always be edge cases where the application could be closed just as you're about to hook onto it, but if you're talking milliseconds/a couple of seconds I imagine it would be few and far between. As for Windows assigning the same PID immediately afterwards, I don't know for sure but they seem pretty random and now allocated again immediately after use, but they eventually would do.
What is the best way I can reasonably pull this off while limiting the potential that I kill off the wrong PID?
There is the Management Event Watcher class which appears to allow you to monitor the starting and stopping of processes. Maybe this could be used to capture events whenever they are closed for your given process name, so this way you know that it no longer exists?
Another answer discussing Management Event Watcher
MSDN ManagementEventWatcher class with example usage
Consider opposite approach - adjust permissions on service account so it can't kill processes of other users.
I believe such permissions are very close to default for non-admin accounts (or just default) - so unless you run service as box admin/system you may be fine with no-code solution.
A process id is guaranteed to stay the same as long as the process continues to run. Once the process exits... there is no guarantee.
When a new process starts, Windows will pick a random process ID and assign it to the new process. Its unlikely, but possible that the id chosen was associated with a process that recently exited.
Have you looked at System.Diagnostics.Process?
They have a GetProcessesByName method that will return a list of Process objects.
Process [] localByName = Process.GetProcessesByName("notepad");
Then you can simply iterate through the Processes and kill them. Since the Process object has a handle to the process... an attempt to kill it will generate a useful exception, which you can catch.
foreach (Process p in localByName)
{
try
{
p.Kill();
}
catch (Exception e)
{
// process either couldn't be terminated or was no longer running
}
}

C# equivalent to fork()/exec()

I'm developing a program that needs to call an outside program, but needs to wait for it to execute. This is being done in C# (to which I am brand new, but have lots of experience in C++, Qt, and C) and CreateProcess does not seem to be what I'm looking for (starts the process, then forgets it, which I don't need).
This is one of my first Windows projects (or at least, only Windows and definitely only .NET) and I'm much more used to doing this sort of thing for *nix where I would use fork and then exec in the child, then wait for the child to terminate. But I have no idea where to even start looking to do something like this.
Oh, and I'm pretty sure I'm stuck in .NET because I need read access to the registry to complete this project and .NET's registry access is absolutely amazing (in my opinion, I don't have anything to compare it to).
Thanks.
You can use the Process class. It lets you specify some options about how you want to execute it, and also provides a method which waits the process to exit before executing the next statement.
look at this link (the msdn reference):
http://msdn.microsoft.com/fr-fr/library/system.diagnostics.process.aspx
basically what you can do is:
Process p;
// some code to initialize it, like p = startProcessWithoutOutput(path, args, true);
p.WaitForExit();
an example of initializing the process (that's just some code I used once somewhere):
private Process startProcessWithOutput(string command, string args, bool showWindow)
{
Process p = new Process();
p.StartInfo = new ProcessStartInfo(command, args);
p.StartInfo.RedirectStandardOutput = false;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = !showWindow;
p.ErrorDataReceived += (s, a) => addLogLine(a.Data);
p.Start();
p.BeginErrorReadLine();
return p;
}
as you can see in this code you can also do some output redirection, error redirection.... If you dig in the class I think you'll find quite quickly what you need.
var p = System.Diagnostics.Process.Start("notepad");
p.WaitForExit();
You can use the Process class to start external processes.
It will let you start arbitrary programs
http://msdn.microsoft.com/en-us/library/system.diagnostics.process.aspx

Allow/Block windows process in a winform application

I've made a winform application that allows you to kill processes and gives a notification for a new process that starts. I need to add functionality to allow/block i.e blacklist/whitelist a process, so that it won't run while my application is running.
Any suggestions?
If I understand your question correctly - Here is a basic example of how to work with processes.
This is based on the assumption that you have a list of process names named blackList and you want to kill any process which is on this list:
List<string> blackList = new List<string>();
// TODO: Populate the list with "black listed" processes
// Kill any process which is in the blacklist
foreach (Process process in Process.GetProcesses())
{
if (blackList.Any(x => x.ToLowerInvariant().Equals(process.ProcessName.ToLowerInvariant())))
{
process.Kill();
}
}
This should help get you started in the right direction...

Can the Process Class be used to determine if a process is already running?

I'm using the Process Class to start processes, but don't ever want more than one instance of any program to be running.
Looking at the documentation, there are lots of likely-looking properties, but nothing that stands out as the most obvious.
What's the best way to determine if a process is running?
Edit: John Fisher is right: it's an existing application that I'm starting and I'm unable to modify it.
You can call this method
Process.GetProcesses()
and loop through the result (a collection of type Process) to see if the name matches. Something like this:
foreach (Process prc in Process.GetProcesses())
{
if (prc.ProcessName.Contains(MyProcessName))
{
//Process is running
}
}
I guess that all depends on what you mean by "best way"? Do you mean the fastest, the most accurate, or one that will handle some odd circumstances?
The way I would start is by listing the processes and checking the executable file name against the one I'm trying to start. If they match (case insensitive), it's probably running.
You should use the Singleton application pattern for that:
bool createdNew = true;
using (var mutex = new Mutex(true, "YourProcessName", out createdNew))
{
if (createdNew)
{
// Run application
}
}

Process Monitoring

I'm quite familiar with the System.Diagnostics.Process class. But, I'm wondering about how I can monitor a specific process (i.e. Check to see if it's running every XX mins/secs). I need to be able to checking whether a process is running and if it is, continue with initialising the rest of the program.
Thanks,
-Zack
Checking if it's still running is easy: Process.HasExited.
Rather than polling this periodically, however, you could set EnableRaisingEvents to true, and attach a handler to the Exited event.
EDIT: To answer the question in the comment about "fetching" the process - that depends on what you already know. If you know its process ID, you could use Process.GetProcessById. If you only know its name, you would have to use Process.GetProcessesByName and work out what to do if you get multiple results. If you don't know the exact name, you could use Process.GetProcesses and look for whatever you do know about it. Those options are effectively in order of preference :)
If you didn't start the process yourself, you get find the Process object associated with a process by looking through the list returned by Process.GetProcessesByName(...) or Process.GetProcesses(...)
Once you have the process, you can listen read its properties (including HasExited) and (as Jon mentions in his response) if you set EnableRaisingEvents you can listen to its events (including Exited).
Something like this, maybe?
Process[] processlist = Process.GetProcesses();
bool found = false;
foreach (Process theprocess in processlist)
{
if(theprocess.ProcessName == "YourProcessName")
{
found = true;
break;
}
}
if (!found)
{
return;
}

Categories

Resources