Передача структуры по ссылке, вызывающей AccessViolationException - PullRequest
1 голос
/ 25 августа 2009

Еще один из моих вопросов P / Invoke! У меня есть эта функция C:

int _ei_x_new(ei_x_buff* x);

По сути, он инициализирует новую структуру буфера. В C # у меня есть это:

[DllImport(EIDLL, EntryPoint = "_ei_x_new")]
public static extern int ei_x_new(out ei_x_buff x);

ei_x_buff довольно просто:

typedef struct ei_x_buff_TAG {
    char* buff;
    int buffsz;
    int index;
} ei_x_buff;

[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct ei_x_buff {
    [MarshalAsAttribute(UnmanagedType.LPStr)]
    public string buff;
    public int buffsz;
    public int index;
}

Но когда я сделаю это:

ei_x_buff buffer;
Ei.ei_x_new(out buffer);

Я получаю AccessViolationException :

Попытка чтения или записи в защищенную память. Это часто указывает на то, что другая память повреждена.

Нужно ли выделять память или что-то еще? Это такой простой кусок кода, что я не вижу в этом каких-либо явных проблем.

РЕДАКТИРОВАТЬ: Собственный код для _ei_x_new:

// In my wrapper library
DLL_EXPORT int _ei_x_new(ei_x_buff* x) {
    return ei_x_new(x);
}

// In external library being wrapped
int ei_x_extra = 100;

int ei_x_new(ei_x_buff* x)
{
    x->buff = malloc(ei_x_extra);
    x->buffsz = ei_x_extra;
    x->index = 0;
    return x->buff != NULL ? 0 : -1;
}

Ответы [ 3 ]

0 голосов
/ 25 августа 2009

Следует ли пометить буфер как закрепленный в памяти с помощью оператора fixed :

пример:

// assume class Point { public int x, y; }
// pt is a managed variable, subject to garbage collection.
Point pt = new Point();
// Using fixed allows the address of pt members to be
// taken, and "pins" pt so it isn't relocated.
fixed ( int* p = &pt.x )
{
    *p = 1; 
}
0 голосов
/ 27 августа 2009

Я думаю, что это будет работать и со строкой, если вы просто правильно инициализируете буфер на стороне C. Помните, что в буфере возвратов malloc может содержаться мусор, поэтому вы должны добавить что-то вроде

if (x-> buff) x-> buff [0] = '\ 0';

Еще одна вещь, которую вы можете перепроверить, это то, что вы используете одно и то же соглашение о вызовах на нативной и управляемой стороне. CLR предполагает _stdcall, если вы не укажете что-либо еще в атрибуте DllImport.

0 голосов
/ 25 августа 2009

Пара вещей

  • Используйте not ref в сигнатуре PInvoke, так как вы хотите, чтобы данные маршалировались в обоих направлениях (в и из собственной функции)
  • Можете ли вы опубликовать собственную подпись, так как это может быть проблемой с определением. В частности член баффа

РЕДАКТИРОВАТЬ

Просто чтобы исключить одну возможность, переключите элемент баффа на тип IntPtr без атрибутов. Если это не приводит к сбою, то, скорее всего, это проблема с типом строки.

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