0

I'm calling a C library function from a C# method; something like this:

[DllImport("libfoo.dll")]
public static extern int GetData(StringBuilder buffer);

It returns the number of characters that it put into the buffer, and there's a known maximum limit on the number of characters; so it could be called like:

StringBuilder sb = new StringBuilder(5000);

int received = GetData(sb);

So the problem/question: the C function is using a character array as a byte array; we're not necessarily looking at normal strings, and the character array may well include null characters.

It seems that this default, naive usage of StringBuilder results in a C# string that is cut off at the first null character / null byte.

What else could be done? Is there a way to force StringBuilder to accept strings with null characters? Or is there a better approach for accessing the C library function?

Edit: C function is something like:

int GetData (char *buffer);
tjr
  • 143
  • 1
  • 8
  • SB doesn't encapsulate a char array, so treating it as one is a flawed premise. – Servy Mar 05 '16 at 00:22
  • 1
    What is the signature of the C method? – IS4 Mar 05 '16 at 00:39
  • 1
    A C string uses a 0 to indicate the end of the string. There is no additional Length-like member, it is merely an array of characters. So, inevitably, zeros can not give you what you want. The pinvoke marshaller has to stop copying chars when it encounters a 0. You must include another *out* argument or return value that indicates how many chars were copied into the buffer. And use byte[] instead. Use Encoding.Default.GetString(byte[], int, int) to convert. – Hans Passant Mar 05 '16 at 06:38

3 Answers3

3

Okay, so as Fredou pointed out, StringBuilder strings can have null characters, but something was still getting lost in between the C code and the C# code. Turns out that StringBuilder usually is a fine choice for receiving regular strings, but for byte arrays, using, well, a byte array works better.

Answer here: PInvoke char* in C DLL handled as String in C#. Issue with null characters

Community
  • 1
  • 1
tjr
  • 143
  • 1
  • 8
1

if you just want to convert the StringBuilder into array of string you can always do

var myArray = sb.ToString().Split('\0');

ex(dotnetfiddler);

using System;
using System.Text;

public class Program
{
    public static void Main()
    {
        var sb = new StringBuilder();
        sb.Append("abc\0def");

        Console.WriteLine(sb.ToString());
        var myArray = sb.ToString().Split('\0');

        Console.WriteLine("myArray.Length " + myArray.Length);
        foreach(var a in myArray)
        {
            Console.WriteLine(a);
        }
    }
}

I will also add that StringBuilder do support null character, example above prove it

Fredou
  • 19,848
  • 10
  • 58
  • 113
1

It's usually not a good idea to interpret regular bytes using a string in C#. Why don't you pass a normal byte array instead, if you know its maximum size?

[DllImport("libfoo.dll")]
public static extern int GetData([Out] byte[] buffer);
IS4
  • 11,945
  • 2
  • 47
  • 86
  • 1
    That's right. It's also what the OP already posted as an answer 8 hours ago. –  Mar 05 '16 at 10:05