【问题标题】:How to pass and receive data from a char * from C# to an unmanaged C++ DLL如何从 C# 中的 char * 向非托管 C++ DLL 传递和接收数据
【发布时间】:2013-08-31 23:51:20
【问题描述】:
  • 我没有完全访问 DLL 源的权限,只有标题。
  • 我的实际代码中的参数名称更具描述性

我正在尝试调用一个接受所有 char * 变量的非托管 DLL,其中两个充当“返回”值。 in1-8 是输入,in9 和 10 是长度为 512 的 char *,并传入空。调用完成后,它们应该填充结果数据。

这是我尝试使用的示例定义:

[DllImport("mydll.dll")]
public static extern IntPtr foo(
    IntPtr in1,
    IntPtr in2,
    IntPtr in3,
    IntPtr in4,
    IntPtr in5,
    IntPtr in6,
    IntPtr in7,
    IntPtr in8,
    ref IntPtr result1,
    ref IntPtr result2);

这是我的电话:

IntPtr param1 = Marshal.StringToHGlobalUni("testdata");
IntPtr param2 = Marshal.StringToHGlobalUni("testdata");
IntPtr param3 = Marshal.StringToHGlobalUni("testdata");
IntPtr param4 = Marshal.StringToHGlobalUni("testdata");
IntPtr param5 = Marshal.StringToHGlobalUni("testdata");
IntPtr param6 = Marshal.StringToHGlobalUni("testdata");
IntPtr param7 = Marshal.StringToHGlobalUni("testdata");
IntPtr param8 = Marshal.StringToHGlobalUni("testdata");
IntPtr param9 = IntPtr.Zero;
IntPtr param10 = IntPtr.Zero;

foo(param1, param2, param3, param4, param5, param6, param7, param8, ref param9, ref param10);

要打印一个 IntPtr,我正在做:

string str = Marshal.PtrToStringUni(param9);
Console.WriteLine(str);

在给我的“示例”中,C++ 调用如下所示:

char result1[512]="";
char result2[512]="";
foo("testdata", "testdata", "testdata", "testdata", "testdata", "testdata", "testdata", "testdata", result1, result2);
printf("%s,%s\n",result1,result2);

问题:在我尝试过的所有方式中,包括将 char[512] 转换为 byte[]、StringBuilder 大小为 512、IntPtr 等。每次返回时,param9 和 param10 值都是空的。谁能帮我解决这个问题?提前致谢。

编辑 在下面的一些有用的 cmets 和更多的谷歌搜索之后,我修补了我凌乱的代码来工作。这是编辑:

[DllImport("mydll.dll")]
public static extern IntPtr foo(
    IntPtr in1,
    IntPtr in2,
    IntPtr in3,
    IntPtr in4,
    IntPtr in5,
    IntPtr in6,
    IntPtr in7,
    IntPtr in8,
    IntPtr result1,
    IntPtr result2);

我去掉了两个结果字符数组上的 ref。

IntPtr param1 = Marshal.StringToHGlobalAnsi("testdata");
IntPtr param2 = Marshal.StringToHGlobalAnsi("testdata");
IntPtr param3 = Marshal.StringToHGlobalAnsi("testdata");
IntPtr param4 = Marshal.StringToHGlobalAnsi("testdata");
IntPtr param5 = Marshal.StringToHGlobalAnsi("testdata");
IntPtr param6 = Marshal.StringToHGlobalAnsi("testdata");
IntPtr param7 = Marshal.StringToHGlobalAnsi("testdata");
IntPtr param8 = Marshal.StringToHGlobalAnsi("testdata");
IntPtr param9 = Marshal.AllocHGlobal(512 * sizeof(int));
IntPtr param10 = Marshal.AllocHGlobal(512 * sizeof(int));

foo(param1, param2, param3, param4, param5, param6, param7, param8, param9, param10);

上面我分配了 param9 和 10 而不是 IntPtr.Zero

//printing..
string str = Marshal.PtrToStringAnsi(param9);

也是使用字符串的一种更简单的方法,感谢以下答案:

[DllImport("mydll.dll")]
public static extern IntPtr foo(
    string in1,
    string in2,
    string in3,
    string in4,
    string in5,
    string in6,
    string in7,
    string in8,
    StringBuilder result1,
    StringBuilder result2);

然后:

StringBuilder resultA = new StringBuilder(512);
StringBuilder resultB = new StringBuilder(512);

foo("test", "test", "test", "test", "test", "test", "test", "test", resultA, resultB);

印刷:

Console.WriteLine(resultA.ToString());

现在看起来好多了,而且现在可以正常工作了,谢谢大家!打开 50 个 google 搜索标签很容易混淆。

【问题讨论】:

  • 你试过没有 ref 参数的 StringBuilder 吗?我认为这应该可行。
  • 你确定你的 C++ 方法是正确的,并且将一些数据复制到 char 数组中吗?
  • StringToHGlobalUni() 错误,应该是 StringToHGlobalAnsi()。将这些参数声明为 string 会更简单。除了最后两个,StringBuilder。这是一个残暴的功能,避免使用它。
  • 哦,我看到你在我打字的时候找到了答案。

标签: c# .net marshalling dllimport unmanaged


【解决方案1】:

假设你有以下 c 声明

extern "C" __declspec(dllexport) {
    void foo(char * input, char * output);
}

我将定义以下 C# 定义:

[DllImport("mydll.dll", EntryPoint="foo")]
public static extern void Foo(string input, StringBuilder output);

电话会是这样的:

string input = "input";
var output = new StringBuilder(512);
Foo(input, output);

如果可能,尽量避免使用不安全的代码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-09
    • 2013-01-07
    相关资源
    最近更新 更多