什么是双*&;其指向非托管数组
本文关键字:数组 amp 什么 | 更新日期: 2024-10-18 12:39:44
我正在包装一个在c#中进行高质量采样率转换的c++dll,我不确定我应该为op0参数使用哪种类型。C++包装器会这样称呼它:
int _cdecl process(double* const ip0, int l, double*& op0)
文件中提到了参数:
"@param[out]op0此变量接收指向重新采样数据的指针。此指针可以指向"ip0"输入缓冲区内的地址,或者指向*此对象的内部缓冲区。在实时应用中,建议将此指针传递到下一个输出音频块并消耗任何数据在调用process()函数。返回时"op0"指向的缓冲区可能由重采样器所有,因此它不应由调用者释放。"
我想做的是:
[DllImport("r8bsrc.dll", EntryPoint="process", CallingConvention = CallingConvention.Cdecl)]
public static extern int Process([in] double[] ip0,
int length,
[out] double[] op0);
但我确信这是行不通的,因为马歇尔无法知道op1背后的内存有多大,或者我错了吗?
所以我想我必须自己将op1后面的值复制回托管数组。也许:
[DllImport("r8bsrc.dll", EntryPoint="process", CallingConvention = CallingConvention.Cdecl)]
public static extern int Process([in] double[] ip0,
int length,
out IntPtr op0); //or do i need out double* ?
然后用再次包装
private IntPtr FOutBufferPtr; //reuse it as recommeded
public int Process(double[] input, out double[] output)
{
var outSamples = R8BrainDLLWrapper.Process(input, input.Length, out FOutBufferPtr);
output = new double[outSamples];
Marshal.Copy(FOutBufferPtr, output, 0, outSamples);
}
涉及最少副本数量的最佳方式是什么?
第2版:
这是当前的代码,它工作得很好:
public int Process(double[] input, ref double[] output)
{
//pin the input during process
var pinnedHandle = GCHandle.Alloc(input, GCHandleType.Pinned);
//resample
var outSamples = R8BrainDLLWrapper.Process(FUnmanagedInstance, pinnedHandle.AddrOfPinnedObject(), input.Length, out FOutBufferPtr);
//copy to output array
if(output.Length < outSamples)
output = new double[outSamples];
Marshal.Copy(FOutBufferPtr, output, 0, outSamples);
//free pin
pinnedHandle.Free();
return outSamples;
}
现在的签名是:
[DllImport("r8bsrc.dll", EntryPoint="r8b_process", CallingConvention = CallingConvention.Cdecl)]
public static extern int Process(IntPtr instance,
IntPtr ip0,
int length,
out IntPtr op0);
@param[out]op0
此变量接收指向重新采样数据的指针。此指针可以指向"ip0"输入缓冲区内的地址,也可以指向*此对象的内部缓冲区。在实时应用程序中,建议将此指针传递到下一个输出音频块,并在再次调用process()函数之前,先消耗上一个输出声音块留下的任何数据。返回时"op0"指向的缓冲区可能归重采样器所有,因此调用者不应释放它。
这立即对ip0
提出了一个约束。您必须安排ip0
指向的缓冲区在函数调用结束后保持稳定。这意味着您必须在调用函数之前将其固定。这反过来意味着它必须声明为IntPtr
。
对于op0
,它指向重采样器拥有的内存,或者指向ip0
输入缓冲区内的位置。所以,你必须再次使用IntPtr
,这次是out
参数。
因此,声明必须是:
[DllImport("r8bsrc.dll", EntryPoint="process",
CallingConvention = CallingConvention.Cdecl)]
public static extern int Process(IntPtr ip0, int length, out IntPtr op0);
如上所述,在ip0
中传递的指针必须使用GCHandle
类获得,这样才能固定数组。