问题
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