C# - 方法的类型签名与 PInvoke 不兼容。使用 MarshalDirectiveException
C# - Method's type signature is not PInvoke compatible. With MarshalDirectiveException
当我使用 运行 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];
}
}
}
这是我用 MSVC2015 32 位编译的 C++ 结构:
struct ChessBoard
{
char board[8][8];
};
我必须自己编写代码并进行测试才能确定。
好的。我写了代码并测试了它。
因为它是 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;
}
当我使用 运行 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];
}
}
}
这是我用 MSVC2015 32 位编译的 C++ 结构:
struct ChessBoard
{
char board[8][8];
};
我必须自己编写代码并进行测试才能确定。
好的。我写了代码并测试了它。
因为它是 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;
}