【发布时间】:2015-07-10 18:53:21
【问题描述】:
我已经构建了一个 Word 加载项,它必须在用户关闭文档时执行一项任务。我为Application 对象的DocumentBeforeClose 事件安装了一个事件处理程序来执行此操作。问题是,例如,当我将现有 Word 文档嵌入 Excel 工作簿时,事件处理程序似乎会阻止 Word 进程退出。
当我通过功能区插入 > 对象 > 从文件创建,然后选择 Word 文档将文档嵌入 Excel 时,会出现问题。然后将文档加载到工作簿中。当我关闭 Excel 时 winword.exe 仍在运行且窗口不可见。
当我禁用我的加载项时,winword.exe 仅运行大约一秒钟以嵌入文档。这也是我希望启用插件后的行为。
为了缩小问题范围,我创建了一个简单的 VSTO Word 插件进行测试。这些是我对 Visual Studio 生成的类所做的更改:
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
Application.DocumentBeforeClose += Application_DocumentBeforeClose;
}
void Application_DocumentBeforeClose(Word.Document Doc, ref bool Cancel)
{
System.Windows.Forms.MessageBox.Show("Application_DocumentBeforeClose");
}
private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
{
System.Windows.Forms.MessageBox.Show("ThisAddIn_Shutdown");
}
当我启动 Word 并再次关闭它时,此加载项会按预期显示两个消息框。当我在 Excel 工作簿中嵌入 Word 文档时,大约一秒钟后会弹出“DocumentBeforeClose”消息,但不会出现“Shutdown”消息。即使我关闭 Excel,winword.exe 仍会继续运行。
删除连接事件处理程序的行会导致插件在嵌入文档 1 秒后显示“关闭”消息,并且 winword.exe 退出。
这让我认为事件处理程序会导致对 Word 的应用程序对象的引用,这会阻止它关闭。所以我反过来测试了它,因为我也有一个执行相同任务的 Excel 插件。为了测试这一点,我构建了一个 Excel 插件,就像上面的 Word 插件一样,在 Word 文档中嵌入了一个工作簿,Excel 插件在不留下 excel.exe 进程的情况下显示了这两条消息。
为了弄清楚问题的本质,我尝试在 DocumentBeforeClose 中解开事件处理程序:
Application.DocumentBeforeClose -= Application_DocumentBeforeClose;
GC.Collect();
这允许 winword.exe 关闭但也禁用我的加载项的功能。我不能使用该解决方案,因为如果只有一个文档并且用户关闭它但想要继续使用 Word,也会发生该事件。插件也必须继续工作。
我希望 Word 文档也将嵌入到其他 3rd 方应用程序中,not embedding it 也不适用于我。
至少在上面显示的 VSTO 2007 加载项和使用 PIA 的 Word 2013 加载项中会出现此问题。
我认为weak event handlers 不会起作用,因为对 COM 对象的弱引用是不可能的,对吧?
我可以阻止事件处理程序使 Word 进程保持活动状态吗?有没有其他方法可以在 .NET 中挂钩 DocumentBeforeClose 事件或 COM 事件?
编辑:我还能够在 Word 2003 中使用用 Visual Basic 6 编写的插件重现该问题。因此它似乎与 .NET 无关。
【问题讨论】: