Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET Frustration - Process.GetProcessById Returns New Reference

I'm writing a c# program that will launch many child processes. At some time later on, I'll need to retrieve those processes by ID and then match those processes to a set of processes stored in a Dictionary that were added to the Dictionary when they were first created. However, I'm running into a problem that seems like pure ridiculousness...

Process notepad = new Process();
notepad.StartInfo.FileName = "notepad";
notepad.Start();

Process n2 = Process.GetProcessById(notepad.Id);

Debug.WriteLine(notepad == n2);       //'False', but Why isn't this true???
Debug.WriteLine(notepad.Id == n2.Id); //'True'

I've used .NET Reflector to find out that GetProcessById returns a 'new Process(...)', but it seems like it should just find a reference to the already running process and return it instead.

You can assume the first Debug statement is essentially a call like

MyCustomDataType data = myDictionary[notepad];

I would expect to get the data I originally inserted, instead I get a KeyNotFoundException probably because the default comparer is doing a reference check. To counter this, I've added a custom IComparer on my dictionary that just checks that the two Process objects have the same ID, so I can get the associated data as expected. However, this has its own problem in that Processes that are not running do not have process IDs, so sometimes the call in my custom IComparer to Process.ID throws an InvalidOperationException!!! So, I've fixed one problem only to create another.

So, I guess I have two questions:

  • Why doesn't .NET just return a reference to an already running Process instance?
  • What can I do to match processes stored in my dictionary since using process ID is not always valid for the lifetime of the Process object?
like image 438
Chad Avatar asked Sep 14 '26 16:09

Chad


2 Answers

Not really sure why you had to resort to Reflector, since the GetProcessByID MSDN documentation clearly states:

Creates a new Process component, and associates it with the existing process resource that you specify.

The framework can't return to you the same instance you have. To be able to do this, the framework would have to keep a reference to all Process instances ever created and compare the process ID for them to find out the one you already have. I'll leave to you to imagine the implications this would have on the memory and the perf of the framework.

Besides, the Process class is a wrapper around the process handle returned by the OpenProcess Win32 API. And it is possible to have multiple handles to the same process. And input/output redirection can be done on a per-handle basis, thus, it is expected scenario to be able to have two Process instances that represent the same process and one of them dealing with the output and error streams and the other one with the input stream.

On a separate note, it seems to me that you are using the Process object itself as the key for the Dictionary. But the Process object does not represent the identity of the actual process, it is just a representation of the process. You should use as a key something that represents the identity of the process instead.

like image 144
Franci Penov Avatar answered Sep 16 '26 06:09

Franci Penov


Running programs are operating system processes, not instances of the Process managed type. The Process type is one type of managed wrapper object around an operating system concept. It allows control of the target process by hiding the P/Invoke calls. The operating system does not require a particular instance of the Process class perform these operations, which is why GetProcessById can return a new instance and still expect everything to work.

The ID is valid for the life of the process itself. Perhaps you could set EnableRaisingEvents to true and add an event handler to the Process.Exited event that removes the process from your cache?

like image 26
Sam Harwell Avatar answered Sep 16 '26 06:09

Sam Harwell



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!