У меня есть 3 участника C библиотека, которая одна из его экспортировали метода заключается в следующем:итерация над выделенной памяти с Marshal.AllocHGlobal()
#define MAX_INDEX 8
int GetStuff(IN char* index[MAX_INDEX], OUT char* buf, IN size_t size);
Первый аргумент заполняется с указателями в 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# являются символами Unicode, а не символами 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(). Значение каждого индекса имеет решающее значение для понимания того, что вы смотрите во втором аргументе буфера.
Я ценю любые предложения.
Спасибо, Энди
Мне понравилось это предложение и попробуете, когда какое-то оборудование освободится (эта сторонняя библиотека работает против оборудования, которое я и двое - другие). Я обязательно буду отмечать как ответ, если он соответствует законопроекту. Думаю, так и будет. Знаешь, я не думал о создании массива IntPtr. Это довольно пятно. –
Большое спасибо за решение. В цикле foreach я не смог проверить элемент item.Zero, и поэтому условие должно быть, если (item! = IntPtr.Zero). Я редактировал код, но он должен быть проверен экспертом (разумная предосторожность). Еще раз спасибо. –
@AndrewFalanga Это решение в порядке. Это означает то же самое. Я думаю, что были внесены некоторые изменения в IntPtr с .net 4. Вы используете более низкую версию? –