I have rephrased this question.
When .net objects are exposed to COM Clients through COM iterop, a CCW (COM Callable Wrapper) is created, this sits between
I've been struggling with this too, to try to get server lifetime correct for my Preview Handler, as described here: View Data Your Way With Our Managed Preview Handler Framework
I needed to get it into an out of process server, and suddenly I had lifetime control issues.
The way to get into an out of process server is described here for anyone interested: RegistrationSrvices.RegisterTypeForComClients community content which implies that you may be able to do it by implmenting IDispose, but that didn't work.
I tried implementing a finalizer, which did eventually cause the object to be released, but because of the pattern of usage of the server calling my object, it meant my server hung around forever. I also tried spinning off a work item, and after a sleep, forcing a garbage collect, but that was really messy.
Instead, it came down to hooking Release (and AddRef because the return value of Release couldn't be trusted).
(Found via this post: http://blogs.msdn.com/b/oldnewthing/archive/2007/04/24/2252261.aspx#2269675)
Here's what I did in my object's constructor:
// Get the CCW for the object
_myUnknown = Marshal.GetIUnknownForObject(this);
IntPtr _vtable = Marshal.ReadIntPtr(_myUnknown);
// read out the AddRef/Release implementation
_CCWAddRef = (OverrideAddRef)
Marshal.GetDelegateForFunctionPointer(Marshal.ReadIntPtr(_vtable, 1 * IntPtr.Size), typeof(OverrideAddRef));
_CCWRelease = (OverrideRelease)
Marshal.GetDelegateForFunctionPointer(Marshal.ReadIntPtr(_vtable, 2 * IntPtr.Size), typeof(OverrideRelease));
_MyRelease = new OverrideRelease(NewRelease);
_MyAddRef = new OverrideAddRef(NewAddRef);
Marshal.WriteIntPtr(_vtable, 1 * IntPtr.Size, Marshal.GetFunctionPointerForDelegate(_MyAddRef));
Marshal.WriteIntPtr(_vtable, 2 * IntPtr.Size, Marshal.GetFunctionPointerForDelegate(_MyRelease));
and the declarations:
int _refCount;
delegate int OverrideAddRef(IntPtr pUnknown);
OverrideAddRef _CCWAddRef;
OverrideAddRef _MyAddRef;
delegate int OverrideRelease(IntPtr pUnknown);
OverrideRelease _CCWRelease;
OverrideRelease _MyRelease;
IntPtr _myUnknown;
protected int NewAddRef(IntPtr pUnknown)
{
Interlocked.Increment(ref _refCount);
return _CCWAddRef(pUnknown);
}
protected int NewRelease(IntPtr pUnknown)
{
int ret = _CCWRelease(pUnknown);
if (Interlocked.Decrement(ref _refCount) == 0)
{
ret = _CCWRelease(pUnknown);
ComServer.Unlock();
}
return ret;
}