MFC in einer DLL



  • Ob ich eine reguläre DLL bauen will oder nicht, das versuche ich gerade herauszufinden. In erster Linie will ich eine funktionierende DLL schreiben, die nur ein CWnd-abgeleitete Klasse enthält, die dann mittels des DLL-Interface vom ladenden Programm instanziert werden kann.

    1. Klar, das ist Teil des Problems.

    2. Aha, mir war nicht klar, dass ein CWinApp-Objekt in einer DLL unbedingt benötigt ist. Das hatte ich nämlich bis jetzt nirgendwo gelesen. Ich hatte das dann also aus dem erzeugten Standard-Code gelöscht.

    3. Gibt es für diesen Fall nicht das Makro AFX_MANAGE_STATE(AfxGetStaticModuleState()), wenn das Framework schon im ladenden Programm läuft?

    4. Das ist ein Missverständnis. AfxOleInit() wird in meinem Hauptprogramm in InitInstance() aufgerufen, nicht in der DLL. Es ist halt einfach das Problem, dass beim Laden der DLL diese Methode nochmal aufgerufen wird.

    Jetzt heißt es also, dass ich eine Extension-DLL schreiben muss, wenn ich keine Applikations-Klasse in meiner DLL haben will? Dann scheine ich ja die Lösung zu haben. Ich werde mich nochmal in diese Richtung informieren.

    Aber mich wundert es ein wenig, wozu eine DLL mit einer ganzen MFC-Applikation darin gut sein soll?


  • Mod

    Du irrst. CWinApp ist keine ganze Applikation!
    CWinApp ist nur ein Wrapper für CWinThread ist in diesem Fall einfach ein Objekt, dass die Daten der aktuellen MFC Instanz (also Deines DLL Modules) hält.
    Wieso denkst Du das mit CWinApp "viel" verbunden ist. Das Objekt ist gerade mal ein paar 100 Bytes groß. Jeder Thread in der MFC erzeugt ein äquivalentes CWinThread Objekt.

    CWinApp::InitInstance ist in diesem Sinne in einer regulären DLL nichts anderes als ein Wrapper für DllMain (an alle Spezialisten: Ich weiß das der Vergleich hinkt und es Unterschiede gibt).

    Das Löschen des CWinApp Objektes war ein Fehler 😉

    MFC Extension DLLs können nur aus anderen Programmen benutzt werden, die auch MFC Programme sind auch und garantiert die gleiche MFC Version als shared DLL verwenden. Dies ist eine Einschränkung über die Du dir klar sein musst.

    HTH



  • Ich habe meine DLL also jetzt als Extension angelegt. Allerdings tritt jetzt beim Laden der DLL ein anderes Problem auf. Es gibt in einer Header-Datei im ausgeführten Programm eine Deklaration einer Instanz meiner CWinApp-Klasse mittels extern. Und in der dazugehörigen cpp-Datei wird diese dann definiert. Aber wenn ich jetzt die DLL lade, dann gibt es einen Fehler im Konstruktor von CWinApp bei ASSERT(AfxGetThread() == NULL). Der Call-Stack sagt aus, dass wir uns in der DLL befinden. Es wird also beim Laden der DLL von dort aus noch einmal meine globale App-Instanz konstruiert. Wie umgehe ich denn dieses Problem jetzt? Eigentlich ich der Header, in dem das Objekt deklariert wird, vom Code meiner DLL aus gar nicht sichtbar. Ich bin also etwas überrascht, dass so etwas passiert.


  • Mod

    Nein! Eine Extension DLL hat kein CWinApp Objekt. Hast Du das evtl. nicht entfernt?



  • Sorry, da liegt wohl wieder ein Missverständnis vor. Ich habe mein DLL-Projekt mit den entsprechenden Einstellungen komplett neu angelegt, also gibt es da keine Altlasten. Es gibt auch kein CWinApp-Objekt in meiner DLL. Ich sprach von der Instanz der CWinApp-abgeleiteten Klasse in der EXE, die die DLL lädt. Der Fehler tritt beim Laden der DLL auf, weil dieses Objekt erneut konstruiert wird, allerdings aus der DLL heraus (der Call-Stack zeigt den Namen der DLL vor dem Funktionsnamen, nicht den der EXE).


  • Mod

    Das kann nicht sein. Die Extension DLL erzeugt kein CWinApp Objekt und instanziiert auch kein neues.
    Wie sieht der Callstack aus?
    Benutzt Du in einem Konstruktor evtl. schon Objekte, die in der EXE noch nicht instanziiert sind?

    Du kannst nicht gleich ein CWnd Objekt anlegen in einem KOnstruktor einens statischen Objektes, denn InitInstance in der EXE ist evtl. ja nicht abgelaufen...



  • Das Laden der DLLs, bei dem der Absturz erfolgt, wird in der Tat in InitInstance() der EXE gemacht, also bevor InitInstance() fertig ist. Allerdings wird dabei weder ein CWnd-Objekt, noch irgend etwas anderes benutzt, das mit MFC zu tun hat. Außerdem habe ich die Methode zum Testen mal aus InitInstance() herausbewegt, und der Fehler tritt immer noch genau so wie vorher auf.

    Der Callstack sieht in Auszügen so aus:

    mfc80ud.dll!CWinApp::CWinApp(...)
    Plugin.dll!CExeApp::CExeApp(...)
    Plugin.dll!`dynamic initializer for 'theApp''()
    ...
    Plugin.dll!_DllMainCRTStartup(...)
    ...
    Application.exe!PluginLoader::loadPlugins(...)
    Application.exe!CExeApp::InitInstance()
    ...
    

    Dabei ist Plugin.dll die DLL, die geladen werden soll. Application.exe ist das Programm, das die DLL laden soll. CExeApp ist die CWinApp-Klasse in meiner EXE, und theApp ist die Instanz dieser Klasse, von der ich schon sprach. Was eben merkwürdig ist, ist dass dieses Objekt (das sich eigentlich in der EXE befindet) aus der DLL nochmal konstruiert wird.



  • Ich entschuldige mich für den Doppelpost. Ich glaube aber, dass ich die Sache vielleicht ein wenig aufklären kann.

    Das Problem scheint mir nach einiger Recherche mittlerweile folgendes zu sein: Beim Laden der DLL durch die EXE wird (wie im Call Stack zu erkennen ist) das globale CWinApp-Objekt im EXE-Code aus der DLL heraus noch einmal dynamisch initialisiert. Und so wie ich das sehe ist die Lösung des Problems, das zu verhindern.

    Ich kenne allerdings nicht die Ursache für dieses Verhalten. Die DLL sollte mit globalen Objekte der EXE nichts zu tun haben. Ich kann hier nur Vermutungen anstellen und darum bitten, dass jemand mit mehr Wissen vielleicht hilft.

    Mir ist allerdings wieder aufgefallen, dass ich meine gesamte Applikation (also die EXE) auch noch als LIB kompliliere und statisch in die DLL linke, weil es sonst zu nicht aufgelösten externen Symbolen beim Kompilieren der DLL kommt. Ich bin mir nicht sicher, ob das die richtige Vorgehenweise ist. Möglicherweise kommt hierbei das globale Objekt der EXE fälschlicherweise in die DLL?


  • Mod

    Der Callstack zeigt doch eindeutig, dass Du ein Objekt mit dem Namen theApp in Deiner DLL definiert hast.

    Was hast Du denn in einem Deiner Header evtl. stehen?



  • Ich habe in keiner Datei, die zur DLL gehört, theApp definiert. Eine Suche im gesamten DLL-Projekt bringt wie erwartet keine Ergebnisse. Wenn ich außerdem im Call Stack zum Ort des "dynamic initializer" springe, dann komme ich zur Definition von theApp in einer CPP-Datei mit Code für die EXE, der eigentlich nie von der DLL aufgerufen werden soll. So wie ich das sehe, gibt es kein theApp in meiner DLL. Ich weiß nicht, wie die DLL an theApp kommt. Das ist nicht beabsichtigt.


Anmelden zum Antworten