退出应用程序时,使用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
谢谢。
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((重载中做任何事情。