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!!!

Eric Ouellet
  • 10,996
  • 11
  • 84
  • 119

3 Answers3

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);
Community
  • 1
  • 1
Sriram Sakthivel
  • 72,067
  • 7
  • 111
  • 189
  • Why `false` on `new SafeWaitHandle`? – N-ate Aug 14 '18 at 18:19
  • @N-ate 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. – Sriram Sakthivel Sep 04 '18 at 19:06
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;
Jeroen Kok
  • 796
  • 5
  • 7
  • Naturally it is also necessary to set `EnableRaisingEvents`, but this whole approach is needlessly wasteful when [the OS process handle is already waitable](https://learn.microsoft.com/en-us/windows/win32/sync/synchronization-objects). – Ben Voigt May 04 '21 at 19:04
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."

Slugart
  • 4,535
  • 24
  • 32
  • Wouldn't `resetEvent.SafeWaitHandle =` leak the event [made by the constructor](https://referencesource.microsoft.com/#mscorlib/system/threading/eventwaithandle.cs,69)? – Kevin Smyth Jan 12 '18 at 21:25