繁体   English   中英

如何使用 SWIG 从 C 调用 C# 方法?

[英]How to call a C# method from C using SWIG?

我一直在寻找一些解释/代码片段,说明如何使用 SWIG 从 C 调用 C# 方法。 我能找到的最好的是: 使用 SWIG 从 C++ 到 C# 回调 唉,这是针对 C++ 而不是 C。 除了 C,我们如何实现相同的功能?

您仍然可以使用 SWIG 来帮助(一点)执行此操作,但从根本上说,如果您使用的是 C 编译器,则无法启用 SWIG 导向器,您链接到的示例依赖于:

test.i:1: Error: Directors are not supported for C code and require the -c++ option

因此,您必须在 C 中重建该功能的某些部分才能执行此操作。 我构建了一个 C++ 启用导向器/回调设置的示例,并以此为基础来建立我对 C# 机制的理解。 让我们从我们要运行的测试开始,倒着做:

public class TestImpl : CallbackInterface {
    public override void callback() {
        System.Console.WriteLine("handling event...");
    }

    public static void Main() {
        CallbackInterface cb = new TestImpl();
        test.test_runner(cb);   
    }
}

我们想定义一个抽象的 class, CallbackInterface ,我们可以传递实例,并让我们的 C 代码调用 C# callback实现。

这是 my.i SWIG 接口文件:

%module test
%{
#include <assert.h>
%}

%typemap(csclassmodifiers) struct CallbackInterface "public abstract class";
%typemap(cscode) struct CallbackInterface %{
  public delegate void callback0(); // [2]

  public CallbackInterface() : this(null) { // [3]
    connect();
  }

  private void connect() {
    setCallback(new callback0(callback));
  }

  public abstract void callback();
%}

// [4]
%typemap(cstype) cb0 "CallbackInterface.callback0";
%typemap(imtype) cb0 "CallbackInterface.callback0";
%typemap(csin) cb0 "$csinput";
%ignore CallbackInterface::cb;

%extend struct CallbackInterface {
  CallbackInterface(cb0 cb) { // [3]
    struct CallbackInterface *ret = malloc(sizeof *ret);
    ret->cb = cb;
    return ret;
  }

  void setCallback(cb0 cb) {
    $self->cb = cb;
  }
}

%inline %{
  typedef void (*cb0)();

  struct CallbackInterface {
    cb0 cb; // [1]
  };

  static void test_runner(struct CallbackInterface *interface) {
    assert(interface->cb);
    fprintf(stderr, "Doing test, pointer=%p, cb=%p\n", interface, interface->cb);
    interface->cb();
  }
%}

通过调查 C# 中的正常导向器实现,似乎 C++ 层通过 pinvoke 接口与 function 指针一起使用。 所以我们在接口 1 中定义了一个结构,它有一个成员,一个 function 指针。

In order to actually get a function pointer out of our C# code we need to use a delegate, we've set things up for this at 2, which is C# code that's going to be part of our CallbackInterface class.

在 SWIG 中,我们已经“扩展”了(但仍然只使用 C)我们的结构来提供一个构造函数,该构造函数在 3 处接受一个委托作为参数。这有点奇怪,因为我们在这里只传递null ,但这有效作为稍后我们默认构造函数的方便重载,并确保我们在创建实例时也至少初始化结构的cb成员,在 3 处调用委托构造函数。(旁白:我最初试图在这里创建委托,但这是一个 static 上下文,看起来你现在不能这样做)。 然后在默认构造函数的主体中,我们调用我们的私有connect方法,该方法设置一个委托并使用我们的%extend setCallback方法来实际修改结构。

如果您愿意,您也可以提供setCallback的重载,例如 C function 指针可以设置为处理程序,但这是一个额外的额外功能,尤其是考虑到 Z0D61F8370CAD1t4D412F70B84D 的所有限制55。 在 4 处使用一些额外的类型映射,以确保委托作为 function 指针传递到 C,我们正在开展业务,因此这个 ZB67911656EF5D18C4ZAE36CB6741B7965 可以为我们运行以下内容并测试

.PHONY: run

all: run

test_wrap.c: test.i
    swig -csharp -Wall -debug-tmsearch test.i

test.cs: test_wrap.c
CallbackInterface.cs: test_wrap.c
testPINVOKE.cs: test_wrap.c

test.exe: test.cs runme.cs CallbackInterface.cs testPINVOKE.cs
    mcs $^

libtest.so: test_wrap.c
    gcc -shared -Wall -Wextra $^ -o $@ -fPIC

run: test.exe libtest.so
    LD_LIBRARY_PATH=. ./test.exe

在 Ubuntu 上使用 Mono 至少可以按预期工作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM