У меня есть сторонняя библиотека C, один из ее экспортированных методов выглядит следующим образом:
#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 является закрытым, потому что я обертываю его функциональность в общедоступный метод "getter", который обрабатывает выделение / освобождение памяти для вызывающей стороны. Когда я использую этот метод в 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 (). Значение каждого индекса имеет решающее значение для понимания того, на что вы смотрите во втором аргументе буфера.
Я ценю любые предложения.
Спасибо,
Andy