Passing StringBuilder to DLL function expecting char pointer

独自空忆成欢 提交于 2019-12-20 01:58:05

问题


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);
    ...
}

Where channelName is type defined as typedef int (CALLBACK* ChannelName)(int,int,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

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.


回答1:


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);

Updated

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.

Updated Again

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;
}

Updated Again

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);
}


来源:https://stackoverflow.com/questions/11508260/passing-stringbuilder-to-dll-function-expecting-char-pointer

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!