2011-04-22 47 views
0

C聲明:C到C#互操作:如何處理這種方法

struct t_name 
{ 
    char first_name[128]; 
    char nickname[128]; 
    int32_t words[7]; 
    uint16_t parts_of_speech[7]; 
    uint32_t language; 
    bool has_name; 
}; 

char* Translation_TranslateNameEnglish(DFHackObject* trans, const t_name* name); 

如何我做它在C#中:

[StructLayout(LayoutKind.Sequential), Serializable] 
public struct DFName 
{ 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] 
    public string FirstName; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] 
    public string NickName; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)] 
    public int[] Words; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)] 
    public ushort[] PartsOfSpeech; 
    public uint Language; 
    public bool HasName; 
} 

[DllImport(DllName)] 
public static extern string Translation_TranslateNameEnglish(IntPtr ptr, ref DFName name); 

呼叫:

DFHack.Translation_TranslateNameEnglish(translation, ref name) 

與合作IntPtr作爲第一參數是沒有問題的,我有類似的調用工作。 DFName結構在另一個調用中被填充並且它包含有效數據。 然而,不起作用的是對TranslateNameEnglish的調用。當該行執行時,出現錯誤「嘗試讀取或寫入受保護的內存,這通常表示其他內存已損壞。」 我在做什麼錯?

我忘了提及哪些可能很重要:DFName結構是作爲另一個結構的一部分檢索的。

[StructLayout(LayoutKind.Sequential), Serializable] 
public struct DFCreature 
{ 
// Snip 
    public DFName Name; 
// Snip 
} 

這與方法

public static extern int Creatures_ReadCreature(IntPtr ptr, uint index, out DFCreature creature); 
+0

請使用相同的電子郵件/ OpenID登錄,這樣您將以同一人身份進行線程連接,並且您將能夠編輯您的答案等。 – abatishchev 2011-04-22 11:29:15

回答

0

檢索務必確保sizeof(t_name)在你的 'C' 的代碼是一樣的Marshal.SizeOf(typeof(DFName))在你的C#代碼。如果不一樣,您需要找出原因 - 特別是查看C代碼中的打包選項以及p/invoke簽名中的Ansi/Unicode選項。

更新:實際上,在這裏檢查它,它看起來沒問題,只要MS'C'編譯器運行時使用默認打包選項,但絕對值得在您的環境中檢查以防萬一發生了變化。

0

是,「嘗試讀取或寫入受保護的內存,這通常表示其他內存已損壞。」預計結果。發生這種情況是因爲您嘗試從函數內返回字符串值。在這種情況下,.NET框架將創建字符串對象並嘗試釋放內存,在該內存中您可以使用CoTaskMemFree函數從函數中獲取字符串。據我所知,你沒有用CoTaskMemAlloc分配這個內存,所以你有的豁免是正確的。爲了避免這種情況,你應該改變你的C#函數原型返回的IntPtr:

[DllImport(DllName)] 
public static extern IntPtr Translation_TranslateNameEnglish(IntPtr ptr, ref DFName name); 

,你可以將它象下面這樣:

string result = Marshal.PtrToStringAnsi(DFHack.Translation_TranslateNameEnglish(translation, ref name); 

[編輯]
它也可能對你有用 - Marshaling unmanaged char** to managed string[]

+0

不幸的是,使用你的方法和方法在文章中描述我得到同樣的異常 – Patrick 2011-04-22 12:18:56

+0

@Patrick:嗯,哪種類型的'名稱'有?嘗試爲它使用StringBuilder。如果這不起作用,我現在就沒有什麼更多的假設了 – 2011-04-22 12:23:35