我一直在研究
Microsoft.Windows.CsWin32
NuGet 包,并将其生成的 P/Invoke 代码与我手写的代码进行比较。在某些情况下,它会使用 SafeHandle.DangerousAddRef
/SafeHandle.DangerousRelease
,而我不会使用。我试图理解为什么,但没有想出任何办法。
这是 Win32
SetInformationJobObject
函数的示例:
[DllImport("KERNEL32.dll", ExactSpelling = true, SetLastError = true)]
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
[SupportedOSPlatform("windows5.1.2600")]
internal static extern unsafe winmdroot.Foundation.BOOL SetInformationJobObject(winmdroot.Foundation.HANDLE hJob, winmdroot.System.JobObjects.JOBOBJECTINFOCLASS JobObjectInformationClass, void* lpJobObjectInformation, uint cbJobObjectInformationLength);
/// <inheritdoc cref="AssignProcessToJobObject(winmdroot.Foundation.HANDLE, winmdroot.Foundation.HANDLE)"/>
[SupportedOSPlatform("windows5.1.2600")]
internal static unsafe winmdroot.Foundation.BOOL AssignProcessToJobObject(SafeHandle hJob, SafeHandle hProcess)
{
bool hJobAddRef = false;
bool hProcessAddRef = false;
try
{
winmdroot.Foundation.HANDLE hJobLocal;
if (hJob is object)
{
hJob.DangerousAddRef(ref hJobAddRef);
hJobLocal = (winmdroot.Foundation.HANDLE)hJob.DangerousGetHandle(); // <-- THIS
}
else
throw new ArgumentNullException(nameof(hJob));
winmdroot.Foundation.HANDLE hProcessLocal;
if (hProcess is object)
{
hProcess.DangerousAddRef(ref hProcessAddRef);
hProcessLocal = (winmdroot.Foundation.HANDLE)hProcess.DangerousGetHandle();
}
else
throw new ArgumentNullException(nameof(hProcess));
winmdroot.Foundation.BOOL __result = PInvoke.AssignProcessToJobObject(hJobLocal, hProcessLocal); // calls the `extern` overload
return __result;
}
finally
{
if (hJobAddRef)
hJob.DangerousRelease();
if (hProcessAddRef)
hProcess.DangerousRelease();
}
}
我期望第二个函数是这样的:
[DllImport("KERNEL32.dll", ExactSpelling = true, SetLastError = true)]
[SupportedOSPlatform("windows5.1.2600")]
internal static unsafe winmdroot.Foundation.BOOL AssignProcessToJobObject(SafeHandle hJob, SafeHandle hProcess)
{
var localJob = (winmdroot.Foundation.HANDLE)hJob.DangerousGetHandle();
var localProcess = (winmdroot.Foundation.HANDLE)hProcess.DangerousGetHandle();
return (winmdroot.Foundation.BOOL)PInvoke.AssignProcessToJobObject(localJob, localProcess);
}
它似乎正在制作手柄的防御性副本,但我不知道这有什么帮助。即使
SafeHandle
持有的句柄发生变化(据我所知,它不应该发生变化),我们仍然会将 some 句柄传递给 extern
重载。
我尝试检查源生成器的代码以获取提示,并发现添加了调用的提交,但这并没有告诉我。我假设它是基于封送拆收器使用
SafeHandle
所做的事情。
关于为什么我们需要在这里增加引用计数有什么想法吗?
来自官方文档:
使用 DangerousGetHandle 方法可能会带来安全风险,因为: 如果句柄已被标记为无效
,SetHandleAsInvalid
仍然返回原始的,可能已经过时 处理值。返回的句柄也可以随时回收。 充其量,这意味着手柄可能会突然停止工作。最坏的情况是, 如果句柄或句柄代表的资源被公开 不受信任的代码,这可能会导致对 重复使用或返回的句柄。例如,不受信任的调用者可以查询 句柄上的数据刚刚返回并接收信息 完全不相关的资源。DangerousGetHandle
[强调我的:] 参见
和DangerousAddRef
方法以获取有关使用的更多信息DangerousRelease
安全方法。DangerousGetHandle
DangerousAddRef 方法可防止公共语言运行时回收句柄使用的内存(当运行时调用 ReleaseHandle 方法时会发生这种情况)。您可以使用此方法手动增加 SafeHandle 实例上的引用计数。 [...].
所以这似乎是为了确保句柄在使用时不会失效。