在 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 生成的代码。
我是 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 生成的代码。