问题
I have built a Word Add-in which has to do a task when the user closes the document. I installed an event handler for the DocumentBeforeClose
event of the Application
object to do that. The problem is that the event handler appears to prevent the Word process from exiting when I embed an existing Word document in an Excel workbook for example.
The problem occurs when I embed the document in Excel via the Ribbon Insert > Object > Create from File and then select a Word document. The document is then loaded into the workbook. When I close Excel winword.exe is still running and the window is invisible.
When I disable my Add-in, winword.exe is running only for about a second to embed the document. That is the behaviour I want with my Add-in enabled as well.
To narrow down the problem I created a simple VSTO Word Add-in for testing. These are the changes I made to the class generated by 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");
}
When I start Word and close it again, this Add-in shows both message boxes as expected. When I embed a Word document in an Excel workbook, the "DocumentBeforeClose" message pops up a second later or so, but the "Shutdown" message does not appear. winword.exe keeps running even after I have closed Excel.
Removing the line where the event handler is hooked up causes the Add-in to show the "Shutdown" message 1 second after the document has been embedded and winword.exe quits.
This led me to think that the event handler causes a reference to the Application-object of Word, which prevents it from shutting down. So I tested it the other way around because I also have an Excel Add-in which does the same task. To test that, I built an Excel Add-in just like the Word Add-in above, embedded a workbook in a Word document and the Excel Add-in shows both messages without leaving behind an excel.exe process.
To figure out the nature of the problem, I tried unhooking the event handler in DocumentBeforeClose:
Application.DocumentBeforeClose -= Application_DocumentBeforeClose;
GC.Collect();
This allows winword.exe to shutdown but also disables functionality of my Add-in. I can not use that solution because the event also occurs if there is only one document and the users closes it but wants to keep working with Word. The Add-in has to keep working then as well.
I expect that Word documents will also be embedded in other 3rd party applications and not embedding it will not work for me either.
This problem occurs at least with the VSTO 2007 add-in shown above and a Word 2013 add-in using the PIAs.
I don't think weak event handlers will work because weak references to COM objects are not possible, right?
Can I prevent the event handler from keeping the Word process alive? Are there any other ways to hook the DocumentBeforeClose
event or COM events in .NET?
Edit: I was also able to reproduce the problem with an Add-in written in Visual Basic 6 in Word 2003. So it doesn't even seem to be .NET related.
回答1:
Instead of attaching the DocumentBeforeClose
event handler on application startup, consider attaching it on document open—and only if it's not an embedded object.
The tricky part is determining whether the document being opened is an embedded object.
I haven't found any documented way to explicitly check whether an Automation application is currently in embedded mode, but there are a number of things you can check to infer that it is.
For example, I've highlighted some properties of Word's Application object below that are not avaiable when the document being opened is an embedded object. If you want to check whether they're available, you may need to use exception handling, since attempting to access such properties may be invalid.
Another thing you can check is that in the WindowActivate event, the document object has a different value for the Kind property when opened as an embedded object. There's an example described here for a document embedded in an Outlook email.
来源:https://stackoverflow.com/questions/29978430/word-add-in-keeps-word-process-alive-when-document-is-embedded-via-ole