Export (0) Print
Expand All

Basic Concepts in Using Managed Exceptions

In this topic, the basic concepts for exception handling in managed applications are discussed:

For more detailed information on differences in exception handling between managed and unmanaged applications, see Differences in Exception Handling Behavior Under Managed Extensions for C++.

Throwing Exceptions Using Managed Extensions

The C++ throw expression is extended to throw a pointer to any managed type. The following example creates a custom exception type and then throws an instance of that type:

__gc struct MyStruct : public System::Exception { int i; };

void GlobalFunction()
{
   MyStruct* pMyStruct = new MyStruct;
   throw pMyStruct;
}

__value Classes must be boxed before they can be thrown:

__value struct MyValueStruct { int i; };

void GlobalFunction()
{
   MyValueStruct v = {11};
   throw __box(v);
}

Try/Catch Blocks Using Managed Extensions

The same try/catch block structure can be used for catching both managed and unmanaged exceptions. The following example demonstrates a simple try/catch block with managed and unmanaged structures:

// ehtest.cpp
// compile with: /clr /EHsc
#using <mscorlib.dll>

// Needed to access the .NET Framework classes; otherwise, you need to
// use the System:: prefix for .NET Framework classes.
using namespace System;

__gc struct MyStruct : public System::Exception { int i; };
struct CMyClass { double d; };

void GlobalFunction()
{
   MyStruct * pMyStruct = new MyStruct;
   pMyStruct->i = 11;
   throw pMyStruct;
}
void GlobalFunction2()
{
   CMyClass c = {2.0};
   throw c;
}
int main()
{
   for(int i = 1; i >= 0; --i)
   {
    try
    {
     if( i==1) GlobalFunction2();
     if( i==0) GlobalFunction();
    }
    catch(CMyClass& catchC)
    {
     Console::WriteLine(L"Inside 'catch(CMyClass& catchC)'");
     Console::WriteLine(catchC.d);
    }
    catch(MyStruct* catchException)
    {
     Console::WriteLine(L"Inside 'catch(MyStruct* catchException)'");
     Console::WriteLine(catchException->i);
    }
   }
   return 0;
}

Output

Inside 'catch(CMyClass& catchC)'
2
Inside 'catch(MyStruct* catchException)'
11

Order of Unwinding for C++ Objects

Unwinding occurs for any C++ objects with destructors that may be on the run-time stack between the throwing function and the handling function. Because __gc classes are allocated on the heap, unwinding does not apply to them.

Catching Unmanaged C++ Types

When an unmanaged C++ object type is thrown, it is wrapped with an exception of type System::Runtime.InteropServices::SEHException. When searching for the appropriate catch clause, there are two possibilities.

  • If an unmanaged C++ type is encountered, the exception is unwrapped and compared to the type encountered. This comparison allows an unmanaged C++ type to be caught in the normal way.
  • However, if a catch clause of type SEHException or any of its base classes is examined first, the clause will intercept the exception. Therefore, you should place all catch clauses that catch unmanaged C++ types first before any catch clauses of managed types.

For samples that demonstrate this concept, see the following samples: Mixed, NDPExceptions, and Unspecified.

Managed Extensions and the __finally Keyword

In addition to try and catch clauses, Managed Extensions support a __finally clause. The semantics are identical to the __finally block in structured exception handling (SEH). A __finally block can follow a try or catch block.

The purpose of the __finally block is to clean up any resources left after the exception occurred. Note that the __finally block is always executed, even if no exception was thrown. The catch block is only executed if a managed exception is thrown within the associated try block.

The following example demonstrates a simple __finally block:

// keyword__finally.cpp
// compile with: /clr
#using <mscorlib.dll>
using namespace System; // Needed to access the .NET Framework classes

__gc class MyException : public System::Exception
{
};
void ThrowMyException()
{
   throw new MyException;
}

int main()
{
   try
   {
    ThrowMyException();
   }
   catch (MyException *e)
   {
    Console::WriteLine("in catch");
    Console::WriteLine(e->GetType());
   }
   __finally
   {
    Console::WriteLine("in finally");
   }
   return 0;
}

Output

in catch
MyException
in finally

See Also

Handling Exceptions Using Managed Extensions for C++ | __try_cast | Exception Handling | Exceptions Samples

Show:
© 2014 Microsoft