开发者

C to C# interop: How to handle this method

C declaration:

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);

How i am doing it in 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);

The Call:

DFHack.Translation_TranslateNameEnglish(translation, ref name)

Working with the IntPtr as first param is no problem, i have that working in similar calls. The DFName struct is filled in another call and it contains valid data. What is not working however is the call to Translate开发者_C百科NameEnglish. When that line executes i get an error "Attempted to read or write protected memory. This is often an indication that other memory is corrupt." What am i doing wrong?

What i forgot to mention which might be important: The DFName struct is retrieved as part of another struct.

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

which is retrieved with method

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


Make absolutely sure that sizeof(t_name) in your 'C' code is the same as Marshal.SizeOf(typeof(DFName)) in your C# code. If it's not the same, you need to find out why - particularly look at packing options in the C code, and Ansi/Unicode options in p/invoke signature.

Update: Actually, checking this here, it looks OK, as long as the MS 'C' compiler is running with the default packing options, but it's definitely worth checking in your environment in case that's been changed.


Yes, "Attempted to read or write protected memory. This is often an indication that other memory is corrupt." is expected result. This happens because of you try to return string value from within function. In this case .NET framework creates string objects and tries to free memory in which you have take string from function with CoTaskMemFree function. As I understand you are not alocated this memory with CoTaskMemAlloc so exeption you have is correct. To avoid this you should change your C# function prototype to return IntPtr:

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

And you can you it like below:

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

[EDIT]
It also may be useful for you - Marshaling unmanaged char** to managed string[]

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜