c# - 如何从 C++ dll 在 C# 函数中传递大小未知的数组?

标签 c# c++ dll pinvoke

我有一个 C++ dll 文件,其中包含一个名为 fn(double* p, int* pLength) 的导出函数,其中,p 是一个指针(是一个输出C#中使用的array), pLength 在此函数中计算的是p的长度(size)。代码在这里:

void _stdcall fn(double* p, int* pLength)
{
    int i=0;
    double p_=0;
    do
    {
        p[i]=p_;
        p_=an expression!!!!!;
        i++;
    }
    while (condition with p_);  //Condition of loop
 
    *pLength=i;
 
    return;
}

我成功编译成dll文件。此文件名为“testFile.dll”并将其移至 System32 文件夹。 现在,我启动 C# 控制台项目并声明从“testFile.dll”导出的函数 fn(),此代码为:

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
 
namespace ConsoleApplication1
{
    class Program
    {
        [DllImport("testFile.dll")]
        public static extern void fn(double[] p, ref int pLength);
        static void Main(string[] args)
        {
            // I want to declare an array with unknown length (size),
            // because the length is calculated from fn() function!!!
            // And pass to fn() function to get p[i].....
            double[] p;
            int pLength;
            fn(p, ref pLength);
 
            // Display pLength and p[i]
            Console.WriteLine(pLength);
            for (int i = 0; i < pLength; i++)
                Console.WriteLine(p[i]);
            Console.ReadKey();
        }
    }
}

我运行并得到两个错误:

Error 1 Use of unassigned local variable 'p'

Error 2 Use of unassigned local variable 'pLength'

如何修复它们?,我想从 fn() “testFile.dll”中的函数。提前致谢。

最佳答案

据我了解,您需要调用该函数两次。一旦你将传递一个空数组并要求函数计算所需的长度。然后您再次调用分配的数组,该函数将填充该数组。

非托管代码可能如下所示:

void __stdcall fn(double p[], int* pLength)
{
    int i = 0;
    double p_ = 0;
    do
    {
        if (p) p[i] = p_;
        p_ = ...;
        i++;
    }
    while (...);
    *pLength = i;
}

请注意,代码会检查 p 是否已分配,如果已分配,则只写入数组。

在托管端,代码如下所示:

[DllImport(...)]
public static extern void fn(double[] p, out int pLength);
....
int pLength;
fn(null, out pLength);
double[] p = new double[pLength];
fn(p, out pLength);

一个更安全的版本是将数组的长度传递给函数。这将允许该函数确保它不会注销结尾。

void __stdcall fn(double p[], int* pLength)
{
    int i = 0;
    double p_ = 0;
    do
    {
        if (p)
        {
            if (i >= *pLength) return -1; // or some other error code
            p[i] = p_;
        }
        p_ = ...;
        i++;
    }
    while (...);
    *pLength = i;
}

管理端:

[DllImport(...)]
public static extern void fn(double[] p, ref int pLength);
....
int pLength = 0;
fn(null, ref pLength);
double[] p = new double[pLength];
fn(p, ref pLength);

如果您只想调用该函数一次,则需要执行以下操作:

  1. 在非托管代码中动态分配内存。使用 GlobalAlloc 以便托管代码可以释放它。
  2. 如果您的初始分配被证明长度不足,请准备好在非托管代码中重新分配。
  3. 在托管代码中使用 IntPtr 类型的 out 参数获取指向非托管内存的指针。
  4. 使用Marshal.Copy 将数组内容复制到您的托管double[] 对象中。
  5. 调用 Marshal.FreeHGlobal 释放非托管内存。

这项技术要复杂得多,涉及更多的样板文件。只有在我概述的第一种方法中存在显着性能开销时,您才采用这种方法。


旁白。请不要将您的文件放在系统目录中。它属于系统,您不应修改它。将 DLL 放在与主机可执行文件相同的目录中。

关于c# - 如何从 C++ dll 在 C# 函数中传递大小未知的数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22753557/

相关文章:

c++ - 模板化的 Pointer 类可以有一个虚拟析构函数吗?

dll - 为什么我们必须将全局钩子(Hook)过程放在单独的 DLL 中

c# - 使用 MVC 的异步发布模型和负载响应

c++ - 无法在 NetBeans 7.0 上编译 C++ 代码

c# - 解析字符串中的名称

c++ - 将字符串注入(inject) 'cin'

c# - 从 C# dll 调用 C++ dll 但什么也得不到

c# - MEF 插件找不到引用的库

c# - Task<WebResponse>.Result 始终为 null

c# - 为什么 DefaultAzureCredential 尝试在本地计算机上使用 ManagedIdentityCredential?