Problem mit ESP (ich glaub heisst extended stack pointer)



  • Hallo. Ich habe folgendes Problem. Ich habe einen Basisklassenpointer, der in einer Dll mit einem anderen Objekt instanziert wird. Dies passiert natürlich über eine Funktionspointer. Anschliessend (der Pointer ist initalisiert) erstelle ich einen Visitor (eine andere klasse) und rufe dann mit meinen basisklassenpointer die methode acceptDowncast mit meiner Visitorinstanz auf. Leider kommt er in diese Methode nicht mal rein sondern meldet:

    Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.

    Naja der Code sieht so aus:

    if (!(hDll = LoadLibraryEx (dllname, NULL, 0)))
    		{
    			*mglog << "Error binding Dll to application's address space" << endl;
    		}
    
    		GUI_PLG gplg = NULL;
    		gplg = (GUI_PLG) GetProcAddress (hDll, "XExport");
    		gplg (hDll, (XComGuiBase**)&ptr_base, ptr_message);
    
    		XComVisitor* tmp = new XComDowncastVisitor ();
    		ptr_base->acceptVisitor (tmp);
    

    GUI_PLG ist dabei der Funktionszeiger (ein typedef) und XExport (...) instanziert meinen basisklassenzeiger (ptr_base).

    Kann mir da einer was zu sagen? Wie gesagt, der Funktionspointer funktioniert und die XExport wird auch noch genauso exakt aufgerufen wie am ersten Tag also daran scheint es nicht zu liegen...

    Gruß Sebastian



  • Dies kommt normal dann vor wenn du beim Exportieren und beim Aurufen unterschiedliche calling-convetion verwendest (sprich __cdecl, __stdcall,...) oder eine unterschiedliche Anzahl an Parameter.

    BTW,
    ist eigentlicher das falsche Forum -> nach WinAPI verschieben



  • wieso falsches forum das hat doch mehr mit c++ als mit winapi zu tun. Das Laden der dll geht ja. Es geht ja nur nicht, wenn ich die letzten beiden zeilen ausführe. Also das Laden der Dll funktioniert, das Aufrufen der Dllfunktion geht auch.



  • Standard C++ kennt keine DLLs 🙄



  • das weiss ich aber trotzdem kennt standart c++ diese fehlermeldung.... und ich wette sie kommt nicht von der dll!



  • Nein, kennt er nicht und doch, der Fehler kommt zu 99,9% von deiner DLL :p Lies mal die Fehlermeldung genau durch:

    Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.

    ScriptGod hat deine Frage eigentlich auch schon beantwortet.

    PS. Standard schreibt man mit d



  • Hmmm,

    nehmen wir mal an, ihr habt recht und es liegt wirklich an der dll. Das wäre das beste, denn ihr könnt euch freuen das das problem weg ist und ich kann mich auch freuen, weil ich habe was gelernt. was muss ich dann machen???

    Also ich nehme mal an meine Klassenmehtoden werden mit __thiscall aufgerufen oder? Ich finde die aussage zwar nett, aber was muss ich da jetzt genau beachten?!



  • was muss es denn sein?

    __thiscall
    __stdcall
    __fastcall
    __declspec

    bzw. was ist denn der unterschied dazwischen?



  • Welche davon ist eigentlicher egal, es sei des es handelt sich um Klassen dann musst du __thiscall verwendent. Es muss nur bei beiden das gleiche sein.

    Die unterscheiden sich in welcher Reihenfolgen die Parameter übergeben werden,ob nach oder vom dem return der Stack aufgeräumt wird usw.



  • naja es handelt sich um eine Klasse. Dann muss ich vor jede Methode __tniscall schreiben? Wieso musste ich das denn bisher nicht machen? Muss ich das nur in deklaration machen oder auch in der Implementierung??

    Gruß Sebastian



  • __thiscall ist nur dann nötig, wenn die Funktionen von Klassen in DLLs sind. Also wenn in deinem Fall z.B. acceptVisitor von der DLL exportiert werden würde.

    schreib einfach mal den typedef von GUI_PLG und die Deklaration in deiner DLL



  • also bei mir ist nur die XComWin32 in der Dll, die instanziert wird! Die Visitorklasse selber ist nicht in der Dll!

    der funktionspointer sieht so aus :

    extern "C" typedef unsigned long (*GUI_PLG) (HINSTANCE hdll, XComGuiBase**, XGuiMessageSystem*);
    
    void XComGuiWin32::acceptVisitor (XComVisitor* tmp)
    {
    	tmp->downcast(this);
    }
    
    extern "C" __declspec (dllexport) void  XExport (HINSTANCE hdll, XComGuiBase** ptr_base, XGuiMessageSystem* ptr_message)
    {
    
    	*ptr_base = new XComGuiWin32 (ptr_message);   
    }
    
    class XComGuiWin32 : public XComGuiBase
    {
    	private:
    		HWND hWindow;             /*window handle*/
    		HWND m_hTree;
    		bool b_keys [256];        /*array of key flags*/
    		XGuiMessageSystem* m_ptr_message;
    		INITCOMMONCONTROLSEX m_comctrl;
    	public:
    		XComGuiWin32 (XGuiMessageSystem* ptr_message);
    		~XComGuiWin32 (void);
    
    		virtual unsigned long executeCommand (void);
    		virtual unsigned long registerPlugin (void);
    		virtual unsigned long unregisterPlugin (void);
    		virtual void* getPluginMethods (void);
    
    		virtual void acceptVisitor (XComVisitor* tmp);
    
    	protected:
    };
    

    so siehts aus (habe einige methoden aus der klassendefinition entfernt die nix damit zu tun haben....

    muss ich jetzt vor die acceptVisitor nen __thiscall machen oder wie oder was?



  • void -> kein Rückgabewert

    extern "C" __declspec (dllexport) void  XExport (HINSTANCE hdll, XComGuiBase** ptr_base, XGuiMessageSystem* ptr_message)
    

    unsigned long -> Rückgabewert

    extern "C" typedef unsigned long (*GUI_PLG) (HINSTANCE hdll, XComGuiBase**, XGuiMessageSystem*);
    

    in diesem Fall brauchst die auch kein extern "C" da du ja nicht mit einer .Lib oder änhlichen die DLL verlinkst. In einem typedef darf auch garkein extern "C" vorkommen.

    extern "C" unsigned long (*GUI_PLG) (HINSTANCE hdll, XComGuiBase**, XGuiMessageSystem*);
    

    so wenn du das statisch linken willst

    typedef unsigned long (*GUI_PLG) (HINSTANCE hdll, XComGuiBase**, XGuiMessageSystem*);
    

    oder so wenn du das dynamisch linken willst (das was du ja in deinem Beispiel machst)

    BTW,
    du hast bei beiden keine calling-convetion angegeben um Probleme zu vermeiden würde ich das bei diesen zwei tun - sprich:

    extern "C" __declspec (dllexport) void __cdecl XExport (HINSTANCE hdll, XComGuiBase** ptr_base, XGuiMessageSystem* ptr_message)
    
    typedef unsigned long (__cdecl *GUI_PLG) (HINSTANCE hdll, XComGuiBase**, XGuiMessageSystem*);
    


  • hehe,

    danke für deinen tipp ich habs jetzt mal nach dem Muster angepasst, das du zuletzt gepostet hast. Leider kommt der Fehler immer noch!

    Was ist da los?



  • Hab gemerkt, dass des hier ja auch falsch ist

    extern "C" __declspec (dllexport) void __cdecl XExport (HINSTANCE hdll, XComGuiBase** ptr_base, XGuiMessageSystem* ptr_message)
    typedef unsigned long (__cdecl *GUI_PLG) (HINSTANCE hdll, XComGuiBase**, XGuiMessageSystem*);
    

    so ist das richtig:

    extern "C" __declspec (dllexport) void __cdecl XExport (HINSTANCE hdll, XComGuiBase** ptr_base, XGuiMessageSystem* ptr_message)
    typedef void (__cdecl *GUI_PLG) (HINSTANCE hdll, XComGuiBase**, XGuiMessageSystem*);
    

    Hast du mal das Programm debugged? Nach welchem Befehl kommt genau dieser Fehler?



  • Ja klar habe ich das, ich sagte auch schon, dass ich mir nicht vorstellen kann dass es an dem funktionspointer lieget, denn:

    Der Aufruf meiner XExport Funktion in der Dll hat immer geklappt und da gab es auch nicht das geringste Problem. Ich konnte auch (zwar von der exe und nicht von der lib wie jetzt) immer die methoden in der klasse der dll aufrufen, dass hat auch immer geklappt.

    Ich wollte jetzt mal so nen visitor da rein bauen, den ich schon getestet habe in einer anderen anwendung. Dort klappt er auch. Nur wenn ich von der lib aus die neue Methode der Klasse aufrufe, bringt er diesen fehler (wie gesagt, der funktionspointer ist zu dem zeitpunkt schon komplett ausgeführt und sollte keinen einfluss mehr darauf haben).

    Achja ich habe noch einen Hinweis bekommen. Wenn ich das Programm mit dem Debugger von VC++ debugge, und eine andere methode aufrufe, kommt kein Fehler mehr, sondern das Programm springt irgendwohin und verliert den Cursor. Das kapiere ich auch nicht so ganz.

    Gruß Sebastian



  • if (!(hDll = LoadLibraryEx (dllname, NULL, 0))) 
            { 
                *mglog << "Error binding Dll to application's address space" << endl; 
            } 
    
            GUI_PLG gplg = NULL; 
            gplg = (GUI_PLG) GetProcAddress (hDll, "XExport"); 
            gplg (hDll, (XComGuiBase**)&ptr_base, ptr_message); 
    
            XComVisitor* tmp = new XComDowncastVisitor (); 
            ptr_base->acceptVisitor (tmp);
    

    bei welcher Zeile genau bekommst du da den Fehler beim Debuggen?

    gibt es die Funktion acceptVisitor auch bei XComGuiBase? Wie ise die deklaration von ptr_base?



  • Ich will auch mit DLLs arbeiten, deshalb einige Fragen:
    Ich soll vor jede Klasse die exportiert werden soll neben __declspec (dllexport)auch noch __thiscall davor schreiben? Und was hat es mit dem __cdel auf sich?

    mfg



  • Steht alles in deiner Doku.



  • Glamdrink schrieb:

    Ich will auch mit DLLs arbeiten, deshalb einige Fragen:
    Ich soll vor jede Klasse die exportiert werden soll neben __declspec (dllexport)auch noch __thiscall davor schreiben? Und was hat es mit dem __cdel auf sich?

    mfg

    __thiscall wird automatisch eingefügt, da dies bei Klasse garnicht anderst geht.
    __cdecl gibt an, dass der Aufrufer den Stack mit den Argumenten füllt und wieder aufräumt, damit man Funktionen mit variablen Parameter benutzen kann.


Anmelden zum Antworten