I've got a small issue regarding P/Invoke. Currently, I am implementing a wrapper for a C API for a hardware device whose original C# implementation sucks. The issue/inconvenience I am having is the following:
The API implements multiple structs for getting/setting device settings. These are of similar structure, thus I am giving an example implementation:
typedef struct _Struct1
{
bool b1;
unsigned int ui1;
unsigned int ui2;
unsigned int ui3;
unsigned int ui4;
unsigned int ui5;
} Struct1;
The getter and setter are implemented as follows:
unsigned int SetSetting(bool b1, Struct1 s1);
unsigned int GetSetting(bool b1, Struct1 &s1);
The C# DllImport is:
[DllImport("api.dll", EntryPoint = "GetSetting", CallingConvention = CallingConvention.StdCall]
public static extern uint GetStatus(bool b1, CStruct1 s1);
[DllImport("api.dll", EntryPoint = "SetSetting", CallingConvention = CallingConvention.StdCall]
public static extern uint SetStatus(bool b1, SStruct1 s1);
The C# struct implementation is done using LayoutKind.Sequential and represents the C struct exactly and the P/Invoke calls work quite well except for: As you may noticed, the getter and setter DllImports differ slightly in that the setter uses a C# struct (SStruct1) and the getter a C# class (CStruct1):
[StructLayout(LayoutKind.Sequential)]
public struct SStruct1
{
public bool b1;
public uint ui1;
public uint ui2;
public uint ui3;
public uint ui4;
public uint ui5;
}
[StructLayout(LayoutKind.Sequential)]
public class CStruct1 { /* same as struct */ }
I have not been able to get P/Invoke working using just one, either a class or a struct.
Do you have any tips regarding a more convenient solution for this problem?
Changing the struct to class and vice versa does give a PInvokeStackImbalance exception.
I am guessing this has to do with the fact that the setter is expecting a struct by value and the getter by reference, given it's out-parameter-equivalent. I've tried any Marshal attribute and parameter definitions, I could think of, but am hitting a dead end. Google does not seem to help.
Any help is greatly apprechiated.
Edit
I've been mistaken: The API is ANSI C, not C++.
Update
I've tried the solution suggested (SStruct for setter, out SStruct for getter) and although working fine for a function with a struct consisting entirely of uints, it produces complete garbage for the struct in question:
| Name | correct value | returned value |
| ---- | --------------- | -------------- |
| b1 | False | True |
| ui1 | 0 | 3355443223 |
| ui2 | 0 | 1677721600 |
| ui3 | 0 | 0 |
| ui4 | 0 | 0 |
| ui5 | 0 | 0 |
Remember: When using using aforementioned DllImports, this works just fine.