none
Outlook.Application.Quit qui ne fonctionne pas RRS feed

  • Question

  • Bonjour,

    Souhaitant supprimer des Items (Mails, Items, Calendrier) d'une catégorie particulière depuis une Application WinForm, j'ai établie le code ci dessous:

    //Connexion à Outlook Microsoft.Office.Interop.Outlook.Application application = new Microsoft.Office.Interop.Outlook.Application(); Microsoft.Office.Interop.Outlook.NameSpace nameSpace = application.GetNamespace("MAPI"); nameSpace.Logon(userlogin, password, Missing.Value, Missing.Value); nameSpace = null; //Récupération du dossier contact de l'utilisaeur Microsoft.Office.Interop.Outlook.Folder ContactFolder = (Microsoft.Office.Interop.Outlook.Folder)application.Session.GetDefaultFolder(OlDefaultFolders.olFolderContacts); string filter = String.Format("[Categories] = 'macateg"); //suppression de tout les contacts de la categorie macateg foreach (ContactItem contact in ContactFolder.Items.Restrict(filter)) { contact.Delete(); } application.Quit(); }

    En effet malgré l'utilisation de la méthode Quit(), l'application tourne encore car je continue d'avoir des message d'alerte provenant d'un Add-In travaillant en arrière-plan lorsque j'utilise Outlook.

    Y'a-t-il une solution pour vraiment fermer Outlook définitivement ?

    Autre question, la partie contact.Delete() ne fonctionne pas correctement, il ne me supprime pas la totalité des contacts de la catégorie voulue, lorsque je check ce que me renvoie ContactFolder.Items.Restrict(filter) J'ai effectivement le bon nombre de contact que je souhaite supprimé, cependant il ne me les supprime pas tous.

    Cordialement,

    jeudi 4 décembre 2014 11:25

Réponses

  • Bonjour,

    Je ne connais pas très bien l'interop de la partie Outlook, mais j'ai eu l'occasion de travailler avec les interops de word et excel. Si c'est similaire, alors concernant le problème de quitter Outlook, on peut essayer de reproduire ce que j'ai fait pour excel quand j'ai eu un problème similaire dessus: il suffit d'appeler le garbage collector dans la fonction qui a appelé. ça avait fonctionné pour moi pour excel, peut-être que ça fonctionnera ici.

    Voici comment procéder pour cela :

    Votre code est appelé à partir d'une fonction :

    void SuppressionContactsOutlook()
    {
    //Connexion à Outlook
                Microsoft.Office.Interop.Outlook.Application application = new Microsoft.Office.Interop.Outlook.Application();
                Microsoft.Office.Interop.Outlook.NameSpace nameSpace = application.GetNamespace("MAPI");
                nameSpace.Logon(userlogin, password, Missing.Value, Missing.Value);
                nameSpace = null;
     
                //Récupération du dossier contact de l'utilisaeur
                Microsoft.Office.Interop.Outlook.Folder ContactFolder = (Microsoft.Office.Interop.Outlook.Folder)application.Session.GetDefaultFolder(OlDefaultFolders.olFolderContacts);
     
                string filter = String.Format("[Categories] = 'macateg");
               
                //suppression de tout les contacts de la categorie macateg
                foreach (ContactItem contact in ContactFolder.Items.Restrict(filter))
                {
                    contact.Delete();
                }
                application.Quit();
    
            }
    }

    Eh bien, il suffit d'avoir un autre appel à cette fonction qui est fait ainsi :

    void AppelSuppressionContactsOutlook()
    {
        SuppressionContactsOutlook();
        GC.Collect(); //Force le ramasse-miette à se mettre en route
        GC.WaitForPendingFinalizers(); //Attend la fin des destructeurs
    }

    Il est très important que l'appel du garbage collector soit fait dans une fonction différente que celle où se trouve l'objet de type application Outlook sinon le garbage collector ne va pas considérer l'objet application Outlook comme étant "garbage collectable" (vive les néologismes! lol)

    Maintenant en ce qui concerne votre problème sur le "Delete", la doc MSDN sur le sujet spécifie entre autres qu'il faut parcourir la collection dans le sens inverse pour supprimer tous les éléments, ce qui est logique, d'ailleurs.


    Philippe


    mardi 16 décembre 2014 13:32

Toutes les réponses

  • Bonjour,

    Pour fermer Outlook définitivement essayez:

    System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);

    Merci de nous tenir au courant.

    Cordialement,

    Nina


    Microsoft propose ce service gratuitement, dans le but d'aider les utilisateurs et d'élargir les connaissances générales liées aux produits et technologies Microsoft. Ce contenu est fourni "tel quel" et il n'implique aucune responsabilité de la part de Microsoft.

    vendredi 5 décembre 2014 10:54
    Modérateur
  • C'est effectivement la solution à mon premier problème cependant elle ne marche pas. j'ai du m'orienter vers une autre solution du au caractéristiques de l'environnement de travail de l'application.

    Je récupère mon processus et je le kill pour évité de tuer les autres.

    vendredi 5 décembre 2014 11:01
  • bonjour,

    Essayer ce code :=)

    //programmatically start local Outlook
    System.Diagnostics.Process proc = new System.Diagnostics.Process();
    proc.StartInfo.FileName = "outlook.exe";

    /// star outlook

    proc.Start();

    ///fermer outlook
    proc.Kill();

    jeudi 11 décembre 2014 07:44
  • Je vais essayer merci.

    En faite cette méthode bossera sur serveur, donc plusieurs processus Outlook tourneront à ce moment là, je dois donc arrêter seulement mon processus ;)

    jeudi 11 décembre 2014 15:58
  • bonjour,

    votre solution pose problème, je suis obligé de d'instancier une nouvelle Application pour pouvoir m'y connecter et récupérer le namespace et ensuite me connecter avec le login de mon choix.

    Si par contre qqn connait un moyen de récupérer l'objet Application lier au processus, ça règlerait le problème, du moins je pense.

    vendredi 12 décembre 2014 08:52
  • bonjour,

    essayez ça :

    Do this " System.Diagnostics.Process.GetProcessesByName("outlook.exe")[0].Id"

    puis kill

    lundi 15 décembre 2014 14:47
  • Bonjour,

    Ça ne marche pas. Si vous pouviez fournir un code plus concis ça m'aiderait grandement

    Cordialement,

    lundi 15 décembre 2014 15:35
  • Le code que j'ai actuellement marche parfaitement et tue bien le processus que j'ai créer en conservant tout les aures processus Outlook en cours

    public void CreateAppointment(string Categ, string subject, DateTime start, DateTime end, string location, string userlogin, string password)
            {
                Process[] process1 = Process.GetProcesses();
                //Connexion à Outlook
               
                Microsoft.Office.Interop.Outlook.Application application = new Microsoft.Office.Interop.Outlook.Application();
                Microsoft.Office.Interop.Outlook.NameSpace nameSpace = application.GetNamespace("MAPI");
                nameSpace.Logon(userlogin, password, Missing.Value, Missing.Value);
                nameSpace = null;
                Process[] process2 = Process.GetProcesses();
    
                //Récuperation des catégories
                Categories categories = application.Session.Categories;
    
                //Création de la catégorie si elle n'existe pas encore
                if (application.Session.Categories[Categ] == null)
                {
                    categories.Add(Categ,
                         OlCategoryColor.olCategoryColorPeach,
                         OlCategoryShortcutKey.olCategoryShortcutKeyCtrlF11);
                }
    
                //Création et sauvegarde du rendez-vous
                AppointmentItem appointment = (AppointmentItem)application.Application.CreateItem(OlItemType.olAppointmentItem);
                appointment.Subject = subject;
                appointment.Start = start;
                appointment.End = end;
                appointment.Location = location;
                appointment.Categories = Categ;
                appointment.Save();
    
                GetMyProcess(process1, process2);
    
                if (this.ProcId == 0)
                {
                    return;
                }
                else
                {
                    Process.GetProcessById(ProcId).Kill();
                }
            }

    La procédure getMyProcess récupère mon processus par élimination en comparant les processus avant le l'instanciation de mon objet Outlook et après l'avoir lancé. Ainsi le processus n'étant pas présent dans la première liste est donc mon processus.

    voici le code de la procédure

    private void GetMyProcess(Process[] process1, Process[] process2)
            {
                bool bMonProcessXL;
    
                for (int j = 0; j <= process2.GetUpperBound(0); j++)
                {
                    if (process2[j].ProcessName == "OUTLOOK")
                    {
                        bMonProcessXL = true;
    
                        for (int i = 0; i <= process1.GetUpperBound(0); i++)
                        {
                            if (process1[i].ProcessName == "OUTLOOK")
                            {
                                if (process2[j].Id == process1[i].Id)
                                {
                                    bMonProcessXL = false;
                                }
                            }
                        }
                        if (bMonProcessXL == true)
                        {
                            ProcId = process2[j].Id;
                        }
                    }
                }
            }

    J'aimerais juste trouver une façon moins bourrin de quitter le Outlook que je lance. :)

    Cordialement,

    lundi 15 décembre 2014 15:42
  • Bonjour,

    Je ne connais pas très bien l'interop de la partie Outlook, mais j'ai eu l'occasion de travailler avec les interops de word et excel. Si c'est similaire, alors concernant le problème de quitter Outlook, on peut essayer de reproduire ce que j'ai fait pour excel quand j'ai eu un problème similaire dessus: il suffit d'appeler le garbage collector dans la fonction qui a appelé. ça avait fonctionné pour moi pour excel, peut-être que ça fonctionnera ici.

    Voici comment procéder pour cela :

    Votre code est appelé à partir d'une fonction :

    void SuppressionContactsOutlook()
    {
    //Connexion à Outlook
                Microsoft.Office.Interop.Outlook.Application application = new Microsoft.Office.Interop.Outlook.Application();
                Microsoft.Office.Interop.Outlook.NameSpace nameSpace = application.GetNamespace("MAPI");
                nameSpace.Logon(userlogin, password, Missing.Value, Missing.Value);
                nameSpace = null;
     
                //Récupération du dossier contact de l'utilisaeur
                Microsoft.Office.Interop.Outlook.Folder ContactFolder = (Microsoft.Office.Interop.Outlook.Folder)application.Session.GetDefaultFolder(OlDefaultFolders.olFolderContacts);
     
                string filter = String.Format("[Categories] = 'macateg");
               
                //suppression de tout les contacts de la categorie macateg
                foreach (ContactItem contact in ContactFolder.Items.Restrict(filter))
                {
                    contact.Delete();
                }
                application.Quit();
    
            }
    }

    Eh bien, il suffit d'avoir un autre appel à cette fonction qui est fait ainsi :

    void AppelSuppressionContactsOutlook()
    {
        SuppressionContactsOutlook();
        GC.Collect(); //Force le ramasse-miette à se mettre en route
        GC.WaitForPendingFinalizers(); //Attend la fin des destructeurs
    }

    Il est très important que l'appel du garbage collector soit fait dans une fonction différente que celle où se trouve l'objet de type application Outlook sinon le garbage collector ne va pas considérer l'objet application Outlook comme étant "garbage collectable" (vive les néologismes! lol)

    Maintenant en ce qui concerne votre problème sur le "Delete", la doc MSDN sur le sujet spécifie entre autres qu'il faut parcourir la collection dans le sens inverse pour supprimer tous les éléments, ce qui est logique, d'ailleurs.


    Philippe


    mardi 16 décembre 2014 13:32
  • Bonjour,

    je vais essayer de suite et je vous tiens au courant

    ________________________________________

    [MAJ]

    Ça me tue toute les fenêtres d'Outlook ouvertes malheureusement, j'ouvre 5 fenêtres Outlook (donc 5 processus si je ne me trompe pas) et ils sont tous fermé :/


    mardi 16 décembre 2014 13:46
  • Oui, en effet ça me revient maintenant : on a eu aussi ce problème avec excel [edit non c'était word]... Et visiblement il y a le même problème avec Outlook : lorsque je créait une nouvelle instance Application dans mon code, si Word était déjà lancé il se rattachait dessus, sinon il créait un nouveau processus Word auquel il se rattachait.

    J'avais fait un subterfuge qui avait très bien fonctionné mais c'était vraiment tordu : je créait une première instance d'application qui servait d'"appât", et là je m'abonnais à un événement de cette application (mais je ne me rappelle plus quel événement) au cas où un utilisateur aurait eu l'idée saugrenue (lol) d'ouvrir lui-même l'application avant, et lorsque cet événement se déclenche je savais qu'il fallait lancer une autre instance d'application car sinon la fermeture de ma première instance d'application allait aussi supprimer les documents ouverts par l'utilisateur...

    Il faudrait que je retrouve à nouveau comment j'avais fait exactement tout cela car j'avais fait ce code dans une entreprise précédente...

    ça y est, ça commence à me revenir :

    En fait je créais forcément 2 instances d'application (ce qui n'était pas génial c'est qu'il y aurait toujours 2 applications en process, mais bon...). Une première instance d'application servait d'appât pour une application utilisateur déjà lancée éventuellement, et une autre servait pour notre propre opération.

    Ensuite, je m'abonnais à l'événement Quit de la première instance et quand il cet événement était levé, je savais que c'est l'utilisateur qui quitte l'application word lancée. Alors à ce moment-là, je savais qu'il fallait ouvrir une autre instance d'application "appât" au cas où l'utilisateur du PC aurait l'idée de relancer à nouveau Word.

    Dans tous les cas, il ne fallait pas supprimer cette instance "appât" au niveau du code.

    Donc pour résumer : il y a une instance "appât" et une instance qu'on utilise et qu'il faut fermer aussi rapidement que possible.

    C'était une mini-usine à gaz mais ça fonctionnait à merveille...


    Philippe





    • Modifié PhGr_ mardi 16 décembre 2014 14:52 Corrections
    mardi 16 décembre 2014 14:22
  • Mais dans un univers réseaux ou plusieurs processus Outlook tournerait ca en ciblerait un au hasard ? ou ca les fermerait tous aussi ?
    mardi 16 décembre 2014 14:53
  • Mais dans un univers réseaux ou plusieurs processus Outlook tournerait ca en ciblerait un au hasard ? ou ca les fermerait tous aussi ?

    En fait, quand il y a 2 fenêtres Outlook, il n'y a qu'un seul processus Outlook qui tourne (en tous cas, c'est comme ça que ça fonctionne sur la version 2010) et word fonctionnait sur le même principe : à partir du moment où il y a plusieurs documents ouverts, c'est avec le même processus. Je viens juste de faire le test avec mon Outlook, et je confirme donc que c'est pareil.

    Du coup, si plus d'un processus Outlook tourne, les autres sont alors lancés par une application qui a fait de l'interop Outlook. C'est vrai qu'avec la façon de faire que j'ai montré, je partait sur le postulat où notre application était la seule à faire de l'interop.

    A propos, avais-tu bien noté ma modification sur mon post précédent? C'est vrai que je l'ai modifié plusieurs fois, ma version finale est celle avec le texte barré.


    Philippe

    mardi 16 décembre 2014 15:02
  • C'est noté :)

    en faite l'Add-in tournera en RDP/client léger , d'ou le problème d'environnement, si je quitte l'application ca relèverait de l'hécatombe x)

    lundi 22 décembre 2014 09:19