使用SWIG在C#中捕获自定义C++异常时遭遇SEHException问题求助
Let's break down why you're hitting that SEHException instead of your custom C# CustomException, and walk through actionable fixes for each likely issue:
1. Missing EStatus Definition in SWIG Interface
SWIG has no knowledge of the EStatus enum used in your C++ exception, which can lead to invalid integer conversions or type mismatches when passing the status value to the C# callback. This breaks the exception handling flow before it even reaches your C# code.
Fix:
Add the EStatus definition to your SWIG interface before including custom_exception.h. If it's defined in another header, include that first; if it's a local enum, define it directly in the .i file:
// Add this before %include "custom_exception.h" // Option 1: Include the header with EStatus %include "estatus_definition.h" // Option 2: Define EStatus directly if it's not in a separate header namespace ns { namespace exception { enum EStatus { StatusSuccess, StatusInvalidInput, StatusInternalError // Add your actual enum values here }; } }
2. Buffer Overflow in C++ Exception Constructor
Your C++ code uses strcpy(m_msg, msg) without checking input length. If the message exceeds 99 characters (since m_msg is size 100), this causes a buffer overflow—triggering an SEH exception (memory corruption) before SWIG can handle the exception.
Fix:
Replace strcpy with a safe string copy to prevent overflow:
CustomException(const char* msg, EStatus status) : m_status(status) { strncpy(m_msg, msg, m_max_len - 1); m_msg[m_max_len - 1] = '\0'; // Guarantee null termination }
3. Callback Registration Timing Issues
Your current callback registration runs in a static helper class constructor, but there's a chance this executes after a method that throws the exception is called. This leaves the C++ customExceptionCallback pointer NULL, leading to an access violation (another form of SEHException).
Fix:
Move registration to the C# module class's static constructor to ensure it runs before any method calls:
%pragma(csharp) imclasscode=%{ public delegate void CustomExceptionDelegate(string message, int status); [global::System.Runtime.InteropServices.DllImport("$dllimport", EntryPoint="CustomExceptionRegisterCallback")] private static extern void CustomExceptionRegisterCallback(CustomExceptionDelegate customCallback); static void SetPendingCustomException(string message, int status) { SWIGPendingException.Set(new CustomException(message, status)); } static $imclassname() { CustomExceptionRegisterCallback(SetPendingCustomException); } %}
4. Verify SWIG Throws Typemap Matching
A typo in the fully qualified exception name will make SWIG ignore your typemap, letting the exception propagate as an SEH error. Double-check the typemap matches your C++ exception's exact namespace and class name.
Confirm:
Your typemap should correctly reference ns::exception::CustomException:
%typemap(throws, canthrow=1) ns::exception::CustomException { SWIG_CSharpSetPendingExceptionCustom($1.what(), (int)($1.status())); return $null; }
5. Ensure C++ Code Throws the Correct Exception Type
Make sure your C++ functions explicitly throw ns::exception::CustomException (not raw strings or other exception types). For example:
void riskyOperation() { throw ns::exception::CustomException("Failed to process request", ns::exception::StatusInternalError); }
Final Verification
After applying these fixes:
- Re-generate SWIG bindings
- Recompile your C++ DLL
- Test catching the exception in C#:
try { custom_exception.riskyOperation(); } catch (custom_exception.CustomException ex) { Console.WriteLine($"Caught custom exception: {ex.Message}, Status: {ex.status}"); }
This should now catch your custom exception instead of hitting the unhandled SEHException.
内容的提问来源于stack exchange,提问作者Jonathhan Goor

