2010-12-06 20 views
5

J'ai une application WinForms où j'utilise Word Automation pour créer des documents via un modèle, puis les enregistrer dans la base de données. Une fois le document créé, je récupère le document de la base de données, l'écris dans le système de fichiers dans un répertoire temporaire, puis j'ouvre le document à l'aide des services Word Interop.Word Automation - Le fichier est utilisé par une autre application ou un autre utilisateur

Il existe une liste de documents chargés et l'utilisateur ne peut ouvrir qu'une seule instance de chaque document, mais peut ouvrir plusieurs documents différents simultanément. Je n'ai pas de problèmes avec ouverture, l'enregistrement et la fermeture quand ils ouvrent 1 document cependant, quand ils ouvrent plusieurs documents en même temps, je reçois l'erreur suivante lors de la fermeture l'un de mes instances de 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. 

J'utilise le code suivant pour ouvrir le document et gérer l'événement 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); 
    } 
} 

quelqu'un voit quelque chose de mal que je fais pour permettre l'ouverture de plusieurs documents en même temps? Je suis relativement nouveau à Word Automation et aux services Word Interop, donc tout conseil est apprécié. Merci.

+0

-vous ouvrez directement le fichier verrouillé dans votre code (C: \ ... \ Templates \ Normal.dotm) ou est-ce accessible automatiquement? Si vous êtes celui qui l'ouvre, vous pouvez créer une copie ou quelque chose comme ça pour éviter le verrouillage ou essayer d'y accéder en lecture seule. –

Répondre

8

Je trouve la solution via cet article MSDN: http://support.microsoft.com/kb/285885

Vous devez le faire avant d'appeler Application.Quit();

_wordApplication.NormalTemplate.Saved = true; 

Cela empêche Word d'essayer d'enregistrer le modèle Normal.dotm. J'espère que ça aidera quelqu'un d'autre.

+0

vous devez accepter votre propre réponse, que je sais, semble étrange, mais est la bonne chose à faire –

+0

Je dois attendre quelques jours avant qu'il me le permet, malheureusement. – Brandon

0

Gardez à l'esprit que le code:

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

aura toujours tourner une nouvelle instance de Word, même s'il y a déjà une instance chargée.

Habituellement, il vaut mieux vérifier une instance chargée (via GETOBJECT) et l'utiliser s'il y en a une, et seulement tourner une nouvelle instance si nécessaire.

2

J'ai utilisé Word dans l'application C# doc2pdf. Avant doc proximité, définissez l'option Enregistrer comme ceci:

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

J'ai des liens d'aide dans ma demande et je voulais ouvrir un mot doc à un signet particulier. Si le document est déjà ouvert, il ne doit pas l'ouvrir à nouveau. Si Word est déjà ouvert, il ne doit pas ouvrir une nouvelle instance de Word.

Ce code a fonctionné pour moi:

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