none
MFC-Application steuert mittels OLE-Automation Office 2016 plötzlich sehr langsam

    Frage

  • Hallo zusammen,

    wir haben eine MFC-Application mit OLE-Automation.
    Entwicklungsumgebung Visual Studio 2017.
    Wir nehmen ein bereits vorhandenes RTF-Dokument, positionieren dort in eine Tabellen-Spalte und befüllen diese Spalte und speichern dieses Dokument ab.

    Mit Word 2007, Word 2010, Word 2013 funktioniert dies wunderbar.
    Auch Word 2016 hat anfangs funktioniert.
    Aber seit kurzer Zeit geht diese Automatisierung sehr langsam.

    Das Manipulieren einer Tabellen-Zeile und das Speichern des Dokuments funktioniert schnell - aber das abbauen der Word 2016-Instanz dauert 20 Sekunden (minimum).
    Geht man in den Task-Manager und schießt gezielt die Word-Instanzen ab, so kehren wir sofort in das Programm zurück und das veränderte Dokument ist auch korrekt abgelegt.

    Mit Word 2013 geht der gleich Source-Code in einem Rutsch. Aufbau der Instanz im Task-Manager, Manipulation der Datei, Abbau der Instanz.

    Mit Word 2016 Version 16.0.6741.2048 vom 13.06.2016 funktioniert auch alles wunderbar,
    mit Word 2016 Version 16.0.9029.2161 vom 23.02.2018 geht es nur noch sehr sehr zäh.

    Hier hakt es irgendwie:
        oDoc.Save();
        oDoc.SetSaved(TRUE);
        oDoc.Close(vtFalse, vtOptional, vtOptional);
        oWord.Quit(vtFalse, vtOptional, vtOptional);
        oWord.ReleaseDispatch();

    Dies hilft ein bisschen:

    Sleep(1000);
        oDoc.Save();
    Sleep(1000);
        oDoc.SetSaved(TRUE);
    Sleep(1000);
        oDoc.Close(vtFalse, vtOptional, vtOptional);
    Sleep(1000);
        oWord.Quit(vtFalse, vtOptional, vtOptional);
    Sleep(1000);
        oWord.ReleaseDispatch();


    Viele Grüße,

    Thomas Huber




    Mittwoch, 28. Februar 2018 14:32

Alle Antworten

  • Vom Grundsatz läuft da sowieso etwas falsch.

    Office wird per COM-Interop als Out-of-Process-Komponente gesteuert.
    Ich nehme mal an, dass oWord auf Word.Application und oDoc auf das Dokument verweist.

    oWord.Quit() ist in der Regel wirkungslos, da du auf diesem Wege eine COM-Referenz nicht los wirst und Word sich damit nicht beendet.

    Wenn du das Objektmodell von Office betrachtest, so hält oDoc wiederum selber eine Referenz auf Word, so dass der Prozess da immer noch nicht beendet werden kann.

    Der normale Weg ist ganz einfach:

    C#:

    oDoc = null;
    oWord = null;

    VB

    oDoc = nothing
    oWord = nothing

    Auch ggf. alle anderen Variablen, die irgendwann mal auf Objekte in Word verwiesen haben, sind auf jeden Fall auf null/nothing zu setzen.

    Wenn der letzte Verweis entfernt ist, schlägt der GC irgendwann zu und setzt die COM-Referenz auf 0, so dass der Prozess dann endet.
    Dies kann man forcieren, wenn man GC.Collect()  mit GC.WaitForPendingFinalizers() gezielt aufruft.

    Man darf nie ReleaseDispatch() oder Marshal.ReleaseComObject() verwenden, wenn irgend ein Objekt noch Referenzen haben sollte.
    COM-Objekte werden aufgelöst, wenn der Verwendungszähler auf 0 gesetzt wird.
    Die Release-Funktionen setzen den Zähler direkt auf 0, egal wieviele Verweise es noch gibt. Wird dann irgendeine andere Variable vom GC erfasst und aufgelöst, so versucht dieser wiederum den Zähler um 1 zu vermindern.
    Da das Ziel-Objekt aber zerstört ist, kommt es intern beim GC auch zu Exceptions, was den Prozess verlangsamen kann.

    Wichtig ist bei COM-Objekten vor allem eins:
    Sobald die Variable nicht mehr benötigt wird muss diese auf "null" gesetzt werden.

    Mehr ist nicht zu tun.

    Nachtrag:
    Ich habe gerade geshen, MFC-Anwendung.
    In diesem Fall verwendest du ja COM-Pointer, die mit Release() den Zähler um 1 vermindern und bei 0 das Objekt freigeben. Verwendest du CComPtr macht das die Klasse selber bei der Zuweisung von NULL.

    • Bearbeitet bfuerchau Mittwoch, 28. Februar 2018 16:28
    Mittwoch, 28. Februar 2018 16:24
  • also Office 2016 mit Konto Office 365 oder Konto Office 365 Plus geht alles wie gehabt schnell wie immer ohne Code - Änderung:

    allerdings gibt es hier bereits die Version: 16.0.9120.2015

    also ich kann sagen es liegt nicht am Code (MFC) sondern am Word 2016

    Mittwoch, 28. Februar 2018 21:08
  • Danke schonmal für die Antwort. Rein von der Arbeitsweise her kommt dieser Code:

    https://github.com/gyk001/PrintCaseInfo2x/blob/master/DocExport/WordTools.cpp

    unserem Code schon sehr nahe. Wir haben aus der MSWord.OLB eine IDispatch-Wrapper-Klasse maschinen generieren lassen. Und über diese IDispatch-Wrapper-Klasse werden nun zum Word hin Befehle übermittelt. (hier die Wrapper-Klasse)

    https://github.com/gyk001/PrintCaseInfo2x/blob/master/DocExport/msword.h

    Dies läuft nun seit Jahren Klasse. Und auch mit Office 2016 lief dies richtig gut. Beim Schritt von Win7 auf Win8 haben wir einen ordentlichen Geschwindigkeitsanstieg erkennen können. Aber jetzt plötzlich ist der Hund drin.

    Es ist auch so: Trennen wir den Rechner vom Netz, dann kommen wir auch wieder schneller in unsere Applikation zurück. Die Rechner, mit denen wir testen sind nicht mit OneDrive verbunden. Das sind keine Office-365-Installationen sondern normale Professional-Lizenzen.

    • Bearbeitet thomas.a.huber Donnerstag, 1. März 2018 10:03 Formatierung
    Donnerstag, 1. März 2018 10:02
  • Wie immer, Microsoft lässt sich ständig was neues einfallen, um auf das Internet zuzugreifen.

    Wenn das Office-Update schuld ist, dann dreht es einfach zurück. Ich mache persönlich nur ganz selten Officeupdates und meist nur dann wenn mal was nicht gelaufen ist.

    Donnerstag, 1. März 2018 10:57
  • Ggf. betrifft dies an dieser Stelle ein ähnliches Problem:

    https://social.technet.microsoft.com/Forums/de-DE/89821b76-a392-443d-ae7a-3906f7593a0f/proxyanmeldung-beim-start-von-office-anwendungen?forum=Office2016ITProDE

    Office möchte sich wohl irgendwie mit diesen genannten Adressen verbinden und bekommt u.U. Timeouts, was zu dieser Verlangsamung führt.

    Freitag, 2. März 2018 08:40