为啥包含枚举的 C++ 方法会导致 SWIG/C# 中的 AccessViolationExceptions?
Posted
技术标签:
【中文标题】为啥包含枚举的 C++ 方法会导致 SWIG/C# 中的 AccessViolationExceptions?【英文标题】:why are c++ methods containing enums causing AccessViolationExceptions in SWIG/C#?为什么包含枚举的 C++ 方法会导致 SWIG/C# 中的 AccessViolationExceptions? 【发布时间】:2015-03-31 16:39:06 【问题描述】:我正在使用 SWIG 生成原生 32 位 c++ dll 的包装器。 SWIG 生成一个 C++ 包装文件和大量生成的 C# 代码,这些代码被编译成一个 dll(C++/CLI 和 C# 项目都构建为 x86),并且生成的函数可以通过 C# 很好地调用,但包含枚举的函数除外。一个例子:
SWIG 生成的 interface_wrap.cxx 文件:
SWIGEXPORT int SWIGSTDCALL CSharp_myMethod(long jarg1, long jarg2, void * jarg3, void * jarg4)
int jresult ;
long arg1 ;
long arg2 ;
myEnum arg3 ;
double *arg4 = 0 ;
myEnum const *argp3 ;
int result;
arg1 = (long)jarg1;
arg2 = (long)jarg2;
argp3 = (myEnum *)jarg3;
if (!argp3)
SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentNullException, "Attempt to dereference null myEnum const", 0);
return 0;
arg3 = *argp3;
arg4 = (double *)jarg4;
if (!arg4)
SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentNullException, "double & type is null", 0);
return 0;
result = (int)myMethod(arg1,arg2,arg3,*arg4);
jresult = result;
return jresult;
C#外部函数委托定义:
[global::System.Runtime.InteropServices.DllImport("ProjectWrapper", EntryPoint="CSharp_myMethod")]
public static extern int myMethod(int jarg1, int jarg2, [MarshalAs(UnmanagedType.U4)]myEnum jarg3, out double jarg4);
Interface.i 文件提取:
%module ProjectWrapper
%
#include "myEnumDefinition.h"
%
%include "enums.swg"
// %typemap(csbase) myEnum "short" // is something like this needed??
%typemap(cstype, out="myEnum") myEnum&, const myEnum& "ref myEnum"
%typemap(cstype, out="myEnum") myEnum, const myEnum "myEnum"
%typemap(imtype, inattributes="[MarshalAs(UnmanagedType.U4)]", outattributes="[return: MarshalAs(UnmanagedType.U4)]", out="myEnum") myEnum&, const myEnum& "ref myEnum"
%typemap(imtype, inattributes="[MarshalAs(UnmanagedType.U4)]", outattributes="[return: MarshalAs(UnmanagedType.U4)]") myEnum, const myEnum "myEnum"
%typemap(csin) myEnum&, const myEnum& "ref $csinput"
%typemap(csin) myEnum, const myEnum "$csinput"
int myMethod(const long start,const long end,const myEnum enumvalue, double& result);
枚举的C#定义:
public enum myEnum
myEnum_value1,
myEnum_value2,
myEnum_value3
枚举的 C++ 定义(来自 myEnumDefinition.h)
enum myEnum
myEnum_value1,
myEnum_value2,
myEnum_value3
;
当它调用 C# myMethod extern 委托时,它每次都会抛出 AccessViolationException。如果我尝试在没有任何枚举作为参数的情况下调用其他方法,它工作正常。
我不明白这里有什么问题。我尝试以不同的方式MarshalAs
枚举,但我无法避免抛出此异常。生成包装器时,我是否遗漏了 SWIG 接口文件中的某些内容?
【问题讨论】:
swig.org/Doc1.3/CSharp.html 项目符号的项目都在谈论它。 请您更具体地说明哪些要点? 我认为这是您需要使用 %exception 的 18.4.2 C# 异常示例的部分 感谢您的帮助,但担心我看不到您指向我的部分的相关性。接受的答案反而解决了我的问题。 【参考方案1】:根据这一行,看起来 Swig 期待一个指向枚举值的指针:
argp3 = (myEnum *)jarg3;
看起来 C++ 方法在其第三个参数中期望 myEnum*
值。因此,您可能应该将枚举参数作为 ref 传递:
public static extern int myMethod(int jarg1, int jarg2, ref myEnum jarg3, out double jarg4);
【讨论】:
非常感谢,这确实是问题所在,通过 ref 传递枚举解决了它!万一其他人遇到这种情况,我尝试在 SWIG 中为我的枚举使用%val
关键字,但这不起作用并且可能已被弃用。最后,我将%typemap(imtype)
行更改为"ref myEnum"
,这通过引用传递了枚举,但其他所有内容保持不变。以上是关于为啥包含枚举的 C++ 方法会导致 SWIG/C# 中的 AccessViolationExceptions?的主要内容,如果未能解决你的问题,请参考以下文章