C#从C+编组双*+;动态链接库? 我有一个C++函数,它有一个导出函数: extern "C" __declspec(dllexport) double* fft(double* dataReal, double* dataImag) { [...] }
该函数计算两个双数组(实数组和虚数组)的FFT,返回一个双数组,其中实数组和虚数组的分量交错:{Re,Im,Re,Im,…} 我不知道如何在C#中调用此函数。 我正在做的是:C#从C+编组双*+;动态链接库? 我有一个C++函数,它有一个导出函数: extern "C" __declspec(dllexport) double* fft(double* dataReal, double* dataImag) { [...] },c#,c++,interop,marshalling,dllimport,C#,C++,Interop,Marshalling,Dllimport,该函数计算两个双数组(实数组和虚数组)的FFT,返回一个双数组,其中实数组和虚数组的分量交错:{Re,Im,Re,Im,…} 我不知道如何在C#中调用此函数。 我正在做的是: [DllImport("fft.dll")] static extern double[] fft(double[] dataReal, double[] dataImag); 当我这样测试它时: double[] foo = fft(new double[] { 1, 2, 3, 4 }, new double[] {
[DllImport("fft.dll")]
static extern double[] fft(double[] dataReal, double[] dataImag);
当我这样测试它时:
double[] foo = fft(new double[] { 1, 2, 3, 4 }, new double[] { 0, 0, 0, 0 });
double[] foo = new double[8];
fft(new double[] { 1, 2, 3, 4 }, new double[] { 0, 0, 0, 0 }, 4, out foo);
我得到一个MarshalDirectiveException异常:
无法封送“返回值”:无效的托管/非托管类型组合
我假设这是因为C++<代码>双*与C++代码> double []/CODE >不太一样,但我不知道如何修复它。有什么想法吗
编辑: 我已更改签名,以便现在传递一些额外信息:extern "C" __declspec(dllexport) void fft(double* dataReal, double* dataImag, int length, double* output);
我们总是知道输出的长度
将是2倍长度
及
测试如下:
double[] foo = fft(new double[] { 1, 2, 3, 4 }, new double[] { 0, 0, 0, 0 });
double[] foo = new double[8];
fft(new double[] { 1, 2, 3, 4 }, new double[] { 0, 0, 0, 0 }, 4, out foo);
现在我得到的是AccessViolationException,而不是MarshalDirectiveException。您的示例存在一些问题: C++代码不知道这些数组有多大。封送拆收器将向它们传递一个有效指针,但如果没有相应的长度参数,则无法判断它们有多大。在大多数平台上,sizeof(dataReal)和sizeof(dataImag)可能是4或8(即sizeof(void*))。可能不是你想要的
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
}
相应的p/Invoke签名为:
[DllImport("fft.dll")]
static extern void fft(double[] dataReal, int dataRealLength, double[] dataImag, int dataImagLength, double[] result, int resultLength);
然后是一个调用的示例:
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);
编辑:根据描述的fft操作进行更新。无需更改签名。 您可以使用以下命令:
[DllImport( "fft.dll", EntryPoint = "fft" )]
public static extern IntPtr fft( double[] dataReal, double[] dataImag );
然后需要从返回的IntPtr
复制字节。因为您知道输出的大小是输入的两倍,所以可以按以下方式执行:
double[] result = new double[ doubleSize ];
Marshal.Copy( pointer, result, 0, doubleSize );
结果将包含fft
函数返回的字节
编辑:
我相信您会发现P/Invoke Interop Assistant
工具很有用:这不是很好的Interop原型。有两种方法可以解决此问题:
更改C++函数原型并通过参数返回所有双倍(希望你有C++ FUNC的源码)
使用休止翼所述的IntPtr
只有在使用CoTaskMemAlloc函数分配内存的情况下,返回内存引用才能正常工作。否则,在释放内存期间,您将出现运行时异常(CLR始终尝试使用CoTaskMemFree释放返回内存)
<>我认为最好的方法是第一种方式,它在Peter Huene的回答中描述。它不能将C++ <代码>双*<代码>转换成C<代码> double []/COD>。因为封送代码不知道数组有多长。根据你的描述,我假设它是输入数组的两倍,但是我不知道C++函数是如何知道输入数组的长度的。C++函数决定数组长度:int lengthImag=sizeof(dataImag)/sizeof(double);不,没有dataReal
只是一个指向double
的指针,它的大小与数组中的元素数无关,这就是数组在C(++)中作为参数传递的方式。另外:我们不知道谁的工作是释放结果数组(以及如何释放)。好的,我明白了。(对不起,我在C#vs C/C++方面的经验要丰富得多)。那么我还需要传递数组的长度吗?至于释放,它们不是在堆栈中吗?这意味着当函数结束时,内存会自动释放?如果不是,你建议我如何释放它?只是想澄清一下:你实际上是指double[]result=double[8],对吗?是的。我没有密切注意fft的实际功能。根据您的要求,您可以通过值传递resultLength。