emxArray_real_T到C#结构加初始化
本文关键字:结构 初始化 real emxArray | 更新日期: 2023-09-27 18:00:47
我正在尝试为此C#结构创建一个"构造函数"(包括初始尝试):
[StructLayout(LayoutKind.Sequential)]
public struct emxArray_real_T
{
public IntPtr data;
public IntPtr size;
public int allocatedSize;
public int numDimensions;
[MarshalAs(UnmanagedType.U1)]
public bool canFreeData;
public emxArray_real_T(double[] cSharpData)
{
var arraySize = Marshal.SizeOf(cSharpData[0]) * cSharpData.Length;
this.data = Marshal.AllocHGlobal(arraySize);
// ????
numDimensions = 1;
canFreeData = false;
}
}
C对应的C结构如下所示:
typedef struct emxArray_real_T
{
real_T *data;
int32_T *size;
int32_T allocated;
int32_T numDimensions;
boolean_T canFreeData;
} emxArray_real_T;
并在这里进行解释。
期待任何意见/答复。谢谢
关于如何做到这一点,您有几个选择。您可以分配非托管内存。然后将托管内存的内容复制到各处。然后,当您对本机代码的调用返回时,大概会将其复制回来。
由于您的示例将canFreeData
设置为false
,所以我想您希望以另一种方式进行操作。这就是将托管内存传递给本机代码。为了做到这一点,您需要固定它以保护它免受GC移动的影响。
为了使这两种方法都起作用,我认为您需要一个包装器类来管理本机内存或钉扎。以下是我如何解决钉扎方法:
[StructLayout(LayoutKind.Sequential)]
public struct emxArray_real_T
{
public IntPtr data;
public IntPtr size;
public int allocatedSize;
public int numDimensions;
[MarshalAs(UnmanagedType.U1)]
public bool canFreeData;
}
public class emxArray_real_T_Wrapper : IDisposable
{
private emxArray_real_T value;
private GCHandle dataHandle;
private GCHandle sizeHandle;
public emxArray_real_T Value {
get { return value; }
}
public emxArray_real_T_Wrapper(double[] data)
{
dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
value.data = dataHandle.AddrOfPinnedObject();
sizeHandle = GCHandle.Alloc(new int[] { data.Length }, GCHandleType.Pinned);
value.size = sizeHandle.AddrOfPinnedObject();
value.allocatedSize = data.Length;
value.numDimensions = 1;
value.canFreeData = false;
}
public void Dispose()
{
dataHandle.Free();
sizeHandle.Free();
GC.SuppressFinalize(this);
}
~emxArray_real_T_Wrapper()
{
Dispose();
}
}
代码:
[StructLayout(LayoutKind.Sequential)]
public struct emxArray_real_T
{
public IntPtr data;
public IntPtr size;
public int allocatedSize;
public int numDimensions;
[MarshalAs(UnmanagedType.U1)]
public bool canFreeData;
}
public class emxArray_real_T_Wrapper : IDisposable
{
private emxArray_real_T value;
private GCHandle dataHandle;
private GCHandle sizeHandle;
public ref emxArray_real_T Value
{
get { return ref value; }
}
public double[] Data
{
get
{
double[] data = new double[value.allocatedSize];
Marshal.Copy(value.data, data, 0, value.allocatedSize);
return data;
}
}
public emxArray_real_T_Wrapper(double[] data)
{
dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
value.data = dataHandle.AddrOfPinnedObject();
sizeHandle = GCHandle.Alloc(new int[] { 1, data.Length }, GCHandleType.Pinned);
value.size = sizeHandle.AddrOfPinnedObject();
value.allocatedSize = data.Length;
value.numDimensions = 1;
value.canFreeData = false;
}
public void Dispose()
{
dataHandle.Free();
sizeHandle.Free();
GC.SuppressFinalize(this);
}
~emxArray_real_T_Wrapper()
{
Dispose();
}
声明:
[DllImport("TestFunc.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void TestFunc(int n, double WnLow, double WnHigh, ref emxArray_real_T kernel);
使用它:
public double[] CalculateBandPassCoefficients(int order, double FreqCutoffNormLow, double FreqCutoffNormHigh)
{
double[] kernel = new double[order];
using (emxArray_real_T_Wrapper wb = new emxArray_real_T_Wrapper(kernel))
{
TestFunc(order, FreqCutoffNormLow, FreqCutoffNormHigh, ref kernelWrapper.Value);
kernel = kernelWrapper.Data;
}
return kernel;
}