2013-12-05 3 views
0

я создаю адаптер .NET для следующего C API:Native C строка списка слабая ссылка на C#

void GetStringList(const char *** listOut, rsize_t * listCountOut); 

Я хочу # адаптер C, который выглядит как:

[DllImport("api.dll", CallingConvention = CallingConvention.Cdecl)] 
static extern 
void GetStringList(
    out string[] listOut, 
    out int listCountOut 
    ); 

Это Безразлично» t, потому что маршаллер не знает, что длина внешнего списка обеспечивается вторым параметром. Кроме того, я не могу настроить IntPtr, потому что длина не известна, пока функция не вернется.

Я могу решить это с помощью небезопасных.

Есть ли лучший способ без опасностей?

+0

«небезопасный», кажется, лучше всего подходит здесь, «лучший способ». Что значит «лучше?» –

+0

«лучше» == полностью управляемое решение –

+0

char *** - это переменная out, которая принимает char **, например char * [] или PSTR []. Это происходит там, где C-код владеет памятью и предлагает слабую ссылку на список строк. –

ответ

1

Я нашел способ без опасностей. Он должен использовать IntPtr для списка, а затем сверлить, чтобы получить элемент списка IntPtrs.

[DllImport("api.dll", CallingConvention = CallingConvention.Cdecl)] 
static extern 
void GetStringList(
    out IntPtr listOut, 
    out int listCountOut 
    ); 

, а затем что-то вроде

IntPtr listOut; 
int listCountOut; 

GetStringList(out listOut, out listCountOut); 

string[] managedList = new string[listCountOut]; 
for(int i = 0 ; i < listCountOut ; i++) 
{ 
    IntPtr item = Marshal.ReadIntPtr(listOut, i * Marshal.SizeOf(typeof(IntPtr))); 
    managedList[i] = Marshal.PtrToStringAnsi(item); 
} 

достаточно хорошо для моих целей.

+0

Должен 'Marshal.ReadIntPtr (list, ...' be 'Marshal.ReadIntPtr (listOut, ...'? –

+0

это все еще не _Safe_, потому что указатель на память, возвращаемую функцией C, не освобождается. – Mgetz

+0

@Scott - да, исправлено, thx –

Смежные вопросы