Маршалинг C массив структур в C #

1

Я пытаюсь (в течение последних 10 часов.... grr) заставить эту вещь работать, но до сих пор все, что я пробовал - она отказывается :)

В основном я делаю одолжение для кого-то - моя сила - это не windows/.NET-кодирование, и я пытаюсь исправить какой-то код из того, что у меня уже есть.

В чем проблема?

Я пытаюсь вызвать метод библиотеки DLL C, возвращающий 2d массив структур в С#.

Но, похоже, я делаю что-то неправильно в отношении того, как я читаю данные из С#.

Я разработал простую консольную консоль C, и я звоню в DLL оттуда - все в порядке - никаких проблем вообще. Только С# терпит неудачу!

Вот реализация C метода:

int get_available_devices(idevice_info_t **devices, uint32_t *count) {
char **dev_list = NULL;
char *dev_name = NULL;
int i, total_devices;

if (idevice_get_device_list(&dev_list, &total_devices) < 0) {
    fprintf(stderr, "ERROR: Unable to retrieve device list!\n");
    return -1;
}

idevice_info_t *tmpArr = (idevice_info_t*)calloc(total_devices, sizeof(idevice_info));

int ii = 0;
int res_name = 0;

idevice_info_t dtmp = NULL;

for (i = 0; i <= total_devices - 1; i++) {
    res_name = idevice_get_device_name(dev_list[i], &dev_name);
    dev_name = (res_name == 0 ? dev_name : "");

    printf("%s: %s\n", dev_name, dev_list[i]);

    dtmp = (idevice_info_t)malloc(sizeof(struct idevice_info));
    strncpy_s(dtmp->udid, sizeof dtmp->udid - 1, dev_list[i], sizeof dtmp->udid - 1);
    strncpy_s(dtmp->name, sizeof dtmp->name - 1, dev_name, sizeof dtmp->name - 1);
    tmpArr[i] = dtmp;
}
idevice_device_list_free(dev_list);

*devices = tmpArr;
*count = total_devices;

return 0;}

Вот что я делаю на стороне С#:

[DllImport(LIBNAME, CallingConvention = CallingConvention.Cdecl)]
    static public extern short get_available_devices(out IntPtr devices, out uint count);

public static Dictionary<string, string> getAvailableDevices()
    {
        IntPtr p = IntPtr.Zero;
        Dictionary<string, string> ret = null;

        uint totalDevices = 0;

        int res = External.get_available_devices(out p, out totalDevices);

        if (res != 0 || totalDevices < 1)
        {
            return null;
        }

        ret = new Dictionary<string, string>();

        External.idevice_info ppStruct;
        int sSize = Marshal.SizeOf(typeof(External.idevice_info));

        for (int i = 0; i <= totalDevices - 1; i++)
        {
            p = (IntPtr)Marshal.PtrToStructure(p, typeof(IntPtr));
            ppStruct = (External.idevice_info)Marshal.PtrToStructure(p, typeof(External.idevice_info));

            ret.Add(ppStruct.udid, ppStruct.name);

            p = new IntPtr(p.ToInt64() + sSize);
        }

        return ret;
    }

В чем проблема?

Как только я дойду до второй итерации цикла for(), я получу нарушение доступа:

An unhandled exception of type 'System.AccessViolationException' occurred in mscorlib.dll

Изображение 174551

Я думаю, что я не правильно вычисляю указатель, но... я действительно пробовал много разных сценариев, и ничего не работает.

ПОМОГИТЕ! :)

Теги:
dll
marshalling

1 ответ

1
Лучший ответ

Вы разыгрываете p с p = (IntPtr)Marshal.PtrToStructure(p, typeof(IntPtr)); и затем в конце, когда он пытается увеличиться, все ад разрывается.

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

Например:

    for (int i = 0; i <= totalDevices - 1; i++)
    {
        IntPtr pp = (IntPtr)Marshal.PtrToStructure(p, typeof(IntPtr));
        ppStruct = (External.idevice_info)Marshal.PtrToStructure(pp, 
                      typeof(External.idevice_info));

        ret.Add(ppStruct.udid, ppStruct.name);

        p += sSize; // easier, does the same :)
    }
  • 0
    Я вижу, :) Но это все еще идет плохо :( Проблема 1 в том, что (p + = sSize) не работает - я на 3.5 SDK - я думаю, что это причина - поэтому я заменил его снова на: p = new IntPtr (p.ToInt64 () + sSize); исключение теперь другое: NullReferenceException - снова в строке 'ppstruct = ...'. До того, как это будет вызвано, 'p' стало равным нулю.
  • 1
    Я только что решил это :))) Я должен делать: p = new IntPtr (p.ToInt64 () + IntPtr.Size); вместо: p = new IntPtr (p.ToInt64 () + sSize); Все идеально сейчас! Спасибо БОЛЬШОЕ !!!!!!
Показать ещё 6 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню