我已经构建了一个Word加载项,当用户关闭文档时,该加载项必须执行任务。我为DocumentBeforeClose
对象的Application
事件安装了一个事件处理程序来执行此操作。问题是,当我在Excel工作簿中嵌入现有Word文档时,事件处理程序似乎阻止Word进程退出。
当我通过Ribbon Insert>将文档嵌入Excel时,会出现问题。对象>从文件创建,然后选择Word文档。然后将该文档加载到工作簿中。当我关闭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并再次关闭它时,此加载项会按预期显示两个消息框。当我在Word工作簿中嵌入Word文档时," DocumentBeforeClose"消息会在稍后左右弹出,但是" Shutdown"消息不会出现。即使我关闭了Excel,winword.exe也会继续运行。
删除连接事件处理程序的行会导致外接程序显示" Shutdown"嵌入文档并退出winword.exe后1秒消息。
这让我认为事件处理程序会引发对Word的Application对象的引用,从而阻止它关闭。所以我反过来测试它,因为我还有一个Excel加载项,它执行相同的任务。为了测试这一点,我构建了一个Excel加载项,就像上面的Word加载项一样,将工作簿嵌入到Word文档中,Excel加载项显示这两个邮件而不会留下excel.exe进程。
为了弄清楚问题的本质,我尝试在DocumentBeforeClose中解开事件处理程序:
Application.DocumentBeforeClose -= Application_DocumentBeforeClose;
GC.Collect();
这允许winword.exe关闭,但也禁用我的加载项的功能。我无法使用该解决方案,因为如果只有一个文档并且用户关闭它但希望继续使用Word,则也会发生该事件。加载项也必须继续工作。
我希望Word文档也会嵌入到其他第三方应用程序中,而not embedding it也不适用于我。
至少上面显示的VSTO 2007加载项和使用PIA的Word 2013加载项会出现此问题。
我不认为weak event handlers会起作用,因为对COM对象的弱引用是不可能的,对吗?
我可以阻止事件处理程序使Word进程保持活动状态吗?有没有其他方法可以在.NET中挂钩DocumentBeforeClose
事件或COM事件?
编辑:我还能够使用Word 2003中的Visual Basic 6编写的加载项重现该问题。因此它似乎与.NET无关。< / p>
答案 0 :(得分:1)
不要在应用程序启动时附加DocumentBeforeClose
事件处理程序,而是考虑将其附加到文档打开 - 并且仅当它不是嵌入对象时才会附加。
棘手的部分是确定正在打开的文档是否是嵌入对象。
我没有找到任何记录的方法来明确检查自动化应用程序当前是否处于嵌入模式,但是有很多事情可以检查以确定它是什么。
例如,我突出显示了下面Word的Application对象的一些属性,当打开的文档是嵌入对象时,这些属性是不可用的。如果要检查它们是否可用,则可能需要使用异常处理,因为尝试访问此类属性可能无效。
您可以检查的另一件事是,在WindowActivate事件中,当作为嵌入对象打开时,文档对象具有不同的Kind属性值。有一个示例描述了嵌入在Outlook电子邮件中的文档here。