Migration Strategies for Exception Handling

Snoops

   

 
Migrating to .NET: A Pragmatic Path to Visual Basic .NET, Visual C++ .NET, and ASP.NET
By Dhananjay  Katre, Prashant  Halari, Narayana  Rao  Surapaneni, Manu  Gupta, Meghana  Deshpande

Table of Contents
Chapter 9.   Migrating to Visual C++ .NET


In the previous section, we saw the basic architecture of exception handling in managed extensions. Here, we will deal with the following strategies of exception handling:

graphics/icon01.gif graphics/icon01.gif graphics/icon01.gif graphics/icon01.gif graphics/icon01.gif graphics/icon01.gif graphics/icon01.gif graphics/icon01.gif
  1. Exception handling in the case when the exception is thrown by a managed class and is handled in the managed class only. In this we will deal with the __ gc and __value classes. This code is in the directory Migrationstrategy_1 .

     graphics/icon01.gif //Declare an unmanaged class  class     UnmanagedException{  private:      char* m_Description;  public:      char* GetDescription(){            return m_Description;  }  void SetDescription(char* f_Description){  m_Description = (char *) malloc  (strlen(f_Description)*sizeof(char));        strcpy(m_Description, f_Description);      }  };  //Declare a value class  __value class ValueException{  private:      String* m_Description;  public:      __property String* get_Description(){            return m_Description;      }      __property void set_Description(String* f_Description){            m_Description = f_Description;      }  };  //Declare a gc class  __gc class GCException: public Exception{  private:      String* m_Description;  public:      __property String* get_Description(){            return m_Description;      }      __property void set_Description(String* f_Description){            m_Description = f_Description;      }  };  void main(){      //Instantiate the classes      UnmanagedException objUnmgdException;      ValueException objValException;      GCException * pGCException = new GCException;      try{            for (int i=0; i<4; i++){                  try{                        switch (i){  //Throw exception of the unmanaged class                        case 0 :                              objUnmgdExcetion.SetDescription  ("This is an exception of an unmanaged class");                              throw objUnmgdException;  //Throw exception of the value class                        case 1 :  objValException.Description = S"This is an exception of a value  class";              throw __box (objValException);  //Throw exception of the gc class                        case 2 :  pGCException->Description = S"This is an exception of a managed  GC class type";                              throw pGCException;  //Throw any other exception                        default:                              throw new Exception;                        } // switch                  }  //Catching exception thrown by the unmanaged class            catch (UnmanagedException & objUnmgd){                  Console::WriteLine  (objUnmgd.GetDescription());            }            //Catching exception thrown by the value class            catch (__box ValueException * pVal){                  Console::WriteLine(pVal->Description);            }            //Catching exception thrown by the gc class            catch (GCException * pGC){                  Console::WriteLine(pGC->Description);            }            //Catching other exceptions thrown            catch (Object *ex){                  Console::WriteLine("Generic exception.");            }      } // try  } // for  __finally{  Console::WriteLine("The application is now in the finally  block");  } // finally  } 

    Output:

     This is an exception of an unmanaged class  This is an exception of a value class  This is an exception of a managed GC class type  Generic exception.  The application is now in the finally block 
  2. The second case is where a function in an unmanaged class throws an exception and it is caught in the managed class. Let us first declare an unmanaged class in a new solution:

     graphics/icon01.gif //Declare an unmanaged class  #pragma unmanaged  class UnmanagedException{  private:      char* m_Description;  public:      void ThrowUnmanagedException();      char* GetDescription(){  return m_Description;  }      void SetDescription(char* f_Description){  m_Description = (char*)  malloc(strlen(f_Description)*sizeof(char));            strcpy(m_Description, f_Description);      }  }; 

    In this code, you may be wondering what the #pragma unmanaged means. When you declare #pragma unmanaged before a class, the entire class and its member functions will be compiled as unmanaged. Because in this case we are declaring an unmanaged class in the .NET environment and we want it to be compiled as an unmanaged class, the #pragma has been used. The just-declared unmanaged class has a member function called ThrowUnmanagedException that will throw an object of the unmanaged class. The function implementation is as follows :

     graphics/icon01.gif void UnmanagedException::ThrowUnmanagedException(){      throw new UnmanagedException;  }  //Now declare an managed class.  #pragma managed  //Declare a managed class  __gc class GCException{  private:      String* m_Description;  public:      void ThrowManagedException();      __property String* get_Description(){            return m_Description;      }      __property void set_Description(String* f_Description){            m_Description = f_Description;      }  }; 

    Declaring #pragma managed before a class indicates that the class and all its member functions will be compiled as a managed class. This managed class contains a member function ThrowManagedException that will call the ThrowUnmanagedException of the unmanaged class and catch the exception thrown by that function:

     graphics/icon01.gif void GCException::ThrowManagedException(){      UnmanagedException objUnmgdException;      GCException *pGCException = new GCException;      try{  pGCException->Description = S"This is an exception of the  unmanaged class caught in the managed class";          objUnmgdException.ThrowUnmanagedException();      }      catch(Exception* pEx){            Console::WriteLine(pGCException->Description);      }      } 

    Instantiate the managed class and call its member function. When the member function of the managed class is called, it will internally call the member function of the unmanaged class that in turn will throw an object of the unmanaged class. This object is caught in the function of the managed class, thus indicating that unmanaged exceptions can be caught in the managed class. The following code is in the directory Migrationstrategy_2 .

     graphics/icon01.gif void main(){      //Instantiate the classes        GCException *pGCException = new GCException;      pGCException->ThrowManagedException();  } 

    Output:

     This is an exception of the unmanaged class caught in the  managed class 
  3. The third case that should be considered is the handling of managed exceptions in an unmanaged class. For this, create a simple .NET component. The code snippet for the .NET component follows:

     graphics/icon01.gif namespace NetCom{      public __gc __interface IGCException{      public:            void ThrowManagedException();      };  public __gc class CGCException:public IGCException{  private:      char* m_Description;  public:      CGCException()    {}      void ThrowManagedException(){            CGCException *pGCException = new CGCException;  Console::WriteLine("This is a managed exception that is being  caught in an unmanaged class");            throw new Exception;      }  };  }//namespace NetCom 

    This code snippet will create a .NET component that will output a message when called from the client. It will also throw an exception. For this .NET component we will code a Visual C++ 6.0 client. The client will catch this exception. The client contains two catch blocks. One handles an unmanaged object, and the other catch block is the catchall block, which is generic. The code snippet for the client follows:

     graphics/icon01.gif class UnmanagedException  {  private:      char* m_Description;  public:      char* GetDescription(){  return m_Description;  }      void SetDescription(char* f_Description){  m_Description = (char*)  malloc(strlen(f_Description)*sizeof(char));            strcpy(m_Description, f_Description);      }  }; 

    Here we have declared an unmanaged class. Use this unmanaged class to access the .NET component in main. The following code is in the directory Migrationstrategy_3 .

     graphics/icon01.gif #import "NetCom.tlb"  using namespace NetCom;  int main(int argc, char* argv[]){      UnmanagedException objUnmgdException;      CoInitialize(NULL);      try{  char* l_Description = "This is a property of the unmanaged  class";            objUnmgdException.SetDescription(l_Description);            IGCExceptionPtr pNetCom(__uuidof(CGCException));            pNetCom->ThrowManagedException();      }      catch(UnmanagedException &objUnmgdException){            cout<< objUnmgdException.GetDescription();      }      catch(...)  {  cout<<"Throwing managed exception"<<endl;      }      CoUninitialize();      return 0;  } 

    Output:

     This is a managed exception that is being caught in an unman- aged class  Throwing managed exception 

    This piece of code will terminate abnormally after showing the message if the catch ( ) block is not included. This indicates that an unmanaged catch cannot handle an exception thrown by a managed class.

This is one way of catching an exception thrown by a managed class in an unmanaged catch handler, thus preventing abnormal termination of the handler. The order of events for a thrown exception are as followed:

  • The stack is first searched for the correct catch clause by the runtime. In the case of structured exception handling (SEH), an SEH except filter is searched for. The search for the catch clause is first in the lexical order and then moves dynamically down the stack.

  • The stack is unwound at the point where the correct handler is found. The local objects are destructed for each function call on the stack. __finally blocks are executed from most nested outwards.

  • The catch clause is executed once the stack is unwound.

We must specify one of the compiler options (/GX, /Ehs, or /Eha) while throwing and catching unmanaged exceptions.

Now that we understand the basic concepts of exception handling in managed exceptions, we will deal with the restrictions and the deviation from the standard behavior of exception handling as far as managed extensions is concerned .

In managed code a jump from the __ finally block results in a compilation error. A return , goto , continues , or break in a __finally block will evaluate to a compilation error. The same applies to C++ exception handling in managed extensions. Such a piece of code when compiled will give a compilation error indicating that a jump statement in the __finally block is not possible.

Disassociated Rethrows

Rethrowing an exception outside a catch handler is not supported in managed extensions. Managed extensions treats these types of exceptions as C++ rethrows. When a disassociated rethrow is encountered in a managed exception, it is wrapped in the same manner as a C++ exception and then rethrown. Hence, exceptions of this type are caught only by the exceptions of type System::SEHException . This will be illustrated in the following example, which is in the directory disassociated_rethrow .

 graphics/icon01.gif //Declaring a managed class  __gc class GCException{  private:      String* m_Description;  public:      __property String* get_Description() {  return m_Description;  }      __property void set_Description(String* f_Description){            m_Description = f_Description;      }  };  void rethrow(void){      throw;  }  void main(){      GCException *pGCException = new GCException;      try{            try{  pGCException->Description = S"Throwing an exception of the  managed class";                  throw pGCException;            }  catch(GCException *ex){                  rethrow();            }      }      catch(GCException *ex){            Console::WriteLine(ex->Description);  Console::WriteLine("Exception caught in the managed exception  catch block");      }      catch(Runtime::InteropServices::SEHException* pEx){  Console::WriteLine("Exception caught in the Structured Excep- tion Handler");      }  } 

Output:

 Exception caught in the Structured Exception Handler 

In this example, in the catch block we are calling another function, rethrow , that is not associated with the managed class in any way. Hence, the throw from that function will not be recognized by the catch block of the managed code and it will be caught by the SEH, as is evident from the output. This is a disassociated rethrow.

If instead of rethrow , throw , throw(ex) , or rethrow(GCException* ex) is used, the throw will be recognized as a managed throw and will be caught by the managed catch block. An example follows, which is in the directory disassociated_rethrow :

 graphics/icon01.gif //Declaring a managed class  __gc class GCException{  private:      String* m_Description;  public:      __property String* get_Description() {  return m_Description;}      __property void set_Description(String* f_Description){            m_Description = f_Description;      }  };  void rethrow(GCException *ex){      throw(ex);  }  void main(){      GCException *pGCException = new GCException;      try{            try{  pGCException->Description = S"Throwing an exception of the  managed class";                  throw pGCException;            }  //Catching a managed exception            catch(GCException *ex){                  rethrow(ex);            }      }  //Catching a managed exception      catch(GCException *ex){            Console::WriteLine(ex->Description);  Console::WriteLine("Exception caught in the managed exception  catch block");      }      //Catching Structured Exceptions      catch(Runtime::InteropServices::SEHException* pEx){  Console::WriteLine("Exception caught in the Structured Excep- tion Handler");      }  } 

Output:

 Throwing an exception of the managed class  Exception caught in the managed exception catch block 

Snoops

   
Top


Migrating to. NET. A Pragmatic Path to Visual Basic. NET, Visual C++. NET, and ASP. NET
Migrating to. NET. A Pragmatic Path to Visual Basic. NET, Visual C++. NET, and ASP. NET
ISBN: 131009621
EAN: N/A
Year: 2001
Pages: 149

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net