C# - Method的类型签名与PInvoke不兼容。使用MarshalDirectiveException

时间:2016-11-14 18:21:56

标签: c# c++ exception pinvoke

运行GetBoard方法时出现以下异常(但方法Initialize正常):

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: 

我编写了以下基于x86设置的C#结构:

[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];
        }
    }
}

这是我的C ++结构,由MSVC2015 32位编译:

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

1 个答案:

答案 0 :(得分:2)

我必须编写代码并测试自己,所以我可以肯定。

确定。我编写代码并对其进行测试。

因为它是C#代码中的结构,所以你不能从本机C代码中获取它,所以你必须通过GC分配它,然后通过API填充它,或者你只是获得一个指向本机代码中的结构的指针并将其编组为您在C#中的结构

第一个:

C代码:

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

C#代码:

[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;
}

第二种方法:

C代码:

__declspec(dllexport) ChessBoard* __cdecl GetBoard();

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

C#代码:

[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;
}