【问题标题】:Problem returning unsigned char value from C++ dll to C#将无符号字符值从 C++ dll 返回到 C# 的问题
【发布时间】:2021-10-18 23:13:45
【问题描述】:

在以下示例中,我尝试通过将值传递给 C++ dll 并返回单个字符串来连接两个无符号字符(这是必需的)。我得到的输出不正确。

C#:

using System;
using System.Runtime.InteropServices;   
using System.Text;

class HelloWorld
{
    [DllImport("cpp_func.dll")]

    public static extern IntPtr concat_fun(byte[] a,byte[] b, int c, int d);

    static void Main()
    {
        int x,y;
        IntPtr return_value;
        string hello = "hello", world = "world", final;
        byte[] hel = Encoding.ASCII.GetBytes(hello);
        byte[] wor = Encoding.ASCII.GetBytes(world);
        x = hel.Length;
        y = wor.Length;
        return_value = concat_fun(hel, wor, hel.Length, wor.Length);
        final = Marshal.PtrToStringAuto(return_value);
        Console.WriteLine("Concatenated string:" +final);
        Console.Read();
    }
}

我已将它们声明为 byte[],因为这就是 .NET 中原生类型 uint8_t 的表示方式(https://docs.microsoft.com/en-us/dotnet/standard/native-interop/type-marshaling) 我已经将两个字节数组及其长度作为参数传递了。

C++:

_declspec(dllexport) unsigned char * concat_fun(unsigned char a[], unsigned char b[], int d, int e) {
    int i, ind = 0;
    unsigned char c[20];

    for (i = 0; i < d; i++) {
        c[ind] = a[i];
        ind++;
    }
    for (i = 0; i < e; i++) {
        c[ind] = b[i];
        ind++;
    }
    return c;
}

我得到的输出是这样的:

Concatenated string:????????????????

如何获得连接的字符串? 注意:将输入作为 dll 函数参数的无符号字符,是一项要求 我知道我在这里犯了一些小错误,因为我只是一个初学者。

【问题讨论】:

  • 这个问题与 C# 无关,与没有意识到 c 是一个超出范围的局部变量有关。您的编译器是否警告过您?如果是这样,这就是您不忽略警告的原因。现在如何从导出的 DLL 函数中正确返回字符串是另一个问题,对此有几个答案。
  • C# 代码应该提供了输出byte[] 缓冲区以将连接的字符串写入 DLL 函数。但是,您当前的函数签名对此没有参数。换句话说,DLL 函数不应该是负责创建缓冲区的函数。如果你这样做了,那么返回一个局部变量就成了一个有争议的问题。
  • 这里有数百个关于这个主题的问题。您真正的问题是没有进行足够稳健的研究。您的代码中还有很多其他问题。局部变量返回。对二进制数据而非文本的 unsigned char 的滥用。对可能的缓冲区溢出缺乏关注。文本编码不匹配。坦率地说,您需要先复习一些基础知识,然后才能正确编写此互操作代码,我的意思是希望以一种建设性的方式进行。

标签: c# c++ .net dll dllimport


【解决方案1】:

c 数组的内存是在concat_fun 函数中分配的,并且有这个函数的作用域和生命周期,所以当你离开函数体时,内存就会被释放。 尝试在调用函数 Main 中分配 c 数组或使用动态内存分配:concat_fun 中的 new/delete 或 malloc/free。

【讨论】:

  • 有比将分配内存的责任留给 C++ 代码更安全的方法。客户端可以简单地传递一个由 C++ 代码填充的缓冲区。
  • @PaulMcKenzie,这不是我建议的“尝试在调用函数 Main 中分配 c 数组”吗? “分配”不仅仅意味着“动态分配”。静态和堆栈分配也是分配。
  • 我的意思是 DLL(C++ 代码)不需要分配任何东西,这是大多数(如果不是所有)Windows API 函数的操作方式。所有缓冲区,包括输出缓冲区,都由客户端提供(在本例中为 C# 代码),而 C++ 代码仅写入输出缓冲区。
  • @PaulMcKenzie,这取决于。有时不能在客户端分配,例如当DLL由于某种原因应该拥有分配的内存时。这更具架构性,与这个问题无关。同样,我建议将这个(在模块 Main 中分配内存)选项作为第一个选项,所以我不明白你为什么要重复它。我的回答涵盖了这两种选择。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-01
  • 1970-01-01
  • 2018-03-08
  • 2021-08-04
  • 1970-01-01
  • 2014-01-12
  • 2013-05-03
相关资源
最近更新 更多