Create and allocate a pointer inside struct C# - c#

I am facing the following issue.
I have a C++ API passed to C# through DLL. Here is how the api looks like:
header.h
extern "C" __declspec( dllexport) bool f(CustomClass* myclass);
where:
struct CustomClass
{
double* grades;
int* ages;
char name[16];
}
So I intend to call this f from C# and face difficulties to allocate the pointers:
To be more precise, I can allocate the CustomClass* but cannot the underlying types:
struct CustomClass
{
public unsafe char* name;
public unsafe double* grades;
public unsafe int* ages;
};
fixed(CustomClass* instances = new CustomClass[5]) // this is fine
{
instances[0].grades = new double[10];// no good, , cannot implicitly convert from double[] to double*
fixed(instances[0].grades = new double[10]) // no good, instances is a variable but used as a type
{
}
}
Can anyone help to understand how to allocate a pointer inside a class?
Or maybe any other workaround to satisfy the C++ DLL api?

You need to define the struct using fixed-size arrays. Fill in the necessary size for each
struct CustomClass
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
double[] grades = new double[10];
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
int[] ages = new int[10];
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
char[] name = new char[16];
}

Related

Writing complex structure to memory-mapped-file

I try to write following struct to a memory mapped file, but I still have problem with the array (writing throws exception that the struct can not contain reference)
[StructLayout(LayoutKind.Explicit)]
struct IndexEntry {
[FieldOffset(0)]
public byte key;
[FieldOffset(4)]
public int lastValueIdx;
[FieldOffset(8)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.PART_ENTRY_SIZE)]
public long[] values;
}
I use this calling for writing:
UnmanagedMemoryAccessor.Write<IndexEntry>(0, ref entry);
Can you please tell me, what am I doing wrong? Thx
The solution of this is using the fixed size array and unsafe code. So the struct should look like this:
[StructLayout(LayoutKind.Explicit)]
unsafe struct IndexEntry {
[FieldOffset(0)]
public byte key;
[FieldOffset(1)]
public int lastValueIdx;
[FieldOffset(5)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = Constants.PART_ENTRY_SIZE)]
public fixed long values[Constants.PART_ENTRY_SIZE];
}
Note that the program (or a single project containing that struct) must be compiled with the "/unasfe" option and the array must be then accessed like this:
fixed(long* arr = this.values) {
// Setting value
arr[index] = value;
}
unsafe {
// Getting value
x = obj.values[index];
}
Then the UnmanagedMemoryAccessor.Write<T>(...) and UnmanagedMemoryAccessor.Read<T>(...) functions work perfectly.

Try Call Dll, But the method has a complicated struct type, I can't define it in .Net

The struct define in C++ is:
typedef struct _DEVICE_PATH_LIST_
{
int NumDevice;
TCHAR *devicePath[DEVICE_PATH_LIST_SIZE];
} DEVICE_PATH_LIST;
and the C++ function's definition is:
LandiWin_iGetDevicePathList( int iDeviceType, DEVICE_PATH_LIST * devicePathList);
Then I want to call that method, so I need to define a struct that can represent the DEVICE_PATH_LIST. Here is my definition in C#:
[StructLayout(LayoutKind.Sequential)]
public unsafe struct DevicePathType
{
public int NumDevice;
[MarshalAs(UnmanagedType.ByValArray,SizeConst=32)]
public char*[] devicePath;
}
but it's not right, I also tried all other type but all failed. please help me define a right struct.
The code of C++ like:
typedef struct _DEVICE_PATH_LIST_
{
int NumDevice;
TCHAR *devicePath[DEVICE_PATH_LIST_SIZE];
} DEVICE_PATH_LIST;
The code of C# need to be like:
[StructLayout(LayoutKind.Sequential)]
public struct DevicePathType
{
public int NumDevice;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public IntPtr[] devicePath;
}

How to avoid copying during PInvoke marshalling when struct contains array of integers?

I have a "C" struct which is defined as:
typedef unsigned char tUI8;
typedef struct
{
tUI8 Mode;
tUI8 Data[16];
} TestStruct;
And a function which takes a pointer to this structure and fill the data:
void FillTest(tUI8 Mode, TestStruct *s);
To PInvoke to this function, I wrote the C# code as:
[StructLayout(LayoutKind.Sequential)]
struct TestStruct
{
public byte Mode;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public byte[] Data;
}
static class NativeTest
{
[DllImport("Native.dll")]
public static extern void FillTest(byte mode, ref TestStruct s);
}
This works but I suspect that during the PInvoke marshaller is copying the struct during call and return instead of pinning it. I can say that because even if I don't initialize the struct, it works fine.
TestStruct s;
//here s.Data == null!
NativeTest.FillTest(10, ref s); //<<< I expected an error here
//here s.Data points to a valid byte[] of length 16
Console.WriteLine(BitConverter.ToString(s.Data));
My question is how can I define a PInvoke signature, using either struct or class, which avoid copying the data during marshalling?
I suspect you want a fixed size buffer, which will inline the data in your struct:
[StructLayout(LayoutKind.Sequential)]
unsafe struct TestStruct
{
public byte Mode;
public fixed byte Data[16];
}
You should now be able to pass that by reference directly to your unmanaged code. (You'll also need to explicitly allow unsafe code.)
I don't know what attributes you'll then need to use for marshalling, if any, but it's worth a try...
This can be done without using unsafe code.
By marshalling as ByValArray
[StructLayout(LayoutKind.Sequential)]
struct TestStruct
{
public byte Mode;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public byte[] Data;
}

How to use unichar array in C# struct with DLLImport of unmanaged C

I am trying to build a struct in C# to pass to unmanaged C++, I was wondering what is the correct type of variable to use for a unichar array in my struct and what it should be marshalled as.
I have already figured this out for an unsigned char array
C/C++
typedef struct _foo {
void *fileId;
unsigned char fileName[15];
} foo;
C#
[StructLayout(LayoutKind.Sequential)]
public struct foo
{
public IntPtr fileId;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 15)]
public string fileName;
}
So if I have the following in C++
typedef struct _foo {
void *fileId;
unichar fileName[15]; // UTF-16LE
} foo;
What would be the correct struct to use in C#?
Specify the structure as a unicode structure:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct foo
{
public IntPtr fileId;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 15)]
public string fileName;
}
I'm guessing the same struct would do, but you need to set the DllImportAttribute.CharSet property to Auto or it will default to Ansi. Unicode would do too, but unless you are using Windows 98 or Me (no comments) Auto will marshal strings as Unicode.

Unions in C# - incorrectly aligned or overlapped with a non-object field

I am marshaling via PInvoke to a native C dll which expects the following call.
private static extern int externalMethod(IntPtr Data, [MarshalAs(UnmanagedType.U4)] ref int dataLength);
The dataLength parameter is the length of the struct being passed via the IntPtr Data parameter. It throws an exception if the two do not match. The external method uses a C Union joining together four types.
I've managed to recreate unions in C# by using the FieldOffsetAttribute. I am then calculating the length of the C# union and calling the method with the following:
int len = Marshal.SizeOf(data);
IntPtr ptr = Marshal.AllocCoTaskMem(len);
externalMethod(ptr, len);
However, I get the error System.TypeLoadException : ... Could not load type because it contains an object field at offset 0 that is incorrectly aligned or overlapped by a non-object field. with the following code. I believe it is perhaps either one of the strings or the integer array (variable B7)? How would I go about changing this to make it work - do I have to break the integer array into multiple variables?
[StructLayoutAttribute(LayoutKind.Explicit)]
public struct Union{
[FieldOffset(0)]
public A a;
[FieldOffset(0)]
public B b;
[FieldOffset(0)]
public C c;
[FieldOffset(0)]
public D d;
}
[StructLayout(LayoutKind.Sequential)]
public struct A
{
public int A1;
public int A2;
public int A3;
[MarshalAs(UnmanagedType.LPTStr, SizeConst = 17)]
public string A4;
[MarshalAs(UnmanagedType.LPTStr, SizeConst = 4)]
public string A5;
}
[StructLayout(LayoutKind.Sequential)]
public struct B
{
public int B1;
[MarshalAs(UnmanagedType.LPTStr, SizeConst = 2)]
public string B2;
[MarshalAs(UnmanagedType.LPTStr, SizeConst = 4)]
public string B3;
[MarshalAs(UnmanagedType.LPTStr, SizeConst = 6)]
public string B4;
public int B5;
public int B6;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U4, SizeConst = 255)]
public int[] B7;
}
[StructLayout(LayoutKind.Sequential)]
public struct C
{
public int C1;
public int C2;
public int C3;
public int C4;
[MarshalAs(UnmanagedType.LPTStr, SizeConst = 32)]
public string C5;
public float C6;
public float C7;
public float C8;
public float C9;
public float C10;
public float C11;
public float C12;
public float C13;
public float C14;
}
[StructLayout(LayoutKind.Sequential)]
public struct D
{
public int D1;
[MarshalAs(UnmanagedType.LPTStr, SizeConst = 36)]
public string D2;
}
Just use the A/B/C/D structs directly and skip the union. In your extern calls, simply substitute the correct struct in the method declaration.
extern void UnionMethodExpectingA( A a );
If the unmanaged methods actually accept a union and behave differently based on the type passed, then you can declare different extern methods that all end up calling the same unmanaged entry point.
[DllImport( "unmanaged.dll", EntryPoint="ScaryMethod" )]
extern void ScaryMethodExpectingA( A a );
[DllImport( "unmanaged.dll", EntryPoint="ScaryMethod" )]
extern void ScaryMethodExpectingB( B b );
Updated for "length" parameter. The logic still applies. Just create a "wrapper" method and do the same thing.
void CallScaryMethodExpectingA( A a )
{
ScaryMethodExpectingA( a, Marshal.SizeOf( a ) );
}
It is difficult to answer this question without knowing what you are trying to achieve. An explicitly-layouted struct is a very bad choice for any normal use-case; this only makes sense if you are using the data in native calls (pinvoke), and in those cases you definitely don’t want to use the managed class string. The [MarshalAs] attribute only takes effect during the call invocations, not constantly every time the field is read from or written to by your managed code. It doesn’t allow you to overlap a string pointer with an int because doing so would allow you to set the pointer to a meaningless value and then accessing the string would crash the CLR. The same is true for arrays, so you can’t use char[] either.
If you are the author of the native code that you need to call, then I strongly recommend to write four separate methods instead of a single one that accepts four completely different data structures.
If you cannot change the native code, then you could always declare your four structs A, B, C and D the way you do now and just use them directly, without the union. Just declare four different pinvoke declarations for the same native function (use the EntryPoint property on the [DllImport] attribute).

Categories