2

I have two applications, both of which I have written. AppA was written in C++ using MFC. During startup it registers a CSingleDocTemplate and creates a document. The document provides a COM interface and registers itself in the ROT:

  LPUNKNOWN punk = GetInterface(&IID_Welder); // doesn't AddRef
  ::RegisterActiveObject(punk, CLSID_Interface, ACTIVEOBJECT_WEAK, &m_dwRegister);

AppA revokes the entry in the ROT when it is destroyed:

  if (m_dwRegister)
    ::RevokeActiveObject(m_dwRegister, NULL);

The destructor is only called when AppA terminates.

AppB is written in C# and is a client of the interface provided by AppA:

private void Connect()
  {
  welderInterface = (Welder.Interface)Marshal.GetActiveObject("Welder.Interface");
  Marshal.GetIUnknownForObject(welderInterface);    // AddRef's it ...
  }

private void Disconnect() { if (welderInterface != null) { Marshal.ReleaseComObject(welderInterface); welderInterface = null; } }

(error handling omitted for clarity)

That all works perfectly the first time AppB runs after AppA has started; AppB can call Connect and Disconnect as often as it wants and use the interface between. However, if AppB terminates and runs again (AppA still running) the interface is no longer available - Marshal.GetActiveObject throws an exception from MK_E_UNAVAILABLE. The only way to make the interface available again is to restart AppA - not an acceptable solution!

Please can someone suggest how I might fix this?

Phil J Pearson
  • 547
  • 6
  • 11
  • Just a suggestion, but have you tried using GetRunningObjectTable and CreateBindCtx to access the ROT and get your COM interface instead. Does this approach have the same issue? – Tim Lloyd Aug 02 '10 at 11:30
  • No I haven't tried that but I have no reason to suppose it would be any different. I think the problem is somewhere in the MFC code (or the way I'm using it). I may try it if I get time. I believe I will have to p/Invoke those functions. Am I correct? – Phil J Pearson Aug 02 '10 at 12:03
  • Yes using GetRunningObjectTable will involve P/Invoke. Please see the following for a related example: http://stackoverflow.com/questions/3268483/getting-running-visual-studio-2010-instances-and-programmatically-attaching-to-a/3268736#3268736 – Tim Lloyd Aug 02 '10 at 13:05
  • Heres an article that shows how to go about doing that http://www.codeproject.com/KB/cs/automatingvisualstudio.aspx – Terrance Dec 01 '10 at 19:31

2 Answers2

4
 ::RegisterActiveObject(punk, CLSID_Interface, ACTIVEOBJECT_WEAK, &m_dwRegister);

ACTIVEOBJECT_WEAK is your problem here. From the RegisterActiveObject docs:

Weak registration keeps a pointer to the object in the running object table, but does not increment the reference count. Consequently, when the last external connection to a weakly registered object disappears, OLE releases the object's stub, and the object itself is no longer available.

Which is exactly what's happening in your program. Trivially solve the problem with ACTIVEOBJECT_STRONG.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
0

I found the problem. The interface was being deleted when AppB disconnected even though the MFC document that implemented it was still alive. I had delved fairly deep in the MFC code and not found anything but it must be happening somewhere in there.

I AddRef'd the interface in the doc constructor and Release'd it in the destructor and the problem was solved.

Phil J Pearson
  • 547
  • 6
  • 11