none
The COM object via a C++ pointer that won't die RRS feed

  • Question

  • OK, this is a bit of a weird one, but here's the deal:

    Background: Our application is written in native C++ can interact with DLL's as plugins that may be written in .NET and exposed via COM. These plugin DLL's need to share a COM object with the C++ application; it's important that it's the same instance of the object to preserve its state. The C# DLL uses this form of marshalling in the interface it exposes to the C++ EXE to receive an IDispatch pointer:

        // Use late binding
        [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
        public interface IPluginInterface
        {
            // ... snipped ...
            [DispId(6)]
            void SetCOMPointer([MarshalAs(UnmanagedType.IDispatch)] object com);
        }

        // ... snipped ...

        public void SetCOMPointer(object com)
        {
            if (_com == null)
                _com = (COMType)
    com;
        }

    The problem: As we create a new Form from within this C# DLL, our shared COM object is never released after we close this form and even the main application itself! Otherwise, the COM object is released, if we never open a form. The form can be something without anything in the constructor (not even the IDE-generated InitializeComponents() call) that doesn't even use our shared COM object, opening a form like that from another function exposed by our C# DLL will still make our shared COM object not get released.

    I have tried using
    Marshal.Release()
    as well as Marshal.ReleaseComObject(_com) with no success. What's so strange is that the C# code doesn't seem to be causing this alone, as it's interacted with before opening the form, and in that case, the COM object is released properly. The form is opened with a "null" parent window; could this be why? It's almost like if the form corrupts some state in the C# DLL so it "forgets" to release the shared COM object. *shrug*

    Or am I supposed to do something different in the marshalling here? Maybe take it as an IntPtr and use Marshal.GetInterfaceForObject() and then Marshal.Release()? These Marshal methods are a bit of a jungle to me... Sad
    Friday, March 14, 2008 8:23 PM

Answers

  • Solved in a way I didn't really prefer to (I had hoped I could have handled this problem from within the .NET DLL's themselves), but it fixes my problem anyway. This is code from within our C++ app:

                COurSharedCOMObject obj;
                IDispatch* x = obj.GetDispatch();
                int i;
                do
                {
                    i = x->Release();
                } while (i > 0);

    I saw that extra references had indeed been added if having opened a .NET form in the plugin DLL, and that was why it wouldn't get freed in that case. But I have no idea why .NET behaves this way after having opened a plain form without even using the COM object in question (just something straight from the auto-generated code). The code above frees our main app's reference as well as any extras have been added, for whatever reason. A bit ugly since it's a safety net solution, but it works and I don't have time to dig into this more at the moment; I've already spent two days on this.

    Feel free to come up with more solutions though.
    Friday, March 14, 2008 11:15 PM

All replies

  • Here's a small update:

    Simply doing this in my C# DLL makes the shared COM object remain after both closing the form and my main EXE:
    (the form can be a freshly created form from the IDE with nothing in it)

    MainForm form = new MainForm();
    form.Show(null);

    If I however do this:

    MainForm form = new MainForm();
    //form.Show(null);

    ... the COM object is released properly. Also, if I set form.Visible = true, the COM object is again not released even after exiting my main app, as described above.

    I think it's really strange. Could it have something to do with UI threads doing something to the state of my DLL? Everything is fine until I in some way open a GUI, it seems.

    One more thing, it didn't seem to help to set the parent window to a valid window, and I didn't really expect it to either.
    Friday, March 14, 2008 9:44 PM
  • Solved in a way I didn't really prefer to (I had hoped I could have handled this problem from within the .NET DLL's themselves), but it fixes my problem anyway. This is code from within our C++ app:

                COurSharedCOMObject obj;
                IDispatch* x = obj.GetDispatch();
                int i;
                do
                {
                    i = x->Release();
                } while (i > 0);

    I saw that extra references had indeed been added if having opened a .NET form in the plugin DLL, and that was why it wouldn't get freed in that case. But I have no idea why .NET behaves this way after having opened a plain form without even using the COM object in question (just something straight from the auto-generated code). The code above frees our main app's reference as well as any extras have been added, for whatever reason. A bit ugly since it's a safety net solution, but it works and I don't have time to dig into this more at the moment; I've already spent two days on this.

    Feel free to come up with more solutions though.
    Friday, March 14, 2008 11:15 PM