CsWin32 generates `SafeHandle` parameter for `LPPROC_THREAD_ATTRIBUTE_LIST` in `CreateRemoteThreadEx`
alexrp opened this issue · comments
Actual behavior
Expected behavior
Probably no SafeHandle
-ification for this parameter.
Repro steps
NativeMethods.txt
content:
CreateRemoteThreadEx
NativeMethods.json
content (if present):
{
"$schema": "https://raw.githubusercontent.com/microsoft/CsWin32/main/src/Microsoft.Windows.CsWin32/settings.schema.json",
"className": "WindowsPInvoke",
"allowMarshaling": false,
"wideCharOnly": false,
"emitSingleFile": true
}
Context
- CsWin32 version: 0.3.106
- Win32Metadata version (if explicitly set by project): 60.0.34-preview
- Target Framework:
net8.0
LangVersion
(if explicitly set by project):latest
Additionally, the generated overload throws ArgumentNullException
if a null SafeHamdle
is passed for lpAttributeList
, even though this is perfectly valid according to the native signature.
Maybe this is just a Win32Metadata bug?
I'm on 0.3.106 and don't see the problem with offering a SafeHandle overload. A non-SafeHandle overload is also offered. This is typical behavior.
As for throwing ArgumentNullException
, that does look like a bug, since the metadata attributes that parameter with [Optional]
.
I'm on 0.3.106 and don't see the problem with offering a SafeHandle overload. A non-SafeHandle overload is also offered. This is typical behavior.
Just to clarify: Are you saying that you do see the SafeHandle lpAttributeList
overload, but you don't see why offering it would be a problem?
Assuming I understood you correctly: The problem is that it just isn't a handle. Calling CloseHandle()
on it will not work; you're supposed to use DeleteProcThreadAttributeList()
. So representing it as a handle ironically ends up being very error-prone and unsafe. I should probably have clarified earlier that CsWin32 0.3.49-beta didn't do this, which is why the code in the screenshots above only broke after updating.
SafeHandle
is an abstract class, and we use derived types in .NET for a variety of native resources, where CloseHandle
is just one way of releasing them. With CsWin32, we emit custom SafeHandle
-derived types for many of these native resources. In this case, the metadata indicates that LPPROC_THREAD_ATTRIBUTE_LIST
is a handle to a native resources released by DeleteProcThreadAttributeList
, so CsWin32 is emitting the SafeHandle overload in anticipation that a SafeHandle
-derived type may exist to track this type and release it when no longer used.
What I don't see here is an actual SafeHandle
-derived type being emitted by CsWin32 even when the allocating InitializeProcThreadAttributeList
function is generated. This is unexpected, and is probably due to InitializeProcThreadAttributeList
using an output parameter to provide the handle to its caller instead of its return value. CsWin32 may not be prepared to trigger its SafeHandle overload and type for allocating functions except by return value. I'll file an issue to track that.
Hmm. If CsWin32 is going to encourage SafeHandle
s for non-handle resources like this, I would at least suggest that the generated overloads should be strongly-typed - i.e. take ProcThreadAttributeListSafeHandle
(or whatever it'd be called) instead of SafeHandle
.
By taking just SafeHandle
, type safety is lost in a way not dissimilar to the olden days of .NET interop where everyone would pass IntPtr
around due to irrational fear of unsafe
, thus having less type safety and more fragile code than they would have had with properly-typed pointers.
Your concern about the input parameters being typed as SafeHandle
instead of the specific derived type is valid, and an ongoing discussion tracking it is in #125.