简体   繁体   中英

PInvoke has unbalanced the stack

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 .

The default calling convention for C/C++ is CDecl (see this article ).

__cdecl is the default calling convention for C and C++ programs. Because the stack is cleaned up by the caller, it can do vararg functions. The __cdecl calling convention creates larger executables than __stdcall, because it requires each function call to include stack cleanup code. The following list shows the implementation of this calling convention.

In your code you specify CallingConvention = CallingConvention.StdCall . This is incompatible. Change to CallingConvention.Cdecl More on calling conventions can be found here .

Take a look at this discussion:

A call to PInvoke function '[...]' has unbalanced the stack

Maybe the problem lies in the calling convention.

...

Apparently adding __std in the function prototype and declaration fixes it. Thanks

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM