Генерация SWIG-Proxy для C-функции с параметром "char **" - PullRequest
0 голосов
/ 17 июня 2019

Я пытаюсь создать оболочку с SWIG для этого C-кода:

extern APIKeyRef_t parse_api_key(char* p0, char** p1)

Второй параметр p1 генерируется SWIG как SWIGTYPE_p_p_char, который бесполезен в C #. Как мне сказать SWIG генерировать здесь параметр "out string" или "ref string"? Я прочитал документы SWIG, но понимаю только половину. Это может быть легко для SWIG-профи.

Метод автоматически генерируется из функции Go. «APIKeyRef_t» и «char *» работают отлично - SWIG генерирует для них красивые оболочки.

Спасибо!

1 Ответ

0 голосов
/ 21 июня 2019

Вы можете сделать это в 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);
  }
}

Который работает как положено.

...