We figured out what the problem was. In case this helps other people: Our application is a free-threaded COM server. Following standard protocol, it calls CoAddRefServerProcess() when a client creates a new COM object, and CoReleaseServerProcess() when a COM object is destroyed. When the last COM object is destroyed, CoReleaseServerProcess() automatically calls CoSuspendClassObjects(), which prevents new activation requests from coming in. Since our application continues to run until the user explicitly quits it, we immediately call CoResumeClassObjects() right after this to continue to allow COM clients. Again, this is standard procedure for managing COM server lifetimes, and works with all other COM clients.
Apparently, either C# or .NET doesn't like this behavior. If CoReleaseServerProcess() decrements the lock count to zero, something in C# or .NET creates problems, so that no other COM client can ever access our interfaces again without causing another instance of our application to be launched. We solved this by calling CoAddRefServerProcess() when our application starts up, and CoReleaseServerProcess() when we exit, so that the lock count never goes below 1 during normal operation. This seems to keep C# happy. Jeff You can read messages from the Advanced DOTNET archive, unsubscribe from Advanced DOTNET, or subscribe to other DevelopMentor lists at http://discuss.develop.com.
