Word Automation - файл используется другим приложением или пользователем.

У меня есть приложение WinForms, в котором я использую Word Automation для создания документов по шаблону, а затем сохраняю их в базе данных. После создания документа я извлекаю документ из базы данных, записываю его в файловую систему во временный каталог, а затем открываю документ с помощью служб Word Interop.

Существует список загруженных документов, и пользователь может открыть только 1 экземпляр каждого документа, но может одновременно открывать несколько разных документов. У меня нет проблем с открытием, сохранением и закрытием, когда они открывают 1 документ, однако, когда они открывают несколько документов одновременно, я получаю следующую ошибку при закрытии любого из моих экземпляров 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.

Я использую следующий код, чтобы открыть документ и обработать событие BeforeDocumentClosed:

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);
    }
}

Кто-нибудь видит что-то не так, что я делаю, чтобы разрешить одновременное открытие нескольких документов? Я новичок в Word Automation и службах Word Interop, поэтому приветствую любые советы. Спасибо.


person Brandon    schedule 06.12.2010    source источник
comment
Вы напрямую открываете заблокированный файл в своем коде (C: \ ... \ Templates \ Normal.dotm) или это происходит автоматически? Если вы открываете его, вы можете вместо этого создать копию или что-то в этом роде, чтобы избежать блокировки, или попробуйте получить к нему доступ только для чтения.   -  person Simon D.    schedule 06.12.2010


Ответы (4)


Я нашел решение в этой статье MSDN: http://support.microsoft.com/kb/285885

Это нужно сделать перед вызовом Application.Quit ();

_wordApplication.NormalTemplate.Saved = true;

Это предотвращает попытки Word сохранить шаблон Normal.dotm. Надеюсь, это поможет кому-то другому.

person Brandon    schedule 06.12.2010
comment
ты должен принять свой ответ, который, я знаю, звучит странно, но это правильный поступок - person David Heffernan; 06.12.2010
comment
К сожалению, мне нужно подождать пару дней, прежде чем это позволит мне. - person Brandon; 06.12.2010

Я использовал Word в приложении C # doc2pdf. Перед закрытием документа установите параметр сохранения следующим образом:

object saveOption = Microsoft.Office.Interop.Word.WdSaveOptions.wdDoNotSaveChanges;
oDoc.Close(ref saveOption, ref oMissing, ref oMissing);
oWord.Quit(ref saveOption, ref oMissing, ref oMissing);
person forestk    schedule 29.06.2012

В моем приложении есть справочные ссылки, и я хотел открыть документ с определенным словом для определенной закладки. Если документ уже открыт, не следует открывать его снова. Если Word уже открыт, он не должен открывать новый экземпляр Word.

Этот код работал у меня:

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();
}
person Coxy    schedule 16.08.2013

Имейте в виду, что код:

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

всегда будет запускать новый экземпляр Word, даже если он уже загружен.

Обычно лучше проверять загруженный экземпляр (через GETOBJECT) и использовать его, если он есть, и запускать новый экземпляр только при необходимости.

person DarinH    schedule 06.12.2010