2

I'm trying to determine if a process is still alive (at the moment I did check, I'm aware it can be closed right after I do the check) by calling WaitForSingleObject() with a handle get from Process.MainWindowHandle which works just fine with IsIconic() but it return WAIT_FAILED and GetLastError() a ERROR_INVALID_HANDLE

UInt32 r = WaitForSingleObject(handle, 0);
if(r == WAIT_OBJECT_0)
{
    MessageBox.Show("still running!");
}
if(r == WAIT_FAILED)
{
    throw new Win32Exception(Marshal.GetLastWin32Error());
}
MethodMan
  • 18,625
  • 6
  • 34
  • 52
Jack
  • 16,276
  • 55
  • 159
  • 284
  • Possible duplicate of [Calling WaitForSingleObject from C#](http://stackoverflow.com/questions/33718217/calling-waitforsingleobject-from-c-sharp) – MethodMan Jun 24 '16 at 17:18
  • 1
    You can't wait on a window's handle. Check the docs at https://msdn.microsoft.com/en-us/library/windows/desktop/ms687032.aspx for the types of handles that can be waited on.. – dxiv Jun 24 '16 at 17:20
  • The system says that your handle is not valid. Your handle is not valid. – David Heffernan Jun 24 '16 at 17:25

1 Answers1

5

You cannot wait on a window handle. You can pass window handles to window-related functions, like IsIconic(), but they are not kernel objects so you cannot wait on them. The documentation gives a list of objects that you can wait on:

The WaitForSingleObject function can wait for the following objects:

  • Change notification
  • Console input
  • Event
  • Memory resource notification
  • Mutex
  • Process
  • Semaphore
  • Thread
  • Waitable timer

So, if you want to wait on a process until it ends, you can wait on the process's handle, which is accessible via the Process.Handle property.

But you don't actually need to P/Invoke the Win32 function at all. The .NET Process wrapper class has WaitForExit() and WaitForInputIdle() member functions that can be used to wait on a process (note that both have overloads taking a timeout value).

If this is a process that you started using the Process class wrapper, you can simply interrogate the Process.HasExited property.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
  • 2
    If you have a `Process` object, shouldn't you be able to use `HasExited` regardless of whether you were the one who actually spawned the process? I don't see why it should care if the caller is also the spawner. – Remy Lebeau Jun 24 '16 at 20:10
  • thanks for your answer, I don't want wait until it exit, haven't started the process too. I want to check if a determined process is still alive at a particular time before doing some action (it happens every x seconds) – Jack Jun 24 '16 at 20:53
  • @remy The reason I wrote that is I remember reading somewhere that this didn't work. Presumably the Process class doesn't track this information unless it starts the process. Looking to corroborate my memory, I found [this how-to article](https://msdn.microsoft.com/en-us/library/y111seb2.aspx), which says at the top: *"Note: This value is only returned for processes that are started by a Process component."* That may not be entirely true; you'd need to check the reference source to be absolutely certain. – Cody Gray - on strike Jun 25 '16 at 11:42
  • 1
    @jack Then it sounds like you have a good old-fashioned race condition. Checking if the process is alive won't do you a lot of good in that case. Just try to perform the action and handle failures gracefully. It also sounds suspiciously to me like you might be trying to implement this via polling, which is pretty much always a bad design. – Cody Gray - on strike Jun 25 '16 at 11:43
  • @Jack by definition, a process is still alive if it has not exited yet. So either check `HasExited`, or like Cody said, you can call `WaitForExit()` with a timeout: "*If you pass 0 (zero) to the method, it returns true only if the process has already exited; otherwise, it immediately returns false*". That is the same effect as calling `WaitForSingleObject()` with a 0ms timeout. – Remy Lebeau Jun 25 '16 at 13:08