Word Automation - File is in use by another applic

2019-04-28 02:00发布

I have a WinForms application where I am using Word Automation to build documents via a template, and then save them to the database. After the document is created, I retrieve the document from the database, write it to the file system in a temp directory, and then open the document using the Word Interop services.

There is a list of documents loaded and the user can open only 1 instance of each document, but can open multiple different documents simultaneously. I don't have any problems with opening, saving, and closing when they open 1 document, however, when they open multiple documents simultaneously, I get the following error when closing any of my instances of Word:

The file is in use by another application or user. (C:\...\Templates\Normal.dotm) 
This error is commonly encountered when a read lock is set on the file that you are attempting to open.

I am using the following code to open the document and handle the BeforeDocumentClosed event:

public void OpenDocument(string filePath, Protocol protocol, string docTitle, byte[] document)
{
    _protocol = protocol;
    documentTitle = docTitle;
    _path = filePath;

    if (!_wordDocuments.ContainsKey(_path))
    {
        FileUtility.WriteToFileSystem(filePath, document);

        Word.Application wordApplication = new Word.Application();
        wordApplication.DocumentBeforeClose += WordApplicationDocumentBeforeClose;

        wordApplication.Documents.Open(_path);

        _wordDocuments.Add(_path, wordApplication);
    }
    _wordApplication = _wordDocuments[_path];
    _currentWordDocument = _wordApplication.ActiveDocument;

    ShowWordApplication();
}

public void ShowWordApplication()
{
    if (_wordApplication != null)
    {
        _wordApplication.Visible = true;
        _wordApplication.Activate();
        _wordApplication.ActiveWindow.SetFocus();
    }
}

private void WordApplicationDocumentBeforeClose(Document doc, ref bool cancel)
{
    if (!_currentWordDocument.Saved)
    {
        DialogResult dr = MessageHandler.ShowConfirmationYnc(String.Format(Strings.DocumentNotSavedMsg, _documentTitle), Strings.DocumentNotSavedCaption);

        switch (dr)
        {
            case DialogResult.Yes:
                SaveDocument(_path);
                break;
            case DialogResult.Cancel:
                cancel = true;
                return;
        }
    }

    try
    {
        if (_currentWordDocument != null)
            _currentWordDocument.Close();
    }
    finally
    {
        Cleanup();
    }
}

public void Cleanup()
{
    if (_currentWordDocument != null)
        while(Marshal.ReleaseComObject(_currentWordDocument) > 0);

    if (_wordApplication != null)
    {
        _wordApplication.Quit();
        while (Marshal.ReleaseComObject(_wordApplication) > 0);
        _wordDocuments.Remove(_path);
    }
}

Does anyone see anything wrong that I am doing to allow opening of multiple documents at the same time? I am fairly new to Word Automation and the Word Interop services, so any advice is appreciated. Thanks.

4条回答
等我变得足够好
2楼-- · 2019-04-28 02:49

Keep in mind that the code:

Word.Application wordApplication = new Word.Application();

will always spin up a new instance of Word, even if there's already an instance loaded.

Usually, you're better off checking for a loaded instance (via GETOBJECT) and using it if there is one, and only spinning up a new instance if you need to.

查看更多
萌系小妹纸
3楼-- · 2019-04-28 02:52

I found the solution via this MSDN article: http://support.microsoft.com/kb/285885

You need to do this before calling Application.Quit();

_wordApplication.NormalTemplate.Saved = true;

This prevents Word from trying to save the Normal.dotm template. I hope this helps someone else.

查看更多
可以哭但决不认输i
4楼-- · 2019-04-28 02:59

I have used Word in C# doc2pdf application. Before close doc, set the save option like this:

object saveOption = Microsoft.Office.Interop.Word.WdSaveOptions.wdDoNotSaveChanges;
oDoc.Close(ref saveOption, ref oMissing, ref oMissing);
oWord.Quit(ref saveOption, ref oMissing, ref oMissing);
查看更多
做个烂人
5楼-- · 2019-04-28 03:04

I have help links in my application and wanted to open a particular word doc to a particular bookmark. If the document is already open, it should not open it again. If Word is already open, it should not open a new instance of Word.

This code worked for me:

object filename = @"C:\Documents and Settings\blah\My Documents\chapters.docx";
object confirmConversions = false;
object readOnly = true;
object visible = true;
object missing = Type.Missing;
Application wordApp;

object word;
try
{
    word = System.Runtime.InteropServices.Marshal.GetActiveObject("Word.Application");
}
catch (COMException)
{
    Type type = Type.GetTypeFromProgID("Word.Application");
    word = System.Activator.CreateInstance(type);
}

wordApp = (Application) word;
wordApp.Visible = true;
Console.WriteLine("There are {0} documents open.", wordApp.Documents.Count);
var wordDoc = wordApp.Documents.Open(ref filename, ref confirmConversions, ref readOnly, ref missing,
                                        ref missing, ref missing, ref missing, ref missing,
                                        ref missing, ref missing, ref missing, ref visible,
                                        ref missing, ref missing, ref missing, ref missing);
wordApp.Activate(); 
object bookmarkName = "Chapter2";
if (wordDoc.Bookmarks.Exists(bookmarkName.ToString()))
{
    var bookmark = wordDoc.Bookmarks.get_Item(bookmarkName);
    bookmark.Select();
}
查看更多
登录 后发表回答