简体   繁体   English

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

[英]Using UnsafeRegisterWaitForSingleObject failed with exception when exiting app?

I'm trying to use ThreadPool.UnsafeRegisterWaitForSingleObject to notify if some app exits. 我正在尝试使用ThreadPool.UnsafeRegisterWaitForSingleObject通知某些应用程序是否退出。 It works at least at what I want but right after I close the main form, it throws the exception: 它至少可以满足我的要求,但是在我关闭主窗体后,它会抛出异常:

SEHException : External component has thrown an exception SEHException:外部组件引发了异常

Stack trace: 堆栈跟踪:

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()

Here is the code: 这是代码:

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);
};

I don't even need to wait the callback to be invoked, just run the code and right after that closing the main form will throw the exception. 我什至不需要等待回调被调用,只需运行代码,然后在关闭主窗体后立即抛出异常。

Interestingly enough that if using OpenProcess native function to get the process handle instead of using the Process class like this: 有趣的是,如果使用OpenProcess本机函数来获取进程句柄,而不是使用像这样的Process类:

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

it then works OK without any exception but I'm not so sure if it's better to stick to managed wrapper as much as possible in this case. 然后它可以正常工作,没有任何异常,但是我不确定在这种情况下是否最好坚持使用托管包装器。 Also I would like to understand why this exception is thrown when using Process class. 我也想了解为什么在使用Process类时抛出此异常。 Looks like the Synchronize flag (a required flag as documented) is what making it different between using OpenProcess and the wrapper Process . 看起来Synchronize标志(已记录为必需标志)使它在使用OpenProcess和包装器Process之间有所不同。 If so looks like Process cannot replace OpenProcess in this case or I missed something here? 如果看起来像Process在这种情况下无法替换OpenProcess ,或者我在这里错过了什么?

Other info: Visual Studio 2010, targeting .NET 4.0 其他信息:Visual Studio 2010,面向.NET 4.0

Thank you. 谢谢。

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

That's where the problem started. 那是问题开始的地方。 You now have two SafeHandles that are wrapping the same handle. 现在,您有两个包装相同手柄的SafeHandle。 One in the Process object, another in the ManualResetEvent object. 一个在Process对象中,另一个在ManualResetEvent对象中。 Inevitably one of them will always lose. 不可避免地,其中之一会永远失败。 Your code will always crash, in this case it happened because the finalizer for the MRE ran first. 您的代码将始终崩溃,在这种情况下,它的发生是因为MRE的终结器首先运行。 You have 50% odds for the other way around, happens when the Process finalizer runs first. 反之,您有50%的几率发生在Process finalizer首先运行时。

The first approach is to just not do this. 第一种方法就是不这样做。 You already have an excellent event available to do this, use the Process.Exited event . 您已经有一个出色的事件可用于执行此操作,请使用Process.Exited事件 You can even run it on the right thread so that MessageBox doesn't disappear behind another window, use its SynchronizingObject property. 您甚至可以在正确的线程上运行它,以便MessageBox不会在另一个窗口后面消失,请使用其SynchronizingObject属性。

The other approach is duplicating the handle by pinvoking DuplicateHandle. 另一种方法是通过粉刺DuplicateHandle复制句柄。 Bleh. 的Bleh。 Or just address the reason why you abused this ManualResetEvent in the first place. 或者只是解决您首先滥用此ManualResetEvent的原因。 The Process class was designed in .NET 1.0, you wouldn't have had this problem if its Handle property was SafeHandle. Process类是在.NET 1.0中设计的,如果它的Handle属性是SafeHandle,则不会出现此问题。 But its IntPtr, they couldn't fix that anymore. 但是它的IntPtr,他们再也解决不了了。 Fix it by deriving your own class from SafeHandle, don't do anything in the ReleaseHandle() overload. 通过从SafeHandle派生自己的类来对其进行修复,不要在ReleaseHandle()重载中执行任何操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 退出应用时保存游戏 - Save game when exiting app 退出Windows 8.1应用时执行代码 - Execute code when exiting Windows 8.1 App 退出应用程序后,类型为'System.FormatException'的未处理异常 - An unhandled exception of type 'System.FormatException' after exiting the app “断言失败。” 退出程序时出错 (HDF5 1.8.6) - “Assertion failed!” error when exiting program (HDF5 1.8.6) 使用 LINQ orderby 时出现异常:“无法比较数组中的两个元素” - Exception when using LINQ orderby: "Failed to compare two elements in the array" 退出WP应用程序时是否需要关闭SQLite连接? - Do we need to close SQLite connection when exiting WP app? 登录到Facebook帐户而不使用Facebook客户端API退出应用程序 - Login to facebook account without exiting app using facebook client API 退出方法时不使用而处置所有IDisposables? - Dispose all IDisposables when exiting the method without using? 使用 String.ToUpper() 时程序退出; 在一个有空格的字符串上 - Program exiting when using String.ToUpper(); on a string that has spaces in it 作为参数传递时未加载特定于环境的配置 - “未处理的异常无法映射应用程序设置部分” - Environment specific config not loaded when passed as an argument - "Unhandled exception Failed to map app settings section"
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM