Взаимодействие с C #: как справиться с этим методом - PullRequest
0 голосов
/ 22 апреля 2011

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

Ответы [ 2 ]

0 голосов
/ 22 апреля 2011

Да, «Попытка чтения или записи защищенной памяти. Это часто указывает на то, что другая память повреждена». Ожидаемый результат. Это происходит потому, что вы пытаетесь вернуть строковое значение из функции. В этом случае .NET Framework создает строковые объекты и пытается освободить память, в которой вы берете строку из функции с помощью функции 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);

[EDIT]
Это также может быть полезно для вас - Выделение неуправляемого символа ** в управляемую строку []

0 голосов
/ 22 апреля 2011

Убедитесь, что sizeof(t_name) в вашем коде 'C' совпадает с Marshal.SizeOf(typeof(DFName)) в вашем коде C #.Если это не то же самое, вам нужно выяснить, почему - особенно посмотрите на параметры упаковки в коде C и параметры Ansi / Unicode в сигнатуре p / invoke.

Обновление: на самом деле, проверяя это здесь, выглядитХорошо, пока компилятор MS 'C' работает с опциями упаковки по умолчанию, но это определенно стоит проверить в вашей среде на случай, если это было изменено.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...