将StringBuilder传递给期望char指针的DLL函数 [英] Passing StringBuilder to DLL function expecting char pointer

查看:146
本文介绍了将StringBuilder传递给期望char指针的DLL函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试与在Delphi中创建的DLL库进行交互。在C ++中,我进行了很好的调用:

I'm trying to interact with a DLL library created in Delphi. In C++, I made this call perfectly fine:

for(int y = 1; y <= 12; y++)
{
    char * chanName = (char *) malloc(21); 
    memset(chanName,0,21);
    channelName(y,20,chanName);
    ...
}

其中 channelName 的类型定义为 typedef int(CALLBACK * ChannelName)(int,int,char *);

现在我正在尝试在C#中做同样的事情。我搜索后发现, StringBuilder 通常用作DLL函数的char指针。这是我声明函数的方式:

Now I'm trying to do the same thing in C#. I've searched and found that StringBuilder is commonly used as a char pointer for DLL functions. Here is how I declared my function:

[DllImport("myDLL.dll")]
public static extern int ChannelName(int x, int y, StringBuilder z);

这就是我要称呼它的方式:

And here is how I'm trying to call it:

for (int x = 0; x < 12; x++)
{
    StringBuilder b = new StringBuilder(100);
    DLLInterface.ChannelName(x+1, b.Length, b);
    Console.WriteLine(b.ToString());
}

这只是使控制台打印出乱码,例如:

This is just making the console print out jibberish, for example:

☺ §
☺ î☺8f9
☺ î☺8f9
☺ î☺8f9
☺ î☺8f9
☺ î☺8f9
☺ î☺8f9
☺ î☺8f9
☺ î☺8f9
☺ î☺8f9
☺ î☺8f9
☺ î☺8f9

我记得在C ++中遇到了类似的问题这就是为什么我 memset 我将 malloc 设置为0的内存的原因。我试图在C#中找到一个等效项,但也许是 StringBuilder 出现问题?如果我的问题不太清楚,我只想能够将一个字符串传递到我的函数中,让该函数填充它,然后将其打印出来。字符串在C#中是不可变的,并且不存在任何好的指针选项,这就是为什么我尝试 StringBuilder

I remember running into a similar problem in C++ which is why I memset the memory that I malloc to 0. I tried to find an equivalent in C#, but maybe it's an issue with the StringBuilder instead? In case my question isn't very clear, I just want to be able to pass a string into my function, have the function fill it up, and then print it out. Strings are immutable in C# and no good pointer options exist which is why I'm trying StringBuilder.

推荐答案

在.NET中,字符串(和StringBuilders)是16位Unicode字符。我的猜测是您的本机函数使用8位ASCII字符。在编组字符时,您需要告诉Marshaller如何转换字符。像这样更改您的DllImport属性:

In .NET, strings (and StringBuilders) are 16-bit Unicode characters. My guess is that you native function deals in 8-bit ASCII characters. You need to tell the Marshaller how to convert the characters when marshalling them. Change your DllImport attribute like so:

[DllImport("myDLL.dll", CharSet=CharSet.Ansi)]
public static extern int ChannelName(int x, int y, [Out] StringBuilder z);

已更新

此外,您还应该在StringBuilder上指定[Out]属性,以使Marshaller仅在出行时不进行封送。

Also you should specify the [Out] attribute on the StringBuilder so that the Marshaller only marshals on the way out as you are passing nothing on the way in.

再次更新

[In,Out]属性是多余的(这是默认值),但是将其放在此处可以明确表明您知道自己想要

The [In,Out] attribute is redundant (that's the default), however putting it there makes it explicit that you know you desire both In and Out copying.

[DllImport("myDLL.dll")]
private static extern int ChannelName(int x, int y, [In,Out] byte[] z);
public static int ChannelName(int x, int y, out string result)
{
    byte[] z = new byte[100];
    int ret = ChannelName(x, y, z);
    result = Encoding.ASCII.GetString(z);
    return ret;
}

再次更新

看起来(命名不正确)'y'参数是传入的char *缓冲区的长度,我的猜测是它返回写入缓冲区的字符数。如果是这种情况,我将以更自然的C#方式包装此调用:

It looks like the (poorly named) 'y' parameter is the length of the char * buffer passed in and my guess is that it returns the number of characters written into the buffer. If that is the case, I would wrap this invocation in a more natural C# way:

[DllImport("myDLL.dll")]
private static extern int ChannelName(int x, int y, [In, Out] byte[] z);

public static string ChannelName(int x)
{
    byte[] z = new byte[100];
    int length = ChannelName(x, z.Length, z);
    return Encoding.ASCII.GetString(z, 0, length);
}

这篇关于将StringBuilder传递给期望char指针的DLL函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆