Repository navigation
Should PHIDP_PREPARSED_DATA be a SafeHandle? #1675
Replies: 2 comments
|
CsWin32 only generates a SafeHandle when win32metadata says what frees the type (the CloseApi field, e.g. HKEY -> RegCloseKey). PHIDP_PREPARSED_DATA has no CloseApi, so you get a plain struct. The real fix is a one-line win32metadata PR adding HidD_FreePreparsedData there. Until then wrapping it yourself is fine: sealed class PreparsedDataSafeHandle : SafeHandleZeroOrMinusOneIsInvalid
{
public PreparsedDataSafeHandle(PHIDP_PREPARSED_DATA data) : base(ownsHandle: true) => SetHandle(data.Value);
public PHIDP_PREPARSED_DATA Data => new(handle);
protected override bool ReleaseHandle() => PInvoke.HidD_FreePreparsedData(new PHIDP_PREPARSED_DATA(handle));
}Wrap it immediately after HidD_GetPreparsedData returns, with nothing that can throw in between. |
|
Once both are released, the generated overload has an The BOOLEAN ok = PInvoke.HidD_GetPreparsedData(device, out HidD_FreePreparsedDataSafeHandle preparsed);
using (preparsed)
{
if (ok)
{
NTSTATUS status = PInvoke.HidP_GetCaps(preparsed.DangerousValue, out HIDP_CAPS caps);
}
}
If the owner outlives one method, for example in a field that another thread can dispose, take a lease for each use. using var lease = this.preparsed.Lease();
NTSTATUS status = PInvoke.HidP_GetCaps(lease.Value, out HIDP_CAPS caps);We ran both patterns with CsWin32 from #1859 and a winmd built from microsoft/win32metadata#2376. They read the capabilities of 32 HID collections on a test machine. Over 20,000 get-and-dispose cycles, private bytes grew by under 1 MB. The same loop without a free grew them by over 9 MB. The annotation goes on the Until both changes are released, the wrapper posted above is a good way to handle this. When you switch, you can delete the wrapper, change the |
Uh oh!
There was an error while loading. Please reload this page.
Hi,
I'm working on migrating to use CsWin32 instead of our own native interop definitions to ensure the interop is correct but I'm not sure how to proceed with Hid Preparsed data.
CsWin32 has created this definition for HidD_GetPreparsedData:
internal static unsafe winmdroot.Foundation.BOOLEAN HidD_GetPreparsedData(SafeHandle HidDeviceObject, out winmdroot.Devices.HumanInterfaceDevice.PHIDP_PREPARSED_DATA PreparsedData)The PHIDP_PREPARSED_DATA is a struct that only contains a nint property, and is only passed to other HidD_* functions, but is allocated by the HidD_GetPreparsedData and must be freed with HidD_FreePreparsedData when no longer required.
Recently we discovered a memory leak in our software where the preparsed data was not being freed in some cases and changed our interop definitions to use a custom PreParsedDataSafeHandle, but I'm not sure how to proceed with CsWin32 when the definition it returns a struct containing a single nint. Should I bundle the PHIDP_PREPARSED_DATA in a custom SafeHandle, or should CsWin32 be providing a definition that returns a SafeHandle?
many thanks.
All reactions