在C#PInvoke中引用对象数组

时间:2016-06-30 15:49:41

标签: c# c++ arrays pinvoke pass-by-reference

我正在构建一个使用C#GUI和本机C ++逻辑dll的光谱测定应用程序。我正在尝试使dll填充由C#端引用传递的简单C ++结构数组。但是,当我尝试打印[应该被填充的]数组元素时,我得到了System.NullReferenceExceptions,并且数组元素在内存中被标记为null。

这是C ++结构定义和方法实现:

typedef struct intensitytype {
    unsigned short usEchelleOrder;      // echelle order
    unsigned short usPixel;             // horizontal camera pixel index (unbinned !!)
    double dIntensity;                  // intensity
    double dWaveLen;                    // wave length [nm]
} intensitytype;


void CameraControl::getResults(intensitytype* graphData)
{
    graphData = _spectroData; // _spectroData is a pointer to a dynamic intensitytype array.
}

这是C#类定义和签名

[StructLayout(LayoutKind.Sequential)]
    public class intensitytype
{
    public ushort usEchelleOrder = 0;      // echelle order
    public ushort usPixel = 0;             // horizontal camera pixel index (unbinned !!)
    public double dIntensity = 0;                  // intensity
    public double dWaveLen = 0;                    // wave length [nm]
}

 [DllImport(@"Elemission.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern void getResults(bool freeData, out intensitytype[] graphData);

我不确定在这个实例中需要什么类型的C#引用标识符,或者即使需要手动指针编组也是如此。如果你们其中一个人能指出我正确的方向,我将永远感激。

1 个答案:

答案 0 :(得分:0)

我终于找到了我的问题的解决方案,并且正在为需要澄清的人发布这个:

首先,正如大卫指出的那样,只需将引用的参数视为指针并为其指定数组的地址就行不通了。您必须将整个数组内容复制到引用的数组中。轻松修复。

第二个错误是在C#方法签名中;这里需要的描述是" [Out]",用括号与简单的" out"相比较(再次感谢大卫)。

所以,最终的结果是:

结构不会改变,但C#中的函数签名会:

[DllImport(@"Elemission.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern void getResults([Out] intensityType[] graphData);

以下是函数调用的片段:

int arraySize;
DllMethods.executeAcquisition(out arraySize); // arraySize is the Struct array length
intensityType[] resultData = new intensityType[arraySize];
DllMethods.getResults(resultData);

同时在C ++中,包装器接收C#调用并传递给成员函数...

__declspec(dllexport) void getResults(intensitytype* graphData)
{
    MainControl::getInstance()->getCamera()->getResults(graphData);
}

......并且看,结构数组已经填满。

void CameraControl::getResults(intensitytype* graphData)
{
    for (int i = 0; i < _spectroDataLength; i++)
        graphData[i] = _spectroData[i];
}