C# COM加载项:解决WinWord.exe中的DisconnectedContext错误

C# COM加载项:解决WinWord.exe中的DisconnectedContext错误,c#,multithreading,visual-studio,com,C#,Multithreading,Visual Studio,Com,我为Microsoft Word构建了一个附加组件。当用户单击一个按钮时,它会运行一系列进程,将Microsoft Word文档列表导出为过滤后的HTML。这个很好用 代码失败的地方在于处理大量文件。文件转换完成后,我调用下一个函数,应用程序崩溃,我从Visual Studio获得以下信息: 托管调试助手“DisconnectedContext”在“C:\Program Files\Microsoft Office\root\Office16\WINWORD.EXE”中检测到问题 其他信息:转换

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

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

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

其他信息:转换为COM上下文0x56255b88,用于 此RuntimeCallableWrapper失败,出现以下错误:System 呼叫失败。(HRESULT的例外情况:0x80010100 (RPC_E_系统_调用_失败))。这通常是因为COM上下文 已删除创建此RuntimeCallableWrapper的0x56255b88 已断开连接或正在忙于执行其他操作。释放 来自当前COM上下文(COM上下文0x56255cb0)的接口。这 可能导致损坏或数据丢失。为了避免这个问题,请 确保所有COM上下文/单元/线程保持活动状态,并且 可用于上下文转换,直到应用程序完全完成 使用表示COM组件的RuntimeCallableWrappers完成 他们住在里面

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

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

我觉得这就是我想做的:

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

不幸的是,我真的不知道该怎么做,也不知道这是否可能。非常感谢你的帮助

或者它正忙着做别的事情

您得到的托管调试助手诊断非常糟糕,但这正是消息中准确描述实际问题的部分。您有消防软管问题,这是与线程相关的第三个最常见问题。这场灾难很难诊断,因为它在“管道”一词中出错,而不是在代码中

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

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

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

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


如果这些解决方案都不有效或太不实用,那么考虑一下,您可以自动地减慢程序的速度,并确保队列被清空,偶尔从Office程序中读取一些内容。一些愚蠢的事情,任何属性获取者调用都可以。在Office程序跟上之前,您必然无法获得属性值。这仍然可能失败,互操作调用也有60秒的超时。但这是可以修复的,您可以在程序中调用CoRegisterMessageFilter()来安装一个在超时触发时运行的回调。也很好,但是剪切和粘贴代码很好。

非常感谢您的详细回复。这是第一个真正让我完全了解情况的答案。虽然我看到我有很多潜在的选择,但在处理每个新文件之前使用
Thread.Sleep(3000)
似乎已经成功了。现在,我将看到这是如何进行的,并将创建一个值,用户可以修改,如果他们有问题。我的测试用例是为了达到产品功能的上限而设计的,所以我希望这不会成为一个普遍的问题。如果是的话,我会的