使用ref代替P/Invoke的固定指针 我试图为C++编写的非托管库编写包装器。库的编码人员给了我一个C#包装器示例,其中包括DllImports,如下所示: [DllImport(LibraryPath, CallingConvention = CallingConvention.Cdecl)] internal static extern int doSomething(int inputArraySize, byte* inputArrayPointer, out int outputInteger, out int outputArraySize, out float* outputArrayPointer); public static int DoSomething(byte[] inputArray, out int outputInteger, out float[] outputArray) { int arraySize = inputArray.Length; int outputArraySize; float* outputArrayPointer; outputArray = null; fixed (byte* arrayPointer = inputArray) { int result = doSomething(arraySize, arrayPointer, out outputInteger, out outputArraySize, out outputArrayPointer); if (result == 0) { outputArray = new float[outputArraySize]; for (int i = 0; i < outputArraySize; i++) { outputArray[i] = outputArrayPointer[i]; } // This is another imported function. freePointer(outputArrayPointer); } } return result; }

使用ref代替P/Invoke的固定指针 我试图为C++编写的非托管库编写包装器。库的编码人员给了我一个C#包装器示例,其中包括DllImports,如下所示: [DllImport(LibraryPath, CallingConvention = CallingConvention.Cdecl)] internal static extern int doSomething(int inputArraySize, byte* inputArrayPointer, out int outputInteger, out int outputArraySize, out float* outputArrayPointer); public static int DoSomething(byte[] inputArray, out int outputInteger, out float[] outputArray) { int arraySize = inputArray.Length; int outputArraySize; float* outputArrayPointer; outputArray = null; fixed (byte* arrayPointer = inputArray) { int result = doSomething(arraySize, arrayPointer, out outputInteger, out outputArraySize, out outputArrayPointer); if (result == 0) { outputArray = new float[outputArraySize]; for (int i = 0; i < outputArraySize; i++) { outputArray[i] = outputArrayPointer[i]; } // This is another imported function. freePointer(outputArrayPointer); } } return result; },c#,c++,pointers,dll,unmanaged,C#,C++,Pointers,Dll,Unmanaged,上面的代码在意义上是否等同于第一个带指针的代码 使用我的版本可以吗 使用我的版本有什么缺点吗 当我使用ref时,传递给非托管libraray函数的数组在整个函数运行期间是否安全 您认为freePointer()函数的作用是什么?指针将被垃圾收集收集。为什么我们需要这样一个函数 我非常感谢你对此事的任何建议 > >编辑:我认为我不能只得到C++指针,而不需要额外的代码。最好的方法是什么?有没有一种方法可以在不使用不安全代码和指针的情况下完成所有这些工作 edit2:我认为freePointer(

上面的代码在意义上是否等同于第一个带指针的代码

  • 使用我的版本可以吗
  • 使用我的版本有什么缺点吗
  • 当我使用
    ref
    时,传递给非托管libraray函数的数组在整个函数运行期间是否安全
  • 您认为
    freePointer()
    函数的作用是什么?指针将被垃圾收集收集。为什么我们需要这样一个函数
  • 我非常感谢你对此事的任何建议

    <> > >编辑:我认为我不能只得到C++指针,而不需要额外的代码。最好的方法是什么?有没有一种方法可以在不使用不安全代码和指针的情况下完成所有这些工作

    edit2:我认为
    freePointer()
    函数可以释放非托管代码分配的数组。但是,它如何在不将数组大小作为参数的情况下,仅使用指向它的指针释放数组呢?

    您的代码(经过一些小的修改)将用于将指向数组的指针从托管代码传递到本机代码。它不会朝相反的方向工作,因为本机代码不知道如何分配托管数组(
    float[]
    ),所以不能期望将其视为托管端的数组

    但是,您可以将原始的
    float*
    输入为返回
    IntPtr
    ,而不是返回,并使用来提取数据

    综上所述,新的p/Invoke签名和代码如下所示:

    [DllImport(...)]
    internal static extern int doSomething(int arraySize, byte[] arrayPointer,
        out int outputInteger, out int outputArraySize,
        out IntPtr outputArrayPointer);
    
    [DllImport(...)]
    internal static extern void freePointer(IntPtr pointer);
    
    public static int DoSomething(byte[] inputArray, out int outputInteger, out float[] outputArray)
    {
        outputArray = null;
        int outputArraySize;
        IntPtr outputArrayPointer;
    
        int result = doSomething(inputArray.Length, inputArray, out outputInteger, out outputArraySize, out outputArrayPointer);
    
        if (result == 0)
        {
            outputArray = new float[outputArraySize];
            Marshal.Copy(outputArrayPointer, outputArray, 0, outputArraySize);
    
            freePointer(outputArrayPointer);
        }
    
        return result;
    }
    
    当p/Invoke签名被写入一个数组时,封送层会自动将该数组固定在内存中(因此它不能被释放或移动,从而可以安全地将其传递给本机代码),然后将指向数组中第一个元素的指针传递给本机代码。相反,
    ref-inputArray
    传递指向托管数组对象(内存中的另一个位置)的指针


    这些更改将使您消除
    fixed(byte*arrayPointer
    从您的调用代码,您可以使用
    IntPtr
    作为本机代码将数据传回给您。由于本机代码分配了内存,.NET垃圾回收器不知道如何释放它,因此在复制数据后调用
    freePointer
    非常重要。它将知道有多少数据被释放ata被释放,因为分配内存的分配例程将已将分配块的大小存储在某个位置(通常在分配内存之前的头块中);这意味着您不需要将数组大小传递给
    freePointer

    我可以使用
    IntPtr
    而不是
    float*
    ?@hattenn:是的,您可以--这是一个很好的建议!我改进了代码,以演示如何使用
    IntPtr
    [DllImport(...)]
    internal static extern int doSomething(int arraySize, byte[] arrayPointer,
        out int outputInteger, out int outputArraySize,
        out IntPtr outputArrayPointer);
    
    [DllImport(...)]
    internal static extern void freePointer(IntPtr pointer);
    
    public static int DoSomething(byte[] inputArray, out int outputInteger, out float[] outputArray)
    {
        outputArray = null;
        int outputArraySize;
        IntPtr outputArrayPointer;
    
        int result = doSomething(inputArray.Length, inputArray, out outputInteger, out outputArraySize, out outputArrayPointer);
    
        if (result == 0)
        {
            outputArray = new float[outputArraySize];
            Marshal.Copy(outputArrayPointer, outputArray, 0, outputArraySize);
    
            freePointer(outputArrayPointer);
        }
    
        return result;
    }