1

我正在通过 Assembly.LoadFile 使用运行时 dll 初始化来为我的项目加载其他视口。我已经以这种方式成功启动了 WPF 表单和 CS-SDL 表单(均构建为 dll),但 MonoGame 表单在 60 秒后给了我一个错误。运行:

托管调试助手“ContextSwitchDeadlock”检测到问题。CLR 在 60 秒内无法从 COM 上下文 0x5b16f8 转换到 COM 上下文 0x5b1920。拥有目标上下文/单元的线程很可能要么进行非泵送等待,要么处理非常长时间运行的操作而不泵送 Windows 消息。等等

插件(作为类库构建的表单)初始化代码:

foreach (PluginInfo plginfo in _gameManager.XmlReader.ReadViewPlugins(System.Environment.CurrentDirectory + "\\plugins\\plugins.xml"))
{
    if (plginfo.Correct)
    { 
        //create new thread for every plugin 
        Thread thread = new Thread(RunViewControlPlugin);
        thread.Name = plginfo.Name;
        //set it to single-threaded if plugin requires so
        if (plginfo.STA)
            thread.SetApartmentState(ApartmentState.STA);
        thread.Start(plginfo);
    }
}

RunViewControl 方法:

void RunViewControlPlugin(object data)
    {
        PluginInfo plginfo = (PluginInfo)data;
        string path = System.Environment.CurrentDirectory + "\\plugins\\" + plginfo.FileName;
        //load assembly from the path and create instance of the required type
        Assembly assembly = Assembly.LoadFile(path);
        Type type = assembly.GetType(plginfo.AssemblyData);
        IViewControlPlugin plugin = (IViewControlPlugin)Activator.CreateInstance(type);

        lock(locker)
        {
            _viewcontrolpluginList.Add(plugin);
        }

        //on shutdown close dispatcher, remove plugin from the active plugins list and unsubscribe
        EventHandler handler = null;
        handler = (s, e) =>  {
            if (plginfo.DispatcherNeeded)
                System.Windows.Threading.Dispatcher.CurrentDispatcher.BeginInvokeShutdown(System.Windows.Threading.DispatcherPriority.Background);
            _gameManager.DebugLogger.LogGeneralInfo(plginfo.Name+" stopped.");
            _viewcontrolpluginList.Remove(plugin);
            plugin.Closed -= handler;
        };
        plugin.Closed += handler;

        //send manager instances to the plugin
        plugin.AddGameDataManager(_gameDataManager);
        plugin.AddGameManager(_gameManager);
        _gameManager.DebugLogger.LogGeneralInfo(plginfo.Name + " started.");

        //start dispatcher (wpf forms require dispatcher to run)
        if (plginfo.DispatcherNeeded)
                System.Windows.Threading.Dispatcher.Run();
        plugin.Start();
    }

我想知道如何解决这个问题(除了关闭 MDA)。我应该明确实施消息泵送吗?

表单做得很好,它可以看到鼠标/键盘事件并且可以移动。唯一的问题是可能与这种情况有关的内存泄漏(MDA 描述表明它可能导致内存泄漏)。

更新:为 XNA 线程设置 STA 似乎可以抑制这个错误,尽管我不清楚为什么。也许我应该更深入地研究 Windows 内部机制。

4

0 回答 0