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:
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.
There is no need to change signature. You can use following:
[DllImport( "fft.dll", EntryPoint = "fft" )]
public static extern IntPtr fft( double[] dataReal, double[] dataImag );
Then you will need to copy bytes from returned IntPtr
. Since you know the size of the output is double of the input, you do it in following way:
double[] result = new double[ doubleSize ];
Marshal.Copy( pointer, result, 0, doubleSize );
The result
will contain bytes returned by the fft
function.
EDIT:
I believe you will find P/Invoke Interop Assistant
tool helpful: Managed, Native, and COM Interop
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With