IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

Fermer word proprement, mission impossbile?


Sujet :

C#

  1. #1
    Membre confirmé
    Inscrit en
    Mars 2007
    Messages
    122
    Détails du profil
    Informations forums :
    Inscription : Mars 2007
    Messages : 122
    Par défaut Fermer word proprement, mission impossbile?
    Bonjour,

    Je n'arrive pas à fermer word proprement, lors de la génération des 1000 documents sur mon serveur, je trouve tous les winword qui ne sont pas fermés, est ce qu'il y a un moyen de fermer ces processus, car je ne comprends pas pourquoi ils sont toujours ouvert, merci infiniment de votre aide.
    NB : j'ai un warning aux lignes 37 et 38 :
    Ambiguity between method 'Microsoft.Office.Interop.Word._Document.Close(ref object, ref object, ref object)' and non-method 'Microsoft.Office.Interop.Word.DocumentEvents2_Event.Close
    Est ce que c'est l'origine de mon problème?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
     
     public void FUSION(string s)
            {
     
                    Console.Write("1");
     
                    String[] tbStr2 = s.Split(new Char[] { ';' });
                    string nb = tbStr2[0];
                    Object oMissing = System.Reflection.Missing.Value;
                    Object oTrue = true;
                    Object oFalse = false;
                    Microsoft.Office.Interop.Word.Application oWord = new Microsoft.Office.Interop.Word.Application();
                    Microsoft.Office.Interop.Word.Document oWordDoc = new Microsoft.Office.Interop.Word.Document();
                    oWord.Visible = true;
                    oWord.Visible = false;
                    Object oTemplatePath = modelee;
                    oWordDoc = oWord.Documents.Add(ref oTemplatePath, ref oMissing, ref oMissing, ref oMissing);
                    bool sympb = false; bool E = false; bool n = false; bool p = false; bool r = false;
     
    foreach (Microsoft.Office.Interop.Word.Range range in oWordDoc.Words)
                    {if (range.Text.Trim().Contains("$"))
                        {   int pos = range.Text.Trim().IndexOf("$");
                            string str = range.Text.Trim().Replace("$", "");
                            range.Text = str;} }
     
                    foreach (Microsoft.Office.Interop.Word.Range range in oWordDoc.Words)
                    {if (range.Text.Trim().Contains("$$"))
                        {   int pos = range.Text.Trim().IndexOf("$$");
                            string str = range.Text.Trim().Replace("$$", "");
                            range.Text = str;} }
     
                    Object oSaveAsFile ="./1.doc";
                    oWordDoc.SaveAs(ref oSaveAsFile, ref oMissing, ref oMissing, ref oMissing,
                    ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing,
                    ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing,
                    ref oMissing, ref oMissing);
                    oWordDoc.Close(ref oFalse, ref  oMissing, ref oMissing);
                    oWord.Quit(ref oMissing, ref oMissing, ref oMissing);
     
     
     
     
            }

  2. #2
    Membre émérite Avatar de NicoL__
    Homme Profil pro
    Architecte
    Inscrit en
    Janvier 2011
    Messages
    399
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Architecte

    Informations forums :
    Inscription : Janvier 2011
    Messages : 399
    Par défaut
    Je pense qu'appeler le méthode FUSION en masse est risqué car tu ouvres et ferme word à chaque appel.
    Le mieux serait de créer une seule instance Microsoft.Office.Interop.Word.Application avec de multiple document que tu ouvres et ferme dans FUSION. En suite du oWord.Quit dans la méthode appelante une fois.
    Mais j'avoue qu'avec une architecture web derrière ce n'ai pas évident voir, word n'est pas conçu pour ça.
    Sinon pour générer des document office :
    http://www.microsoft.com/downloads/e...DisplayLang=en

    ou mieux encore (mais pas testé)

    http://flexdoc.codeplex.com/

  3. #3
    Membre confirmé
    Inscrit en
    Mars 2007
    Messages
    122
    Détails du profil
    Informations forums :
    Inscription : Mars 2007
    Messages : 122
    Par défaut
    Comment peut on concaténer les document word, je m'explique, au lieu de faire 1000 créations, on fait un seule document de 1000 pages (chaque document est sur une seule page) puis on enregistre uniquement un seule document au lieu de 1000, merci infiniment.

  4. #4
    Membre confirmé
    Inscrit en
    Mars 2007
    Messages
    122
    Détails du profil
    Informations forums :
    Inscription : Mars 2007
    Messages : 122
    Par défaut
    Bonjour,

    Très diffcilement, j'ai réussi à trouver comment terminer les processus winword.exe, ci dessous le code que j'ai rajouté à la fin de FUSION :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    System.Runtime.InteropServices.Marshal.ReleaseComObject(oWordDoc);
    oWordDoc = null; oWord = null;
     
    GC.Collect();
    GC.WaitForPendingFinalizers();
     
    GC.Collect();
    GC.WaitForPendingFinalizers();
    cependant la génération devient très lente, pour la suppression de 63 processus, ça prend dans les 2min, comment peut on optimiser? merci infiniment.

  5. #5
    Membre émérite
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2010
    Messages
    479
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2010
    Messages : 479
    Par défaut
    Bonjour sinon j'ai une solution je laisse les critique décider de sa perspicacité

    -1 Tu déclares un public static ArrayList conteneur_word dans ta classe Program.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public static ArrayList msw_Objects = new ArrayList();
    -2 Dans le constructeur de ta classe qui maipule Word tu ajoutes chaque nouvel objet à ce conteneur.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    public Microsoft_Word(bool show)//,ArrayList msw_Ob)
    {
    //initialisation etc.....
    oWord = new Microsoft.Office.Interop.Word.Application();
    Program.msw_Objects.Add(oWord);
    }
    -3 Dans le destructeur de ta classe tu mets une boucle sur ce objet et tu leur demande de se fermer. Ca tue le processus.
    Moi j'ai laissé la propriété enableWarning qui prévient l'utilisateur que le doc veut se fermer mais toi qui utilise ca coté serveur tu peux la désactiver.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    ~Microsoft_Word()
    {
    for (int i = 0; i < Program.msw_Objects.Count; i++)
    {
        Microsoft.Office.Interop.Word._Application oWord = (Microsoft.Office.Interop.Word._Application)Program.msw_Objects[i];
        oWord.Quit();
     
    }
    Program.msw_Objects.Clear();
    		}

  6. #6
    Membre confirmé
    Inscrit en
    Mars 2007
    Messages
    122
    Détails du profil
    Informations forums :
    Inscription : Mars 2007
    Messages : 122
    Par défaut
    Peut être que ta solution est la meilleur, sauf que parfois je réalise la génération de plus de 4000 fichiers word, j'ai pas envi de terminer les processus à la fin du traitement (destructeur), car le serveur devient trop trop long, merci d'avance de votre aide.

  7. #7
    Membre émérite
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2010
    Messages
    479
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2010
    Messages : 479
    Par défaut
    Il te suffit simplement de déplacer la méthode du constructeur vers une autre méthode de ton choix.
    Le but du jeu étant de pouvoir balayer la liste des tes objets Word afin de les quitter proprement quand tu le désires.
    Je partage également l'avis de NicoL__ une seule instance Word serait plus profitable.
    Parfois il vaut mieux perdre deux heures, revenir en arrière et modifier un peut l'arch de son appli plutôt que de se trainer un paquet de process Word lourds et lents... Ça se comprend que ton serveur rame

    Que décides tu ?

  8. #8
    Membre émérite
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2010
    Messages
    479
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2010
    Messages : 479
    Par défaut
    ou sinon

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    int processId = 0;
    // 1. Additionner les identifiants des processus winword avant l'ouverture de l'automation :
    foreach (Process item in Process.GetProcessesByName("winword"))
        processId -= item.Id;
     
    // 2. Ouvrir l'automation :
    ApplicationClass monAppli = new ApplicationClass();
     
    // 3. Ajouter les identifiants des processus winword après l'ouverture de l'automation,
    // la différence (après - avant) donnera l'identifiant du processus ouvert :
    foreach (Process item in Process.GetProcessesByName("winword"))
        processId += item.Id;
     
    // Automation...
     
    // Enfin, lorsque l'automation est terminée, il suffit de tuer le processus à partir de son identifiant :
    Process.GetProcessById(processId).Kill();
    Kill() est un peu barbare mais radical;

    Cf http://dotnet.developpez.com/faq/csh...DotNETOffice08

  9. #9
    Membre confirmé
    Inscrit en
    Mars 2007
    Messages
    122
    Détails du profil
    Informations forums :
    Inscription : Mars 2007
    Messages : 122
    Par défaut
    oui, j'ai essayé cette solution, il me met un bug, (processus non trouvé).

  10. #10
    Membre émérite
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2010
    Messages
    479
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2010
    Messages : 479
    Par défaut
    Tu as un problème d'id de process alors...
    Essayes ça :

    Dans ta méthode FUSION
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
      Process[]WordProcessesBefore = Process.GetProcessesByName("WINWORD");
                this.m_Application = new ApplicationClass();
                .... ton code fusion
    ....
    ....
     Microsoft.Office.Interop.Word.Application oWord = new Microsoft.Office.Interop.Word.Application();
                    Microsoft.Office.Interop.Word.Document oWordDoc = new Microsoft.Office.Interop.Word.Document();
                Process[]WordProcessesAfter = Process.GetProcessesByName("WINWORD");
                int process_id = this.GetProcessId(WordProcessesBefore, WordProcessesAfter);
    .... ton code fusion
    ....
    ....
    Process.GetProcessById(process_id).Kill();
    Dans ta classe tu ajoutes ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    private int GetProcessId(Process[] WordProcessesBefore, Process[] WordProcessesAfter)
            {
                bool IsMyProcess = false;
                int Result = -1;
     
                // Si mon processus est le seul à être instancié
                // inutile de parcourir le tableau, il n'y a qu'une seule instance :
                if (WordProcessesBefore.Length == 0 && WordProcessesAfter.Length == 1)
                {
                    Result = WordProcessesAfter[0].Id;
                }
                else
                {
                    // Parcours des processus après instanciation de l'objet :
                    foreach (Process ProcessAfter in WordProcessesAfter)
                    {
                        // Parcours des processus avant instanciation de l'objet :
                        IsMyProcess = true;
                        foreach (Process ProcessBefore in WordProcessesBefore)
                        {
                            // Si je le retrouve, ce n'est pas celui que je cherche :
                            if (ProcessAfter.Id == ProcessBefore.Id)
                            {
                                IsMyProcess = false;
                            }
                        }
     
                        // J'ai retrouvé mon processus :
                        if (IsMyProcess)
                        {
                            Result = ProcessAfter.Id;
                        }
                    }
                }
     
                return Result;
            }

  11. #11
    Membre confirmé
    Inscrit en
    Mars 2007
    Messages
    122
    Détails du profil
    Informations forums :
    Inscription : Mars 2007
    Messages : 122
    Par défaut
    Merci pour le retour, malheureusement j'ai toujours la même erreur, est ce qu'il y a une autre manière sans le kill ?

  12. #12
    Membre émérite Avatar de NicoL__
    Homme Profil pro
    Architecte
    Inscrit en
    Janvier 2011
    Messages
    399
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Architecte

    Informations forums :
    Inscription : Janvier 2011
    Messages : 399
    Par défaut
    Je ne sais pas quelles sont tes contraintes en terme de version de Word, mais si tu es au niveau de 2007 ou plus, pour faire de la génération de document dans de telle quantité il faut utiliser OpenXml et la Dll fourni par microsoft, ainsi tu n'as plus besoin d'utiliser une instance de Word sur ton serveur ce qui de toute façon n'est pas prévu et déconseillé et pas microsoft.

  13. #13
    Membre confirmé
    Inscrit en
    Mars 2007
    Messages
    122
    Détails du profil
    Informations forums :
    Inscription : Mars 2007
    Messages : 122
    Par défaut
    Bonjour,

    J'utilise office 2010 sur mon serveur et je manipule les .doc, .docx et .odt, sachant que l'openXml ne manipule que du .docx, je ne pense pas que c'est la bonne solution pour mon gros problème, merci d'avance.

  14. #14
    Membre averti
    Homme Profil pro
    Inscrit en
    Avril 2011
    Messages
    17
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Orne (Basse Normandie)

    Informations forums :
    Inscription : Avril 2011
    Messages : 17
    Par défaut
    Je n'ai malheureusement pas mon bouquin de référence sous la main, et ma mémoire me fait défaut.

    Mais il me semble que ton problème vienne du fait que close représente à la fois une méthode et un évènement, et que ton système s'embrouille entre les deux (peut-être lève-t-il l'évènement au lieu de fermer ton programme ?)

    Dans ce cas, lorsque l'on ajoute un using vers le microsoft.interop correspondant, il crée des classes, autres que la classe Application, qui permettent justement de ne taper que sur les méthodes ou les évènements. Faudrait creuser dans ce sens.

  15. #15
    Membre confirmé
    Inscrit en
    Mars 2007
    Messages
    122
    Détails du profil
    Informations forums :
    Inscription : Mars 2007
    Messages : 122
    Par défaut
    Bonjour,

    J'ai essayé en faisant ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    ((Microsoft.Office.Interop.Word._Document)oWordDoc).Close(ref oFalse, ref oMissing, ref oMissing);            
    ((Microsoft.Office.Interop.Word._Application)oWord).Quit(ref oMissing, ref oMissing, ref oMissing);
    c'est exactement le meme résultat, merci d'avance de votre aide.

  16. #16
    Membre émérite Avatar de NicoL__
    Homme Profil pro
    Architecte
    Inscrit en
    Janvier 2011
    Messages
    399
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Architecte

    Informations forums :
    Inscription : Janvier 2011
    Messages : 399
    Par défaut
    Bon alors s'il faut utiliser Word en mode serveur, je pense que le plus simple est d'utiliser qu'une instance de l'application Word (singleton) et d'ouvrir tous les documents dedans. Normalement la fermeture des docuements ne devrait pas pauser de problème.
    Et ensuite il faut trouver un astuce pour quitter word de temps à autre. Peut-être en maintenant un compteur du nb de document ouvert et de fermer dès qu'il est à zéro et de passer la variable application à null (le singleton se chargera de l’instanciation).
    Mais je pense qu'il est inévitable de temps à autre de faire le ménage dans les process word.

Discussions similaires

  1. [WD-MAC 2004] Impossible de fermer word
    Par Iris17 dans le forum Word
    Réponses: 1
    Dernier message: 09/02/2012, 01h08
  2. Fermer word après aperçu
    Par exile69 dans le forum C#
    Réponses: 3
    Dernier message: 26/05/2009, 18h46
  3. Comment fermer Excel proprement
    Par RJDTGA dans le forum VBA Access
    Réponses: 11
    Dernier message: 20/03/2009, 11h57
  4. Fermer fenêtre proprement ?
    Par eSbii dans le forum GLUT
    Réponses: 0
    Dernier message: 14/03/2008, 23h06
  5. Fermer Word proprement depuis excel
    Par Australia dans le forum VBA Word
    Réponses: 5
    Dernier message: 21/11/2006, 09h37

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo