[solved] Dynamisch eingebundene DLL schmeißt exceptions.
-
Bei mir funktioniert's:
// DLL class StrategyInterface { public: virtual ~StrategyInterface(){} virtual string getStrategyName() = 0; virtual string getStrategyBrief() = 0; }; class Strategy : public StrategyInterface { public: string getStrategyName() { return "blubb"; } string getStrategyBrief() { return "bla"; } }; #define STRATEGYDLL_API __declspec(dllexport) BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReasonForCall, LPVOID pReserved) { switch(dwReasonForCall) { case DLL_PROCESS_ATTACH: break; case DLL_PROCESS_DETACH: break; } return TRUE; } extern "C" STRATEGYDLL_API Strategy* getClass() { return new Strategy; }// exe class StrategyInterface { public: virtual ~StrategyInterface(){} virtual string getStrategyName() = 0; virtual string getStrategyBrief() = 0; }; typedef StrategyInterface*(__stdcall *getClass)(void); int main() { HMODULE hDLL; getClass fGet; StrategyInterface *cClass; hDLL = LoadLibraryA("VTableTest.dll"); // Funktioniert, hDLL ist nicht null. if(hDLL == NULL) { MessageBoxA(NULL, "Can't load library!", "Error", NULL); } fGet = (getClass)(GetProcAddress(hDLL,"getClass")); // Funktion wird auch gefunden. if(fGet == NULL) { MessageBoxA(NULL, "Can't get process address!", "Error", NULL); } else { StrategyInterface* bla = fGet(); std::cout << bla->getStrategyName() << std::endl; // hier gibt es einen Fehler. } system("pause"); }
-
okay... vielen Dank dafür das du es mal getestet hast!
Du hast zwar nur die vereinfachte Version getestet aber vom Ding her müsste es also funktionieren.
Ich werd das gleich mal auch in der vereinfachten Version testen und dann schauen wo da bei mir der wurm drin ist.
-
Belli schrieb:
MichelRT schrieb:
Belli schrieb:
Er reicht doch da nur Zeiger rum!?
Er reicht einen Zeiger auf ein Interface herum.
Mit dem Zeiger ruft er eine Methode auf -> Bumm.
Da liegt doch die Vermutung nahe, dass das aufrufende Progamm irgendwie das auf das der Zeiger zeigt falsch interpretiert
Deswegen meine Frage nach Compiler und Compilereinstellungen.
Mein Zwischenruf bezog sich auf den Hinweis " keine gute Idee Instanzen von Klassen als Parameter oder Rückgabewerte von Funktionen zu verwenden."
Und mein Einwurf bezog sich auf Methoden und funktionen einer DLL.
Klar darf man sonst Objekte als Parameter oder Rückgabewerte verwenden.
-
Lass mal den
typedef DllClassGetFunctionsehen.
Wenn da nicht so wie im vereinfachten Beispiel von asdfghjklöäqwert der stdcall steht dann ist es logisch dass Du Müll auf dem Stack siehst.
-
Ja, aber er reicht ja keine Instanzen (Objekte) herum, sondern lediglich Zeiger auf solche. Und das sollte meiner Meinung nach auch zwischen Client einer DLL und DLL keine Probleme bereiten.
-
Belli schrieb:
Ja, aber er reicht ja keine Instanzen (Objekte) herum, sondern lediglich Zeiger auf solche. Und das sollte meiner Meinung nach auch zwischen Client einer DLL und DLL keine Probleme bereiten.
Naja, wenn Compiler A den vtable einer Klasse vor das Objekt packt und Compiler B ans Ende und dann in B eine DLL aus A geladen wird und versucht eine virtuelle Funktion aufzurufen....
-
Sollte die V-Table nicht immer am selben Ort sein? Steht doch bestimmt in der Spezifikation, sonst hätte man das Problem unnötiger weiße bei anderen Versuchen Libs einzubinden ja auch.
-
Mr.Long schrieb:
Sollte die V-Table nicht immer am selben Ort sein? Steht doch bestimmt in der Spezifikation, sonst hätte man das Problem unnötiger weiße bei anderen Versuchen Libs einzubinden ja auch.
Soweit ich weis hat C++ keine einheitliche ABI, Microsoft hat allerdings durch COM einen quasi - Standard etabliert (also nicht für die komplette ABI sondern nur für die v-Table).
floorball
-
Unter was ordnet man dann __stdcall, __fastcall usw. ein?
-
calling conventions, stammt aus C
-
Nathan schrieb:
Belli schrieb:
Ja, aber er reicht ja keine Instanzen (Objekte) herum, sondern lediglich Zeiger auf solche. Und das sollte meiner Meinung nach auch zwischen Client einer DLL und DLL keine Probleme bereiten.
Naja, wenn Compiler A den vtable einer Klasse vor das Objekt packt und Compiler B ans Ende und dann in B eine DLL aus A geladen wird und versucht eine virtuelle Funktion aufzurufen....
Ist das denn wirklich so schwer zu verstehen?
MichelRT schrieb:
Ansonsten ist es keine gute Idee Instanzen von Klassen als Parameter oder Rückgabewerte von Funktionen zu verwenden.
Belli schrieb:
Ja, aber er reicht ja keine Instanzen (Objekte) herum, sondern lediglich Zeiger auf solche.
Was ist daran auszusetzen?
-
Belli schrieb:
Nathan schrieb:
Belli schrieb:
Ja, aber er reicht ja keine Instanzen (Objekte) herum, sondern lediglich Zeiger auf solche. Und das sollte meiner Meinung nach auch zwischen Client einer DLL und DLL keine Probleme bereiten.
Naja, wenn Compiler A den vtable einer Klasse vor das Objekt packt und Compiler B ans Ende und dann in B eine DLL aus A geladen wird und versucht eine virtuelle Funktion aufzurufen....
Ist das denn wirklich so schwer zu verstehen?
Genau dasselbe Problem ist auch mit Pointern...
-
Der sieht tatsächlich genauso aus wie der von ihm.
typedef StrategyInterface*(__stdcall *getClass)(void);
-
@Nathan:
Von verschiedenen Compilern war aber doch erst später die Rede. Zum Zeitpunkt meines Einwurfs hatte MichelRT darauf hingewiesen, dass man keine Objektinstanzen herumreichen soll und ich habe bemerkt, dass der TE das ja auch gar nicht tut.Dass für die DLL und die Anwendung derselbe Compiler verwendet wird, hat der TE auch schon (längst) erklärt:
MichelRT schrieb:
DLL und Dein Programm sind mit demselben Compiler und denselben Einstellungen erstellt?
cl90 schrieb:
Ja. Beide MSVC2012 beide x64 eingestellt.
-
Belli schrieb:
@Nathan:
Von verschiedenen Compilern war aber doch erst später die Rede. Zum Zeitpunkt meines Einwurfs hatte MichelRT darauf hingewiesen, dass man keine Objektinstanzen herumreichen soll und ich habe bemerkt, dass der TE das ja auch gar nicht tut.Ja, aber ich wollte lediglich klar stellen, dass das komplett egal ist, ob es Zeiger oder Instanzen sind.
-
Wie findet denn der Compiler die Adressen der Funktionen aus der DLL nur anhand des Headers?
-
Okay.... Was genau hast du gemacht "asdffdaöshge" ?
bei mir funktioniert dein EXAKTER code nicht. er wirft die gleichen Fehler wie vorher.
Das hier ist der Vollständige ungekürzte Code:
DLL erstellen:
#include <string> #include <Windows.h> using namespace std; // DLL class StrategyInterface { public: virtual ~StrategyInterface(){} virtual string getStrategyName() = 0; virtual string getStrategyBrief() = 0; }; class Strategy : public StrategyInterface { public: string getStrategyName() { return "blubb"; } string getStrategyBrief() { return "bla"; } }; #define STRATEGYDLL_API __declspec(dllexport) BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReasonForCall, LPVOID pReserved) { switch(dwReasonForCall) { case DLL_PROCESS_ATTACH: break; case DLL_PROCESS_DETACH: break; } return TRUE; } extern "C" STRATEGYDLL_API Strategy* getClass() { return new Strategy; }Dll Lesen
#include <string> #include <iostream> #include <Windows.h> using namespace std; // exe class StrategyInterface { public: virtual ~StrategyInterface(){} virtual string getStrategyName() = 0; virtual string getStrategyBrief() = 0; }; typedef StrategyInterface*(__stdcall *getClass)(void); int main() { HMODULE hDLL; getClass fGet; StrategyInterface *cClass; hDLL = LoadLibraryA("D:\\testDll.dll"); // Funktioniert, hDLL ist nicht null. if(hDLL == NULL) { MessageBoxA(NULL, "Can't load library!", "Error", NULL); } fGet = (getClass)(GetProcAddress(hDLL,"getClass")); // Funktion wird auch gefunden. if(fGet == NULL) { MessageBoxA(NULL, "Can't get process address!", "Error", NULL); } else { StrategyInterface* bla = fGet(); std::cout << bla->getStrategyName() << std::endl; // hier gibt es einen Fehler. } system("pause"); }edit:
Getestet mit 32Bit compiler und mit x64. Beide mal wirft er die Exception beim Aufrufen der string Funktion.
vlt wirds langsam relevant was für ein System ich hab...Win7 x64, mit MSVC 2010
edit2:
... in Zwei völlig neuen Projekten funktioniert der Sourcecode.
Ich beginne die Einstellungsfehlersuche
-
Problem vorraussichtlich gefunden.
Ich war mir sicher das ich es getestet hatte, aber irgendwie ist mir bei dem Test wohl ein Fehler unterlaufen.Starte ich Kompiler der dll und Kompiler der exe im debug modus läuft alles glatt. Eine Exceptions etc.
Dll im release und exe im debug führt zu exceptions.Also entweder wirft die Dll jetzt immer noch exceptions welche durch den Release Modus nicht mehr gefangen/angezeigt werden, oder die dlls müssen im selben Mode kompiliert werden.
Ich hoffe zweiteres, denn beide unter Debug, scheint ja super zu funktionieren.
Seltsam aber gar nicht so abwegig...Ich Setze den Thread mal auf solved, aber fals jemand lust hat mir das zu erklären wäre ich da sehr dankbar.
Danke nochmal

Gruß,
Chris