locked
Interop: .NET COM (CCW) fails to clean up; application won't exit RRS feed

  • Question

  • I'm seeing a problem in a rather large body of code. I have distilled it down considerably, and have arrived at the following end point.

    There is a large body of code (C++, unmanaged, using COM).  It's the COM client.
    This code makes use of COM to talk with a DLL.  This works quite well.
    I'm adding a new COM server, and for a variety of reasons, it's in .NET(managed C#, using .NET 1.1). This approach uses a CCW.
    Mechanically, this is very simple and everything appears to work.  The client calls the server, the server does some work, the server finishes, everyone is happy.
    The issue is that the application will not exit.
    An observable item is that if the finalizer for the .NET class is called, the app will exit.  If not, no exit.
    I can, sometimes, get the finalizer to be called if I can do enough "other stuff", and presumably get the GC to run.  Simply waiting isn't sufficient.

    I am constrained in that the COM interface and client exist and cannot be modified.  The .NET COM server, using CCW, appears to work.  Something, somewhere is left dangling.  It's almost as if there's a non-zero reference count on something, but what that might be is unknown to me.  The fact that I can sometimes cause enough activity to get the finalizer to be called indicates to me that it's not likely that it's something I have control over.

    I've been able to reduce the .NET class to, basically,

      public void foo() { Trace.WriteLine("foo called"); }

    which is about as simple a server as possible, and the app will not exit even with this very simple server.

    While I cannot change the deployed COM application client, I can debug a local copy. I have determined that the reference count on the COM object does, indeed, go to zero. I don't know how to determine if the CCW releases its reference on the managed object. Or, basically, to determine what the application exit is waiting for.

    This is very much like the problem mentioned here (http://www.msdner.net/dev-archive/76/9-31-767816.shtm), which I found by searching around for answers. Unfortunately, while it sounds like the same issue, there's no suggested answer or workaround.

    Ideas ?  Suggestions ?

    Thanks !
    Monday, February 11, 2008 7:48 PM

Answers

  • This might because that the managed object still can not be collected by GC.

     

    Recommended create an AppDomain object and use AppDomain.CreateInstance to create the foo object and use it in COM side.

     

    After using the foo object, you can call AppDomain.Unload to unload the created AppDomain in addition to release the reference counter of the AppDomain.

    Tuesday, February 19, 2008 9:19 AM
  • Yes, that's what it turned out to be. It took quite a while to distill all of the code and cases. In the end, it turned out that an explicit GC.Collect at the end of a form's Dispose method is what made the difference.  Thanks for your replies.  While I had  expected that the error could likely have been mine, tracking this down was non-trivial.
    Thursday, February 28, 2008 4:14 PM

All replies

  • To troubleshoot this issue, we really need the source code and the detailed repro steps to reproduce the problem, so that we can investigate the issue in house. It is not necessary that you send out the complete source of your project. We just need a simplest sample to reproduce the problem. You can remove any confidential information or business logic from it.


    You can send a sample project and repro steps in details to may email address which can be found in my personal profile page.

    Wednesday, February 13, 2008 9:30 AM
  • Ok, thanks for the offer.  It sounds like it's nothing either simple or obvious.

    Let me see what I can do about creating a smaller sample case.  The existing client is extremely large, so I'll need to distill out the pieces that I need to demonstrate the issue.  That may take a little bit of time to do.

    Thanks!

    Wednesday, February 13, 2008 3:26 PM
  • This might because that the managed object still can not be collected by GC.

     

    Recommended create an AppDomain object and use AppDomain.CreateInstance to create the foo object and use it in COM side.

     

    After using the foo object, you can call AppDomain.Unload to unload the created AppDomain in addition to release the reference counter of the AppDomain.

    Tuesday, February 19, 2008 9:19 AM
  • Yes, that's what it turned out to be. It took quite a while to distill all of the code and cases. In the end, it turned out that an explicit GC.Collect at the end of a form's Dispose method is what made the difference.  Thanks for your replies.  While I had  expected that the error could likely have been mine, tracking this down was non-trivial.
    Thursday, February 28, 2008 4:14 PM