Specifically, if I make a struct that has a single field, that essentially acts as a wrapper around that value, is it safe to pass this struct to a P/Invoke method expecting the underlying type?
I'm working with a native library whose API involves a lot of pointer-to-struct types, and I'd like to use something a bit more typesafe than IntPtr
to keep them all straight, by wrapping IntPtr
in a generic struct. Would that work? (And has it already been done?)
No. The size of all the types in the struct , and thus the offset to each member from the beginning of the struct , is known at compile-time, so the address used to fetch the values in the struct is every bit as knowable as the addresses of individual variables.
No. Struct does not add any size, or have any overhead in the compiled C. It is a layer of syntax that requires additional work by the compiler, but has no overhead at runtime.
Yes except for padding. The struct occupies one "area" in memory. I say "area" because this is poorly defined in C due to manual memory management. Each item in the struct comes after the previous one, but there may be padding between them.
From what I've read, a struct should only be used if it's 16 bytes or less; otherwise it should be a class.
Don't pass it as a struct, then.
Instead of figuring out how to do this directly with P/Invoke, just keep the P/Invoke methods private
, and expose public methods that will take your wrapper type directly - and handle whatever you need to do to pass it forward. Your code is then only going to use these public methods without having to worry about unsafe structures :)
Mixing different types and expecting them to magically work is a recipe for disaster. Make yourself explicit, and don't rely on hiding and implicit forced casts.
The best thing about this is that it allows you to very easily use some pointer wrapper that is actually safe - you can keep it as a reference, and if it's ever lost, you can use a finalizer to dispose of the unmanaged resource as needed. Have a look at how SafeHandle
and it's descendants work for a great sample.
So long as you use LayoutKind.Sequential
, then the struct's single field will be located at offset zero. Therefore, your assumption is correct.
I presume that by pointer-to-struct type, you mean an opaque pointer. The struct is forward declared but never defined. However, in that case I cannot see how declaring a struct in your C# code can really help you. An opaque pointer is, well, opaque. Only the library implementation knows how to allocate it. You can't allocate it in the consumer.
Update
Perhaps you want to wrap an opaque pointer in a struct like this:
[StructLayout(LayoutKind.Sequential)]
struct FooHandle
{
IntPtr handle;
}
// and so on for other handle types
Interop with this struct will be indistinguishable from interop with IntPtr
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With