Stack Exchange
How can I marshal this character array parameter from C to a string in C#?
I have the following function, written as part of another class in C:
int example(char *remoteServerName)
{
    if (doSomething(job))
        return getError(job);
    if (job->server != NULL) {
        int length = strlen(jobPtr->server->name); // name is a char * of length 1025
        remoteServerName = malloc (length * sizeof(char));
        strncpy(remoteServerName, jobPtr->server->name, length);
    }
    return 0;
}

How can I get the remoteServerName back from it? I have tried the following:
[DllImport("example.dll")]
public static extern int example(StringBuilder remoteServerName);

var x = new StringBuilder();
example(x);
Console.WriteLine(x.ToString());

But the string is always empty.

C does not support classes.

You need to allocate some space for the string to be returned in. Instead of:
var x = new StringBuilder();

provide a capacity value:
var x = new StringBuilder(1024);

You should also remove your call to malloc. The caller allocates the memory. That is the purpose of marshalling with StringBuilder.
You are not using strncpy correctly, and so fail to write a null terminator. You could pass the buffer length like this:
int example(char *remoteServerName)
{
    if (doSomething(job))
        return getError(job);
    if (job->server != NULL) {
        // note that new StringBuilder(N) means a buffer of length N+1 is marshaled
        strncpy(remoteServerName, jobPtr->server->name, 1025);
    }
    return 0;
}

But that would be a bit wasteful, with all the zero padding that is implied. Really, strncpy is next to useless and you should use a different function to copy, as has been discussed many times before here. I don't really want to get drawn into that because it's a little off to the side of the question.
It would be prudent to design your API to allow the caller to also pass the length of the character array so that the callee can make sure not to overrun the buffer, and so that you don't need to use magic constants as the code here does.

I am trying this but there is something else not working here, because its still empty. I can verify that the int length variable has a value of 9.

Yes, there were other mistakes in your code that I did not see originally. Sorry. Now fixed, I hope.

@Alexandru For an example of how the Windows API manages buffer size reporting, see GetWindowText() and GetWindowTextLength()

David, I hate bringing this up but this code you posted has a bit of a small problem, but the solution to it is in the following link. Perhaps you could update your answer in order to take this into account? https://stackoverflow.com/questions/45103396/pinvoking-with-stringbuilder-in-a-unit-test

@Alexandru Can you explain what is wrong with this answer to this question?

@DavidHeffernan My code requires another function to get the buffer length, a change to the existing function to pass the buffer length alongside the StringBuilder, and the StringBuilder needs to include capacity for the null terminator. The C code should memset the buffer to 0 and then do the strncpy, otherwise the StringBuilder sometimes returns more than the capacity you provide to it with random memory values. Check out my link. Don't get upset at me for raising this, I'm only raising it because I came across it now. I think your answer is a step in the right direction, 99% there.

That's not really part of this question. Remember that I don't know the design of your functions. I addressed the main issue in this question. Anyway, StringBuilder is initialised to the empty string, so if the unamanged code does not write to the buffer, an empty string is returned to the caller.

You're right, its not part of the question and as far as providing a guide on how to perform the functionality, you totally nailed it, but you know, a lot of guys are gonna come to this page and look at this solution, and they might make mistakes like I just did. Wouldn't you want to guide them a bit further to doing the right thing? Well if not, I provided a link that they can look at. Thanks for all your help, by the way.

@DavidHeffernan Two changes, really. In the line with var x = new StringBuilder(1024);, it should instead be set to a capacity of 1025. Secondly, at the beginning of the example function, you should do a memset(remoteServerName, 0, 1025); in case remoteServerName is in fact truly NULL. You may as well lose the comment // note that new StringBuilder(N) means a buffer of length N+1 is marshaled as well because its not true.

I disagree with everything you state in that comment.
