为何在DangerousGetHandle前后需调用DangerousAddRef/DangerousRelease?
核心原因是防止GC在Win32函数执行期间回收SafeHandle,导致句柄失效,具体拆解如下:
SafeHandle的本质:它是.NET封装的托管句柄类型,自带自动回收机制——当GC判定SafeHandle不再被引用时,会自动调用其
ReleaseHandle方法释放底层Win32句柄。但如果直接调用DangerousGetHandle()获取IntPtr传递给Win32函数,此时GC并不知道这个IntPtr和SafeHandle的关联,仍可能在Win32函数执行过程中回收SafeHandle。CsWin32的安全保障:生成代码中调用
DangerousAddRef()会强制增加SafeHandle的引用计数,阻止GC回收该实例;Win32函数调用完成后再调用DangerousRelease()减少计数,恢复正常的GC回收逻辑。这样就能保证在AssignProcessToJobObject执行的整个周期内,传入的作业对象或进程句柄始终有效,不会出现因句柄被提前释放导致的调用失败、崩溃等问题。手动实现的潜在风险:如果你直接调用
DangerousGetHandle()传递IntPtr,没有手动管理引用计数,就存在GC触发时机的不确定性——比如Win32函数执行耗时较长,或者GC刚好在此时进行回收,SafeHandle被销毁,底层句柄被关闭,AssignProcessToJobObject就会操作一个无效句柄,引发不可预期的错误。与封送器的关联:.NET封送器在直接传递SafeHandle类型参数时,会自动处理引用计数的增减,但CsWin32生成的代码中,很多时候是将SafeHandle转换为IntPtr后传递(比如适配某些特殊的函数签名),此时封送器无法自动识别关联,所以需要手动调用
DangerousAddRef/DangerousRelease来补上这个安全环节,确保句柄生命周期覆盖Win32函数的执行过程。
内容的提问来源于stack exchange,提问作者Matt Tsōnto

