我需要从C#中删除C ++并返回结构的2D数组。我已经完成了所有设置,如果我连接调试器,一切看起来都是正确的,除了我的2D数组没有正确编组。如果我在调用本机方法之前用值加载它,然后从本机端查看数组,我在VS的监视窗口中会得到很多“无效”指针。然后C ++代码继续前进,并使用正确的值加载数组,但在编组回C#时,我得到内存访问冲突。
我宁愿不做这个1d数组。
这是我的C ++结构和方法定义:
struct DoubleStringStruct
{
BSTR Value;
BSTR NumberFormat;
};
HRESULT WINAPI NativeArrayHandler(LONG rMax, LONG cMax, DoubleStringStruct** values)
{
for(LONG rn=1; rn <= rMax; rn++)
{
for (LONG cn = 1; cn <= cMax; cn++)
{
DoubleStringStruct s;
s.Value = _wcsdup(L"Test");
s.NumberFormat = _wcsdup(L"Test");
values[rn][cn] = s;
}
}
return S_OK;
}
和我的C#代码:
[StructLayout(LayoutKind.Sequential)]
public struct DoubleStringStruct
{
[MarshalAs(UnmanagedType.BStr)]
public string value;
[MarshalAs(UnmanagedType.BStr)]
public string numberFormat;
}
[System.Runtime.InteropServices.DllImport(c_dllName)]
public static extern void NativeArrayHandler(int hMax, int cMax, DoubleStringStruct[,] args);
public void sometMethod()
{
DoubleStringStruct[,] someDSS= new DoubleStringStruct[4,3];
NativeArrayHandler(4, 3, someDSS);
}
答案 0 :(得分:0)
嗯,Hans Passant帮助我得到了这个答案,所以对他有道具。
我的代码有三个问题
1)_wcsdup返回WCHAR_T *,但我的结构包含BSTR,这实际上是一个WHCAR *
2)marshaller不会为我们创建一个二维数组,而是一个必须以有趣的方式编入索引的一维数组。请注意以下内容。
3)我需要确保我在本机代码中创建的任何内存都会被我自己或Marshaller清理干净。例如,几乎所有我在问题中使用的本机内存永远不会被释放,导致巨大的内存泄漏。目前,当本机代码返回托管代码时,我丢失了所有需要释放的内存指针。我在调用本机代码时解决了这个问题。本机代码完成其工作,将函数调用回托管,返回,并允许本机代码进行内务处理。一个简单的方法就是使用CComSafeArray和CComBSTR的功能来管理自己。 (我知道我应该能够简单地将CComSafeArray传递给编组器,他们将在.net代码中清理,但我无法弄清楚如何做到这一点。)
不幸的是,二维数组的编组需要自定义编组,这导致我的口味过多的COM调用。因此,根据Hans Passant的建议,我整理了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);