[VC++ Debug] Fehler beim verlassen einer Fkt.



  • Der Fehler kann (min.) drei Gründe haben:
    - Falsche calling Convention
    - Speicherüberschreiber
    - Verwenden eines ungültigen Zeigers



  • Der Fehler scheint bei der Zerstörung der Fkt.-Parameter zu entstehen:

    // dll header
    MY_DLL	bool C_CALL	myLoad(const std::string filename);
    

    Wenn ich den Callstack weiter runtergehe, treffe ich irgendwann auf den basic_string - Destruktor.

    > msvcp80d.dll!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::~basic_string<char,std::char_traits<char>,std::allocator<char> >() Line 878 C++

    Innerhalb der DLL-Fkt. reiche ich den Anruf nur an eine Klasse weiter:

    bool myLoad(const std::string filename)
    {
    	bool res = singleton().load(filename);
    
    	// hier kommt jetzt der Fehler ..
    	return res;
    }
    

    Diese Memberfkt. arbeitet jetzt mit einer Referenz:

    bool	load(const std::string&  filename);
    

    Hilft das weiter?



  • Deine DLL und die EXE müssen aber die DLL-Version der CRT verwenden!!! Und auch noch extakt die gleiche (also vom gleichen Compiler erstellt; sonst geht das soweiso nicht, da sonst unterschiedliche Hepas verwendet werden!



  • Danke, das war's. 🙂

    Bei den Projekteinstellungen hat sich die 'runtime library' unterschieden. Jetzt läuft's prima. Bei dem anderen korrekten Projekt war die Einstellung richtig.

    Gruß,
    don_basto.

    <edit> btw: Bedeutet das, dass man aus VB, C#, etc. die DLL nicht benutzen kann? </edit>



  • don_basto schrieb:

    Bedeutet das, dass man aus VB, C#, etc. die DLL nicht benutzen kann?

    Wenn Du kein VB/C+ hast, hat es für Dich keine Bedeutung...
    Aus VB.NET/C# kann man halt nur C-Funktionen aus DLLs aufrufen (oder COM).



  • also wenn ich meinem Dll-Header die Makros auflöse, steht da folgendes:

    // so steht's im Header
    extern "C" __declspec(dllexport) bool __cdecl myLoad(std::string filename);
    
    // richtiger C-Stil ???
    extern "C" __declspec(dllexport) bool __cdecl myLoad(const char* filename);
    

    Das einzigste, was nicht C ist, ist der namespace (std) und vermutlich der String-Typ.

    Hätte ich die Aufrufprobleme nicht mit dem 2. Fkt.-deklaration gehabt?



  • don_basto schrieb:

    Hätte ich die Aufrufprobleme nicht mit dem 2. Fkt.-deklaration gehabt?

    fast 100%iger Treffer... (bool würde ich noch durch BOOL ersetzen und noch stdcall verwenden...)



  • Jochen Kalmbach schrieb:

    fast 100%iger Treffer... (bool würde ich noch durch BOOL ersetzen und noch stdcall verwenden...)

    Hehe. War geraten. 😃

    Hab von normalem C keine Ahnung. Hast du einen Link, wo die Regeln für eine saubere C-Schnittstelle zur DLL-Programmierung zu finden sind?



  • // besserer C-Stil ???
    extern "C" __declspec(dllexport) int __cdecl myLoad(const char* filename);
    

    Das MSDN sagt, das C kein bool kennt, also muss es raus.
    Aber __cdecl ist laut MSDN die Standardkovention für C und C++, warum sollte es durch __stdcall ersetzt werden?



  • don_basto schrieb:

    Aber __cdecl ist laut MSDN die Standardkovention für C und C++, warum sollte es durch __stdcall ersetzt werden?

    Ist nicht unbedingt notwendig... aber z.B. VB6 Applikationen können nur stdcall Funktionen aufrufen... und die gesamte WinAPI ist stdcall...



  • Muss nochmal den Thread herausholen, da ich wieder das gleiche Problem habe. Also beim Verlassen der DLL-Funktion kommt wieder dieser Heap-Fehler.

    Ich habe unter Properties->Code Generation->Runtime Library von MT-Dll auf MT umgestellt, damit die DLLs auf anderen Rechnern starten. Nach der Umstellung, tun sie das auch, aber nun kommt wieder dieser Fehler. 😞

    Diesmal es stimmen die Aufrufkonventionen(__cdecl) und Runtime Library ist auch identisch.

    Woran kann's noch liegen?

    <edit>
    Also ich hab ein Dll-Funktion folgendermaßen deklariert:

    MY_DLL	void C_CALL myTest(const std::string test);
    

    Wenn ich dies jetzt mit /MD kompiliere, kann ich es aufrufen und verwenden. Wenn ich es mit /MT kompiliere, ist bei der Zerstörung des Strings Schluss. Und zwar genau dann, wenn der String 16 oder mehr Zeichen besitzt. 😮

    Wenn ich auf den String verzichte, klappt's.

    My_DLL	void C_CALL myTest(const char* test);
    

    Was geht da in den Tiefen des Systems vor sich?
    Warum erscheint der Fehler nur bei /MT?
    Wieso sind Strings bis 15 Zeichen akzeptabel?

    Ich hab keine Ahnung, ihr vielleicht? 🙂
    </edit>



  • Hatten wir das nicht schonmal???

    Wenn Du STL/MFC/ATL in Deiner DLL-Schnittstelle verwendest, dann musst Du die DLL-Version der CRT verwenden!!! Und alle Programme die diese DLL verwenden müssen mit den gleichen Compiler Settings für die CRT übersetzt werden (und natürlich den gleichen Compiler).



  • Das dass für die STL gilt, wusste ich noch nicht. Macht aber Sinn, wenn jeder Compiler die STL auf seine Art implementiert. Allerdings erklärt das mir nicht den Fehler, da beide Projekte mit dem selben Compiler (VC8) und der selben Runtime (/MT) erstellt wurden sind.



  • Ich hatte vergessen das Wort DLL-Version der CRT Fett zu markieren 😉



  • Achso, hatte ich wohl überlesen. 😉

    Und warum eigentlich?



  • Weil sich alle DLLs/EXEn die selber CRT teilen müssen, damit das allokieren/freigeben von Speicher auch korrekt ablaufenkann (da z.B. std::string intern Speicher allokiert/freigibt und Du nicht sagen kannst ob dies in der DLL oder der EXE passiert).
    Das gleiche gilt übrigens auch für "FILE*" und andere CRT Dinge...



  • Danke. Wieder was gelernt. 🙂


Anmelden zum Antworten