Вы можете сделать это в SWIG.Обычно я не пишу много (читай: любой) C #, и я проверил это с Mono на Linux, так что мой ответ довольно серьезен: вы должны тщательно проверить его правильность.
В любом случае мы можем сгенерироватьОбертка, что я достаточно счастлив, это правильно.SWIG (в большинстве режимов на большинстве языков) создает оболочки из двух частей.Некоторый код, написанный на языке, для которого вы создаете оболочку (например, здесь C #), а также некоторый C или C ++.
Настраивая точку входа C # в оболочку, мы можем установить сцену для нашего аргумента.По сути, мы используем это, чтобы передать IntPtr
(инициализированный в NULL) ссылкой в нашу функцию C.После вызова функции мы затем используем Marshal.PtrToStringAnsi
для чтения выходной строки, адрес которой мы теперь знаем, обратно в мир C # в качестве вывода нашей функции C #.
Наконец, все, что осталосьсделать это убирать.Этот шаг зависит от семантики функции, которую мы вызываем - если мы в конечном итоге владеем строкой, нам нужно освободить ее, как только мы получим копию.Поэтому, если нам не принадлежит строка, мы не должны ее освобождать.И если FreeHGlobal
не правильный способ освободить его, вам нужно заменить альтернативу.
%module test
%typemap(csin,pre="global::System.IntPtr tmp$csinput=global::System.IntPtr.Zero;",
post="$csinput=global::System.Runtime.InteropServices.Marshal.PtrToStringAnsi(tmp$csinput);
global::System.Runtime.InteropServices.Marshal.FreeHGlobal(tmp$csinput);") char **OUTPUT "ref tmp$csinput";
%typemap(cstype) char **OUTPUT "out string";
%typemap(imtype) char **OUTPUT "ref global::System.IntPtr"
%apply char **OUTPUT { char **outarg };
%{
#include <shlwapi.h>
#pragma comment(lib, "Shlwapi.lib")
%}
%inline %{
void foobar(char **outarg) {
fprintf(stderr, "In foobar: outarg is: %p\n", outarg);
fprintf(stderr, "*outarg starts as: %p\n", *outarg); // This will be NULL, we initalised to Zero
*outarg = StrDupA("Hello world"); // This is good enough for testing
fprintf(stderr, "*outarg is now: %p\n", *outarg); // We can see this value by looking at our IntPtr instead of copying it
}
%}
Имея это в виду, мы можем успешно выполнить что-то вроде этого:
public class runme {
static void Main(string[] args) {
string blah;
test.foobar(out blah);
System.Console.WriteLine(blah);
}
}
Который работает как положено.