在 C# 中为 C++ 函数指针生成 SWIG 包装器

Generating SWIG wrapper to C++ function pointers in C#

我是 SWIG 的新手,总体上没有太多 C++ 经验。我无法理解如何生成可以使用 SWIG 调用 C++ dll 的 C# 程序。我浏览了很多示例和论坛帖子,但这一切似乎都超出了我的范围。请有人能用简单的方式向我解释需要什么以及我做错了什么吗?

我有一个带头文件的 C++ dll,只包含 typedef 函数指针定义,我知道导出的函数名称。

例如

/* example.h */
typedef int (*pointer_add) (const long date, const long noDays, long& result);

我只想调用一个简单的方法,在 C# 中我会这样做:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int pointer_add(long date, long noDays, ref long po_res);

public pointer_add addDays { get; protected set; }

// get delegate for function pointer
IntPtr p = NativeMethods.GetProcAddress(libraryHandle, "functionName");
Delegate function = Marshal.GetDelegateForFunctionPointer(p,typeof(pointer_add));
addDays = (pointer_add)function;

// invoke delegate 
addDays(date, noDays, out date); 

但我需要以动态方式解决这个问题,所以 SWIG 是首选工具,尽管我不明白它们应该如何组合在一起...

/* interface.i */
%module wrapper
%{
#include "example.h"
%}

%define %cs_callback(TYPE, CSTYPE)
%typemap(ctype) TYPE, TYPE& "void*"
%typemap(in) TYPE  %{  = (_type)$input; %}
%typemap(in) TYPE& %{  = (_type)&$input; %}
%typemap(imtype, out="IntPtr") TYPE, TYPE& "CSTYPE"
%typemap(cstype, out="IntPtr") TYPE, TYPE& "CSTYPE"
%typemap(csin) TYPE, TYPE& "$csinput"
%enddef

%cs_callback(pointer_addDays, AddDays)
// int AddDays(pointer_addDays c); 

%include "example.h"

// swig -csharp -c++ interface.i

我期待在生成的 interface_wrap.cxx 文件中找到所有的魔法?在 interface.i 文件中注释掉 AddDays 行后,我找不到与 AddDays 相关的任何内容。如果我取消注释 int AddDays(pointer_addDays c);(在原始 .h 文件中找不到),那么我可以在文件中看到生成:

SWIGEXPORT int SWIGSTDCALL CSharp_addDays(void* jarg1) {
  int jresult ;
  pointer_addDays arg1 ;
  int result;

  arg1 = (pointer_addDays)jarg1; 
  result = (int)addDays(arg1); // compiler error - identifier "addDays" is undefined!
  jresult = result; 
  return jresult;
}

我还可以看到在 wrapperPINVOKE.cs 文件中添加了:

  [global::System.Runtime.InteropServices.DllImport("wrapper", EntryPoint="CSharp_addDays")]
  public static extern int addDays(AddDays jarg1);

我在这里的路线完全正确吗?请有人告诉我我做错了什么以获取 wrap.cxx 文件中的错误以及接下来的步骤是什么?

经过反复试验,我想我已经成功了。

code/typemaps 和 %define %cs_callback(TYPE, CSTYPE) 不需要简单地调用我试图获得的函数。这些函数未包含在 .h 文件中,但因为我知道它们的命名约定,所以我可以自己添加它们。

对于我拥有的所有 typedef,我将它们更改为接口 .i 文件中的函数签名:

%module test
%{
#include "example.h"
%}

// all typedefs converted to functions by convention e.g. 
int addDays(const long date, const long noDays, long& result);

由于这些函数未包含在头文件中(需要将其添加到生成的 C++/CLI 包装器项目中),我还必须制作自己的头文件 exportedFunctions.h

// exportedFunctions.h
namespace NamespaceUsedInCPlusPlusCode
{
extern "C" __declspec(dllexport) int addDays(const long date, const long noDays, long& result);
}

并将其包含在 SWIG 生成的 .cpp 中 文件,以便它可以找到函数并编译。

// interface_wrap.cxx
#include "exportedFunctions.h"

这意味着 addDays 函数被 SWIG 包装并在生成的 .cxx 代码中找到,让我编译 SWIG 生成的代码。