Matin Lotfaliee Matin Lotfaliee - 17 days ago 7
C++ Question

C# - Method's type signature is not PInvoke compatible. With MarshalDirectiveException

I get the following exception when I run

GetBoard
method (but the method
Initialize
works ok):

System.Runtime.InteropServices.MarshalDirectiveException was unhandled
HResult=-2146233035
Message=Method's type signature is not PInvoke compatible.
Source=MatinChess.Net
StackTrace:
at MatinChess.Net.ExternMethods.GetBoard()
at MatinChess.Net.MatinChess.GetBoard() in C:\Users\Matin\Documents\GitHub\MatinChessDLL\dotnet\MatinChess.Net\MatinChess.cs:line 12
at MatinChess.Net.Demo.Program.PrintBoard(MatinChess chess) in C:\Users\Matin\Documents\GitHub\MatinChessDLL\dotnet\MatinChess.Net.Demo\Program.cs:line 53
at MatinChess.Net.Demo.Program.Main(String[] args) in C:\Users\Matin\Documents\GitHub\MatinChessDLL\dotnet\MatinChess.Net.Demo\Program.cs:line 14
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:


I have written the following C# structure which is built on x86 setting:

[DllImport("MatinChess.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
public extern static void Initialize();

[DllImport("MatinChess.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
public extern static ChessBoard GetBoard();

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct ChessBoard
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
byte[] board;

public char this[int x, int y]
{
get
{
return (char)board[y * 8 + x];
}
}
}


Here is my C++ structure which is compiled by MSVC2015 32-bit:

struct ChessBoard
{
char board[8][8];
};

Answer

I have to write the code and test myself so I can be sure.

Ok. I write the code and tested it.

Because it is a structure in C# code you cant get it from a native C code so you have to allocate it by GC and then fill it by API or you just get a pointer to a structure in native code and marshal it to your structure in C#

First one:

C code:

    __declspec(dllexport) void __cdecl GetBoard(ChessBoard& chess);

C# code:

[DllImport("testDll.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void GetBoard2(ref ChessBoard  ptr);

public static ChessBoard GetChessBoard()
{
    ChessBoard chess = new ChessBoard();
    GetBoard2(ref chess);
    return chess;
}

Second method:

C Code:

__declspec(dllexport) ChessBoard* __cdecl GetBoard();

__declspec(dllexport) void __cdecl FreeMemory(void *);

C# code:

[DllImport("testDll.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr GetBoard();

[DllImport("testDll.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void FreeMemory(IntPtr ptr);


public static ChessBoard GetChessBoard()
{
    var boradPtr = GetBoard();
    var chessBoard = (ChessBoard)Marshal.PtrToStructure(boradPtr, typeof(ChessBoard));

    FreeMemory(boradPtr);
    return chessBoard;
}
Comments