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

时间:2015-02-17 12:04:52

标签: c# c++ swig

我是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  %{ $1 = ($1_type)$input; %}
%typemap(in) TYPE& %{ $1 = ($1_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文件中找到错误以及接下来的步骤是什么?

1 个答案:

答案 0 :(得分:1)

经过一些反复试验后,我想我已经成功实现了这一目标。

简单地调用我试图获取的函数不需要带%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生成的代码。