退出应用程序时使用 UnsafeRegisterWaitForSingleObject 失败并出现异常?
Using UnsafeRegisterWaitForSingleObject failed with exception when exiting app?
我正在尝试使用 ThreadPool.UnsafeRegisterWaitForSingleObject
通知某些应用程序是否退出。它至少可以按我的要求工作,但在我关闭主窗体后,它会抛出异常:
SEHException : External component has thrown an exception
堆栈跟踪:
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
class 来获取进程句柄:
//ProcessAccessFlags.Synchronize = 0x00100000
var p = OpenProcess(ProcessAccessFlags.Synchronize, false, 8524);
然后它毫无例外地工作正常,但我不确定在这种情况下是否最好坚持使用托管包装器。另外我想了解为什么在使用 Process
class 时抛出此异常。看起来 Synchronize
标志(记录的必需标志)是使用 OpenProcess
和包装器 Process
之间的区别所在。如果在这种情况下看起来 Process
无法替换 OpenProcess
或者我在这里遗漏了什么?
其他信息:Visual Studio 2010,针对 .NET 4.0
谢谢。
wh.SafeWaitHandle = new SafeWaitHandle(p, true);
这就是问题开始的地方。您现在有 两个 个 SafeHandles 包装同一个句柄。一个在 Process 对象中,另一个在 ManualResetEvent 对象中。不可避免地,其中之一将永远失败。您的代码总是会崩溃,在这种情况下,它的发生是因为 MRE 运行 的终结器首先出现。当 Process finalizer 运行s 首先出现时,你有 50% 的可能性相反。
第一种方法就是不这样做。您已经有一个很棒的事件可以执行此操作,请使用 Process.Exited event。您甚至可以 运行 它在正确的线程上,这样 MessageBox 就不会消失在另一个 window 后面,使用它的 SynchronizingObject 属性.
另一种方法是通过调用 DuplicateHandle 来复制句柄。呸。或者只是解决您最初滥用此 ManualResetEvent 的原因。 Process class 是在.NET 1.0 中设计的,如果它的Handle 属性 是SafeHandle,你就不会遇到这个问题。但它的 IntPtr,他们无法再修复它了。通过从 SafeHandle 派生您自己的 class 来修复它,不要在 ReleaseHandle() 重载中做任何事情。
我正在尝试使用 ThreadPool.UnsafeRegisterWaitForSingleObject
通知某些应用程序是否退出。它至少可以按我的要求工作,但在我关闭主窗体后,它会抛出异常:
SEHException : External component has thrown an exception
堆栈跟踪:
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
class 来获取进程句柄:
//ProcessAccessFlags.Synchronize = 0x00100000
var p = OpenProcess(ProcessAccessFlags.Synchronize, false, 8524);
然后它毫无例外地工作正常,但我不确定在这种情况下是否最好坚持使用托管包装器。另外我想了解为什么在使用 Process
class 时抛出此异常。看起来 Synchronize
标志(记录的必需标志)是使用 OpenProcess
和包装器 Process
之间的区别所在。如果在这种情况下看起来 Process
无法替换 OpenProcess
或者我在这里遗漏了什么?
其他信息:Visual Studio 2010,针对 .NET 4.0
谢谢。
wh.SafeWaitHandle = new SafeWaitHandle(p, true);
这就是问题开始的地方。您现在有 两个 个 SafeHandles 包装同一个句柄。一个在 Process 对象中,另一个在 ManualResetEvent 对象中。不可避免地,其中之一将永远失败。您的代码总是会崩溃,在这种情况下,它的发生是因为 MRE 运行 的终结器首先出现。当 Process finalizer 运行s 首先出现时,你有 50% 的可能性相反。
第一种方法就是不这样做。您已经有一个很棒的事件可以执行此操作,请使用 Process.Exited event。您甚至可以 运行 它在正确的线程上,这样 MessageBox 就不会消失在另一个 window 后面,使用它的 SynchronizingObject 属性.
另一种方法是通过调用 DuplicateHandle 来复制句柄。呸。或者只是解决您最初滥用此 ManualResetEvent 的原因。 Process class 是在.NET 1.0 中设计的,如果它的Handle 属性 是SafeHandle,你就不会遇到这个问题。但它的 IntPtr,他们无法再修复它了。通过从 SafeHandle 派生您自己的 class 来修复它,不要在 ReleaseHandle() 重载中做任何事情。