How to wait for the first of the 2: a process and an EventWaitHandle
Asked Answered
F

3

6

I want to WaitForMultipleObjects on 2 different types:

  • an 'EventWaitHandle'
  • a 'Process.Handle' ==> intptr

I don't know how to convert (in the appropriate way) "process.Handle" to a WaitHandle in order to have the following code working:

   var waitHandles = new WaitHandle[2];
   waitHandles[0] = waitHandleExit;
   // Next line is the offending one:
   waitHandles[1] = new SafeWaitHandle(process.Handle, false);
   int waitResult = WaitHandle.WaitAny(waitHandles, timeOut);

Im getting the error:

Error   1   Cannot implicitly convert type 'Microsoft.Win32.SafeHandles.SafeWaitHandle' to 'System.Threading.WaitHandle' ...

Anybody know the right way to wait for a process and an EventWaitHandle ?

Update... Reasons for my choice of answer.

First of all thanks to all: Jaroen, Slugart and Sriram. All answers were very nice.

  • Jaroen solution for a reason I ignored didn't work on my machine. My 'Exited' event never occured (perhaps only on Disposed?).
  • Slugart solution worked perfectly and I tried it before I red its answer.
  • Sriram solution worked perfectly and I opted for it because I do not create a false EventWaitHandle and seems to be more clean according to my vision.

Thanks a lots!!!

Fugger answered 10/11, 2014 at 20:19 Comment(0)
F
10

You could subclass the WaitHandle which represents Process.Handle and use instance of that WaitHandle to wait.

public class ProcessWaitHandle : WaitHandle
{
    private readonly Process process;
    public ProcessWaitHandle(Process process)
    {
        this.process = process;
        this.SafeWaitHandle = new SafeWaitHandle(process.Handle, false);
    }
}

var waitHandles = new WaitHandle[2]
{
    waitHandleExit,
    new ProcessWaitHandle(process)
};
int waitResult = WaitHandle.WaitAny(waitHandles, timeOut);
Fort answered 10/11, 2014 at 20:38 Comment(2)
Why false on new SafeWaitHandle?Supplicatory
@Supplicatory that is the ownsHandle parameter which will be used to release the underlying handle if true while disposing. Now that we have passed false, it won't dispose the process handle.Fort
S
2

You could create your own EventWaitHandle and set it on the Process.Exited event:

var waitHandle = new ManualResetEvent(false);
process.Exited += (sender, e) => waitHandle.Set()
waitHandles[1] = waitHandle;
Shouldst answered 10/11, 2014 at 20:34 Comment(1)
Naturally it is also necessary to set EnableRaisingEvents, but this whole approach is needlessly wasteful when the OS process handle is already waitable.Bobbybobbye
L
2

A process handle is not naturally awaitable nor does it sit in the same inheritance tree as WaitHandle. You need to wrap it in an event (which does extend WaitHandle), e.g.:

 ManualResetEvent resetEvent = new ManualResetEvent(true);
 resetEvent.SafeWaitHandle = new SafeWaitHandle(new IntPtr(process.Handle.ToPointer()), false);
 waitHandles[1] = = resetEvent;

All WaitHandle implementations will use a SafeWaitHandle: "The SafeWaitHandle class is used by the System.Threading.WaitHandle class. It is a wrapper for Win32 mutexes and auto and manual reset events."

Lordship answered 10/11, 2014 at 20:42 Comment(1)
Wouldn't resetEvent.SafeWaitHandle = leak the event made by the constructor?Thrippence

© 2022 - 2024 — McMap. All rights reserved.