C# struct to C++ Marshalling problem - c#

I'm invoking a C++ function from within C#.
This is the function header in C++ :
int src_simple (SRC_DATA *data, int converter_type, int channels) ;
And this is the equivilent C# function :
[DllImport("libsamplerate-0.dll")]
public static extern int src_simple(ref SRC_DATA sd, int converter_type, int channels);
This is the SRC_DATA structure in C++ and then in C# :
typedef struct
{ float *data_in, *data_out ;
long input_frames, output_frames ;
long input_frames_used, output_frames_gen ;
int end_of_input ;
double src_ratio ;
} SRC_DATA ;
This is the C# struct I have defined :
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct SRC_DATA
{
public IntPtr data_in, data_out;
public long input_frames, output_frames;
public long input_frames_used, output_frames_gen;
public int end_of_input;
public double src_ratio;
}
The big problem is that the last parameter , src_ratio, doesn't get delivered properly to the C++ function, (it sees it as 0 or something invalid).
Are my declarations correct?
Thanks

Are you sure that the problem is in src_ratio member? long in C# is 64 bit. In C++ on Win32 platform long is 32 bit, I think you need to use int in C# for long C++ structure members. Also, Pack = 1 looks a bit strange, do you use the same structure member alignment in C++?

You force packing in C# but not in C++. What could be happening is that the C++ compiler is padding the 7 in32's with four additional bytes to ensure the double is 8-byte aligned.
Check the #pragma pack compiler directives.

Check what size an int is in your C++ compiler. A C# int is always 32 bits.

Related

Access legacy C-dll with C# using unsafe fixed size array of struct within struct

I have a legacy C-dll to access a Hardware Device. The dll uses structures containing structure Arrays as function arguments. And I am having a hard time to get this working together with C# (in unsafe mode which is ok since access Speed is an issue here).
The original declaration from DeviceDll.h of the legacy C-dll Looks like:
typedef struct tag_RESULT_JUDGEMENT
{
short nJudgementResult;
} struc_RESULT_JUDGEMENT;
typedef struct tag_RESULT_FORMULA
{
float fFormulaResult[3];
float fAnalogResult;
} struc_RESULT_FORMULA;
typedef struct tag_RESULT_SCRIPT
{
short nScriptNo;
float fTime;
short nFormulaCount;
struc_RESULT_FORMULA sFormula[32];
short nJudgementCount;
struc_RESULT_JUDGEMENT sJudgement[8];
} struc_RESULT_SCRIPT;
WORD PASCAL GetResult(LPCTSTR pDeviceCode, struc_RESULT_SCRIPT_NO_LIST* pList, struc_RESULT_SCRIPT* pResult[]);
Declaring the C-dll functions in C# is done in the following way:
[DllImport("ExternalDevice.dll")]
public unsafe static extern int GetResult(StringBuilder pDeviceCode, struc_RESULT_SCRIPT_NO_LIST* pList, struc_RESULT_SCRIPT **ppResult);
and the structure which I want to access I have declared in a way which unfortunatly gives an error:
[StructLayout(LayoutKind.Explicit)]
public unsafe struct struc_RESULT_SCRIPT {
[FieldOffset(0)]
public Int16 nScriptNo;
[FieldOffset(2)]
public float fTime;
[FieldOffset(6)]
public Int16 iFormulaCount;
[FieldOffset(8)
public fixed struc_RESULT_FORMULA[32] oFormula;
}
Error: Buffer of a fixed size must be of "bool", "Byte", . . . or "double"
Is there a way to declare a fixed structure Array within a structure so that I can use a structure-type variable afterwards as an Argument for calling the legacy DLL ?
What I have tried so far:
Avoiding a structure Array within a structure (rather clumsy but working)
[StructLayout(LayoutKind.Explicit)]
public unsafe struct struc_RESULT_SCRIPT {
[FieldOffset(0)]
public Int16 nScriptNo;
[FieldOffset(2)]
public float fTime;
[FieldOffset(6)]
public Int16 iFormulaCount;
[FieldOffset(8)
public struc_RESULT_FORMULA oFormula01;
[FieldOffset(8 + 16)
public struc_RESULT_FORMULA oFormula02;
. . .
[FieldOffset(8 + 31*16)
public struc_RESULT_FORMULA oFormula32;
}
. . .
struc_RESULT_SCRIPT** ppResult; //local variable => allocated on the stack => so it's already fixed
. . .
int iRv = GetResult(sbMpmIp, &oScriptList, ppResult);
struc_RESULT_FORMULA oFormulaResult = ppResult[0]->oFormula01;
This is working - but accessing oFormula01 … oFormula32 for 32 structure-variables is rather clumsy. I would strongly prefer to get the result as an Array so that I can Access it like oFormula = arrayFormula[xx]; within a for - loop.
Is there a way to declare an unsafe, fixed structure Array within a structure in C# - or a feasable work-around ?
Thank you very much in advance!
According to the documentation for fixed sized buffers there is no way use structs in them.
The best option seem to do as you have done and declare 1..n fields. The anwer to this related question suggest the same thing. If the problem is simply not being able to loop over the fields, then consider adding a iterator block, like:
public IEnumerable<struc_RESULT_FORMULA> GetResultFormulas(){
yield return oFormula01;
...
yield return oFormula32;
}
An alternative would be a large switch statement/expression if you need random indexing.

How to pass parameter class object c# to c++ typedef union struct in unmanaged dll import?

I want to call unmanaged c++ program with struct as parameter.
The c++ struct is like down below.
typedef union {
BYTE byBuffer[32];
struct {
union {
DWORD dwOptionFlag;
struct {
unsigned BIT_IGNOREEXSTOP : 1;
unsigned BIT_USE_CUSTOMACCDEC : 1;
};
} flagOption;
WORD wCustomAccDecTime;
};
} VELOCITY_OPTION_EX;
Function parameter documentation in c++
int FAS_MoveVelocityEx(
BYTE nPortNo,
BYTE iSlaveNo,
DWORD lVelocity,
int iVelDir,
VELOCITY_OPTION_EX* lpExOption
);
C# code I use to import the dll function
[DllImport("EziMOTIONPlusR.dll")]
public static extern EziServoResult FAS_MoveVelocityEx
(byte nPortNo, byte iSlaveNo, long lVelocity, int iVelDir, out VELOCITY_OPTION_EX lpExOption);
How to create the class from c# that match VELOCITY_OPTION_EX in c++?
Note: I only have the documentation + dll library and it's written in c++.

Marshalling Structs from C# to C++ DLL

I have a C DLL which accesses a proprietary database. I want to access this from a C# application which will be used to convert the data into a SQL database.
I am stuck at the moment with marshalling a particularly complex structure from C#.
My C structures are defined as following
typedef struct iseg {
short soffset; /* segment offset */
short slength; /* segment length */
short segmode; /* segment mode */
} ISEG, *LPISEG;
typedef struct iidx {
short ikeylen; /* key length */
short ikeytyp; /* key type */
short ikeydup; /* duplicate flag */
short inumseg; /* number of segments */
LPISEG seg; /* segment information */
char *ridxnam; /* r-tree symbolic name */
} IIDX, *LPIIDX;
typedef struct ifil {
char *pfilnam; /* file name (w/o ext) */
char *pfildes; /* file description */
unsigned short dreclen; /* data record length */
unsigned short dxtdsiz; /* data file ext size */
short dfilmod; /* data file mode */
short dnumidx; /* number of indices */
unsigned short ixtdsiz; /* index file ext size */
short ifilmod; /* index file mode */
LPIIDX ix; /* index information */
unsigned short rfstfld; /* r-tree 1st fld name */
unsigned short rlstfld; /* r-tree last fld name */
int tfilno; /* temporary file number*/
char datetime; /* Update Date & Time Fields */
} IFIL, *LPIFIL;
I have tried a heap of different variants, but this is what my C# structures look like
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, Pack=1)]
public unsafe struct iseg
{
public short soffset;
public short slength;
public short segmode;
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, Pack=1)]
public unsafe struct iidx
{
public short ikeylen;
public short ikeytyp;
public short ikeydup;
public short inumseg;
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, ArraySubType = System.Runtime.InteropServices.UnmanagedType.Struct)]
public iseg[] seg;
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)]
public string ridxnam;
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, Pack=1)]
public unsafe struct ifil
{
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)]
public string pfilnam;
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)]
public string pfildes;
public ushort dreclen;
public ushort dxtdsiz;
public short dfilmod;
public short dnumidx;
public ushort ixtdsiz;
public short ifilmod;
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, ArraySubType = System.Runtime.InteropServices.UnmanagedType.Struct)]
public iidx[] ix;
public ushort rfstfld;
public ushort rlstfld;
public int tfilno;
public byte datetime;
}
I am getting the following exception
A first chance exception of type 'System.AccessViolationException' occurred in Conversion.dll
An unhandled exception of type 'System.AccessViolationException' occurred in Conversion.dll
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
I can't debug the C DLL, even though I selected the Debug Unmanaged Code option in the project. It maybe that the issue is occuring in the marshalling code?
My call to the c code is
public class NativeMethods
{
/// Return Type: int
///lpIfil: LPIFIL->IFIL*
[System.Runtime.InteropServices.DllImportAttribute(#"c:\db\debug\db.dll", EntryPoint = "OPNIFIL")]
public static extern int OPNIFIL(ref ifil lpIfil);
}
if (NativeMethods.OPNIFIL(ref ifil) == 0)
{
// No error occured
}
Sorry, I do not have enough rep to comment.
But:
Do you initialize this structure in C? As your strings are just pointers, check if your C code is allocating memory for the strings it wants to fill in. Maybe you are just checking in C that they are not NULL and trying to find the end of string... if so, initialize the struct before passing it to C code.
An effective approach to this kind of interop problems is to write a very simple C program or dll, that prints each field of the structure you are passing. When you figure out how the structure is arriving in C, you can replace the DLL with the real one.
Another thing to try is to get the sizeof your string in C and compare with the sizeof reported on C#. Even a one byte offset can cause many problems. Write a sanity function and export it on the DLL:
int sanity()
{
return sizeof(IIDX);
}
Then, you can make a sanity check in C#, testing the value returned by sanity with the size of the structure calculated on C#. An alignment problem can be difficult to see and if the structures size change in the future, you can have a warning message.
Also, if the strings are allocated in C, think about how to free these strings later on.
Reference:
http://msdn.microsoft.com/en-us/library/s9ts558h(v=vs.100).aspx#cpcondefaultmarshalingforstringsanchor2
You've incorrectly declared the members iidx.seg and ifil.ix1. You've declared them both as byval, or static, arrays. Because you haven't initialized SizeConst, I think the runtime marshals them as single-element arrays.
This means that the C# runtime thinks that you have a field 6 bytes wide for iidx.seg (the size of one iseg), and 18 or 22 bytes wide (depending on platform) for ifil.ix. But the size of both fields in your C structures is the size of a pointer (4 or 8 bytes, depending on platform).
By the way, you don't need to use the unsafe keyword. You only need that when using pointers, fixed, and sizeof. Marshaling, in general, keeps you from having to use unsafe code.
1 Have you considered using names that bear a stronger resemblance to actual words?

How use pinvoke for C struct array pointer to C#

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.

Some P/Invoke C# to C marshalling questions working with booleans in structs

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!

Categories