VC++ Exceptions

Handling managed exceptions in VC++ is basically the same as C#. VC++ using managed extensions exposes some features of exceptions that are not available in C#. Those differences will be illustrated later. Listing 15.12 shows how to define and use a custom exception class. The full source for this sample can be found in C++ExceptionsBasicExceptions.

Listing 15.12. Basic Managed VC++ Exceptions
__gc class MyException : public System::ApplicationException
{
public:
    MyException() : System::ApplicationException()
    {
    }
    MyException(System::String __gc *msg) : System::ApplicationException(msg)
    {
    }
} ;
void ThrowMyException()
{
    throw new MyException(new System::String("This exception is thrown from
 ThrowMyException"));
}

int wmain(void)
{
    try
    {
        ThrowMyException();
    }
    catch (MyException *e)
    {
        Console::WriteLine("Caught exception");
        Console::WriteLine(e->ToString());
    }
    __finally
    {
        Console::WriteLine("Finally");
    }
        Console::WriteLine("Almost done");
    return 0;
}

The first section of code defines a class that will be the exception class appropriately derived from ApplicationException. Although it is not required, a default constructor and a constructor that allows the user to define an error message have been defined. If the default constructor is used, the message associated with the event is Error in the application, which is not very descriptive. However, the constructor that takes a string argument allows the message that is associated with this exception to be much more descriptive. In the next section, the function that throws the exception is called and the exception is caught and displayed. The output of this code looks like this:

Caught exception
MyException: This exception is thrown from ThrowMyException
   at ThrowMyException() in basicexceptions.cpp:line 23
   at wmain() in basicexceptions.cpp:line 31
Finally
Almost done

The __finally block was added to illustrate how managed VC++ is different from unmanaged VC++ in one aspect. Two rules seem to exist with unmanaged VC++ exceptions. The first rule is that each function can only have one type of exception-handling scheme. If the function uses SEH (__try/__except), then you cannot also use EH (try/catch) in the same function. The second rule is that the __finally block is associated with a __try. You cannot have __finally and __except both associated with the same __try. Managed VC++ and this sample seem to violate both of those rules. Notice from the output that __finally is associated with the set of try/catch blocks and not with the “final” code to be executed when the function is about to return.

In Listing 15.13, you can see that with C++, “any” exception can be specified with the ellipses. This is basically telling the compiler that you want to catch any exception and you don't care to have a lot of information about it.

Listing 15.13. Catching a General VC++ Exception
try
{
    ThrowMyException();
}
catch (...)
{
    Console::WriteLine("Caught general exception");
}
__finally
{
    Console::WriteLine("General exeption finally");
}

Although this might appear to be the most general case, many unmanaged exceptions are actually turned into SEHExceptions that are derived from Exception; therefore, a catch block that is filtering on Exception would handle this exception. This point is illustrated in the next sample (mixed.cpp), starting with Listing 15.14.

One more sample should solidify some basic understanding of exception handling with managed VC++.

This is another long sample, so it has been split into several listings. The full source for Listing 15.14 can be found in C++ExceptionsMixed. First you will look at a custom exception class that is not derived from any of the managed exception classes. It is not possible to translate what is done in Listing 15.14 with C# because the compiler generates an error indicating that the exception is not derived from System.Exception:

The type caught or thrown must be derived from System.Exception

Listing 15.14 shows the definition of a possible VC++ exception that is not derived from any exception class.

Listing 15.14. Custom Unmanaged VC++ Exceptions
struct UnmanagedException
{
    UnmanagedException(int e) : err(e)
    {
    }
    int Error()
    {
        return err;
    }
private:
    int err;
} ;
. . .
   // Throw an exception that is not based on
   // System.Exception so it is an unmanaged exception
   UnmanagedException *e = new UnmanagedException(10);
   throw (e);
. . .
catch (UnmanagedException* u)
{
    Console::WriteLine(S"
Caught an unmanaged exception
");
    std::cout << u->Error() << std::endl;
}

The first section of this code shows the definition of an unmanaged exception class. This exception class is probably more complex than it needs to be for this sample, but it uses “proper” encapsulation for the single private member, err. Obviously, this class could have whatever functionality the user needs for the exception class to have. The main thing to notice about this exception class is that it does not derive from any of the .NET Framework exception classes; therefore, it does not have the core functionality built into those classes. However, this simple class is easy to construct, and throwing and catching such a class will be relatively fast.

The next section of this listing shows the code that would throw this exception. This is nothing new; just construct the class and throw it.

The last section of this listing shows the exception being caught. Because this class is not derived from any of the managed exceptions, it is considered an unmanaged exception. When this section of the code executes, it generates the following output:

Caught an unmanaged exception
10

It is interesting to try an experiment and comment out the catch block for this exception and recompile the project. Now when the unmanaged exception is thrown, the managed exception catches it because it is identified as an SEHException, which is derived from Exception. You would have expected that because this is an unmanaged exception and the explicit filter for this exception is commented out, catch(…) would be the only match for this exception. However, because it is turned into an SEHException, this is not the case.

The rest of the exceptions that are generated in this sample are managed exceptions that are generated as a result of integer divide-by-zero, null reference exception, stack-overflow, and so on. You have seen all of these before.

The interesting case for this sample is in the following throw:

// Unspecified
throw;

Because a type is not associated with this exception, it is treated somewhat special by the runtime. It is turned into an SEHException. Look at the output for this exception:

System.Runtime.InteropServices.SEHException: External component has thrown an exception.
   at _CxxThrowException(Void* , _s__ThrowInfo* )
   at ExceptionGenerator(Int32 i) in mixed.cpp:line 55
   at main() in mixed.cpp:line 65

The hard part of exceptions with VC++ is remembering whether the code was compiled with /CLR (managed). If it was compiled with /CLR, then the code is run in a managed environment and everything is much like C#. However, in a managed environment, certain constructs (such as __finally) are specific to VC++.

In addition, much of the filtering and SEH exception handling functionality that are part of traditional SEH exceptions is disabled or defaults to an effective no-action when running in a managed environment (/CLR). You can have a __try/__except block and pass an expression that evaluates to true in the __except block. This basic level of user filtering is available from VC++ with managed extensions. However, you can only have one __except block, and it cannot be combined with any other exception scheme in the function. The __try/__except keywords are primarily associated with unmanaged code; as such, they are outside the scope of this book. A simple example of using this construct has been included in the mixed.cpp file, but for further detail, see the SDK documentation on SEH exceptions.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.222.138.230