如何使用DllImport将指针(指向doubleArray)从c++代码发送到c#代码(以及从c#发送到c++)

本文关键字:代码 c++ 何使用 DllImport 指针 doubleArray 指向 | 更新日期: 2023-09-27 18:28:43

所以,问题是我有一个double数组,我想通过运行的C++DLL(由我的C#应用程序加载)将其发送到我的C#程序。

我似乎应该使用IntPtr或类似的东西来交换数组或字符串(字符数组),但我真的不知道如何执行。。。

任何人都可以告诉(+示例)向C#/C++代码发送"double[]"或"string"的方法吗?

以下是一些代码作为示例:

C#

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate void FuncPtr([MarshalAs(UnmanagedType.LPArray)] ref double[] dblArr);
[DllImport(dllFilePath, CallingConvention = CallingConvention.Cdecl)]
public static extern void callCSharpFunctionDblArr(IntPtr fctPointer);
public static void printInConsoleDblArr(ref double[] nbArr)
{
    Console.Write("value = ");
    for(int i=0; i<nbArr.Length; i++)
        Console.Write(nbArr[i] + "; ");
    Console.WriteLine();
    for (int i = 0; i < nbArr.Length; i++)
        nbArr[i] = nbArr[i] + 1;
    Console.Write("value = ");
    for (int i = 0; i < nbArr.Length; i++)
        Console.Write(nbArr[i] + "; ");
    Console.WriteLine();
}
static void Main(string[] args)
{        
    FuncPtr printInConsoleDblArrDelegate = 
        new FuncPtr(printInConsoleDblArr);
    IntPtr printInConsoleDblArrPtr = 
        Marshal.GetFunctionPointerForDelegate(printInConsoleDblArrDelegate);
    Console.WriteLine("Second time called from C++ using the call back !!!");
    callCSharpFunctionDblArr(printInConsoleDblArrPtr);
    Console.ReadLine();
}

C++

__declspec(dllexport) void callCSharpFunctionDblArr( void *fctPointer(double*&) )
{
    double* dbl = new double[5];
    for(int i=0; i<5; i++)
        dbl[i] = (0.5*i);
    for(int i=0; i<5; i++)
        std::cout << "Before :: dbl[" << i << "] = " << dbl[i] << std::endl;
    fctPointer(dbl);
    for(int i=0; i<5; i++)
        std::cout << "After :: dbl[" << i << "] = " << dbl[i] << std::endl;
}

使用此代码,我得到以下错误::

An unhandled exception of type 'System.AccessViolationException' occurred in ConsoleApplication1.exe
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

如何使用DllImport将指针(指向doubleArray)从c++代码发送到c#代码(以及从c#发送到c++)

问题是,当您从C++dll调用回调时,nbArr指向在本机代码中创建的double数组中的第一个值。最好的方法是封送到本机代码和从本机代码封送以获得所需的输出。

若要封送此数据,必须将数组作为IntPtr类型而不是double[]类型传递。您还需要传递数组中元素的数量。通过这种方式,我们处理可以封送的指针。

这是完整的代码:

C#

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate void FuncPtr(ref IntPtr dblArr, int size);
[DllImport("test1dll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void callCSharpFunctionDblArr(IntPtr fctPointer);

public static void printInConsoleDblArr(ref IntPtr nbArr, int size)
{
    // Marshal native to managed
    double[] values = new double[size];
    Marshal.Copy(nbArr, values, 0, size);
    Console.Write("value = ");
    for (int i = 0; i < size; i++)
        Console.Write(values[i] + "; ");
    Console.WriteLine();
    for (int i = 0; i < size; i++)
        values[i] = values[i] + 1;
    Console.Write("value = ");
    for (int i = 0; i < size; i++)
        Console.Write(values[i] + "; ");
    Console.WriteLine();
    // Marshal managed to native
    Marshal.Copy(values, 0, nbArr, size);
}
static void Main(string[] args)
{
    FuncPtr printInConsoleDblArrDelegate =
        new FuncPtr(printInConsoleDblArr);
    IntPtr printInConsoleDblArrPtr =
        Marshal.GetFunctionPointerForDelegate(printInConsoleDblArrDelegate);
    Console.WriteLine("Second time called from C++ using the call back !!!");
    callCSharpFunctionDblArr(printInConsoleDblArrPtr);
    Console.ReadLine();
}

C++

__declspec(dllexport) void callCSharpFunctionDblArr( void *fctPointer(double*&, int size) )
    {
        double* dbl = new double[5];
        for(int i=0; i<5; i++)
            dbl[i] = (0.5*i);
        for(int i=0; i<5; i++)
            std::cout << "Before :: dbl[" << i << "] = " << dbl[i] << std::endl;
        fctPointer(dbl, 5);
        for(int i=0; i<5; i++)
            std::cout << "After :: dbl[" << i << "] = " << dbl[i] << std::endl;
    }

您还需要释放在C++本机代码中创建的动态内存。