Dialog aus statisch gelinkter DLL



  • Hat denn keiner eine Idee?



  • also ich net ...



  • dEUs schrieb:

    also ich net ...

    Also ich schon.

    Das hat was mit dem Heap zu tun 😉

    Wahrscheinlich linken Hauptprogramm und DLL nicht mit der gleich C-Runtime (mindestens einer der beiden Teile wird wohl statisch mit der C-Runtime linken).

    Zur C-Runtime gehören, neben einer Menge Funktionen, auch ein paar globale Variablen. Unter diesen befinden sich auch die Variablen, die den Heap bilden.
    Das heißt, das wenn zwei Programmteile gegen unterschiedliche C-Runtimes linken, dann haben diese beiden Programmteile auch ihren eigenen Heap.
    Der einzige Fall, bei dem die Programmteile mit der gleichen C-Runtime linken, ist der, wenn sowohl Hauptprogramm als auch DLL(s) mit der DLL-Version der C-Runtime linken (und zwar mit der gleichen Version 😉 ). Da die CRT-DLL nur einmal geladen wird, gibt es den Heap auch nur einmal. Sobald einer der beiden Teile (oder auch beide) gegen die statische Version der C-Runtime linkt, haben die beiden Teile getrennte Heaps.

    Mit getrennten Heaps wird einiges schwieriger. Folgendes geht z.B. nicht:
    Eine Funktion in der DLL alloziert speicher mit malloc(), und gibt den Pointer darauf ans Hauptprogramm zurück. Diese ruft irgendwann free() mit diesem Pointer auf. Da der Speicherblock zum Heap der DLL gehört, funktioniert das nicht (wird wahrscheinlich crashen). Das gleiche gilt natürlich auch andersherum, oder zwischen DLLs.

    Schauen wir uns den konkreten Fall an:

    Tag.strArtist      = TagEditor.m_strArtist;
    

    Ich gehe einmal davon aus, daß 'strArtist' eine CString-Variable ist.
    Aufgrund der internen Funktionsweise von CStrings (Reference-Couting), wird hier nicht der String direkt kopiert, sondern nur ein Pointer auf den eigentlichen Daten-Bereich. Und somit haben wir den oben geschilderten Fall: DLL alloziert Speicher und gibt den Pointer an das Hauptprogramm; dieses gibt ihn später frei (wenn der CString zerstört wird).

    Die Lösung:
    Es gibt mehrere Lösungsmöglichkeiten; alle haben ihre Nachteile:

    1. Lasse alle Programmteile mit der DLL-Version der C-Runtime linken. Das erspart dir solchen Ärger.

    2. Der Programmteil, der Speicher alloziert, muß ihn wieder freigeben. Im konkreten Fall könntest du die Zeile so umschreiben:
    [cpp]Tag.strArtist = **(LPCTSTR)**TagEditor.m_strArtist;[/cpp]
    Somit wird ein anderer Konstruktor von Tag.strArtist aufgerufen (CString(LPCTSTR) anstatt CString(const CString&), der sich eine Kopie zieht (und den Speicher dafür selbst alloziert, also im Hauptprogramm).
    Wenn man diesen Weg einschlägt, sollte meine die API der DLL so definieren, daß niemals Objekte zurückgegeben werden, und die DLL den von ihr allozierten Speicher immer selbst löscht.

    Am wenigsten Ärger hast du erfahrungsgemäß, wenn du alle Programmteile mit der DLL-Version der C-Runtime linken läßt.

    - Raving Tux



  • Danke schon mal für den Beitrag.
    Der LPCTSTR Operator hat leider garnichts gebracht. Laut MSDN gibt der mir aber auch nur einen Pointer zurück, und genau das möchte ich doch jetzt nicht, so wie ich dich verstanden habe oder?

    Remarks
    
    This useful casting operator provides an efficient method to access the 
    null-terminated C string contained in a CString object. No characters are copied; 
    only a pointer is returned. Be careful with this operator. If you change a CString
     object after you have obtained the character pointer, you may cause a 
    reallocation of memory that invalidates the pointer.
    

    Das mit der C-Runtime hab ich jetzt noch nicht so ganz verstanden. Was link ich jetzt wie genau?



  • the_alien schrieb:

    Danke schon mal für den Beitrag.
    Der LPCTSTR Operator hat leider garnichts gebracht. Laut MSDN gibt der mir aber auch nur einen Pointer zurück, und genau das möchte ich doch jetzt nicht, so wie ich dich verstanden habe oder?

    Doch, das möchtest du. Das ist auch kein Problem, solange du nur auf den Speicher zugreifst; du darfst ihn nur nicht freigeben. Wenn du diesen LPCTSTR-Pointer einem CString zuweist, dann macht der sich eine Kopie davon; der ursprüngliche CString bleibt aber alleine für seinen Speicher verantwortlich.
    Wenn du CStrings einander zuweist, dann wird nicht kopiert, sonder die beiden teilen sich sozusagen die Verantwortlichkeit für den gleichen Speicherblock (dmait sparen sie sich dauernde Kopien -> effizienter).

    Das mit der C-Runtime hab ich jetzt noch nicht so ganz verstanden. Was link ich jetzt wie genau?

    Du mußt ja mit der C-Runtime linken, damit Funktionen wie malloc(), free(), new-operator und delete-operator (und noch viele andere) verfügbar sind.
    Die C-Runtime gibt es als DLL und als statisch Library. Du kannst das auswählen unter Projekt Settings -> C/C++ -> Code generation -> Use run-time library.

    Jetzt bleibt nur noch herauszufinden, warum es nicht funktioniert.
    Verwende den LPCTSTR-Cast-Operator auch für die Zeilen vor dem DoModal() aufruf. Dort weist du auch CStrings einander zu, nur halt vom Hauptprogramm zur DLL statt andersherum. Das Problem ist aber das gleiche.

    Stelle sicher, daß du definitiv keine CStrings einander direkt zuweist, und probiere es nochmal aus.
    Gib Bescheid, ob es klappt.

    Viel Glück!

    - Raving Tux



  • CId3TagEditor TagEditor ;
    	TagEditor.m_strArtist	  = (LPCTSTR)Tag.strArtist;
    	TagEditor.m_strTitle	  = (LPCTSTR)Tag.strTitle;
    	TagEditor.m_strAlbum	  = (LPCTSTR)Tag.strAlbum;
    	TagEditor.m_strComment	  = (LPCTSTR)Tag.strComment;
    	if(Tag.nGenre >= 0)			TagEditor.m_nGenre			= Tag.nGenre;
    	if(Tag.nYear >= 0)			TagEditor.m_nYear			= Tag.nYear;
    	if(Tag.nTrackInAlbum >= 0)	TagEditor.m_nTrackInAlbum	= Tag.nTrackInAlbum;
    	if(TagEditor.DoModal() == IDOK){
    
    		Tag.strArtist	  = (LPCTSTR)TagEditor.m_strArtist;
    		Tag.strTitle	  = (LPCTSTR)TagEditor.m_strTitle;
    		Tag.strAlbum	  = (LPCTSTR)TagEditor.m_strAlbum;
    		Tag.strComment	  = (LPCTSTR)TagEditor.m_strComment;
    		Tag.nGenre		  = TagEditor.m_nGenre;
    		Tag.nYear		  = TagEditor.m_nYear;
    		Tag.nTrackInAlbum = TagEditor.m_nTrackInAlbum;
    
    	}
    

    Die Funktion sieht jetzt so aus.
    Folgendes lässt sich beobachten:
    -Die Integer Werte funktionieren einwandfrei.
    -Wenn in Tag schon vorher EIN String steht funktioniert es, wenn ich im Dialog nix daran ändere. Wenn mehr als EIN String gegeben ist, dann funktioniert der Dialog auch nicht.
    -Wenn ich String Werte eingebe im Dialog schmiert er auch ab.



  • Erzeuge den TagEditor mal mit new auf dem Heap, statt auf dem Stack.
    Mal schauen, was dann passiert...

    (Ich habe da noch eine Theorie, aber die ist etwas komplizierter. Ich will die nur dann erklären müssen, wenn sie auch zutrifft. Sonst bekomme ich noch Blasen an den Fingern 😉 )



  • Den TagEditor aufm Heap anzulegen hat auch nichts gebracht.

    Zu dem Linker: Alle Teile des Programs sind auf "Debug Multithreaded" gestellt... ist das jetzt das richtige?



  • the_alien schrieb:

    Den TagEditor aufm Heap anzulegen hat auch nichts gebracht.

    Zu dem Linker: Alle Teile des Programs sind auf "Debug Multithreaded" gestellt... ist das jetzt das richtige?

    Stells mal auf 'Debug Mulithreaded DLL'. Dann linkst du mit der DLL-Version der C-Runtime. Dann sollte das Problem (theoretisch) verschwinden.
    Du mußt dann allerdings auch gegen die DLL-Version der MFC linken. Das machst du unter Projekt Settings -> General -> Use MFC in a shared dll.

    Ansonsten weiß ich jetzt auch nicht mehr, woran es liegen könnte. Da würde nur noch debuggen, debuggen und nochmal debuggen helfen.
    Aber vielleicht reicht es ja, auf die DLL-Version der C-Runtime umzustellen.



  • Wenn ich auf die DLL Version der Runtime Linke, dann krieg ich in der DLL die sonst einwandfrei funzt 6 Linker errors mit denen ich nix anfangen kann... solangsam wirds etwas frustrierend.



  • the_alien schrieb:

    Wenn ich auf die DLL Version der Runtime Linke, dann krieg ich in der DLL die sonst einwandfrei funzt 6 Linker errors mit denen ich nix anfangen kann... solangsam wirds etwas frustrierend.

    Du mußt schon etwas spezifischer werden, was die Linker-Fehler betrifft.


Anmelden zum Antworten