退出应用程序时,使用UnsafeRegisterWaitForSingleObject失败,出现异常

本文关键字:异常 失败 使用 应用程序 退出 UnsafeRegisterWaitForSingleObject | 更新日期: 2023-09-27 18:12:38

我正在尝试使用ThreadPool.UnsafeRegisterWaitForSingleObject来通知是否有应用程序退出。它至少在我想要的地方工作,但在我关闭主窗体后,它抛出了一个异常:

SEHException:外部组件引发异常

堆栈跟踪:

at Microsoft.Win32.SafeNativeMethods.CloseHandle(IntPtr handle)
at Microsoft.Win32.SafeHandles.SafeProcessHandle.ReleaseHandle()
at System.Runtime.InteropServices.SafeHandle.InternalFinalize()
at System.Runtime.InteropServices.SafeHandle.Dispose(Boolean disposing)
at System.Runtime.InteropServices.SafeHandle.Finalize()

这是代码:

Load += (s, e) => {
   var p = System.Diagnostics.Process.GetProcessById(8524).Handle;
   var wh = new ManualResetEvent(false);
   wh.SafeWaitHandle = new SafeWaitHandle(p, true);                
   var cl = ThreadPool.UnsafeRegisterWaitForSingleObject(
                                            wh, new WaitOrTimerCallback((o, b) => 
                {
                    MessageBox.Show("Exited!");
                }), null, Timeout.Infinite, true);
};

我甚至不需要等待回调被调用,只需运行代码,然后关闭主窗体就会抛出异常。

有趣的是,如果使用OpenProcess本机函数来获取进程句柄,而不是像这样使用Process类:

//ProcessAccessFlags.Synchronize = 0x00100000
var p = OpenProcess(ProcessAccessFlags.Synchronize, false, 8524);

然后它就可以正常工作了,没有任何异常,但我不太确定在这种情况下,尽可能多地使用托管包装器是否更好。此外,我还想了解为什么在使用Process类时会引发此异常。看起来Synchronize标志(如文档所示,这是一个必需的标志(是使用OpenProcess和包装Process的区别所在。如果是这样的话,看起来Process在这种情况下不能取代OpenProcess,或者我错过了什么?

其他信息:Visual Studio 2010,目标是.NET 4.0

谢谢。

退出应用程序时,使用UnsafeRegisterWaitForSingleObject失败,出现异常

wh.SafeWaitHandle = new SafeWaitHandle(p, true); 

这就是问题的根源。现在,您有两个SafeHandles正在包装同一个句柄。一个在Process对象中,另一个在ManualResetEvent对象中。不可避免地,他们中的一个总会输。您的代码总是会崩溃,在这种情况下,这是因为MRE的终结器首先运行。当流程终结器首先运行时,您有50%的几率会发生另一种情况。

第一种方法就是不要这样做。您已经有一个优秀的事件可以执行此操作,请使用Process.Exited事件。您甚至可以在正确的线程上运行它,这样MessageBox就不会消失在另一个窗口后面,使用它的SynchronizingObject属性。

另一种方法是通过固定DuplicateHandle来复制句柄。Bleh。或者首先说明您滥用此手动重置事件的原因。Process类是在.NET 1.0中设计的,如果它的Handle属性是SafeHandle,就不会有这个问题。但这是IntPtr,他们再也无法解决这个问题了。通过从SafeHandle派生自己的类来修复它,不要在ReleaseHandle((重载中做任何事情。