CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 8 of 8
  1. #1
    Join Date
    Oct 2010
    Posts
    4

    Question Unhandled exception in managed DLL

    Hello all,

    I have some managed wrapper for native C++ code, that contains following:

    void Reset(T* ptr)
    {
    try
    {
    if ( m_ptr != NULL && ptr != m_ptr )
    {
    // Free the existing native pointer
    m_ptr->RemoveAllObservers( );
    m_ptr->SetReferenceCount( 0 );
    }

    // Set the new native pointer (sets to NULL if ptr = NULL)
    m_ptr = ptr;

    // Register the new pointer to keep it alive
    if ( m_ptr != NULL )
    {
    m_ptr->Register( );
    }
    }
    catch (System::Exception^ ex)
    {
    Debug::Print("catch reached:"+ex->Message);
    // HACK: Consume the exception, even though it is bad practice.
    // NOTE: This method tends to throw System.AccessViolationExceptions,
    // probably because the memory has been previously freed.
    }
    catch (...)
    {
    Debug::Print("catch reached");
    // HACK: Consume the exception, even though it is bad practice.
    // NOTE: This method tends to throw System.AccessViolationExceptions,
    // probably because the memory has been previously freed.
    }
    }

    Then, I compiled it to dll and add the dll as a reference to my C# application.

    Each time after my C# application ended, I'm getting an AccessViolationException from this code in the DLL. For some unknown reason it does not handled by try-catch block (the dll was compiled with SEH). The Reset(T *ptr) method is called by finalizer in garbage collector after the application was closed, so I have no idea how to handle this.

    Can anyone help? could it be that i missed some important compiler option?

  2. #2
    Join Date
    Apr 2004
    Location
    England, Europe
    Posts
    2,492

    Re: Unhandled exception in managed DLL

    The Reset(T *ptr) method is called by finalizer
    That should never happen. The finalizer should be a very simply function which only does things like freeing unmanaged resources. When it runs, you do not know which other .net objects have already been finalized.
    My hobby projects:
    www.rclsoftware.org.uk

  3. #3
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: Unhandled exception in managed DLL

    Has your wrapper object implemented IDisposable?

  4. #4
    Join Date
    Apr 2004
    Location
    England, Europe
    Posts
    2,492

    Re: Unhandled exception in managed DLL

    In C++/CLI, IDisposable is implemented by writing what looks like a C++ destructor:

    http://www.codeproject.com/KB/mcpp/cppclidtors.aspx
    My hobby projects:
    www.rclsoftware.org.uk

  5. #5
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: Unhandled exception in managed DLL

    There are some difference in syntax between IDisposable on C# and in managed C++.

    The important take away is that a destructor is coded differently than a finalizer.

    Code:
    ref struct A
    {
       // destructor cleans up all resources
       ~A()
      {
        // clean up code to release managed resource
        // ...
        // to avoid code duplication 
        
        // call finalizer to release unmanaged resources
        this->!A();
      }
    
      // finalizer cleans up unmanaged resources
      // destructor or garbage collector will
      // clean up managed resources
      !A()
      {
          // clean up code to release unmanaged resource
          // ...
       }
    };

    Destructors and Finalizers in Visual C++

  6. #6
    Join Date
    Apr 2004
    Location
    England, Europe
    Posts
    2,492

    Re: Unhandled exception in managed DLL

    I'll have a look at that article tomorrow.


    This C++/CLI code:

    Code:
    ref class C
    {
    public:
    
        C()
        {
            pen = gcnew System::Drawing::Pen(System::Drawing::Color::Blue);
            handle = (System::IntPtr)123;
        }
    
        ~C()
        {
            delete pen;
        }
    
        !C()
        {
            handle = System::IntPtr::Zero;
        }
    
        System::IntPtr        handle;
        System::Drawing::Pen^ pen;
    };
    generates these functions:

    Code:
    .method public hidebysig specialname rtspecialname 
            instance void  .ctor() cil managed
    {
      // Code size       40 (0x28)
      .maxstack  2
      .locals init ([0] native int V_0,
               [1] valuetype [System.Drawing]System.Drawing.Color V_1)
      IL_0000:  ldarg.0
      IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
      IL_0006:  call       valuetype [System.Drawing]System.Drawing.Color [System.Drawing]System.Drawing.Color::get_Blue()
      IL_000b:  stloc.1
      IL_000c:  ldarg.0
      IL_000d:  ldloc.1
      IL_000e:  newobj     instance void [System.Drawing]System.Drawing.Pen::.ctor(valuetype [System.Drawing]System.Drawing.Color)
      IL_0013:  stfld      class [System.Drawing]System.Drawing.Pen C::pen
      IL_0018:  ldc.i4.s   123
      IL_001a:  call       native int [mscorlib]System.IntPtr::op_Explicit(int32)
      IL_001f:  stloc.0
      IL_0020:  ldarg.0
      IL_0021:  ldloc.0
      IL_0022:  stfld      native int C::handle
      IL_0027:  ret
    } // end of method C::.ctor
    Code:
    .method public hidebysig virtual final instance void 
            Dispose() cil managed
    {
      // Code size       14 (0xe)
      .maxstack  2
      IL_0000:  ldarg.0
      IL_0001:  ldc.i4.1
      IL_0002:  callvirt   instance void C::Dispose(bool)
      IL_0007:  ldarg.0
      IL_0008:  call       void [mscorlib]System.GC::SuppressFinalize(object)
      IL_000d:  ret
    } // end of method C::Dispose
    Code:
    .method family hidebysig newslot virtual 
            instance void  Dispose(bool  marshal( unsigned int8) A_1) cil managed
    {
      // Code size       43 (0x2b)
      .maxstack  2
      .locals init ([0] class [mscorlib]System.IDisposable V_0)
      IL_0000:  ldarg.1
      IL_0001:  brfalse.s  IL_0015
      IL_0003:  ldarg.0
      IL_0004:  ldfld      class [System.Drawing]System.Drawing.Pen C::pen
      IL_0009:  stloc.0
      IL_000a:  ldloc.0
      IL_000b:  brfalse.s  IL_002a
      IL_000d:  ldloc.0
      IL_000e:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()
      IL_0013:  br.s       IL_002a
      IL_0015:  nop
      .try
      {
        IL_0016:  ldarg.0
        IL_0017:  ldsfld     native int [mscorlib]System.IntPtr::Zero
        IL_001c:  stfld      native int C::handle
        IL_0021:  leave.s    IL_002a
      }  // end .try
      finally
      {
        IL_0023:  ldarg.0
        IL_0024:  call       instance void [mscorlib]System.Object::Finalize()
        IL_0029:  endfinally
      }  // end handler
      IL_002a:  ret
    } // end of method C::Dispose
    Code:
    .method private hidebysig instance void  '!C'() cil managed
    {
      // Code size       12 (0xc)
      .maxstack  2
      IL_0000:  ldarg.0
      IL_0001:  ldsfld     native int [mscorlib]System.IntPtr::Zero
      IL_0006:  stfld      native int C::handle
      IL_000b:  ret
    } // end of method C::'!C'
    Code:
    .method private hidebysig instance void  '~C'() cil managed
    {
      // Code size       17 (0x11)
      .maxstack  1
      .locals init ([0] class [mscorlib]System.IDisposable V_0)
      IL_0000:  ldarg.0
      IL_0001:  ldfld      class [System.Drawing]System.Drawing.Pen C::pen
      IL_0006:  stloc.0
      IL_0007:  ldloc.0
      IL_0008:  brfalse.s  IL_0010
      IL_000a:  ldloc.0
      IL_000b:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()
      IL_0010:  ret
    } // end of method C::'~C'
    Code:
    .method family hidebysig virtual instance void 
            Finalize() cil managed
    {
      // Code size       8 (0x8)
      .maxstack  2
      IL_0000:  ldarg.0
      IL_0001:  ldc.i4.0
      IL_0002:  callvirt   instance void C::Dispose(bool)
      IL_0007:  ret
    } // end of method C::Finalize


    The (inlined) finalizer is automatically called inside the Dispose function.
    Last edited by Zaccheus; November 1st, 2010 at 05:09 PM.
    My hobby projects:
    www.rclsoftware.org.uk

  7. #7
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: Unhandled exception in managed DLL

    Not disagreeing. It was actually a surprise to me that managed C++ had a destructor and a finalizer (and yet doesn't implement the IDisposable.Dispose( ) method).
    Last edited by Arjay; November 1st, 2010 at 05:27 PM.

  8. #8
    Join Date
    Apr 2004
    Location
    England, Europe
    Posts
    2,492

    Re: Unhandled exception in managed DLL

    IDisposable is implemented and there is no need for the class author to explicitly call !C from inside ~C as the generated code does so automatically.
    My hobby projects:
    www.rclsoftware.org.uk

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured