通过 Net Core 将 C++ 数组传递给 C# 层
Posted
技术标签:
【中文标题】通过 Net Core 将 C++ 数组传递给 C# 层【英文标题】:Passing a C++ Array to C# Layer through Net Core 【发布时间】:2019-08-07 13:46:15 【问题描述】:我有一个本地库,我想做的是为这个本地库编写一个 .NET Core 包装器。
在本机方面,我有一个名为 OnSpeechEnded 的事件:
virtual void OnSpeechEnded(SpeechEndInfo seInfo) = 0;
而原生结构SpeechEndInfo具有如下结构:
struct SpeechEndInfo
std::vector<AudioData> UntouchedData;
std::vector<AudioData> AudioAfterPostSpeechUntilSilenceTrigger;
;
对应的.NET标准类:
public struct SpeechEndedInfo
public SpeechEndedInfo(short[] untouchedData, short[] audioAfterPostSpeechUntilSilenceTrigger)
UntouchedData = new short[untouchedData.Length];
untouchedData.CopyTo(UntouchedData, 0);
AudioAfterPostSpeechUntilSilenceTrigger = new short[audioAfterPostSpeechUntilSilenceTrigger.Length];
audioAfterPostSpeechUntilSilenceTrigger.CopyTo(AudioAfterPostSpeechUntilSilenceTrigger, 0);
public short[] UntouchedData get; set;
public short[] AudioAfterPostSpeechUntilSilenceTrigger get; set;
;
在 .NET Standard 方面,定义了以下委托:
delegate void OnSpeechEndedInter(
[In, MarshalAs(UnmanagedType.LPArray)] short[] untouched,
int untouchedSize,
[In, MarshalAs(UnmanagedType.LPArray)] short[] audioAfterPostSpeechUntilSilenceTrigger,
int audioAfterPostSpeechUntilSilenceTriggerSize);
声明 pinvoke:
[DllImport("VadLite.Pinvokable.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void RegisterToSpeechEndedEvent(IntPtr parameters, [MarshalAs(UnmanagedType.FunctionPtr)]OnSpeechEndedInter onSpeechEndedInter);
声明 _onSpeechEndedInter:
private OnSpeechEndedInter _onSpeechEndedInter;
为事件分配方法:
_onSpeechEndedInter = invokedMethod;
...
void invokedMethod(short[] untouchedData,
int untouchedSize,
short[] audioAfterPostSpeechUntilSilenceTrigger,
int audioAfterPostSpeechUntilSilenceTriggerSize)
OnSpeechEnded?.Invoke(new SpeechEndedInfo(untouchedData, audioAfterPostSpeechUntilSilenceTrigger));
最后是发送原生数组的代码:
RegisterToSpeechEndedEvent(
void * possiblyOperations,
void __stdcall onSpeechEndedListener(const int16_t* pUntouchedData, int pUntouchedDataSize, const int16_t *vAudioAfterPostSpeechUntilSilenceTrigger, int vAudioAfterPostSpeechUntilSilenceTriggerSize))
auto op = (OperationParameters *)possiblyOperations;
op->OnSpeechEnded([onSpeechEndedListener](SpeechEndInfo ssInfo)
std::vector<int16_t> untouchedData;
std::vector<int16_t> audioAfterPostSpeechUntilSilenceTrigger;
for (auto & audioData : ssInfo.UntouchedData)
untouchedData.insert(untouchedData.end(), audioData.Samples, audioData.Samples + audioData.SampleCount);
for (auto & audioData : ssInfo.AudioAfterPostSpeechUntilSilenceTrigger)
audioAfterPostSpeechUntilSilenceTrigger.insert(audioAfterPostSpeechUntilSilenceTrigger.end(), audioData.Samples, audioData.Samples + audioData.SampleCount);
onSpeechEndedListener(untouchedData.empty() ? nullptr : untouchedData.data(),
(int)untouchedData.size(),
audioAfterPostSpeechUntilSilenceTrigger.empty() ? nullptr : audioAfterPostSpeechUntilSilenceTrigger.data(),
(int)audioAfterPostSpeechUntilSilenceTrigger.size());
);
在运行测试程序并在本机端获得有意义的数组大小后,C# 数组 UntouchedData 和 AudioAfterPostSpeechUntilSilenceTrigger 的大小似乎总是 1。
我可能遗漏了一个细节。如果需要,我可以提供更多详细信息。谢谢。
【问题讨论】:
【参考方案1】:太好了!,我终于找到了问题所在。在委托声明中,我只需要引入参数 SizeParamIndex :
delegate void OnSpeechEndedInter(
[In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] short[] untouched,
int untouchedSize,
[In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] short[] audioAfterPostSpeechUntilSilenceTrigger,
int audioAfterPostSpeechUntilSilenceTriggerSize);
由于封送拆收器无法确定非托管数组的大小,我们必须考虑方法的签名和从零开始的索引,将其作为单独的参数传入。
【讨论】:
以上是关于通过 Net Core 将 C++ 数组传递给 C# 层的主要内容,如果未能解决你的问题,请参考以下文章
将数组传递给 asp net core web api 操作方法 HttpGet