【问题标题】:COM Add-in: Resolve the error DisconnectedContext in WinWord.exeCOM 插件:解决 WinWord.exe 中的 DisconnectedContext 错误
【发布时间】:2017-02-28 11:22:32
【问题描述】:

我为 Microsoft Word 构建了一个插件。当用户单击一个按钮时,它会运行许多将 Microsoft Word 文档列表导出到过滤 HTML 的进程。这很好用。

代码失败的地方在于处理大量文件。文件转换完成并调用下一个函数后,应用程序崩溃,我从 Visual Studio 获取此信息:

托管调试助手“DisconnectedContext”在“C:\Program Files\Microsoft Office\root\Office16\WINWORD.EXE”中检测到问题。

附加信息:转换为 COM 上下文 0x56255b88 此 RuntimeCallableWrapper 失败并出现以下错误:系统 通话失败。 (来自 HRESULT 的异常:0x80010100 (RPC_E_SYS_CALL_FAILED))。这通常是因为 COM 上下文 创建此 RuntimeCallableWrapper 的 0x56255b88 已被 断开连接或忙于做其他事情。释放 来自当前 COM 上下文(COM 上下文 0x56255cb0)的接口。这 可能导致损坏或数据丢失。为避免此问题,请 确保所有 COM 上下文/单元/线程保持活动状态并且 可用于上下文转换,直到应用程序完全 使用代表 COM 组件的 RuntimeCallableWrappers 完成 住在他们里面。

经过一些测试,我意识到如果我在文件转换后简单地删除所有代码,就没有问题。为了解决这个问题,我将其余代码放在另一个按钮中。

问题是我不想给用户两个按钮。在阅读了各种其他线程之后,听起来我的代码有内存或线程问题。我正在阅读的答案并不能帮助我真正理解下一步该做什么。

我觉得这就是我想做的:

1- 运行转换。 2-关闭转换中的线程/清理内存问题。 3- 继续运行代码。

不幸的是,我真的不知道如何做#2,甚至是否可能。非常感谢您的帮助。

【问题讨论】:

    标签: c# multithreading visual-studio com


    【解决方案1】:

    或者它正忙于做其他事情

    您获得的托管调试助手诊断非常冗长,但这是准确描述真正问题的消息部分。你有一个 firehose 问题,这是与线程相关的第三个最常见的问题。事故很难诊断,因为这在 Word 管道内部而不是您的代码中出错。

    我自己尽量不犯同样的 gobbledygook 罪,问题是您对 Office 程序的互操作调用已排队,等待轮到他们执行。错误代码提示的底层“系统调用”是 PostMessage()。无论哪里有队列,都有队列变得太大的风险。当生产者(您的程序)向队列中添加项目的速度远快于消费者(Office 程序)删除它们时,就会发生这种情况。消防水管问题。除非生产者放慢速度,否则队列将无限增长,如果允许无限增长,某事将会失败,至少进程会耗尽内存。

    不允许接近那个问题。 PostMessage() 使用的底层队列受操作系统保护。当队列已包含 10,000 条消息时,Windows 调用失败。这是一个致命的错误,RPC 不知道如何从中恢复,或者不应该尝试从中恢复。有什么不对劲,而且不漂亮。它会向您的程序返回一个错误代码来告诉您有关它的信息。那是 RPC_E_SYS_CALL_FAILED。在您的程序中没有更好的事情发生,CLR 也不知道如何从中恢复,您的代码也不知道。这样节目就结束了,你发出的互操作调用丢失了,没有被 Word 执行。

    为这个尴尬的问题找到一个完全可靠的解决方法并不是那么简单。请注意,这可能发生在 任何 互操作调用上,因此捕获异常并再次尝试是非常不切实际的。但请记住,Q+D 修复非常简单。一个简单的问题是你的程序运行得太快了,用 Thread.Sleep() 或 Task.Delay() 调用减慢它的速度是很粗糙的,但总能解决这个问题。好吧,假设你延迟得够多。

    我认为,但不知道一个事实,因为没有人发布过重现代码,这个问题也与在您的程序中使用控制台模式应用程序或工作线程有关。如果它是控制台模式应用程序,请尝试将 [STAThread] 属性应用于您的 Main() 方法。如果它是工作线程,则在启动线程之前调用 Thread.SetApartmentState(),但要注意在该工作线程上创建应用程序接口非常重要。否则不是加载项的解决方法。

    如果这些变通办法都无效或太不切实际,那么请考虑通过偶尔从 Office 程序中读取某些内容来自动减慢程序速度并确保队列已清空。一些愚蠢的事情,任何属性获取器调用都可以。在 Office 程序赶上之前,您肯定无法获得房产价值。这可能仍然失败,互操作调用也有 60 秒超时。但这是您可以解决的问题,您可以在程序中调用 CoRegisterMessageFilter() 来安装一个在超时触发时运行的回调。也非常gobbledygooky,但剪切和粘贴代码是readily available

    【讨论】:

    • 非常感谢您如此详细的回复。这是第一个真正让我完全了解正在发生的事情的答案。虽然我看到对我来说有很多潜在的选择,但在处理每个新文件之前使用 Thread.Sleep(3000) 似乎已经成功了。现在,我将看看它是如何进行的,并将创建一个用户在遇到问题时可以修改的值。我的测试用例旨在达到我产品功能的上限,所以我希望这不会成为一个普遍存在的问题。如果是,我将处理您分享的一些更复杂的示例。
    猜你喜欢
    • 1970-01-01
    • 2011-01-04
    • 2021-12-31
    • 1970-01-01
    • 2016-04-14
    • 1970-01-01
    • 2011-08-04
    • 1970-01-01
    • 2013-11-12
    相关资源
    最近更新 更多