c# Calling c++ dll transfer struct array occurs exception - c#

c++ header definition:
#pragma once
#ifndef __AFXWIN_H__
#error "include 'stdafx.h' before including this file for PCH"
#endif
c++ function:
int Detect(Pos* pfps);
c++ struct definition:
struct FaceAngle
{
int yaw;
int pitch;
int roll;
float confidence;
};
typedef struct tagPOINT
{
LONG x;
LONG y;
}
POINT, * PPOINT, NEAR * NPPOINT, FAR * LPPOINT;
struct Pos
{
RECT rcFace;
POINT ptNose;
FaceAngle fAngle;
int nQuality;
BYTE pFacialData[512];
Pos()
{
memset(&rcFace, 0, sizeof(RECT));
memset(&ptNose, 0, sizeof(POINT));
memset(&fAngle, 0, sizeof(FaceAngle));
nQuality = 0;
memset(pFacialData, 0, 512);
}
};
c++ Calling code:
void detect()
{
Pos ptfp[10];
Detect(ptfp);
}
===========================================================================
c# function definition:
[DllImport(THFaceDLLName, EntryPoint = "Detect")]
public static extern int Detect([In, Out] Pos[] posArray);
c# struct definition:
[System.Runtime.InteropServices.StructLayoutAttribute (System.Runtime.InteropServices.LayoutKind.Sequential,
CharSet = System.Runtime.InteropServices.CharSet.Ansi, Pack = 1)]
public struct Pos
{
public RECT rcFace;
public POINT ptNose;
public FaceAngle fAngle;
int nQuality;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]
byte[] pFacialData;
};
[System.Runtime.InteropServices.StructLayoutAttribute (System.Runtime.InteropServices.LayoutKind.Sequential, CharSet = System.Runtime.InteropServices.CharSet.Ansi, Pack = 1)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
[System.Runtime.InteropServices.StructLayoutAttribute (System.Runtime.InteropServices.LayoutKind.Sequential, CharSet = System.Runtime.InteropServices.CharSet.Ansi, Pack = 1)]
public struct POINT
{
public int x;
public int y;
}
[System.Runtime.InteropServices.StructLayoutAttribute (System.Runtime.InteropServices.LayoutKind.Sequential, CharSet = System.Runtime.InteropServices.CharSet.Ansi, Pack = 1)]
public struct FaceAngle
{
int yaw;
int pitch;
int roll;
float confidence;
};
c# calling code:
void detect()
{
Pos[] facePosArray = new Pos[10];
int faceNum = Detect(facePosArray);
}
An “System.AccessViolationException” exception occurs after execution Detect function,
should i convert Pos[] to Intptr? can anyone has good solution

I found a tool that can directly convert c++ struct
such as:
Software Interface
this is the download url:
--download.microsoft.com/download/f/2/7/f279e71e-efb0-4155-873d-5554a0608523/CLRInsideOut2008_01.exe--

Related

Marshalling nested array of structure in C#

How would you marshall this nested array of structure in C#?
C struct:
typedef struct
{
unsigned int appVersionNumber;
unsigned int networkId;
struct
{
int code;
int endDate;
} profiles[4];
} CardEnvHolder;
My C# attempt:
[StructLayout(LayoutKind.Sequential)]
unsafe struct CardEnvHolder
{
public uint appVersionNumber;
public uint networkId;
public Profiles[] profiles;
}
[StructLayout(LayoutKind.Sequential)]
struct Profiles
{
public int code;
public int endDate;
}
C# Main:
unsafe
{
CardEnvHolder envhold = new CardEnvHolder();
void* ptr = (void*)&envhold; //Error here
EnvHolderTest(ptr);
Console.WriteLine(envhold.profil[1].code);
}
Unfortunately I get the error CS0208 "Cannot take the address of, get the size of, or declare a pointer to a managed type ('T')"
As requested,
EnvHolder C function:
void EnvHoldInit(CardEnvHolder* envhold)
{
envhold->appVersionNumber = 4;
envhold->networkId = 8;
envhold->profiles[1].code = 84;
printf("%d\n", envhold->profiles[1].code);
envhold->profiles[1].code++;
}
EXPORT void EnvHolderTest(void* envhold)
{
EnvHoldInit(envhold);
}
EnvHolder C# prototype:
[DllImport("Sandbox.dll", CallingConvention = CallingConvention.Cdecl)]
extern static unsafe void EnvHolderTest([In, Out] void* envhold);

Importing C struct to C# program

The Sctruct
I am not much of a C# or C programmer and have not found much guidance on specifying pointers and structs within a struct. I am attempting to import the following from a C dll into a C# program:
#define MAXFILENAME 259
struct IDentry {
char* IDname;
int length;
};
typedef struct IDentry idEntry;
struct SMOutputAPI {
char name[MAXFILENAME + 1];
FILE* file;
struct IDentry *elementNames;
long Nperiods;
int FlowUnits;
int Nsubcatch;
int Nnodes;
int Nlinks;
int Npolluts;
int SubcatchVars;
int NodeVars;
int LinkVars;
int SysVars;
double StartDate;
int ReportStep;
__int64 IDPos;
__int64 ObjPropPos;
__int64 ResultsPos;
__int64 BytesPerPeriod;
};
I am not sure how to handle the *elementsNames, file or name properties. What I have so far in C# is:
int MAXFILENAME = 259
[StructLayout(LayoutKind.Sequential)]
public struct SMOutputAPI
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAXFILENAME+1)]
public string name;
IntPtr file;
IntPtr elementNames;
public long Nperiods;
public int FlowUnits;
public int Nsubcatch;
public int Nnodes;
public int Nlinks;
public int Npolluts;
public int SubcatchVars;
public int NodeVars;
public int LinkVars;
public int SysVars;
public double StartDate;
public int ReportStep;
public int IDPos;
public int ObjPropPos;
public int ResultsPos;
public int BytesPerPeriod;
};
The C# application builds fine, but when I call the C initialization function that should return a new SMOutputAPI struct I get an error:
System.Runtime.InteropServices.MarshalDirectiveException
Method's type signature is not PInvoke compatible.
Any thoughts on how to properly specify this struct in C# would be much appreciated. Thanks!
Initializing the Struct
The struct is initialized in the c-code with:
SMOutputAPI* DLLEXPORT SMO_init(void)
//
// Purpose: Returns an initialized pointer for the opaque SMOutputAPI
// structure.
//
{
SMOutputAPI *smoapi = malloc(sizeof(struct SMOutputAPI));
smoapi->elementNames = NULL;
return smoapi;
}
The corresponding c# code is:
[DllImport("swmm-output.dll")]
static extern SMOutputAPI SMO_init();
static void Main(string[] args)
{
Console.Write("Hello World!");
SMOutputAPI SMO = SMO_init();
}

Passing structure containing an array of structures between C and C# (DLL and P invoke)

I have C dll with some complicated struct and I ma really a newbie in C#:
typedef struct {
int a;
int b;
} simple_struct;
typedef struct {
int d;
int e;
simple_struct f[20];
short g;
simple_struct h[20];
short i;
} complex_struct;
The issue is that I am not able to interface my C# application with this structure!!
In the DLL there is a function GetData(complex_struct* myStruct) and I shoud call it from C#, so I created:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
unsafe struct simple_struct {
public int a;
public int b;
} ;
[StructLayout(LayoutKind.Sequential, Pack = 1)]
unsafe struct complex_struct {
public int d;
public int e;
public simple_struct[] f;
public short g;
public simple_struct[] h;
public short i;
} ;
but the problem is that when I pass complex_struct as argument of GetData, all the fields are filled back form me, but not my two array of simple_struct (I mean f and h)!! Their values are null!!
Can some one help me please, thanks
Hi and thanks for your reply,
I have done like what you said, but I still have another issue when I call GetData, the process crashes without any message (a kind of Exception):
This is my C sharp code:
namespace dll_test_import_c_sharp
{
class Program
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct simple_struct {
public int a;
public int b;
} ;
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct complex_struct {
public int d;
public int e;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
public simple_struct[] f;
public short g;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
public simple_struct[] h;
public short i;
} ;
[DllImport("test_dll.dll", CharSet = CharSet.Unicode)]
static extern int GetData(ref complex_struct a);
static void Main(string[] args)
{
complex_struct a = new complex_struct();
GetData(ref a);
return;
}
}
}
I have done a lot of printf i GetData and all of them are well executed, it seems like the 'return' instruction crashes!!
I tried to call GetData by ref or by out and both of them don't work...
Hi and thanks for your reply,
I have done like what you said, but I still have another issue when I call GetData, the process crashes without any message (a kind of Exception):
This is my C sharp code:
namespace dll_test_import_c_sharp
{
class Program
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct simple_struct {
public int a;
public int b;
} ;
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct complex_struct {
public int d;
public int e;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
public simple_struct[] f;
public short g;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
public simple_struct[] h;
public short i;
} ;
[DllImport("test_dll.dll", CharSet = CharSet.Unicode)]
static extern int GetData(ref complex_struct a);
static void Main(string[] args)
{
complex_struct a = new complex_struct();
GetData(ref a);
return;
}
}
}
I have done a lot of printf i GetData and all of them are well executed, it seems like the 'return' instruction crashes!!
I tried to call GetData by ref or by out and both of them don't work...
You need to change the array definition on the struct to specify that it's a by value / inline array
[StructLayout(LayoutKind.Sequential, Pack = 1)]
unsafe struct complex_struct {
public int d;
public int e;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
public simple_struct[] f;
public short g;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
public simple_struct[] h;
public short i;
} ;

How to marshal nested structure?

I have three C++ structures that I need to send as parameters when calling a DLL method from C#.
I simplified them as the following:
typedef struct
{
int data1;
int data2;
} A;
typedef struct
{
int numStructA;
A *pStructA;
int moreData;
} B;
typedef struct
{
TCHAR *pStr;
B structB;
} C;
The following is the C++ function I need to call from C#:
int func(C *pStructC, int numStructC);
In my C# code, I define the structs as the following:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
private struct A
{
public int data1;
public int data2;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
private struct B
{
public int numStuctA;
public IntPtr structA;
public int moreData;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
private struct C
{
[MarshalAs(UnmanagedType.LPTStr)]
public string Str;
[MarshalAs(UnmanagedType.Struct)]
public B structB;
}
[DllImport("somedll.dll")]
private static extern int func(IntPtr pStructC, int size);
I tried to marshal the nested structures. However, the C++ function does not receive the data correctly. So far only the data that comes before the nested structure is sent correctly to the C++ function.
How can I marshal the nested structures so the C++ method receives the correct data? Thanks in advance.

How to marshal an array of structure In C#?

I have to call a C++ dll in C#. And the header of the dll is as following(simplified):
//Header of C++
struct vector
{
float x;
float y;
vector()
{}
vector(float x0, float y0)
{
x = x0;
y = y0;
}
};
struct unmanaged_struct
{
int int_var;
float float_var;
char* chars_var;
vector vector_var;
unmanaged_struct(int i, float f, char* ch, float vec_x, float vec_y)
{
int_var = i;
float_var = f;
chars_var = ch;
vector_var = vector(vec_x, vec_y);
}
};
// this function is used to output all the variable values of the struct instance
extern "C" __declspec( dllexport ) void unmanagedstruct_summary(unmanaged_struct* us_list, int length);
And I defined following class in C#
//CSharp
[StructLayout(LayoutKind.Sequential)]
public class Vector
{
public float x;
public float y;
public Vector(float f1, float f2)
{
x = f1;
y = f2;
}
}
[StructLayout(LayoutKind.Sequential)]
public class UnmanagedStruct
{
public int int_var;
public float float_var;
public string char_var;
public Vector vector_var;
public UnmanagedStruct(int i, float f, string s, Vector vec)
{
this.int_var = i;
this.float_var = f;
this.char_var = s;
this.vector_var = vec;
}
}
class UnmanagedDllCallTest
{
[DllImport("unmanageddll.dll", EntryPoint = "unmanagedstruct_summary")]
public static extern void unmanagedstruct_summary([Out]UnmanagedStruct[] usList, int length);
static void Main(string[] args)
{
UnmanagedStruct[] usList = new UnmanagedStruct[1];
usList[0] = new UnmanagedStruct(1, 1.0f, "aa", new Vector(10, 1));
usList[1] = new UnmanagedStruct(2, 2.0f, "ba", new Vector(20, 2));
UnmanagedDllCallTest.unmanagedstruct_summary(usList, 2);
}
And the output is as following:
unmanaged_struct summary:
0
1.12104e-044
Unhandled Exception:
System.AccessViolationException:
Attempted to read or write protected
memory. This is often an indication
that other memory is corrupt. at
callunmanageddll.UnmanagedDllCallTest.unmanagedstruct_summary(UnmanagedStr
uct[] usList, Int32 length) at
callunmanageddll.Program.Main(String[]
args) in c:\users\dynaturtle\docume
nts\visual studio
2010\Projects\callunmanageddll\callunmanageddll\Program.cs:lin
e 68
The C++ dll is OK as I have written test in C++ and the function works well. I have read this thread but it seems the solution didn't work in my case. Any suggestions? Thanks in advance!
Use Marshal.PtrToStructure. There is a sample here.
So you would have to change the signature of the method from out structure array to out IntPtr. However, you need to know the size of the buffer being passed out.
public struct Vector
{
public float x;
public float y;
}
public struct UnmanagedStruct
{
public int int_var;
public float float_var;
public string char_var;
public Vector vector_var;
}
class UnmanagedDllCallTest
{
[DllImport("unmanageddll.dll", EntryPoint = "unmanagedstruct_summary")]
public static extern void unmanagedstruct_summary([Out] IntPtr ptr, int length);
static void Main(string[] args)
{
for(int i=0; i<length; i++)
{
UnmanagedStruc st;
Marshal.PtrToStructure(ptr, st);
// increment ptr and move forward
}
}
First: Vector and UnmanagedStruct should be structs, not classes.
JIC I'd share my approach. Perhaps this is not an expected answer by at one time I spend a time to resolve my issue.
I have the following structure to expose some data from DLL.
//C++ code
struct State
{
const wchar_t * name;
unsigned int state;
};
APIENTRY bool get_states(H_PRCSR, MacroState *, const int sz); //pay attention, function accepts already allocated array and size for it
To accept this data From C++ I can do this way
std::vector<State> states(desired_size);
get_states(hparser, &states[0], states.size());
To do the same on C# I used the following way
//C#
[StructLayout(LayoutKind.Sequential)]
public struct Status
{
public IntPtr name;
public uint state;
public string getName()
{
if (name == IntPtr.Zero) return "<no-value>";
return Marshal.PtrToStringUni(name);
}
}
//And import function...
[DllImport(dll, CallingConvention = CallingConvention.Winapi)]
private static extern bool get_states(IntPtr p, [Out]MacroFlag[] flags, int flags_size);
//And simple decoder
public static Status[] getAll(IntPtr p, int size)
{
var results = new Status[size];
get_states(p, results, size);
return results;
}
As, I saw the are different approaches to do this. This is one of them. And it works for me. Perhaps, this post will not resolve the issue but will be a good point to start

Categories

Resources