I have a C DLL I am PInvoking. The main goal is to get back a GUID string of 39 characters, such as abcd-abcd-abcd-abcd-abcd-abcd-abcd-abcd
.
I first call one method to get the size of this string, which I expect to be 39 characters, and then I call another function passing it a StringBuilder
with a capacity of 39:
[DllImport("test.dll")]
public static extern int get_size();
[DllImport("test.dll")]
public static extern void get_string(StringBuilder result);
My code looks something like this:
int size = get_size(); // Returns 40, because it includes the null terminating character.
var result = new StringBuilder(size - 1); // Gives it a capacity of 39. Subtracting 1 here because this does not fancy that null terminator over the marshaling layer.
get_string(result);
Console.WriteLine(result.ToString());
When I call this in a console application, I get back this result: abcd-abcd-abcd-abcd-abcd-abcd-abcd-abcd
When I call this from a unit test with the exact same code, I get back this result: abcd-abcd-abcd-abcd-abcd-abcd-abcd-abcdq
Note the q
on the end, the extra character that is added, and that from debugging the unit test I can verify that the capacity of the StringBuilder
object has increased significantly up to 42 after the call to get_string
despite being initialized with a capacity of 39. Why is this happening? Is this normal? Am I doing something wrong? Why only in the unit tests?
The C implementation is something like this:
static char *_result = NULL; // At some point result is initialized and set.
int get_size() {
if (_result != NULL)
return strlen(_result) + 1;
return 1;
}
void get_string(char *result) {
if (result != NULL && _result != NULL)
strncpy(result, _result, strlen(_result));
}
This required a few fixes.
The function signature needed to change:
The C implementation needed to change:
The C# call needed to change:
A note to rookies of C...if you're not using
char
, and you're using something likewchar_t
or otherwise, along with your string length calculation methods, you'll need to multiply your buffer sizes bysizeof(wchar_t)
instead when doing operations likememset
, since there's a big difference between number of characters in a string and number of bytes in a string. I just happen to know whatsizeof(char)
is 1 so I've omitted this from the implementation to save code.