c# - COM 加载项 : Resolve the error DisconnectedContext in WinWord. exe

标签 c# multithreading visual-studio com

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

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

Managed Debugging Assistant 'DisconnectedContext' has detected a problem in 'C:\Program Files\Microsoft Office\root\Office16\WINWORD.EXE'.

Additional information: Transition into COM context 0x56255b88 for this RuntimeCallableWrapper failed with the following error: System call failed. (Exception from HRESULT: 0x80010100 (RPC_E_SYS_CALL_FAILED)). This is typically because the COM context 0x56255b88 where this RuntimeCallableWrapper was created has been disconnected or it is busy doing something else. Releasing the interfaces from the current COM context (COM context 0x56255cb0). This may cause corruption or data loss. To avoid this problem, please ensure that all COM contexts/apartments/threads stay alive and are available for context transition, until the application is completely done with the RuntimeCallableWrappers that represents COM components that live inside them.

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

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

我觉得这就是我想做的:

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

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

最佳答案

or it is busy doing something else

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

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

不允许接近那个问题。 PostMessage() 使用的底层队列受操作系统保护。当队列已包含 10,000 条消息时,Windows 将失败调用。这是一个 fatal error ,RPC 不知道如何从中恢复,或者更确切地说,不应尝试从中恢复。有些不对劲,而且不漂亮。它向您的程序返回一个错误代码以告知您有关它的信息。那是 RPC_E_SYS_CALL_FAILED。您的程序中没有发生更好的事情,CLR 也不知道如何从中恢复,您的代码也不知道。所以表演结束了,您进行的互操作调用丢失了,并且没有被 Word 执行。

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

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

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

关于c# - COM 加载项 : Resolve the error DisconnectedContext in WinWord. exe,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40120891/

相关文章:

java - 一个线程可以消耗多个队列吗?

java - 如何在Spring Web Service中实现计划任务?

java - 如何执行一个可调用的固定次数并在每次执行之间有一个 sleep 间隔/延迟

c++ - 在具有不同版本的 visual studio 的静态库中内部使用 STL

c++ - 标题困惑。编译器不识别数据类型

c - Malloc 是否分配了比需要的更多的内存?

c# - System.Data.OracleClient随机无效操作连接被关闭

c# - SQL 查询没有获取所有数据 C#/ASP.net

c# - xsi :type attribute messing up C# XML deserialization

c# - Array.FindIndex 在统一 C# 中始终为空