Хм, хорошо, Ханс Пассант помог мне добраться до этого ответа, поэтому поддержите его.
С моим кодом было три проблемы
1) _wcsdup возвращает WCHAR_T *, но моя структура содержитBSTR, который на самом деле является WHCAR *
2) Маршаллер не создает для нас 2d-массив, а скорее 1-мерный, который нужно забавным образом проиндексировать.Примечание ниже.
3) Мне нужно убедиться, что любая память, которую я создаю в нативном коде, очищается либо мной, либо самим Маршаллером.Например, почти вся собственная память, которую я использовал в этом вопросе, никогда не освобождается, что приводит к огромной утечке памяти.В настоящее время, когда нативный код возвращается к управляемому коду, я теряю все свои нативные указатели на память, которую необходимо освободить.Я решил эту передачу обратного вызова при выполнении вызова в нативный код.Нативный код выполняет свою работу, выполняет функциональный обратный вызов управляемому, который возвращает и позволяет нативному коду выполнять служебную работу.Самый простой способ сделать это - использовать возможности CComSafeArray и CComBSTR, которые будут управлять собой.(Я знаю, что смогу просто передать CComSafeArray маршаллеру, и они будут очищены в коде .net, но я не смог понять, как это сделать).
К сожалению, маршалинг 2D-массива требует пользовательского маршалинга, что приводит к слишком большому количеству COM-вызовов на мой вкус.Следовательно, я собрал 1D массив и проиндексировал его в соответствии с предложением Ганса Пассанта.Более того, из-за нехватки времени я создал массив для каждой строки в DoubleStringStruct
, хотя я мог бы сделать DoubleStringStruct
COMVisible, а затем я мог бы упорядочить его в одном массиве.
Вот последний код, с которым я закончил.
extern "C" __declspec(dllexport)
HRESULT WINAPI NativeArrayHandler(LONG rMax, LONG cMax, void (WINAPI*callback)(SAFEARRAY*, SAFEARRAY*))
{
CComSafeArray<BSTR> valuesArr = CComSafeArray<BSTR>(rMax*cMax);
CComSafeArray<BSTR> formatsArr = CComSafeArray<BSTR>(rMax*cMax);
for(LONG rn=0; rn < rMax; rn++)
{
for (LONG cn = 0; cn < cMax; cn++)
{
int index = cMax * rn + cn;
valuesArr[index] = CComBSTR(L"Test");
formatsArr[index] = CComBSTR(L"Test");
}
}
callback(valuesArr, formatsArr);
valuesArr.Destroy();
formatsArr.Destroy();
return S_OK;
}
И C #
static void Main(string[] args)
{
NativeArrayHandler(4, 3, (v, f) => { printArrays(4, 3, v, f); });
}
public static void printArrays(int rmax, int cmax, string[] valuesArr, string[] formatsArr)
{
// can print the arrays in managed code here
}
[System.Runtime.InteropServices.DllImport("dll location")]
public static extern void NativeArrayHandler(int hMax, int cMax, NativeArrayHandlerCallback cb);
public delegate void NativeArrayHandlerCallback(
[MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR)] string[] arr1,
[MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR)] string[] arr2);