2016-11-14 110 views
0

我出現以下情況例外,當我運行GetBoard方法(但Initialize好的工作方法):C# - 方法的類型簽名不兼容PInvoke。隨着MarshalDirectiveException

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]; 
}; 
+0

我猜它不喜歡的結構返回值。嘗試一個出來參數。在c#代碼中沒有char的地方,CharSet和SetLastError設置看起來是不必要的。 –

+0

http://stackoverflow.com/questions/33806649/c-sharp-p-invoke-c-method-returning-a-byte - 這可能是你所需要的 – csharpfolk

+0

雖然這是一個很好的答案,我不認爲它適用於此。 –

回答

1

I必須編寫代碼並測試我自己,所以我可以肯定。

好的。我編寫代碼並對其進行測試。

因爲它是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; 
}