What causes the InvalidComObjectException: "COM object that has been separated from its underlying RCW cannot be used."?
Asked Answered
O

1

6

I've looked at the various questions that mention this specific exception (this question lists many of them, which I've visited). Also, I have the same general question as this post, but in a different context, so the answer is not helpful to me.

The context

I have a class derived from AxWindowsMediaPlayer that is owned by a class called View, which is within a Panel, within a Workspace. I recently asked a question around this situation, but that question was directed towards whether my workaround for this problem is okay. The background from that question is relevant here:

    .-----------------------.
    |Workspace              |
    |.--------.  .--------. |
    ||Panel1  |  |Panel2  | |
    ||.-----. |  |.-----. | |
    |||View1| |  ||View2| | |
    ||'-----' |  |'-----' | |
    |'--------'  '--------' |
    '-----------------------'

When a View gets disposed, a method called Synchronize() will get called on all of the remaining View objects. For the View that contains the AxWindowsMediaPlayer, it calls videoPlayer.Error.clearErrorQueue().

The problem

When I call Dispose() at the top level (Workspace.Dispose()), if another View gets disposed and then causes Synchronize() to be called on the remaining View objects, the View containing the AxWindowsMediaPlayer class throws an exception on the videoPlayer.Error.clearErrorQueue() line, stating:

InvalidComObjectException: COM object that has been separated from its underlying RCW cannot be used.

I'm puzzled by how the AxWindowsMediaPlayer is getting separated from its underlying RCW (Runtime Callable Wrapper). I've read this article that talks about this exception and the dangers of calling Marshal.ReleaseComObject(). I am not calling this method explicitly. I have put breakpoints at the Dispose methods of Panel and View and VideoPlayerControl (derives from AxWindowsMediaPlayer) classes, but none of those get hit before the exception happens.

My workaround is to make sure that the View with the media player always gets disposed first. This was the motivation behind my previous question. But I'd like to understand how this is happening so I can see whether this is something I need to fix. Who is causing the AxWindowsMediaPlayer to be separated from its RCW before Dispose is getting called on the parent class?

My guess is that the AxWindowsMediaPlayer finalizer is getting called by the GC, but I don't understand what is triggering it. For some reason, calling Dispose at the higher level is causing Marshal.ReleaseComObject to get called under the floor. Can someone enlighten me?

Otten answered 14/3, 2011 at 18:45 Comment(0)
L
4

Your workaround is, unfortunately, the solution.

Control.Dispose recursively disposes all ActiveX controls first, and it then recursively calls Dispose on child controls. In your example, if you call Workspace.Dispose, your AxWindowsMediaPlayer will be disposed first, then Panel1, Panel2, View1, View2 (depending on the order you built up your control tree).

We can discover the cause by using Reflector. If we examine Control.Dispose, it is essentially implemented as follows (note, irrelevant code omitted and slightly changed to improve readability):

protected override void Dispose(bool disposing)
{
    if (disposing)
    {
        DisposeAxControls();

        foreach (Control control in Controls)
        {
            control.Parent = null;
            control.Dispose();
        }

        base.Dispose(disposing);
    }
}

And DisposeAxControls is implemented as:

internal virtual void DisposeAxControls()
{
    foreach (Control control in Controls)
    {
        control.DisposeAxControls();
    }
}

The AxHost class overrides DisposeAxControls to destroy the hosted ActiveX control.

I'm not really sure why the DisposeAxControls function exists. It seems that AxHost would have simply overridden Dispose, like everyone else, to destroy the ActiveX control, but that's not how things are implemented.

Lindquist answered 6/4, 2011 at 23:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.