Komfortabler Dateimanager mit vielen Funktionen

Die Sache mit dem leeren Kontextmenü

By Sven on 28.01.2007 - 19:47 in Entwicklung

Im Forum haben Anwender berichtet, dass SpeedCommander neuerdings nach einer gewissen Zeit nur noch ein (fast) leeres Kontextmenü anzeigt. Auch andere Funktionen, wie z.B. Drag & Drop, die Berechnung von Ordnergrößen oder die Anzeige des Dateiverknüpfungsdialogs stellen ihre Arbeit ein. Mit Hilfe des bewährten ShellExView hat akim schließlich herausgefunden, dass die Ursache die Kontextmenü-Erweiterung von Nero CoverEditor ist. Nach Deaktivierung dieser Erweiterung funktioniert alles wieder wie gewünscht.

Kontextmenü-Erweiterungen sind ganz normale Dlls, die bei der Zusammenstellung des Kontextmenüs durch die Shell automatisch geladen und in den Adressraum der jeweiligen Anwendung eingeblendet werden. Die Anwendung selbst hat keinen Einfluss auf die Erstellung des Kontextmenüs sowie darauf, welche Erweiterungen geladen werden. Fehlerhaft programmierte Kontextmenü-Erweiterungen können eine Anwendung damit sofort in den Abgrund reißen. Wesentlich tückischer sind aber Fehler, die beim Entladen der Dll auftreten. In der Regel werden Kontextmenü-Erweiterungen nur mit dem Explorer getestet. Da der Explorer aber hauptsächlich erst mit dem Herunterfahren von Windows beendet wird und die Dlls während der Laufzeit praktisch nie entladen werden, fallen fehlerhafte Kontextmenü-Erweiterungen hier nicht weiter auf.

Die Symptome beim oben geschilderten Fall lassen darauf schließen, dass die Kontextmenü-Erweiterung vom Nero CoverEditor anscheinend die OLE- bzw. COM-Funktionalität deaktiviert. Alle nicht mehr vorhandenen Funktionen basieren auf OLE bzw. COM. Beim Betrachten der exportierten Funktionen von CoverEdExtension.dll mit der Schnellansicht in SpeedCommander fällt gleich auf, dass die Bibliothek nur die Funktion CoUninitialize verwendet. Der Verweis auf ein dazugehörige CoInitialize fehlt dagegen:

OLE-Exporte von CoverEdExtension.dll

CoInitialize und CoUninitialize werden immer als Sandwich verwendet. Vor der Verwendung von COM-Funktionen in einem Thread muss mit CoInitialize immer erst eine Anmeldung an das COM-System erfolgen. Vor dem Beenden des Threads meldet sich dieser mit CoUninitialize wieder ab. Wichtig ist, dass es zu einem CoInitialize immer ein passendes CoUninitialize gibt. COM benutzt intern einen Referenzzähler, so dass innerhalb eines Threads CoInitialize und CoUninitialize auch mehrfach aufgerufen werden können. Erst wenn der Referenzzähler 0 erreicht, wird die Abmeldung vom COM-System endgültig durchgeführt.

Um zu prüfen, ob sich meine Vermutung auch in der Praxis bestätigt, habe ich einen Haltepunkt auf CoUninitialize gesetzt und SpeedCommander im Debugger gestartet. Überraschend war übrigens, wie oft CoUninitialize auch von der Shell aufgerufen wurde, allerdings ging hier wohl immer ein vorheriges CoInitialize voraus. Mit dem Rechtsklick auf eine Nero CoverEditor-Datei (.ncd) wurde auch die CoverEdExtension.dll geladen. Ein paar Sekunden später wurde wieder der Haltepunkt bei CoUninitialize aufgerufen. Im Aufrufstack war eindeutig zu erkennen, dass der Aufruf aus CoverEdExtension.dll kam und während des Entladens einer Dll erfolgte. In einem weiteren Test konnte ich durch einen Haltepunkt auf FreeLibrary erkennen, dass hier das Entladen der CoverEdExtension.dll erfolgte:

OLE32! CoUninitialize@0 address 0x4fedd362
COVEREDEXTENSION! 054c9a71()
NTDLL! LdrpCallInitRoutine@16 + 20 bytes
NTDLL! LdrUnloadDll@4 + 1002 bytes
KERNEL32! FreeLibrary@4 + 21 bytes
OLE32! CClassCache::CDllPathEntry::CFinishObject::Finish(void) + 33 bytes
OLE32! CClassCache::CFinishComposite::Finish(void) + 183736 bytes
OLE32! CClassCache::FreeUnused(unsigned long) + 126 bytes
OLE32! CoFreeUnusedLibrariesEx@8 + 44 bytes
OLE32! CoFreeUnusedLibraries@0 + 9 bytes
AfxOleTermOrFreeLib(int 0, int 0) line 151
AfxUnlockTempMaps(int 1) line 42
CWinThread::OnIdle(long 1) line 712
CWinApp::OnIdle(long 1) line 1012 + 12 bytes
CWinThread::Run() line 617 + 30 bytes
CWinApp::Run() line 898
...

Doch warum ist in diesem Fall nur SpeedCommander so anfällig und nicht auch alle anderen Dateimanager? Der Grund liegt in der Architektur der MFC, auf die SpeedCommander aufgebaut ist. Von Zeit zu Zeit werden in Phasen, in denen die Anwendung nichts zu tun hat und auf Benutzereingaben wartet, nicht mehr benötigte COM-Dlls mit Hilfe der Funktion CoFreeUnusedLibraries freigegeben. Das trifft in diesem Fall auch die CoverEdExtension.dll, die vor dem Entladen leider noch CoUninitialize aufruft. Da aber zuvor kein passendes CoInitialize erfolgte, erreicht der interne Referenzzähler vom COM-System 0 und COM wird für den aktuellen Thread abgemeldet. Der aktuelle Thread ist aber der Hauptthread von SpeedCommander und somit können ab diesem Zeitpunkt keine COM-Funktionen mehr aufgerufen werden.

Wer von diesem Problem betroffen ist, der kann sich also nur damit helfen, die Kontextmenü-Erweiterung von Nero CoverEditor zu deaktivieren. Möglicherweise behebt Nero das Problem auch mit dem nächsten Update.

Es gibt 11 Kommentare zu diesem Beitrag

Trackback URL | RSS-Feed für Kommentare

  1. Kay sagt:

    Eine Funktion die ermittelt ob CoInitialize(Ex) aufgerufen wurde könnte evtl. auch funktionieren:
    //////////////////////////////////////////////////////////////////////////////
    bool CoInitialized()
    {
    void* pv=0;
    return CO_E_NOTINITIALIZED!=CoCreateInstance(GUID_NULL,0,CLSCTX_INPROC_SERVER,IID_NULL,&pv);
    }
    //////////////////////////////////////////////////////////////////////////////

    In OnInitMenuPopup/OnContextMenu könnte dann stehen:
    //////////////////////////////////////////////////////////////////////////////
    if (!CoInitialized())
    CoInitialize(0)
    //////////////////////////////////////////////////////////////////////////////

  2. McDee sagt:

    Hast Du den Fehler bei Nero gemeldet?

  3. Michl sagt:

    Moin Sven,

    ich werde es gleich mal an die entsprechende Stelle forwarden…
    Dann sollte auch was passieren 😉

    Grüße
    Michl

  4. Sven sagt:

    @Kay: Die Prüffunktion ist klasse! Allerdings müsste man dann auch den ganzen SpeedCommander durchgehen, da das Problem ja nicht nur das Kontextmenü betrifft. Es ist aber sicher besser, wenn der Fehler gleich an der richtigen Stelle behoben wird.

    @Michl: Danke Dir! :^

  5. ^^ sagt:

    hab nero auch mal angenervt deswegen 😀

  6. PIGSgrame sagt:

    Sehr interessanter Beitrag! Allerdings hätte ich ein deutlich komplizierteres Problem vermutet – dass die Profis von Nero einen so trivialen Fehler machen und ihn dann vor dem Release noch nichtmal bemerken, wundert mich schon. Abgesehen davon, dass ich für den CoverDesigner nicht sooo dringend eine Kontextmenü-Erweiterung brauche, leider aber keine Option gefunden habe, sie zu deaktivieren.

    Ich hasse es, wenn sich Programme ungefragt ins Kontextmenü (oder woanders hin) einklinken und mir dann keine einfache Möglichkeit geben, das rückgängig zu machen. Wie oft ich schon eine ach so nützliche Erweiterung manuell aus dem HKEY_CLASSES_ROOT geschmissen oder mit ShellExView deaktiviert habe, möchte ich lieber gar nicht wissen – und auch nicht, wie mein Kontextmenü aussähe, wenn ich bisher jeden zusätzlichen Menüeintrag stehengelassen hätte…

  7. Luke sagt:

    Naja, die “Profis” von Nero 😉 Jetzt kommt dann sicher ein 800MB Update für 3 Zeilen Kot. 😀

  8. Michl sagt:

    Hi Sven,

    is gefixt und sollte im nächsten Web-Release drin sein 😉 Merci für den Hinweiß!!

    Grüßle
    Michl

    @PIGSgrame:
    jo, die Profis von Nero können leider nicht immer alle Applikationen mit allen Applikationen testen… manchmal herrscht halt auch dort a bissl Zeitdruck… 😀 hab ich gehört… soll vorkommen 😉

    @Luke: für Dich werden sie eines mit über 1 GB machen… cool oder? 😀

  9. Malachit sagt:

    Ich hab seit dem letzten Nero Update neben dem oben genannten, das Problem, das der U3 Stick nicht mehr sauber läuft, hat da jemand vielleicht ähnliche Erfahrungen?

  10. Sven sagt:

    @Michl: Danke fürs Fixen. :^

  11. thomas sagt:

    wann kommt das update denn raus? vielleicht kommt hier einer noch den nero home bug auf die spur welches bei mir ständig abgeschmiert ist obwohl es nicht installiert war und den sc immer wieder mitgerissen hat. nero deinstalliert und sc funktioniert.

    konnte zwar files ausschneiden aber nicht woanders einfügen und schon kam das nette “ich sende an ms” feature zum vorschein.

    ob das zusammenhängt?

Top