2011-04-28 127 views
5

嘿! 我剛開始擺弄pinvoke並遇到問題。我得到了AccessViolationException。首先,有什麼方法可以調試或追蹤哪個字段導致此錯誤?唯一寫入的是結果結構體。Pinvoke結構編組幫助需要 - System.AccessViolationException

C++的呼叫看起來像:

MyFunc(int var1, _tuchar *var2, _tuchar *var3, _tuchar *var4, MyStruct *Result, 
     _tuchar *var5, _tuchar *var6); 

的C++結構:

typedef struct MyStruct 
{ 
    _tuchar *id; 
    _tuchar *ErrorMessages; 
    int int1; 
    _tuchar language[3]; 
    _tuchar *result; 
    int type; 
    int number; 
    int *type2; 
    _tuchar **blocks; 
} 

C#的結構:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
public struct MyStruct 
{ 
    [MarshalAs(UnmanagedType.LPStr)] 
    public string Id; 

    [MarshalAs(UnmanagedType.ByValArray, SizeConst=500)] 
    public char[] ErrorMessages; 

    public int int1; 

    [MarshalAs(UnmanagedType.LPStr)] 
    public string language; 

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 15)] 
    public char[] result; 

    public int type; 

    public int number; 

    public int type2; 

    [MarshalAs(UnmanagedType.ByValArray)] 
    public string[] blocks; 

C#的方法聲明:

[DllImport(MyPath, EntryPoint = "MyEntryPoint", SetLastError = true, 
      CharSet = CharSet.Unicode)] 
internal static extern int MyFunc(int var1, string var2, string var3, 
     string var4, ref MyStruct Result, string var5, string var6); 

C#的召喚:

var result = new MyStruct(); 
MyFunc(0, "var2", "var3", "var4", ref result, "var5", "var6"); 

希望我什麼都不會被排除在外。 感謝您的幫助!

+0

「MyFunc」聲明在C#中是什麼樣的? – Justin 2011-04-28 05:18:01

+0

啊我忘了一些東西,謝謝隊友^^ – Dashu 2011-04-28 05:21:54

+0

在C++中'int'的大小保證是32位/可以用System.Int32轉換嗎? System.Int32有一個非常精確的保證 - 即使是跨性別的。 – 2011-04-28 05:47:54

回答

4

Ooooh,man!你已經爲你的第一個擺弄經驗挑選了一個相當複雜的案例。我建議先做一些簡單的事情,然後再轉向真正的東西。

首先,CharSet=CharSet.Ansi看起來很可疑。你所有的字符串和字符都是_tuchar,我在那裏收集u意味着「Unicode」,不是嗎?如果是這樣的話,你需要CharSet=CharSet.Unicode

其次,(這是最有可能是罪魁禍首)爲什麼是ErrorMessages場封送ByValArray?你知道ByVal這裏的意思是「按價值」,不是嗎?如在,而不是作爲參考。你知道C++中的小星號意味着「引用」,不是嗎?那麼爲什麼您的參考字段ErrorMessages作爲一個按值數組排列?如果你不知道,一個數組通常被認爲是在所有內容被傳遞時「通過值」傳遞的,而不是僅僅傳遞一個引用(指針)到存儲所有內容的內存位置。在C++結構定義中,指定_tuchar*,意思是「指向某個包含一個或多個_tuchars的內存的引用(指針)」,而在C#中指定[MarshalAs(UnmanagedType.ByValArray, SizeConst=500)],這意味着「500 _tuchars應該在這裏,減」。看到引用(指針)通常需要4個字節(或64位機器上的8個字節),而500個unicode字符需要1000個字節,這裏顯然存在明顯的不匹配。

第三第四,同樣的觀點也適用於resultblocks領域。

第五,則language場正​​好相反的情況:C++代碼說「有3個_tuchars這裏」,而C#代碼表示,「有一個參考(指針)到這裏一個字符串」(如果你不「知道,LPStr的意思是‘長指針,字符串’)

最後,你有固定所有這些問題後,我建議你運行你的程序,並打印出通話的結果Marshal.SizeOf(typeof(MyStruct))。在.NET中,這會給你的結構有多大。去C++端打印出sizeof(MyStruct)。這會給你C++認爲的大小。

如果他們不同,看看有什麼不對。嘗試逐個刪除字段,直到它們變得相同。這會給你罪魁禍首的領域。與他們合作。

總的來說,我建議你需要更好地理解事情是如何工作的。對於初學者來說,這種情況太複雜了。

祝你好運!

+0

好吧,先生,你是男人:)我非常感謝你的意見。會看看我能否解決這個爛攤子。有一件事我無法真正理解,是C++會寫入的字符串......我想如果我發送一個500字符的字符串,那麼C++ dll不會寫在邊界之外。有多大的結果可以限制? – Dashu 2011-04-28 06:09:13

+0

難道是在一個struct中有可寫的字符串字段是不可能的嗎?或者你知道他們應該如何定義(錯誤消息和結果)? – Dashu 2011-05-02 16:39:39

0

這是一個位在黑暗中拍攝的,但你有沒有試着用MarshalAs(UnmanagedType.LPWStr)裝飾字符串參數:

[DllImport(MyPath, EntryPoint = "MyEntryPoint", SetLastError = true, 
    CharSet = CharSet.Unicode)] 
internal static extern int MyFunc(
    int var1, 
    [MarshalAs(UnmanagedType.LPWStr)] 
    string var2, 
    [MarshalAs(UnmanagedType.LPWStr)] 
    string var3, 
    [MarshalAs(UnmanagedType.LPWStr)] 
    string var4, 
    ref MyStruct Result, 
    [MarshalAs(UnmanagedType.LPWStr)] 
    string var5, 
    [MarshalAs(UnmanagedType.LPWStr)] 
    string var6); 

我相信編組選擇了弦的BStr_tuchar應擴大到wchar_t默認所以我猜想LPWStr是正確的編組方法(指向寬字符字符串的指針)。


更新:MyStruct各種各樣的東西看起來不很正確:

ErrorMessages被標記爲ByValArray,所以.NET互操作程序可能是期待MyStruct看起來有點像這樣:

typedef struct MyStruct 
{ 
    _tuchar *id; 
    _tuchar ErrorMessages[500]; 
    // Rest of MyStruct 

這可能會導致問題 - result同樣的問題。

而且我認爲language應該使用ByValArray大小爲3

最後blocks或許應該使用LPArray傳遞是 - ByValArray看起來不正確。

(這是所有主要是憑空猜測順便說一句 - 我希望這是一個指向你在正確的方向,但我沒有有P多少經驗/ Invoke的互操作)


另一個更新:MyStruct你聲明的字符集是Ansi,但在MyFunc它的Unicode ...是unmanaged DLL與Unicode或Ansi編譯?如果它使用Unicode,那麼我認爲在編組字符串時應該使用LPWStr,而使用Ansi時應該使用LPStr

+0

嗯我會嘗試裝飾字符串,但這些字符串只能讀取,不能寫入。我相信問題出現在結果裏面,我讀過被寫入的字符串應該使用stringbuilder,但是你不能在沒有得到編組異常的情況下在結構中使用stringbuilder。不知道uni或ansi,有什麼方法可以搞清楚嗎? – Dashu 2011-04-28 05:41:28

+0

裝飾字符串並沒有解決這個問題 – Dashu 2011-04-28 05:45:07

+0

@Dashu MyStruct上的一些屬性看起來不太正確 - 我更新了我的問題,但被警告我可能不知道我在說什麼! :-p – Justin 2011-04-28 05:52:17