Как уже указывалось другими, вам нужно указать соглашение о вызовах C в вашем P / Invoke, а также использовать строку на управляемой стороне для маршалирования завершенного нулем символа *.
Однако вы должны перенастроить подпрограмму C ++, чтобы взять char * в качестве входного параметра вместе с параметром длины буфера. Затем вы пишете в этот буфер в нативный код. Это позволяет избежать текущей проблемы, заключающейся в том, что данные, поскольку у вас есть код, возвращаются из стека, который, конечно, разматывается при возврате функции.
Предложение использовать static сделает эту память глобальной и, таким образом, позволит избежать проблем с перемоткой стека за счет безопасности потоков. Да, это, вероятно, подойдет для этого варианта использования, но это плохая привычка.