I'm trying to use a C DLL in C# project.
I have a function in C:
extern __declspec(dllexport) void InitBoard(sPiece board[8][8]);
the sPiece struct :
typedef struct Piece
{
ePieceType PieceType; //enum
ePlayer Player; //enum
int IsFirstMove;
} sPiece;
I have PInvoke in C#:
[DllImport("chess_api.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
static extern void InitBoard([MarshalAs(UnmanagedType.LPArray, SizeConst = 64)]ref sPiece[] board);
the sPiece struct on C#:
[StructLayout(LayoutKind.Sequential)]
public struct sPiece
{
public ePieceType PieceType;
public ePlayer Player;
public int IsFirstMove;
}
When I run the PInvoke I get the following error:
A call to PInvoke function 'Chess!Chess.Main::InitBoard' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.
I try to change the calling convention to Cdecl
, but when I run it, the VS stuck.
What am I supposed to do?
You've got two problems. Firstly, you use the wrong calling convention. The unmanaged function use cdecl, and you need your managed function to match that.
The other problem, much more challenging, is the two dimensional array.
void InitBoard(sPiece board[8][8]);
You cannot marshal a two dimensional array using p/invoke. You need to switch to a one dimensional array:
void InitBoard(sPiece board[]);
The managed side looks like this:
[DllImport("chess_api.dll", CallingConvention = CallingConvention.Cdecl)]
static extern void InitBoard(sPiece[] board);
Inside the implementation, you can access elements like this:
To convert from a row/col pair to a linear index use the following relationship:
index = row*8 + col;
Note that I also removed the setting of SetLastError
since I doubt very much that your function does call SetLastError
.