Referencing an object array in C# PInvoke

只愿长相守 提交于 2019-12-14 03:36:16

问题


I'm building a spectrometry application which uses a C# GUI and a native C++ logical dll. I'm trying to make the dll fill an array of simple C++ structs passed by reference from the C# side. However, when I try to print the [supposed to be filled] array elements, I'm getting System.NullReferenceExceptions and the array elements are marked as null in memory.

Here is the C++ struct definition and method implementation:

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.
}

Here are the C# class definition and signature

[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);

I'm not sure what type of C# reference identifier is needed in this instance, or even if manual pointer marshalling is required. If one of you guys can point me in the right direction, I'd be forever grateful.


回答1:


I finally found the solution to my problems, and am posting this for anyone who would need some clarification:

First, as David pointed out, simply treating the referenced argument as a pointer and assigning it the array's address does not work. You have to copy the entire array contents into the referenced array. Easily fixed.

The second mistake was in the C# method signature; the descripton that was needed here was "[Out]", with the brackets, compared to simply "out" (Once again, thanks David).

So, the end result:

The structs do not change, but the function signature in C# does:

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

and here is a snippet of the function call:

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

Meanwhile in C++, the C# call is received by the wrapper and passed to the member function...

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

...and lo and behold, the struct array is filled.

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


来源:https://stackoverflow.com/questions/38127964/referencing-an-object-array-in-c-sharp-pinvoke

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!