Unmanaged C code in C# Marshalling by ref string array!

I am having a really hard time getting this marshalling down.

I have umanaged code that looks like this:

WORD HLP_GetDeviceNames (LPSTR *DevNames, WORD Max_Len, WORD Max_Num)

Just FYI I did not write this unmanaged code but must use it.

Returns: WORD indicating an error.

DevNames: Pointer to an array of char arrays. Basically an array of strings that will be modified and returned back to me!

Max_Len: Length of each string (I am told this must be 256)

Max_Num: Length of array. I am using another Invoke call that is working that tells me number of devices so i know exactly how many strings to send.

I have used P/Invoke interop signatureToolkit to figure alot of this out but also read a bunch to get even further. Where I am now is here:

[DllImport("UsbMeasLib.dll")]
public static extern ushort HLP_GetDeviceNames([MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPStr)] ref StringBuilder[] DevNames, ushort Max_Len, ushort Max_Num);

I call my code like this:

StringBuilder[] DevNames = new StringBuilder[deviceCount];
     for(int i = 0; i< deviceCount; i++)
     {
           DevNames[i] = new StringBuilder().Append(' ', 256);
     }

     HachUsbMeasLib.HLP_GetDeviceNames(ref DevNames, 256, Convert.ToUInt16(DevNames.Count())); 

I am using string builder array because I need the unmanaged code to modify the string builder so that it can return the new string since string is unmutable.

When I run the code, My array is unmodified!

I'm not really sure what is going on but I think it has something to do with CLR telling unmanaged code to not modify my array in place but instead creates a new reference(pointer). Even if this is the case, I dont know how to fix it.

Thanks for any insight anybody can offer!

1
задан skaffman 17 August 2010 в 18:16
поделиться

2 ответа

Я разобрался с этим. Спасибо всем, кто ответил.

Я узнал, как это работает. Я просто предоставляю пространство памяти, но я должен сообщить маршалингу, что я ожидаю входа и выхода с этим объектом, чтобы он позволял неуправляемому коду изменять выделенное пространство.

Я сделал это так:

[DllImport("UsbMeasLib.dll")]
private static extern ushort HLP_GetDeviceNames([In, Out, MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPStr)] string[] DevNames, ushort Max_Len, ushort Max_Num);

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

int numDev = HLP_GetNumDevices();


string[] names = new string[numDev];

for (int i = 0; i < names.Length; i++)
{
    names[i] = new StringBuilder().Append(' ', 256).ToString();
}

ushort errorCode = HLP_GetDeviceNames(names, 256, Convert.ToUInt16(numDev));

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

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

0
ответ дан 2 September 2019 в 22:10
поделиться

Попробуйте работать на низком уровне. Объявите параметр DevNames как IntPtr[]. Подготовьте его следующим образом:

IntPtr[] devNames = new IntPtr[deviceCount];

for(int i = 0; i < deviceCount; i++) 
{ 
    devNames[i] = Marshal.AllocHGlobal[256];
}

Передайте этот массив в HLP_GetDeviceNames. Чтобы обработать выходные данные, примените Marshal.PtrToStringAnsi к каждому члену DevNames. Не забудьте в конце освободить DevNames[i] с помощью Marshal.FreeHGlobal.

2
ответ дан 2 September 2019 в 22:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: