-
October 18th, 2010, 07:02 AM
#1
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?
-
October 22nd, 2010, 02:53 PM
#2
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.
-
October 31st, 2010, 07:28 PM
#3
Re: Unhandled exception in managed DLL
Has your wrapper object implemented IDisposable?
-
November 1st, 2010, 08:32 AM
#4
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
-
November 1st, 2010, 03:22 PM
#5
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++
-
November 1st, 2010, 05:02 PM
#6
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.
-
November 1st, 2010, 05:25 PM
#7
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.
-
November 2nd, 2010, 11:36 AM
#8
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.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|