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 :(得分:0)
确保“C”代码中的sizeof(t_name)
与C#代码中的Marshal.SizeOf(typeof(DFName))
相同。如果它不相同,你需要找出原因 - 特别是看看C代码中的打包选项,以及p / invoke签名中的Ansi / Unicode选项。
更新:实际上,在这里检查一下,看起来没问题,只要MS'C'编译器使用默认的打包选项运行,但是如果已经更改了,那么绝对值得检查你的环境。
答案 1 :(得分: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[]