在 C# PInvoke 中引用对象数组
Referencing an object array in C# PInvoke
我正在构建一个使用 C# GUI 和本机 C++ 逻辑 dll 的光谱测量应用程序。我正在尝试使 dll 填充从 C# 端通过引用传递的简单 C++ 结构数组。但是,当我尝试打印 [supposed to be filled] 数组元素时,我得到 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# class 定义和签名
[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# 引用标识符,或者是否需要手动指针编组。如果你们中的任何一个能给我指出正确的方向,我将永远感激不已。
我终于找到了我的问题的解决方案,并将此发布给任何需要澄清的人:
首先,正如 David 指出的那样,简单地将引用的参数视为指针并为其分配数组地址是行不通的。您必须将整个数组内容复制到引用数组中。轻松修复。
第二个错误在C#方法签名中;此处需要的描述是带括号的“[Out]”,与简单的 "out" 相比(再次感谢 David)。
所以,最终结果:
结构没有改变,但 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];
}
我正在构建一个使用 C# GUI 和本机 C++ 逻辑 dll 的光谱测量应用程序。我正在尝试使 dll 填充从 C# 端通过引用传递的简单 C++ 结构数组。但是,当我尝试打印 [supposed to be filled] 数组元素时,我得到 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# class 定义和签名
[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# 引用标识符,或者是否需要手动指针编组。如果你们中的任何一个能给我指出正确的方向,我将永远感激不已。
我终于找到了我的问题的解决方案,并将此发布给任何需要澄清的人:
首先,正如 David 指出的那样,简单地将引用的参数视为指针并为其分配数组地址是行不通的。您必须将整个数组内容复制到引用数组中。轻松修复。
第二个错误在C#方法签名中;此处需要的描述是带括号的“[Out]”,与简单的 "out" 相比(再次感谢 David)。
所以,最终结果:
结构没有改变,但 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];
}