I’ve been looking into the Microsoft.Windows.CsWin32
NuGet package and comparing the P/Invoke code it generates to what I would write by hand. In some cases it uses SafeHandle.DangerousAddRef
/SafeHandle.DangerousRelease
when I wouldn’t have. I’m trying to understand why, and haven’t come up with anything.
Here’s an example for the Win32 SetInformationJobObject
function:
[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();
}
}
I expected the second function to something like:
[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);
}
It seems to be making a defensive copy of the handle, but I don’t see how that would help anything. Even if the handle held by the SafeHandle
changes—which AFAIK it shouldn’t—we’d still be passing some handle into the extern
overload.
I tried checking out the source generator’s code for hints, and found the commit that added the calls, but that doesn’t tell me. I’m assuming that it was based on what the marshaler would have done with a SafeHandle
.
Any ideas on why we need to increase the reference count here?