5

Is it possible to call a throwing C# function from a C++ call in a C# app such that the C++ stack is unwound properly? Is there any documentation of this?

For example, please consider this C# code:

using System;

public class Test
{
    public static void CalledFromCpp()
    {
        throw new Exception("Is this safe? Is C++ stack unwound properly?");
    }

    public static void Main()
    {
        try {
            CppFunc(CalledFromCpp);
        }
        catch(Exception e)
        {
            Console.Writeline("Exception e: {0}", e);
        }
    }

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    delegate void CsFuncToBeCalledFromCpp();

    [DllImport("CppApp", CallingConvention = CallingConvention.Cdecl)]
    private static extern void
    CppFunc(CsFuncToBeCalledFromCpp callback);
}

Along with this C++ code:

void CppFunc(void (*handler))
{
   SomeResourceWrappingClass releasesResourceOnDestruction();
   handler();
}

I tried this out, and the C# exception was caught successfully, but releasesResourceOnDestruction didn't have it's destructor called. This seems to indicate that the C++ stack is not being unwound properly -- is it possible to get it to unwind properly here? Is there any documentation on this behavior?

For context: I want to sometimes trigger a C# exception from C++ code if possible, so that I don't need every call from C# into C++ have to check something afterwards to see if a C# exception needs to be thrown.

JDiMatteo
  • 12,022
  • 5
  • 54
  • 65
  • How do you know that the destructor of `releasesResourceOnDestruction ` wasn't evoked? – 101010 Sep 09 '14 at 20:06
  • You will have to disable an optimization that the C++ compiler uses when it doesn't see a C++ exception being thrown. Project + Properties, C/C++, Code Generation, Enable C++ Exceptions = /EHa. Actually catching the exception requires using the non-standard __try/__except keywords. There is *very* little reasonable you can do, all of the info that's required to diagnose the exception was lost. That's going to be a support phone call from a ticked-off user that's awfully hard to answer. – Hans Passant Sep 09 '14 at 20:13
  • 40two: I added a printing statement to both the constructor and destructor of releasesResourceOnDestruction. The contructor prints but the destructor never does. – JDiMatteo Sep 09 '14 at 20:14

1 Answers1

2

Try enabling Structured Exception Handling in your C++ project (Project Properties -> C/C++ -> Code Generation -> Enable C++ Exceptions -> "Yes with SEH Exceptions (/EHa)"). Without SEH exceptions, the exception that is returned to the C++ layer does not have enough information to unwind the stack properly.

Velox
  • 254
  • 1
  • 5
  • 1
    There are multiple options under C++ exceptions. The "Yes with SEH Exceptions (/EHa)" needs to be selected. – Velox Sep 09 '14 at 20:23
  • 1
    Velox, do you see any potential problems with this approach? The other answer suggested that odd things would happen if the exception wasn't caught. Also, please consider moving your clarification about "/EHa" in your comment to your answer. – JDiMatteo Sep 09 '14 at 20:35
  • 1
    The problems I see with this approach: 1 - You will have to have a catch clause to catch the exception, or else your program will crash due to the unhandled exception. 2 - Since it's a C# exception being thrown, you will have trouble catching the exact exception. You will probably need a `catch(...)` to catch the exception. – Velox Sep 09 '14 at 20:51
  • Velox, thanks, I was suprised that catch(...) actually does catch the C# exception. This is actually NOT what I wanted, but I guess it makes sense and there is no work around. – JDiMatteo Sep 09 '14 at 21:11
  • 1
    The following is a nice explanation of what /EHa means and why this answer works: http://stackoverflow.com/a/4574319/1007353 . It also explains how EHa is dangerous because with this setting catch(...) swallows exceptions that you shouldn't catch, like access violations and stack overflows. – JDiMatteo Sep 09 '14 at 21:38