如何捕获外部异常

How to catch a external exception

我使用 nVLC dll 在我的应用程序中使用 VLC 媒体播放器。除了一件事,它就像一个魅力。我有一个带有电影列表的 DataGridView。当我 select 来自该 DataGridView 的电影时,它开始在由 nVLC 处理的面板内播放电影。我还使用过滤器来过滤 DataGridView 中的电影。当我这样做几次时,我从 nVLC DLL 收到错误:

CallbackOnCollectedDelegate occurred

Managed Debugging Assistant 'CallbackOnCollectedDelegate' has detected a problem in 'C:\Users\User\Documents\Visual Studio 2013\Projects\Soft.UltimateMovieManager\Soft.UltimateMovieManager\bin\Release\Soft.UltimateMovieManager.vshost.exe'.

Additional information: A callback was made on a garbage collected delegate of type 'nVLC.Implementation!Implementation.VlcEventHandlerDelegate::Invoke'. This may cause application crashes, corruption and data loss. When passing delegates to unmanaged code, they must be kept alive by the managed application until it is guaranteed that they will never be called.

问题是我无法捕获该异常。即使我在应用程序本身上设置了 try/catch,它仍然无法处理。

这是我可以自己解决的问题还是我使用的 nVLC dll 的问题?

if (!string.IsNullOrEmpty(video_url))
{
    if (pnlStartVideo != null)
    {
        pnlStartVideo.Dispose();
    }

    pnlStartVideo = new System.Windows.Forms.Panel();
    pnlStartVideo.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
    pnlStartVideo.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center;
    pnlStartVideo.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
    pnlStartVideo.Location = new System.Drawing.Point(pnlStartInfo.Location.X, (pnlStartInfo.Location.Y + (pnlStartInfo.Height - 1)));
    pnlStartVideo.Name = "pnlStartVideo";
    pnlStartVideo.Size = new System.Drawing.Size(275, 153);
    pnlStartVideo.TabIndex = 3;

    tpStart.Controls.Add(pnlStartVideo);

    m_factory = new MediaPlayerFactory(true);
    m_player = m_factory.CreatePlayer<IDiskPlayer>();
    m_player.WindowHandle = pnlStartVideo.Handle;
    m_player.Events.PlayerStopped += Events_PlayerStopped;
    UISync ui = new UISync();
    ui.Init(this);

    m_media = m_factory.CreateMedia<IMedia>(video_url);

    m_player.Open(m_media);
    m_media.Parse(true);

    m_media.Events.StateChanged += Events_StateChanged;

    m_player.Play();
}

Managed Debugging Assistant 'CallbackOnCollectedDelegate' ...

它不是可捕获的异常,因为它根本不是异常。托管调试助手是添加到调试器的帮助程序代码,可以在运行时检测各种错误。当它看到 VLC 播放器试图使用已处置的委托对象时,就会介入。如果没有调试器,您的程序将崩溃并以更糟糕的方式死掉,即 AccessViolationException,也无法捕获,因为它是失败的本机代码。

查看 VLC 包装器源代码,您必须仅创建 m_player 实例 一次 以避免这种故障模式。当您像现在一样一遍又一遍地创建它时,以前的 IDiskPlayer 实例不再在任何地方引用。垃圾收集器将收集它们,当本机 VLC 代码进行回调以触发事件时,垃圾收集器将收集它们。包装器也没有实现我可以看到的适当清理,确保本机代码在处理对象时不能再触发事件。

强烈建议将 m_player 变量设为 static。只分配一次。

修复包装器需要编写 initializeEventsEngine() 的等价物,但将所有回调设置回 null。这不一定是直截了当的,可能涉及线程竞赛。依赖此代码是一种责任,您可能想继续购物。