是什么原因导致 InvalidComObjectException:“无法使用已与其基础 RCW 分离的 COM 对象。”?
我查看了提到此特定异常的各种问题(这个问题列出了其中的许多,我已经访问过)。另外,我有相同的 一般问题如这篇文章,但在不同的上下文中,所以答案对我没有帮助。
上下文
我有一个派生自 AxWindowsMediaPlayer
由名为 View
的类拥有,该类位于 Panel
内的 工作区
。我最近问了围绕这种情况提出问题,但该问题针对的是我解决这个问题的方法是否可行。该问题的背景与此相关:
.-----------------------. |Workspace | |.--------. .--------. | ||Panel1 | |Panel2 | | ||.-----. | |.-----. | | |||View1| | ||View2| | | ||'-----' | |'-----' | | |'--------' '--------' | '-----------------------'
当 View
被释放时,将在所有剩余的 View
上调用名为 Synchronize()
的方法> 对象。对于包含 AxWindowsMediaPlayer
的 View
,它调用 videoPlayer.Error.clearErrorQueue()
。
问题
当我在顶层调用 Dispose()
(Workspace.Dispose()
) 时,如果另一个 View
> 被释放,然后导致在剩余的 View
对象上调用 Synchronize()
,该 View
包含 AxWindowsMediaPlayer
> 类在 videoPlayer.Error.clearErrorQueue()
行引发异常,指出:
InvalidComObjectException:无法使用已与其基础 RCW 分离的 COM 对象。
我对 AxWindowsMediaPlayer 如何与其底层 RCW 分离感到困惑(运行时可调用包装器)。我读过 这篇文章讨论了此异常以及调用Marshal.ReleaseComObject()
。我没有明确调用这个方法。我在 Panel
和 View
和 VideoPlayerControl
的 Dispose
方法中放置了断点(源自 AxWindowsMediaPlayer< /code>) 类,但在异常发生之前这些类都不会被命中。
我的解决方法是确保带有媒体播放器的 View
始终首先被处理。这是我上一个问题背后的动机。但我想了解这是如何发生的,这样我就可以知道这是否是我需要解决的问题。 在父类上调用 Dispose
之前,是谁导致 AxWindowsMediaPlayer
与其 RCW 分离?
我的猜测是 AxWindowsMediaPlayer 终结器被 GC 调用,但我不明白是什么触发了它。由于某种原因,在较高级别调用
Dispose
会导致在底层调用 Marshal.ReleaseComObject
。有人可以启发我吗?
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
不幸的是,您的解决方法就是解决方案。
Control.Dispose
首先递归地处理所有 ActiveX 控件,然后递归地调用子控件上的Dispose
。在您的示例中,如果您调用Workspace.Dispose
,您的AxWindowsMediaPlayer
将首先被处置,然后是Panel1
、Panel2
、View1
、View2
(取决于您构建控件树的顺序)。我们可以通过使用Reflector来发现原因。如果我们检查
Control.Dispose
,它的基本实现如下(注意,省略了不相关的代码,并稍作更改以提高可读性):的实现如下:
DisposeAxControls >AxHost
类重写DisposeAxControls
以销毁托管的 ActiveX 控件。我不太确定为什么 DisposeAxControls 函数存在。看起来,
AxHost
会像其他人一样简单地重写Dispose
来销毁 ActiveX 控件,但这并不是实现的方式。Your workaround is, unfortunately, the solution.
Control.Dispose
recursively disposes all ActiveX controls first, and it then recursively callsDispose
on child controls. In your example, if you callWorkspace.Dispose
, yourAxWindowsMediaPlayer
will be disposed first, thenPanel1
,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):And
DisposeAxControls
is implemented as:The
AxHost
class overridesDisposeAxControls
to destroy the hosted ActiveX control.I'm not really sure why the
DisposeAxControls
function exists. It seems thatAxHost
would have simply overriddenDispose
, like everyone else, to destroy the ActiveX control, but that's not how things are implemented.