Word Automation - 文件正在被其他应用程序或用户使用

发布于 2024-10-05 22:28:36 字数 2508 浏览 2 评论 0原文

我有一个 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 服务还很陌生,因此我们将不胜感激。谢谢。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

哭了丶谁疼 2024-10-12 22:28:36

我通过这篇 MSDN 文章找到了解决方案: http://support.microsoft.com/kb/285885

您需要执行以下操作在调用 Application.Quit() 之前执行此操作;

_wordApplication.NormalTemplate.Saved = true;

这可以防止 Word 尝试保存 Normal.dotm 模板。我希望这对其他人有帮助。

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.

挽清梦 2024-10-12 22:28:36

我在 C# doc2pdf 应用程序中使用了 Word。在关闭文档之前,设置保存选项,如下所示:

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

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);
小伙你站住 2024-10-12 22:28:36

我的应用程序中有帮助链接,并且想要打开特定书签的特定单词文档。如果文档已打开,则不应再次打开它。如果 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();
}

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();
}
南薇 2024-10-12 22:28:36

请记住,代码:

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

始终会启动一个新的 Word 实例,即使已经加载了一个实例。

通常,您最好检查是否已加载实例(通过 GETOBJECT)并在存在时使用它,并且仅在需要时启动一个新实例。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文