I call a native dll from C# Mono and I cannot capture the exceptions with a try catch clause c# side. Apparently Mono does not support that, regardless of the flags being set (as according to other posts here about this problem). Mono will always just close down as soon as the exception leaves the native side.
The solution, I came up with, is to pass an [Out]IntPtr errorText
with all my dll extern methods from c#. This is recieved native side as a char**. The native c++ function wrap everything in a try catch(const std::exception& ex)
clause. If there is no exception, I set the errorText to nullptr but if there is an exception I set it to *errorText=ex.what()
When the native call returns, it either has a null pointer to error, meaning no exception or it is non null in which case I extract it as Marshal.PtrToStringAnsi(errorText)
This works and does not work. The exceptions get caught and the pointer is being set, but the marshal call returns null from the IntPtr. After some testing, I realize that if I set the native error text pointer to a constant like *errorText="a test"
then it works as intended.
The issue seems to be that the native exception object goes out of scope when the native function returns and at this point the what()
text becomes invalid, meaning it is invalid when I try to marshal the contents from the pointer to it.
One solution is to always myself throw const strings as exceptions like throw "something bad"
and catch that, because those constant strings remain valid, and then catch other std::exception
s returning just a generic error string like "undefined std::exception".
That is obviously not perfect, though it can work. The question is why exactly I cannot get to the *what()
after leaving the function. While the actual exception object may go out of scope, the message it was created with is generally itself a constant. If I do throw std::exception("something")
then what
should point to the constant "something" and should remain valid after the exception goes out of scope.
I have considered making a persistent char array in the dll and copy the what() into it for later retrieval, but I need to support multiple simultaneous accesses, which could potentially have multiple exceptions at the same time, leading t fighting over this buffer.
I am very interested if anyone have some insight in why the what()
is not available after exception leaves scope or a good idea for solving this more elegantly than by throwing string exceptions.
Edit: One other solution would be to allocate the string for the error message managed side and pass a pointer to that for native side to put an error into. I just need to not allocate a new string every call... would much prefer to just get a pointer to the actual message in what()