【问题标题】:Word Add-in keeps Word process alive when document is embedded via OLE通过 OLE 嵌入文档时,Word 加载项使 Word 进程保持活动状态
【发布时间】: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 无关。

【问题讨论】:

    标签: c# com ms-word vsto ole


    【解决方案1】:

    不要在应用程序启动时附加 DocumentBeforeClose 事件处理程序,而应考虑在打开文档时附加它 - 并且仅当它不是嵌入式对象时。

    棘手的部分是确定正在打开的文档是否是嵌入对象。

    我还没有找到任何记录的方法来明确检查自动化应用程序当前是否处于嵌入式模式,但是您可以检查许多事情来推断它是。

    例如,我在下面突出显示了 Word 应用程序对象的一些属性,当打开的文档是嵌入对象时,这些属性不可用。如果你想检查它们是否可用,你可能需要使用异常处理,因为尝试访问这些属性可能是无效的。

    您可以检查的另一件事是,在 WindowActivate 事件中,文档对象在作为嵌入对象打开时具有不同的 Kind 属性值。对于嵌入在 Outlook 电子邮件中的文档,有一个描述为 here 的示例。

    【讨论】:

    • 如果我将事件处理程序附加到Application.DocumentOpen 我也会遇到同样的问题。但是您的建议给了我一个想法:如果正在打开我关心的文档,它将始终由我的应用程序打开。我想我可以从那里附加DocumentBeforeClose 事件处理程序。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多