C#编组来自C++ DLL的double*?

Ozz*_*zah 12 c# c++ interop marshalling dllimport

我有一个带有导出函数的C++ DLL:

extern "C" __declspec(dllexport) double* fft(double* dataReal, double* dataImag)
{
  [...]
}
Run Code Online (Sandbox Code Playgroud)

该函数计算两个双数组(实数和虚数)的FFT,返回单个双数组,实数为虚数组件交错:{Re,Im,Re,Im,...}

我不知道如何在C#中调用此函数.我在做的是:

[DllImport("fft.dll")]
static extern double[] fft(double[] dataReal, double[] dataImag);
Run Code Online (Sandbox Code Playgroud)

当我像这样测试它:

double[] foo = fft(new double[] { 1, 2, 3, 4 }, new double[] { 0, 0, 0, 0 });
Run Code Online (Sandbox Code Playgroud)

我收到MarshalDirectiveException异常:

无法封送"返回值":无效的托管/非托管类型组合.

我假设这是因为C++ double*与C#不完全相同double[],但我不确定如何解决它.有任何想法吗?

编辑:我已经更改了签名,以便我现在传递一些额外的信息:

extern "C" __declspec(dllexport) void fft(double* dataReal, double* dataImag, int length, double* output);
Run Code Online (Sandbox Code Playgroud)

我们总是知道长度output是2倍length

[DllImport("fft.dll")]
static extern void fft(double[] dataReal, double[] dataImag, int length, out double[] output);
Run Code Online (Sandbox Code Playgroud)

测试如下:

double[] foo = new double[8];
fft(new double[] { 1, 2, 3, 4 }, new double[] { 0, 0, 0, 0 }, 4, out foo);
Run Code Online (Sandbox Code Playgroud)

现在我得到一个AccessViolationException而不是MarshalDirectiveException.

Pet*_*ene 11

您的示例存在一些问题:

  1. C++代码不知道这些数组有多大.编组器会向它们传递一个有效的指针,但没有相应的长度参数,就无法分辨它们有多大.sizeof(dataReal)和sizeof(dataImag)在大多数平台上可能是4或8(即sizeof(void*)).可能不是你想要的.
  2. 虽然可以将指针作为返回值进行编组(然后可以使用它来填充托管数组),但是没有隐含的返回值内存的所有者,从而打开了内存泄漏的可能性.缓冲区是否在fft中分配了新的?如果是这样,那么您需要另一个导出,托管代码可以调用以释放内存或使用LocalAlloc(然后在托管端使用Marshal.FreeHGlobal).这充其量是个问题.

相反,我的建议是以这种方式定义fft:


extern "C" __declspec(dllexport) void __stdcall fft(double const* dataReal, int dataRealLength, double const* dataImag, int dataImagLength, double* result, int resultLength)
{
  // Check that dataRealLength == dataImagLength
  // Check that resultLength is twice dataRealLength
}
Run Code Online (Sandbox Code Playgroud)

相应的P/Invoke签名将是:


[DllImport("fft.dll")]
static extern void fft(double[] dataReal, int dataRealLength, double[] dataImag, int dataImagLength, double[] result, int resultLength);
Run Code Online (Sandbox Code Playgroud)

然后是一个电话示例:


double[] dataReal = new double[] { 1.0, 2.0, 3.0, 4.0 };
double[] dataImag = new double[] { 5.0, 6.0, 7.0, 8.0 };
double[] result = new double[8];
fft(dataReal, dataReal.Length, dataImag, dataImag.Length, result, result.Length);
Run Code Online (Sandbox Code Playgroud)

编辑:根据描述的fft进行更新.