c# - 将 float* 编码到 C#

标签 c# c++ memory-management dll marshalling

我有一个 DLL,它导出一个返回 float* 的函数,我想在我的 C# 代码中使用它。我不确定如何编码我的 float* 以便我可以在 C# 中安全地使用它。 所以,在我的 C++ DLL 中,我声明:

static float* GetSamples(int identifier, int dataSize);

在我的 C# 脚本中,我有:

[DllImport ("__Internal")]
public static extern float[] GetSamples (int identifier, int dataSize);

C++ GetSamples(int,int) 分配内存并返回指向 float 组的指针。如何声明 C# GetSamples 以编码我的 float 组,以及如何访问数据(通过迭代或 Marshal.Copy)? 另外,我可以从 C# 中删除 float* 还是必须调用另一个 C++ 函数来删除分配的内存?

编辑: 所以这就是我到目前为止所尝试的。 首先,在 C# 方面:

声明:

[DllImport ("__Internal")]
public static extern int GetSamples ([In, Out]IntPtr buffer,int length, [Out] out IntPtr written);

尝试调用它:

IntPtr dataPointer = new IntPtr();
IntPtr outPtr;
GetSamples(dataPointer, data.Length, out outPtr);
for (var i = 0; i < data.Length; i++){
    copiedData[i] = Marshal.ReadByte(dataPointer, i);
}

然后在我的 C++ 库中:

int AudioReader::RetrieveSamples(float * sampleBuffer, size_t dataLength, size_t * /* out */ written)
{
    float* mydata = new float[dataLength];

    //This is where I copy the actual data into mydata

    memcpy(sampleBuffer, mydata, dataLength*sizeof(float));

    delete data;
    return dataLength;
}

我真的不知道 outPtr 是干什么用的...而且我知道我还有一些可以删除的额外复制步骤,我只是想让它现在正常工作。

最佳答案

所以这个答案有点复杂......

.NET 不知道如何处理 C++ 内存分配,因此无论返回 float * 充其量是危险的。此外,.NET 内存模型基于 COM,因此它是基于 CoTaskMemAlloc 的,并不是说它真的可以帮助您。所以这是我的建议:

int AudioReader::RetrieveSamples(
     float * sampleBuffer,
     int dataLength,
     int * /* out */ written)
{
     // assuming mydata is already defined
     if(sampleBuffer == NULL || dataLength == 0)
     {
         *written = sizeof(mydata);
         return -1;
     }
     ZeroMemory(sampleBuffer, dataLength);
     int toCopy = min(dataLength, sizeof(myData));
     //This is where I copy the actual data into mydata

     memcpy(sampleBuffer, mydata, toCopy);
     *written = toCopy;
     return 0;
 }
 [DLLImport("__internal")]
 private static extern int GetSamples(
     [In, Out]IntPtr buffer,
     [In] int length,
     [Out] out int written);

 float[] RetrieveFloats()
 {
     int bytesToAllocate = 0;
     GetSamples(IntPtr.Zero, 0, out bytesToAllocate);
     if(bytesToAllocate == 0)
        return null;
     int floatCount = bytesToAllocate/ sizeof(float);
     float[] toReturn = new float[floatCount];
     IntPtr allocatedMemory = Marshal.AllocHGlobal(bytesToAllocate);

     int written = 0;
     if(GetSamples(allocatedMemory, bytesToAllocate, out written) != -1)
     {
         floatCount = written/sizeof(float);
         Marshal.Copy(allocatedMemory, toReturn, 0, floatCount);
     }
     Marshal.FreeHGlobal(allocatedMemory);
     return toReturn;
 }

传递零的 bufferLength 将返回缓冲区所需的空间,然后可以分配并传入。

您需要在 C# 中为缓冲区分配内存,而不能在 C++ 中分配它

关于c# - 将 float* 编码到 C#,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17367620/

相关文章:

c++ - 断言:指针必须来自 'local' 堆

c# - 为什么 FastBitmap 没有被垃圾回收?

c# - 在 TextReader 上实现 ReadKey()

c# - nuget : .net core中的打包项目引用

c++ - 如何可以根据需要多次执行我的功能?

java - 编程初学者

c# - 如何索引和搜索 Lucene.NET 中的日期时间字段?

c# - 获取子对象在父对象中的全局位置

c++ - cpp 单元设置和拆卸功能

c - 如何释放对齐指针?