перебор памяти, выделенной с помощью Marshal.AllocHGlobal()

У меня есть сторонняя библиотека C, один из экспортируемых методов которой выглядит следующим образом:

#define MAX_INDEX 8
int GetStuff(IN char* index[MAX_INDEX], OUT char* buf, IN size_t size);

Первый аргумент заполняется указателями на аргумент buf, где хранятся определенные строки. Размер указывает, как долго каждая строка должна находиться в буфере buf. Мой метод C# P/Invoke для этого в настоящее время выглядит следующим образом:

[DllImport("Path/To/Dll", CharSet = CharSet.Ansi)]
private static extern int GetStuff(IntPtr indecies, IntPtr buf, Int32 size);

Метод C# P/Invoke является приватным, поскольку я оборачиваю его функциональность в общедоступный метод-«геттер», который обрабатывает выделение/освобождение памяти для вызывающего объекта. Когда я использую этот метод в C++, итерация на самом деле довольно проста.Я просто делаю что-то вроде:

char* pIndecies[MAX_INDEX];
char* pBuffer = new char[MAX_INDEX * (256 + 1)]; // +1 for terminating NULL

GetStuff(pIndecies, pBuffer, 256);

// iterate over the items
for(int i(0); i < MAX_INDEX; i++) {
    if(pIndecies[i]) {
        std::cout << "String for index: " << i << " " << pIndecies[i] << std::endl;
    }
}

Из-за того, как они используются в C++, я решил, что мне, вероятно, следует использовать объекты IntPtr и просто выделять память, которая мне понадобится, из кучи, вызывать собственный код и перебирать его. так, как я бы сделал это в C++. Затем я вспомнил, что символы в C# — это символы Юникода, а не символы ASCII. Будет ли итерация в C# работать так же, даже если я поместил итерацию в небезопасный блок кода? Моей первой мыслью было сделать следующее:

IntPtr pIndecies = Marshal.AllocHGlobal(MAX_INDEX * 4); // the size of a 32-pointer
IntPtr pBuffer = Marshal.AllocHGlobal(MAX_INDEX * (256 + 1)); // should be the same
NativeMethods.GetStuff(pIndecies, pBuffer, 256);

unsafe {
    char* pCStrings = (char*)pIndecies.ToPointer();
    for(int i = 0; i < MAX_INDEX; i++) {
        if(pCStrings[i])
            string s = pCStrings[i];
    }
}

Тогда мой вопрос: "Как мне перебрать то, что возвращает этот метод нативного кода?" Это правильный способ маршала к этой функции? Должен ли я использовать объект StringBuilder для второго аргумента? Одна ограничивающая проблема заключается в том, что первый аргумент представляет собой сопоставление 1:1 структуры, лежащей в основе метода GetStuff(). Значение каждого индекса имеет решающее значение для понимания того, на что вы смотрите во втором аргументе буфера.

Буду признателен за любые предложения.

Спасибо, Энди

5
задан Andrew Falanga 2 April 2012 в 22:56
поделиться