C#从C ++ DLL编组双*? [英] C# Marshalling double* from C++ DLL?

查看:771
本文介绍了C#从C ++ DLL编组双*?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个导出功能的C ++ DLL:

 的externC__declspec(dllexport)的双* FFT(双* dataReal,双* dataImag)
{
[...]
}

该函数计算两个双阵列的FFT(实部和虚)的返回与真实的虚构成分交错一个双数组:{重,IM,再保险公司,IM,...}



我不知道如何调用在C#中此功能。
我做的是什么:

 函数[DllImport(fft.dll)] 
静双的extern [] FFT(双[] dataReal,双[] dataImag);



当我测试它是这样的:

 双击[]富= FFT(新的双[] {1,2,3,4},新的双[] {0,0,0,0}); 



我得到一个MarshalDirectiveException异常:




无法元帅返回值:无效的托管/非托管类型组合




我假设这是因为C ++ 双* 是不太一样的C#双[] ,但我不知道如何修理它。 ?任何想法



编辑:
我已经改变了签名,所以,我现在通过一些额外的信息:

 的externC__declspec(dllexport)的无效​​FFT(双* dataReal,双* dataImag,诠释长度,双输出*); 

我们总是知道的长度输出将是2倍长度



 函数[DllImport(fft.dll)] 
静态外部无效FFT(双[] dataReal,双[] dataImag,INT长度,出双[]输出);



这样的测试:

 双击[]富=新的双[8]; 
FFT(新双[] {1,2,3,4},新的双[] {0,0,0,0},4,出富);

现在我得到一个AccessViolationException而非MarshalDirectiveException。


< DIV CLASS =h2_lin>解决方案

有你的榜样了几个问题:




  1. 的C ++代码不知道这些阵列有多大。编组将通过他们有效的指针,但没有相应的长度参数,有没有办法告诉他们是多么的大。的sizeof(dataReal)和sizeof(dataImag)很可能在大多数平台上4或8(即的sizeof(无效*))。也许不是你的本意。

  2. 虽然可以封送指针回作为返回值(那么你可以使用它来填充托管数组),有回报没有隐含的主人值的记忆中,留下开放的内存泄漏的可能性。是缓冲区新FFT的内部分配呢?如果是这样,那么你需要另一个出口托管代码可以调用来释放内存或(在管理端,然后Marshal.FreeHGlobal)使用LocalAlloc来代替。这就是问题的最好



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

  
的externC__declspec(dllexport)的无效​​__stdcall FFT(双常量* dataReal,INT dataRealLength,双常量* dataImag,INT dataImagLength,双*的结果, INT resultLength)
{
//检查dataRealLength == dataImagLength
//检查resultLength两倍dataRealLength
}

对应的p / Invoke签名是:

  
〔的DllImport(fft.dll)]
静态外部无效FFT(双[] dataReal,INT dataRealLength,双[] dataImag,INT dataImagLength,双[]因此,INT resultLength);

和则调用的例子:

  
双[] = dataReal新的双[] {1.0,2.0,3.0,4.0};
双[] = dataImag新的双[] {5.0,6.0,7.0,8.0};
双[]结果=新的双[8];
FFT(dataReal,dataReal.Length,dataImag,dataImag.Length,因此,result.Length);



编辑:根据描述做什么FFT更新


I have a C++ DLL with an exported function:

extern "C" __declspec(dllexport) double* fft(double* dataReal, double* dataImag)
{
  [...]
}

The function calculates the FFT of the two double arrays (real and imaginary) an returns a single double array with the real an imaginary components interleaved: { Re, Im, Re, Im, ... }

I'm not sure how to call this function in C#. What I'm doing is:

[DllImport("fft.dll")]
static extern double[] fft(double[] dataReal, double[] dataImag);

and when I test it like this:

double[] foo = fft(new double[] { 1, 2, 3, 4 }, new double[] { 0, 0, 0, 0 });

I get a MarshalDirectiveException exception:

Cannot marshal 'return value': Invalid managed/unmanaged type combination.

I'm assuming this is because C++ double* isn't quite the same as C# double[], but I'm not sure how to fix it. Any ideas?

Edit: I've changed the signatures so that I now pass some extra information:

extern "C" __declspec(dllexport) void fft(double* dataReal, double* dataImag, int length, double* output);

We always know the length of output will be 2x length

and

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

tested like this:

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

Now I'm getting an AccessViolationException rather than a MarshalDirectiveException.

解决方案

There are a few problems with your example:

  1. The C++ code has no idea how big those arrays are. The marshaller will pass them a valid pointer, but without a corresponding length parameter, there's no way to tell how big they are. sizeof(dataReal) and sizeof(dataImag) is likely 4 or 8 on most platforms (i.e. sizeof(void*)). Probably not what you intended.
  2. While it's possible to marshal a pointer back as the return value (you could then use it to populate a managed array), there is no implied owner of the return value's memory, leaving open the possibility of memory leaks. Was the buffer allocated inside of fft with new? If so, then you'd need another export the managed code can call to free the memory or use LocalAlloc instead (and then Marshal.FreeHGlobal on the managed side). That's problematic at best.

Instead, my suggestion would be to define fft this way:


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
}

The corresponding P/Invoke signature would be:


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

And then an example of a call:


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

Edit: updating based on what fft is described to do.

这篇关于C#从C ++ DLL编组双*?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆