I have the following c#/c code, where I am doing stuff in a C dll. Am using pinvoke/marshal as the black magic that enables me to dynamically allocate/free stuff in the dll, without c# code knowing anything untoward is going on.
In this snippet, you will see that I am using 2 different ways to alloc/use/free an array of doubles. My question is, what does the "MarshalAs(UnmanagedType..." line do, because both incantations (ie, using or not using the MarshalAs statement) work fine? I should add that I have a poor understanding of C, even less understanding of C#, and I understand the whole pinvoke/marshal about as well as I understand supersymmetric quantum mechanics.
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class row
{
public int a;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
IntPtr[] b;
IntPtr [] c;
}
// c code
struct row
{
int a;
double *b;
double *c;
}
void fooe(void)
{
row.b[4] = (double *) malloc(54000);
row.c[4] = (double *) malloc(54000);
free(row.b[4]);
free(row.c[4]);
}
This particular use of ByValArray changes everything.
First, let's consider the without ByValArray case. Here the array is marshalled as a pointer to the first element. The matching C struct is
struct row
{
int a;
void* *b; // more likely you would use a typed pointer
void* *c;
}
No for the case where you use ByValArray. Here the array is marshalled inline and the equivalent C struct is:
struct row
{
int a;
void* b[12];
void* *c;
}
These two versions are very different.
I also wonder if you really meant to use IntPtr[] in the C# code. Did you perhaps really mean to write double[]? So, perhaps you actually meant:
[StructLayout(LayoutKind.Sequential)]
public class row
{
public int a;
double[] b;
double[] c;
}
In which case the matching C struct would be:
struct row
{
int a;
double *b;
double *c;
}
I've no idea what is meant by the fooe function, but it makes no sense at all and does not compile. It looks like you are trying to assign a pointer to a double which is quite meaningless.
Related
I have a dll which has arguments with double*, eg xyz(double* a, double* b). I am using this DLL to pass two double arrays to function xyz. The problem is when I'm passing a double array by reference using a, the array is being updated but the values are rounded off which happens when you typecast something to and from int. Can you tell me an efficient way of sending this double array to c dll and getting the desired results in decimal. (Changing the DLL is not an option). Also I tried Marshal, I am not entirely sure if I did the right thing, but whenever I used to change the argument of xyz to xyz(IntPtr a, double* b) or something I used to get AccessViolationException, corrupt memory.
Try following :
double[] a = { 1.23, 2.34, 5.45 };
IntPtr aptr = Marshal.AllocHGlobal(a.Length * sizeof(double));
Marshal.Copy(a, 0, aptr, a.Length);
double[] b = { 1.23, 2.34, 5.45 };
IntPtr bptr = Marshal.AllocHGlobal(b.Length * sizeof(double));
Marshal.Copy(b, 0, bptr, b.Length);
xyz(aptr, bptr)
If I understand correctly, you are passing an array from C# to C (or C++) code. The problem with the approach of sending in the array directly to the method like xyz(double* a, double* b) is that the the code has no way of knowing the sizes of the arrays. This can get you access violation exceptions, once the C/C++ code tries to access an element that is out of the bounds of the array.
There are multiple ways around this - either using SafeArray from C# (that already contains the size attribute), sending the arrays to some bridging method with the sizes, or passing the data in a struct, like this:
internal struct ArraysStruct
{
public int floatArraySize;
public IntPtr floatArray;
public int uintArraySize;
public IntPtr uintArray;
}
Which would then be matched on the C/C++ side by something like:
typedef struct ArraysStruct
{
size_t floatArraySize;
float* floatArray;
size_t uintArraySize;
unsigned int* uintArray;
}
You would need to use Marshal.AllocHGlobal() to allocate the arrays to the sizes first (in C#) and then Marshal.FreeHGlobal() once you're done with them.
I'm trying to populate an array of structures from C++ and pass the result back to C#.
I thought maybe creating a struct with an array of structures maybe the way forward as most examples I have come across use structures(but passing basic types). I have tried the following but no luck so far.
Found an example at: http://limbioliong.wordpress.com/2011/08/20/passing-a-pointer-to-a-structure-from-c-to-c-part-2/?relatedposts_exclude=542
I have the following in C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace CSharpDLLCall
{
class Program
{
[StructLayout(LayoutKind.Sequential,Pack=8)]
public struct Struct1
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public double[] d1;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public double[] d2;
}
[StructLayout(LayoutKind.Sequential)]
public struct TestStructOuter
{
public int length;
public IntPtr embedded;
}
static void Main(string[] args)
{
Program program = new Program();
program.demoArrayOfStructs();
}
public void demoArrayOfStructs()
{
TestStructOuter outer = new TestStructOuter();
testStructOuter.embedded = new Struct1[10];
outer.length = 10;
outer.embedded = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Struct1)) * 10);
Marshal.StructureToPtr(outer, outer.embedded, false);
testAPI2(ref outer);
outer = (TestStructOuter)(Marshal.PtrToStructure(outer.embedded, typeof(TestStructOuter)));
Marshal.FreeHGlobal(outer.embedded);
}
[DllImport(#"C:\CPP_Projects\DLL\DLLSample\Release\DLLSample.dll")]
static extern void testAPI2(IntPtr pTestStructOuter);
}
}
In C++ in the header i have
#ifdef DLLSAMPLE_EXPORTS
#define DLLSAMPLE_API __declspec(dllexport)
#else
#define DLLSAMPLE_API __declspec(dllimport)
#endif
#include <iostream>
using namespace std;
#pragma pack(1)
struct struct1
{
double d1[];
double d2[];
};
struct TestStructOuter
{
struct1* embedded;
};
extern "C"
{
DLLSAMPLE_API void __stdcall testAPI2(TestStructOuter* pTestStructOuter);
}
In the cpp I have:
#include "stdafx.h"
#include "DLLSample.h"
__declspec(dllexport) void __stdcall testAPI2(TestStructOuter* pTestStructOuter)
{
// not sure that this is necessary
// for (int i = 0; i < 10 ; ++i)
// {
// pTestStructOuter->embedded = new struct1;
// }
for (int i = 0; i < 10 ; ++i)
{
struct1 s1;
for (int idx = 0; idx < 10; ++idx)
{
s1.d1[i] = i+0.5;
s1.d2[i] = i+0.5;
}
pTestStructOuter->embedded[0] = s1;
}
}
This doesn't seem to work the error i get:
The parameter is incorrect.(Exception from HRESULT:0x80070057 (E_INVALIDARG))
Which probably means that its not recognizing the array of structures. Any ideas how I can do this? Thanks.
Okay, I have a working sample. I'm posting this as another answer because it's a very different approach.
So, on the C++ side, I've got this header file:
struct Struct1
{
int d1[10];
int d2[10];
};
extern "C" __declspec(dllexport) void __stdcall
TestApi2(int* pLength, Struct1 **pStructures);
And the following code:
__declspec(dllexport) void __stdcall
TestApi2(int* pLength, Struct1 **pStructures)
{
int len = 10;
*pLength = len;
*pStructures = (Struct1*)LocalAlloc(0, len * sizeof(Struct1));
Struct1 *pCur = *pStructures;
for (int i = 0; i < len; i++)
{
for (int idx = 0; idx < 10; ++idx)
{
pCur->d1[idx] = i + idx;
pCur->d2[idx] = i + idx;
}
pCur ++;
}
}
Now, the important bit is LocalAlloc. That's actually the place where I've had all the issues, since I allocated the memory wrong. LocalAlloc is the method .NET calls when it does Marshal.AllocHGlobal, which is very handy, since that means we can use the memory in the caller and dispose of it as needed.
Now, this method allows you to return an arbitrary length array of structures. The same approach can be used to eg. return a structure of an array of structures, you're just going deeper. The key is the LocalAlloc - that's memory you can easily access using the Marshal class, and it's memory that isn't thrown away.
The reason you have to also return the length of the array is because there's no way to know how much data you're "returning" otherwise. This is a common "problem" in unmanaged code, and if you've ever done any P/Invoking, you know everything about this.
And now, the C# side. I've tried hard to do this in a nice way, but the problem is that arrays of structures simply aren't blittable, which means you can't simply use MarshalAs(UnmanagedType.LPArray, ...). So, we have to go the IntPtr way.
The definitions look like this:
[StructLayout(LayoutKind.Sequential)]
public class Struct1
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public int[] d1;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public int[] d2;
}
[DllImport(#"Win32Project.dll", CallingConvention = CallingConvention.StdCall)]
static extern void TestApi2(out int length, out IntPtr structs);
Basically, we get a pointer to the length of the "array", and the pointer to the pointer to the first element of the array. That's all we need to read the data.
The code follows:
int length;
IntPtr pStructs;
TestApi2(out length, out pStructs);
// Prepare the C#-side array to copy the data to
Struct1[] structs = new Struct1[length];
IntPtr current = pStructs;
for (int i = 0; i < length; i++)
{
// Create a new struct and copy the unmanaged one to it
structs[i] = new Struct1();
Marshal.PtrToStructure(current, structs[i]);
// Clean-up
Marshal.DestroyStructure(current, typeof(Struct1));
// And move to the next structure in the array
current = (IntPtr)((long)current + Marshal.SizeOf(structs[i]));
}
// And finally, dispose of the whole block of unmanaged memory.
Marshal.FreeHGlobal(pStructs);
The only thing that changes if you want to really return a structure of an array of structures is that the method parameters move into the "wrapping" structure. The handy thing is that .NET can automatically handle the marshalling of the wrapper, the less-handy thing is that it can't handle the inner array, so you again have to use length + IntPtr to manage this manually.
First, don't use unknown-length arrays at all. You're killing any possible use of arrays between managed and unmanaged code - you can't tell the required size (Marshal.SizeOf is useless), you have to manually pass the array length etc. If it's not a fixed length array, use IntPtr:
[StructLayout(LayoutKind.Sequential,Pack=8)]
public struct Struct1
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public double[] d1;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public double[] d2;
}
[StructLayout(LayoutKind.Sequential)]
public struct TestStructOuter
{
public int length;
public IntPtr embedded;
}
(if your array of embedded is fixed length, feel free to ignore this, but do include the ByValArray, SizeConst bit. You also have to add ArraySubType=System.Runtime.InteropServices.UnmanagedType.Struct to the attribute).
As you've probably noticed, the TestStructOuter is pretty much useless in this case, it only adds complexity (and do note that marshalling is one of the most expensive operations compared to native languages, so if you're calling this often, it's probably a good idea to keep things simple).
Now, you're only allocating memory for the outer struct. Even in your code, Marshal.SizeOf has no idea how big the struct should be; with IntPtr, this is even more so (or, to be more precise, you're only requesting a single IntPtr, ie. 4-8 bytes or so + the length). Most often, you'd want to pass the IntPtr directly, rather than doing this kind of wrapping (using the same thing in C++/CLI is a different thing entirely, although for your case this is unnecessary).
The signature for your method will be something like this:
[DllImport(#"C:\CPP_Projects\DLL\DLLSample\Release\DLLSample.dll",
CallingConvention=System.Runtime.InteropServices.CallingConvention.StdCall)]
public static extern void testAPI2(ref TestStructOuter pTestStructOuter) ;
Now, if you're going with the IntPtr approach, you want to keep allocating memory manually, only you have to do it properly, eg.:
TestStructOuter outer = new TestStructOuter();
testStructOuter.length = 1;
testStructOuter.embedded = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Struct1)));
Marshal.StructureToPtr(embedded, testStructOuter.embedded, false);
And finally, you call the method:
// The marshalling is done automatically
testAPI2(ref outer);
Don't forget to release the memory, ideally in the finally clause of a try around everything since the memory allocation:
Marshal.FreeHGlobal(outer.embedded);
Now, this is overly complicated and not exactly optimal. Leaving out the TestStructOuter is one possibility, then you can simply pass the length and pointer to the embedded array directly, avoiding one unnecessary marshalling. Another option would be to use a fixed size array (if it needs to be an array at all :)) in TestStructOuter, which will cure a lot of your headaches and eliminate any need for manual marshalling. In other words, if TestStructOuter is defined as I've noted before:
[StructLayout(LayoutKind.Sequential)]
public struct TestStructOuter
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10,
ArraySubType=UnmanagedType.Struct)]
public Struct1[] embedded;
}
Suddenly, your whole call and everything becomes as simple as
testAPI2(ref outer);
The whole marshalling is done automatically, no need for manual allocations or conversions.
Hope this helps :)
Hint: Leadn C++/CLI. I had to deal with complex interop two times in my life - once with ISDN (AVM devkits make it a lot easier - sadly C++, I needed C#) and now with Nanex (great real time complex and full market ata feeds, sadl complex C++, I need C#)
Both cases I make my own wrapper in C++/CLI, talking down to C++ and exposing a real object model in C#. Allows me to make things a lot nicer and handle a lot of edge cases that our friendly Marshaller can not handle efficiently.
I am creating a new question here as I now know how to ask this question, but I'm still a newb in PInvoke.
I have a C API, with the following structures in it:
typedef union pu
{
struct dpos d;
struct epo e;
struct bpos b;
struct spos c;
} PosT ;
typedef struct dpos
{
int id;
char id2[6];
int num;
char code[10];
char type[3];
} DPosT ;
and the following API function:
int addPos(..., PosT ***posArray,...)
the way I call this in C like this:
int main(int argc, const char *argv[])
{
...
PosT **posArray = NULL;
...
ret_sts = addPos(..., &posArray, ...);
...
}
inside addPos() memory will be allocated to posArray and it will also be populated. allocation is like this using calloc:
int addPos(..., PosT ***posArray, ...)
{
PosT **ptr;
...
*posArray = (PosT **) calloc(size, sizeof(PosT *));
*ptr = (PosT *)calloc(...);
...
(*posArray)[(*cntr)++] = *ptr;
...
/* Population */
...
}
I have another function that will be called to deallocate that memory.
Now I want to do the same in C#,
I have created this in my C# class:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct DPositionT
{
public int Id;
[MarshalAs(UnmanagedType.LPStr, SizeConst = Constants.Id2Len)]
public string Id2;
public int Num;
[MarshalAs(UnmanagedType.LPStr, SizeConst = Constants.CodeLen)]
public string Code;
[MarshalAs(UnmanagedType.LPStr, SizeConst = Constants.TypeLen)]
public string type;
}
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit )]
struct PosT
{
[System.Runtime.InteropServices.FieldOffset(0)]
DPosT d;
};
I have only defined d, as I am only going to use this member of the union in my client code.
Now in order to call addPos() how should I create and pass posArray ?
your help is very much appreciated.
One of the really important thing to note is that the third * from the PosT*** is there just to provide possibility to return the allocated pointer to the caller. This means that in fact the type is PosT** and that in C# parameter will have to be declared either ref or out modifier.
The fragment you've provided is incomplete, but tells few things:
*posArray = (PosT **) calloc(size, sizeof(PosT *)); // A
*ptr = (PosT *)calloc(...); // B1
...
(*posArray)[(*cntr)++] = *ptr; // B2
in (A) an array, PosT* is created, then in (B1)+(B2) some cells of that array are initialized to some new arrays of undisclosed size. Please note that with your code snippet, the first 'some' and the second 'some' may be unrelated.
Also, the sizes of those arrays are unknown, except for the top-most "size" that probably comes from parameters.
This means that from C# point of view, the datastructre you want to actually receive is "PosT[][]", so the P/Invoke signature would be like:
[...]
... addPos(..., out PosT[][] posArray, ....)
so, even in C# it would be an 2-dimensional jagged array of returned by parameter, just like in C/C++.
However, unlike C where you can have loose pointers that points to unspecific blocks of data, in C#, every array must have a precisely known length. As the "size" is probably known to you, you can tell the marshaller what is the size of the first dimension.
If the outer "size" is a constant:
[...]
... addPos(..., [MarshalAs(SizeConst=100)]out PosT[][] posArray, ....)
or, if it is passed by parameter:
[...]
... addPos(int size, ...., [MarshalAs(SizeParamIndex=0)]out PosT[][] posArray, ....)
of course assuming that "size" is really the very first parameter.
However, all of this does not specify the size of the inner arrays. What's more, with the code snippet you've provided, those inner arrays may differ in their lengths. Let me play with the code snippet you have presented:
*posArray = (PosT **) calloc(size, sizeof(PosT *)); // A
(*cntr) = 0
for(int idx = 0; idx<size; ++idx)
{
*ptr = (PosT *)calloc(5+40*(*cntr)); // B1
(*posArray)[(*cntr)++] = *ptr; // B2
}
Even worse, your snippet does not even show whether the inner arrays are unique or not, so even this is allowed with your snippet:
*posArray = (PosT **) calloc(size, sizeof(PosT *)); // A
(*cntr) = 0
*ptr = (PosT *)calloc(5); // B1
*ptr2 = (PosT *)calloc(25);
for(int idx = 0; idx<size / 2; ++idx)
{
(*posArray)[(*cntr)++] = *ptr; // B2
(*posArray)[(*cntr)++] = *ptr2;
}
Note that here I allocate only 2 inner arrays, and I set all cells of the outer array to point to one of those two inner arrays - outer array may have 500 cells, but there are only 2 inner ones. That's also completely correct datastructure and it is possible with your snippet.
In either of those two cases, there is no pretty way of telling the .Net Marshaller about the layout of such data structure. You'd have to obtain the outer array as an array of pointers:
[...]
... addPos(int size, ...., [MarshalAs(SizeParamIndex=0)]out IntPtr[] posArray, ....)
which you can imagine as casting your (PosT**) into (void*) and later then, somewhere in your program, you'd have to manually unpack those various IntPtrs into PosT[] of proper lengths. Of course, you'd have to actually somehow guess what is the correct length.
Here's how to read an array of structs from IntPtr: Getting Array of struct from IntPtr
EDIT:
ah, and I completely forgot that of course, on C# side, you can just obtain the parameter as a raw pointer, so instead of out PosT[][] posarray you can just PosT*** posarray - this one however will require you to add the 'unsafe' modifier to the signature of the "addPos" function on the C# side. Here's some primer on unsafe modifier:
http://www.codeproject.com/Articles/1453/Getting-unsafe-with-pointers-in-C
[Update]
OK, I have made some progress here,
I couldn't get it to work, when I pass it as out IntPtr[] as when returning from unmanaged code it throws exception. But I came across this link and so I tried to pass it using out IntPtr and that seems to work. at least now I get the pointer back. I now need to start working on Marshalling it all to get what I need out of it.
I am trying to use pinvoke to marshall an array of structures inside another structure from C to C#. AFAIK, no can do.
So instead, in the C structure I declare a ptr to my array, and malloc. Problems: 1) How do I declare the equivalent on the C# side? 2) How do I allocate and use the equivalent on the C# side?
//The C code
typedef struct {
int a;
int b; } A;
typedef struct {
int c;
// A myStruct[100]; // can't do this, so:
A *myStruct; } B;
//The c# code:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class A{
int a;
int b;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class B{
int c;
// can't declare array of [100] A structures...
?
}
[EDIT]: Somehow I misinterpreted what I read elsewhere about fixed array of objects on the c# side.
And I can fix the array size in C So compiled ok, but then I get "object reference not set to an instance of an object" when using:
data.B[3].a = 4567; So, reading elsewhere about what this error might be, I added this method:
public void initA()
{
for (int i = 0; i < 100; i++) { B[i] = new A(); }
}
Again, compiled OK, but same error msg.
To marshal "complex" structures like this between C and C#, you have a couple of options.
In this case, I would highly recommend that you try to embed a fixed array into your C-side structure, as it will simplify the C# side a lot. You can use the MarshalAs attribute to tell C# how much space it needs to allocate in the array at run-time:
// In C:
typedef struct
{
int a;
int b;
} A;
typedef struct
{
int c;
A data[100];
} B;
// In C#:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct A
{
int a;
int b;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct B
{
int c;
[MarshalAs(UnmanagedType.LPArray, SizeConst=100)]
A[] data = new data[100];
}
If you don't know, or can't specify, a fixed size for your array, then you'll need to do what you did and declare it as a pointer in C. In this case, you cannot tell C# how much memory the array is going to use at run-time, so you're pretty much stuck with doing all of the marshalling by hand. This question has a good rundown of how that works, but the basic idea is:
You should add a field to your structure that includes a count of the array elements (this will make your life much easier)
Declare the field in C# as: IntPtr data; with no attributes.
Use Marshal.SizeOf(typeof(A)) to get the size of the struct in unmanaged memory.
Use Marshal.PtrToStructure to convert a single unmanaged structure to C#
Use IntPtr.Add(ptr, sizeofA) to move to the next structure in the array
Loop until you run out.
I have some problems working with boolean types and marshalling this in a struct back and forth between C# and C. I am very rusty in C but hopefully there's nothing crucially wrong in that part.
As far as I've read/seen, .NET Boolean and C# bool type is 4 bytes long whilst the C type bool is only 1 byte. For memory footprint reasons, I do not which to use the defined BOOL 4 bytes version in the C code.
Here is some simple test code that hopefully will make my questions clear:
C code:
typedef struct
{
double SomeDouble1;
double SomeDouble2;
int SomeInteger;
bool SomeBool1;
bool SomeBool2;
} TestStruct;
extern "C" __declspec(dllexport) TestStruct* __stdcall TestGetBackStruct(TestStruct* structs);
__declspec(dllexport) TestStruct* __stdcall TestGetBackStruct(TestStruct* structs)
{
return structs;
}
I call this code in C# using the following definitions:
[StructLayout(LayoutKind.Explicit)]
public struct TestStruct
{
[FieldOffset(0)]
public double SomeDouble1;
[FieldOffset(8)]
public double SomeDouble2;
[FieldOffset(16)]
public int SomeInteger;
[FieldOffset(17), MarshalAs(UnmanagedType.I1)]
public bool SomeBool1;
[FieldOffset(18), MarshalAs(UnmanagedType.I1)]
public bool SomeBool2;
};
[DllImport("Front.dll", CharSet = CharSet.Auto, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr TestGetBackStruct([MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] TestStruct[] structs);
and here is the actual test function in C#:
[Test]
public void Test_CheckStructParsing()
{
var theStruct = new TestStruct();
theStruct.SomeDouble1 = 1.1;
theStruct.SomeDouble2 = 1.2;
theStruct.SomeInteger = 1;
theStruct.SomeBool1 = true;
theStruct.SomeBool2 = false;
var structs = new TestStruct[] { theStruct };
IntPtr ptr = TestGetBackStruct(structs);
var resultStruct = (TestStruct)Marshal.PtrToStructure(ptr, typeof(TestStruct));
}
This works in the sense that I do get a struct back (using the debugger to inspect it), but with totally wrong values. I.e. the marshalling does not work at all. I've tried different version of the C# struct without success. So here are my questions (1 & 2 most important):
Is the C function correct for this purpose?
How is the struct to be written correctly in order to get me the correct values in the struct back to C#? (Is it even necessary to define the struct with the StructLayout(LayoutKind.Explicit) attribute using the FieldOffset values or can I use StructLayout(LayoutKind.Sequential) instead)?
Since I am returning a pointer to the TestStruct in C, I guess it should be possible to get back an array of TestStructs in C#. But this does not seem to be possible using the Marshal.PtrToStructure function. Would it be possible in some other way?
Apparantly it is possible to use something called unions in C by having multiple struct fields point to the same memory allocation using the same FieldOffset attribute value. I understand this, but I still don't get yet when such scenario would be useful. Please enlighten me.
Can someone recommend a good book on C# P/Invoke to C/C++? I am getting a bit tired of getting pieces of information here and there on the web.
Much obliged for help with these questions. I hope they were not too many.
Stop using LayoutKind.Explicit and get rid of the FieldOffset attributes and your code will work. Your offsets were not correctly aligning the fields.
public struct TestStruct
{
public double SomeDouble1;
public double SomeDouble2;
public int SomeInteger;
[MarshalAs(UnmanagedType.I1)]
public bool SomeBool1;
[MarshalAs(UnmanagedType.I1)]
public bool SomeBool2;
};
Declare the function in C# like this:
public static extern void TestGetBackStruct(TestStruct[] structs);
The default marshalling will match your C++ declaration (your code is C++ rather than C in fact) but you must make sure that your allocate the TestStruct[] parameter in the C# code before calling the function. Normally you would also pass the length of the array as a parameter so that the C++ code knows how many structs there are.
Please don't try to return the array of structures from the function. Use the structs parameter as an in/out parameter.
I know of no book with an emphasis on P/Invoke. It appears to be something of a black art!