%module csharp_exceptions // throw is invalid in C++17 and later, only SWIG to use it #define TESTCASE_THROW1(T1) throw(T1) %{ #define TESTCASE_THROW1(T1) %} %include %inline %{ class Ex { const char *message; public: Ex(const char *msg) : message(msg) {} const char *what() { return message; } }; %} %exception ThrowByValue() { try { $action } catch(Ex e) { SWIG_exception(SWIG_DivisionByZero, e.what()); } } %exception ThrowByReference() { try { $action } catch(Ex &e) { SWIG_exception(SWIG_DivisionByZero, e.what()); } } %csnothrowexception NoThrowException() { try { $action } catch(Ex) { // swallowed } } %inline %{ // %exception tests void ThrowByValue() { throw Ex("ThrowByValue"); } void ThrowByReference() { throw Ex("ThrowByReference"); } // %csnothrowexception void NoThrowException() { throw Ex("NoThrowException"); } // exception specifications void ExceptionSpecificationValue() TESTCASE_THROW1(Ex) { throw Ex("ExceptionSpecificationValue"); } void ExceptionSpecificationReference() TESTCASE_THROW1(Ex&) { throw Ex("ExceptionSpecificationReference"); } void ExceptionSpecificationString() TESTCASE_THROW1(const char *) { throw "ExceptionSpecificationString"; } void ExceptionSpecificationInteger() TESTCASE_THROW1(int) { throw 20; } %} // test exceptions in the default typemaps // null reference exceptions %inline %{ void NullReference(Ex& e) {} void NullValue(Ex e) {} %} // enums %inline %{ enum TestEnum {TestEnumItem}; void ExceptionSpecificationEnumValue() TESTCASE_THROW1(TestEnum) { throw TestEnumItem; } void ExceptionSpecificationEnumReference() TESTCASE_THROW1(TestEnum&) { throw TestEnumItem; } %} // std::string %include %inline %{ void ExceptionSpecificationStdStringValue() TESTCASE_THROW1(std::string) { throw std::string("ExceptionSpecificationStdStringValue"); } void ExceptionSpecificationStdStringReference() TESTCASE_THROW1(const std::string&) { throw std::string("ExceptionSpecificationStdStringReference"); } void NullStdStringValue(std::string s) {} void NullStdStringReference(std::string &s) {} %} // Memory leak check (The C++ exception stack was never unwound in the original approach to throwing exceptions from unmanaged code) %exception MemoryLeakCheck() { Counter destructor_should_be_called; try { $action } catch(Ex e) { SWIG_exception(SWIG_DivisionByZero, e.what()); } } %inline %{ struct Counter { static int count; Counter() { count++; } ~Counter() { count--; } }; int Counter::count = 0; void MemoryLeakCheck() { throw Ex("testing memory leaks when throwing exceptions"); } %} // test exception pending in the csconstruct typemap %inline %{ struct constructor { constructor(std::string s) {} constructor() TESTCASE_THROW1(int) { throw 10; } }; %} // test exception pending in the csout typemaps %typemap(out, canthrow=1) unsigned short ushorttest %{ $result = $1; if ($result == 100) { SWIG_CSharpSetPendingException(SWIG_CSharpIndexOutOfRangeException, "don't like 100"); return $null; } %} %inline %{ unsigned short ushorttest() { return 100; } %} // test exception pending in the csvarout/csvarin typemaps and canthrow attribute in unmanaged code typemaps %typemap(check, canthrow=1) int numberin, int InOutStruct::staticnumberin %{ if ($1 < 0) { SWIG_CSharpSetPendingException(SWIG_CSharpIndexOutOfRangeException, "too small"); return $null; } %} %typemap(out, canthrow=1) int numberout, int InOutStruct::staticnumberout %{ $result = $1; if ($result > 10) { SWIG_CSharpSetPendingException(SWIG_CSharpIndexOutOfRangeException, "too big"); return $null; } %} %inline %{ int numberin; int numberout; struct InOutStruct { int numberin; int numberout; static int staticnumberin; static int staticnumberout; }; int InOutStruct::staticnumberin; int InOutStruct::staticnumberout; %} // test SWIG_exception macro - it must return from unmanaged code without executing any further unmanaged code %typemap(check, canthrow=1) int macrotest { if ($1 < 0) { SWIG_exception(SWIG_IndexError, "testing SWIG_exception macro"); } } %inline %{ bool exception_macro_run_flag = false; void exceptionmacrotest(int macrotest) { exception_macro_run_flag = true; } %} // test all the types of exceptions %typemap(check, canthrow=1) UnmanagedExceptions { switch($1) { case UnmanagedApplicationException: SWIG_CSharpSetPendingException(SWIG_CSharpApplicationException, "msg"); return $null; break; case UnmanagedArithmeticException: SWIG_CSharpSetPendingException(SWIG_CSharpArithmeticException, "msg"); return $null; break; case UnmanagedDivideByZeroException: SWIG_CSharpSetPendingException(SWIG_CSharpDivideByZeroException, "msg"); return $null; break; case UnmanagedIndexOutOfRangeException: SWIG_CSharpSetPendingException(SWIG_CSharpIndexOutOfRangeException, "msg"); return $null; break; case UnmanagedInvalidCastException: SWIG_CSharpSetPendingException(SWIG_CSharpInvalidCastException, "msg"); return $null; break; case UnmanagedInvalidOperationException: SWIG_CSharpSetPendingException(SWIG_CSharpInvalidOperationException, "msg"); return $null; break; case UnmanagedIOException: SWIG_CSharpSetPendingException(SWIG_CSharpIOException, "msg"); return $null; break; case UnmanagedNullReferenceException: SWIG_CSharpSetPendingException(SWIG_CSharpNullReferenceException, "msg"); return $null; break; case UnmanagedOutOfMemoryException: SWIG_CSharpSetPendingException(SWIG_CSharpOutOfMemoryException, "msg"); return $null; break; case UnmanagedOverflowException: SWIG_CSharpSetPendingException(SWIG_CSharpOverflowException, "msg"); return $null; break; case UnmanagedSystemException: SWIG_CSharpSetPendingException(SWIG_CSharpSystemException, "msg"); return $null; break; case UnmanagedArgumentException: SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentException, "msg", "parm"); return $null; break; case UnmanagedArgumentNullException: SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentNullException, "msg", "parm"); return $null; break; case UnmanagedArgumentOutOfRangeException: SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentOutOfRangeException, "msg", "parm"); return $null; break; } } %inline %{ enum UnmanagedExceptions { UnmanagedApplicationException, UnmanagedArithmeticException, UnmanagedDivideByZeroException, UnmanagedIndexOutOfRangeException, UnmanagedInvalidCastException, UnmanagedInvalidOperationException, UnmanagedIOException, UnmanagedNullReferenceException, UnmanagedOutOfMemoryException, UnmanagedOverflowException, UnmanagedSystemException, UnmanagedArgumentException, UnmanagedArgumentNullException, UnmanagedArgumentOutOfRangeException }; void check_exception(UnmanagedExceptions e) { } %} // exceptions in multiple threads test %exception ThrowsClass::ThrowException(long long input) { try { $action } catch (long long d) { char message[64]; sprintf(message, "caught:%lld", d); SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentOutOfRangeException, message, "input"); } } %inline %{ struct ThrowsClass { double dub; ThrowsClass(double d) : dub(d) {} long long ThrowException(long long input) { throw input; return input; } }; %} // test inner exceptions %exception InnerExceptionTest() { try { $action } catch(Ex &e) { SWIG_CSharpSetPendingException(SWIG_CSharpApplicationException, e.what()); SWIG_CSharpSetPendingException(SWIG_CSharpInvalidOperationException, "My OuterException message"); } } %inline %{ void InnerExceptionTest() { throw Ex("My InnerException message"); } %}