I'm using a native DLL. I'm not sure, but I think I can't use PInvoke decl's with it since it does not export any functions and does not have a manifest. The DLL is delivered with a header file, explaining how to use it. The header file defines countless structs, enums and one class to be constructed using a factory method which is accessed via a Windows function ::GetProcAddress
(security through obscurity).
This class holds functions I would like to use in managed code.
I have successfully wrapped the class in a CLI ref class and can call trivial methods on it, wrapping those as well.
I'm going through the process of converting some structs from the header file to managed structs. For example, Native structs:
struct FooACL{
int action;
unsigned long from,to;
char comment[64];
int reserved[17];
};
Turns into managed struct:
[StructLayout(LayoutKind::Sequential, CharSet = CharSet::Ansi)]
public value struct ManagedFooACL{
int action;
int from,to;
[MarshalAs(UnmanagedType::ByValTStr, SizeConst = 64)]
String^ comment;
[MarshalAs(UnmanagedType::ByValArray, SizeConst = 17)]
array<int>^ reserved;
};
As far as I can tell this should make the managed struct blittable? And any other struct that follows a similar pattern or levels of nested structure. As long as a layout is specified and none blittable are adorned with MarshalAs, will the structure as a whole be blittable?
And so, I'm attempting to see if there is a way to use Marshal::Copy
or Marshal::PtrToStructure
to convert an FooACL*
array to array<ManagedFooACL>^
.
I get the FooACL* array from a function call; I do not allocate it myself.
int total;
FooACL* foos = unamagedClass->GetFooACLS(&total);
total
is an in/out that gets the size of the array returned.
What I managed to do so far, and what work is:
ManagedFooACL first = static_cast<ManagedFooACL>(Marshal::PtrToStructure(IntPtr(&foos [0]), ManagedFooACL::typeid));
What I can't wrap my mind around is why this does not:
array<ManagedFooACL>^ mfoos = gcnew array<ManagedFooACL>(total);
Marshal::PtrToStructure(IntPtr(&foos), mfoos);
This throws a:
System.ArgumentException was unhandled
Message=The specified structure must be blittable or have layout information.
Parameter name: structure
Source=mscorlib
ParamName=structure
Is there a way to copy array data in one call or do I really need to do a for loop? It seems kind of silly with all this marshaling capability.
Having done some more research it looks like the answer is no. It is not possible to auto marshal an array
of struct
s without looping.
I think the main reason struct
marshaling works with PtrToStructure
is because the structure is static/predefined. The compiler knows how to lay out the memory. Since, you get a dynamic size array
there's no way to specify the memory lay out ahead of time. So you must loop dynamic number of struct
s.
Alternatively, if you knew that you will always be getting an array of X length, you could define your own managed struct
holding one element, namely the array of ManagedFooACL
with a ByValArray
and SizeConst
value of X, and just cast the native array
to the struct
.
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