tags:

views:

296

answers:

3

I have an ATL COM exe that I am calling from C#. I import the reference into C# and everything works just fine, the exe is spawned, and I can call functions on it. Now, I instantiate several of these COM objects. Occasionally one of them will hang. Releasing the COM object does nothing, since its still running. I can't kill the process, because I then lose all of my other objects which are behaving just fine. So,

  1. is there a way to truly kill just one?
  2. is there a way to launch one exe for each com object requested?
  3. if my client exits unexpectedly, the COM exe is never cleaned up. Is there any way to fix this?

Ideally, I would be able to launch one COM exe per object instance and have the ability to Process.Kill() it. Are either of these an option? The class I use to create the object is below, RandomID() (artificially) takes a very long time to return in this case. Also, if there is a way to do this in another language, I would be willing to try that out also. Thanks.

public class MyComObject:IDisposable
{
    private bool disposed = false;
    MyMath test;

    public MyComObject()
    {
        test = new MyMath();
    }

    public double GetRandomID()
    {
        if (test != null)
            return test.RandomID();
        else
            return -1;
    }

    public void Dispose()
    {
        Dispose(true);

        GC.SuppressFinalize(this);
    }

    private void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            if (test != null)
                Marshal.ReleaseComObject(test);

            disposing = true;
        }
    }
}

EDIT: It looks like if I can set this to "Single Use" everything will work as I would like. However, I can't find where to set this option in VS 2008

EDIT: Found the answer on google groups

class CMathServerModule : public CAtlExeModuleT< CMathServerModule >
   {

    public :
   DECLARE_LIBID(LIBID_MathServerLib)
   DECLARE_REGISTRY_APPID_RESOURCEID(IDR_MATHSERVER, "{2FA977F0-050C-4010-A09F-4FE6D75F3024}")
   HRESULT RegisterClassObjects(DWORD dwClsContext, DWORD dwFlags) 
   throw() 
    { 
        dwFlags = ((dwFlags & ~(REGCLS_MULTIPLEUSE | REGCLS_MULTI_SEPARATE )) | 
                REGCLS_SINGLEUSE); 
        return CAtlExeModuleT<CMathServerModule>::RegisterClassObjects(dwClsContext, dwFlags); 
    } 
   };
+2  A: 

What happens when the object hangs? i.e. how do you know it has hung?

There are many reasons why it may have hung, but one is that a thread somewhere in the system has initialized COM but is not pumping Windows messages.

Do you control the source code of the COM server exe? It might be much simpler as a DLL server so you could load it in-process, where none of these problems exist.

Update:

Given the info in the comments, you're using COM exe-remoting to solve the problem of 32/64-bit thunking.

My experience with COM exe servers has been nothing but dire. COM DLLs are really simple things, COM exes are deeply complicated and unreliable things. They work okay - just - in some interactive GUI scenarios.

But you'd probably be better off rolling your own IPC mechanism, odd as it sounds. It's not actually that hard. Suppose 64.exe creates a listening socket, and it also maintains a handle to the 32.exe process, creating it on demand. It can create as many or as few as it likes, and kill them on a whim. When the 32.exe starts up, it connects to the socket and reads on it - that's how it gets work to do. 64.exe sends the instructions through the accepted socket connection, which it stores along with the corresponding process handle.

The beauty of this is that if 64.exe dies suddenly, 32.exe will get an error on the socket read and knows to die also.

The format of what you send down the socket can be very simple. A counted buffer is ideal (send the length, followed by that many bytes of data).

Daniel Earwicker
I do control the source, but I have to create it out-of-proc because the COM object is 32 bit and my C# host is 64 bit.
Steve
I am also artificially creating the hanging behavior here, but the actual code also sometimes hangs and its a large project, so I can't depend on everyone else to do it right (sadly)
Steve
+1  A: 

I don't know if this is the answer, but the code in your Dispose method is setting disposing to true, and not disposed. It is allowing multiple calls to ReleaseComObject.

I would set disposed to true, and then see if you have the same issue.

casperOne
A: 

I developed some service exporting COM interface and have no problem, this is running at server pool.
My suggestion is try monitoring your app with WinDbg, compile code including debug info and install pdb files together.

lsalamon