2014-09-20 3 views
1

Я пытаюсь использовать C DLL в проекте C#.PInvoke имеет несбалансированный стек

У меня есть функция в C:

extern __declspec(dllexport) void InitBoard(sPiece board[8][8]); 

Spiece структура:

typedef struct Piece 
{ 
    ePieceType PieceType; //enum 
    ePlayer Player; //enum 
    int IsFirstMove; 
} sPiece; 

У меня PInvoke в C#:

[DllImport("chess_api.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)] 
static extern void InitBoard([MarshalAs(UnmanagedType.LPArray, SizeConst = 64)]ref sPiece[] board); 

структура Spiece на C#:

[StructLayout(LayoutKind.Sequential)] 
public struct sPiece 
{ 
    public ePieceType PieceType; 
    public ePlayer Player; 
    public int IsFirstMove; 
} 

Когда я бегу PInvoke я получаю следующее сообщение об ошибке:

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.

Я пытаюсь изменить соглашение о вызовах в Cdecl, но когда я запускаю его, VS застрял.

Что я должен делать?

+0

@Mark. Я видел этот ответ, и это не помогло, потому что я пытаюсь изменить PInvoke, как было сказано там, и он застрял в моем VS. –

+1

InitBoard ожидает указатель, но вы даете ему указатель-указатель, потому что ref с ссылочным типом является двойным направлением. Это следующая ошибка, которую вы обнаружите. – usr

ответ

3

У вас есть две проблемы. Во-первых, вы используете неправильное соглашение о вызове. Неуправляемая функция использует cdecl, и вам нужно, чтобы ваша управляемая функция соответствовала этому.

Другая проблема, гораздо более сложная, - это двухмерный массив.

void InitBoard(sPiece board[8][8]); 

Вы не можете маршалировать двумерный массив, используя p/invoke. Вы должны переключиться на один одномерный массив:

void InitBoard(sPiece board[]); 

Управляемая сторона выглядит следующим образом:

[DllImport("chess_api.dll", CallingConvention = CallingConvention.Cdecl)] 
static extern void InitBoard(sPiece[] board); 

Внутри реализации, вы можете получить доступ к элементам, как это:

Для преобразования row/col pair к линейному индексу используют следующее соотношение:

index = row*8 + col; 

Обратите внимание, что Я также удалил настройку SetLastError, так как очень сомневаюсь, что ваша функция действительно вызывает SetLastError.

+0

У вас есть мой верхний угол. Я пропустил это с первого взгляда. В C++ массив структур будет находиться в непрерывной памяти с определенной базы, но в массивах объектов C# есть массив ссылок, а объекты хранятся в куче. –

+0

Благодарим вас за подробный ответ! Это мне очень помогло! У меня возникла другая проблема, но я напишу в другом посте! –

-3

Взгляните на эту дискуссию:

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

+0

Я не понимаю, где добавить _std, на прототипе c? –

+0

Это должен быть комментарий, а не ответ. – Mark

1

по умолчанию соглашение о вызове для C/C++ является Cdecl (см это 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.

В вашем коде вы указываете CallingConvention = CallingConvention.StdCall. Это несовместимо. Изменить на CallingConvention.Cdecl Подробнее о вызовах можно найти here.

+0

Я пытаюсь изменить его, и vs застрял, когда я вызываю PIvoke, без каких-либо исключений. –

+0

Возможно ли, что в вашей функции 'InitBoard' есть ошибка, которая развращает кучу или стек (например, за пределами края границ массива и т. д.) –

+3

Один из способов тестирования состоит в том, чтобы функция 'InitBoard' ничего не делала, а возвращалась. Это зависает или создает проблемы? –

Смежные вопросы