DLL-Fkt wird nicht gefunden... Erfahrungsmangel mit dynamischen Dll's... [gelöst]
-
Hallo Gemeinschaft,
ich lese jetzt schon den ganzen Tag Tutorials und Forumseinträge, aber komme trotzdem nicht zum Ziel... es geht um das dynamische Einbinden einer Dll (was soweit funktioniert) und das Aufrufen einer Dll-Funktion (was nicht klappt):
Die Dll heißt Project2.dll und enthält neben einigen Formularen eine *.cpp (ohne zugehörigen Header), die so aussieht:
//--------------------------------------------------------------------------- #include <vcl.h> #include <windows.h> #pragma hdrstop // weitere #include's // Standard-Hinweis bei dll-Units #pragma argsused int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved) { return 1; } //--------------------------------------------------------------------------- __declspec(dllexport)void FormShow(TComponent* Owner) { //... } //----------------------------------------------------------------------------
FormShow versuche ich nun in meiner Anwendung, nach Einbinden der Dll, aufzurufen:
void __fastcall TFormXYZ::MenuTestClick(TObject *Sender) { typedef void (*pImpFkt)(TComponent *); // Funktionszeigertyp deklarieren HINSTANCE hDllLokal= LoadLibrary("Project2.dll"); // Dll laden AnsiString Funktionsname= "FormShow"; if(hDllLokal){ // Dll wurde geladen: pImpFkt ImportFunktion; // Variable vom Typ "Funktionszeigertyp" deklarieren ImportFunktion= (pImpFkt)GetProcAddress(hDllLokal, Funktionsname.c_str()); // Dll-Funktion zuweisen // ImportFunktion= reinterpret_cast<pImpFkt>(GetProcAddress(hDllLokal, Funktionsname.c_str())); if(ImportFunktion == NULL){ Funktionsname= Funktionsname.Insert("_", 1); ImportFunktion= (pImpFkt)GetProcAddress(hDllLokal, Funktionsname.c_str()); // ImportFunktion= reinterpret_cast<pImpFkt>(GetProcAddress(hDllLokal, Funktionsname.c_str())); } if(ImportFunktion != NULL) ImportFunktion(0); // Dll-Funktion aufrufen else{ Funktionsname= "Dll-Funktion \"" + Funktionsname + "\" nicht gefunden! "; Application->MessageBox(Funktionsname.c_str(), "DLL-Fehler", MB_ICONSTOP); // Meldung, wenn auch zweite Version des Funktionsnamen nicht zum Erfolg geführt hat } FreeLibrary(hDllLokal); // Dll freigeben } } //-----------------------------------------------------------------------------
Der Code wird artig compiliert, aber ich bekomme immer nur die MessageBox mit der Fehlermeldung. Ich habe schon etliches versucht:
* windows.h included
* AnsiString gab es zu Anfang nicht, sondern "FormShow" bzw. "_FormShow" waren direkt in GetProcAddress() eingetragen (wollte nur nicht immer beide Fälle extra testen müssen)
* reinterpret_cast<>()aber Nichts war erfolgreich... wo könnte das Problem liegen?
Bin gespannt auf eure Antworten!
MfG
Edit: [gelöst]-Tag in Thread-Überschrift ergänzt
-
Kolumbus schrieb:
aber Nichts war erfolgreich... wo könnte das Problem liegen?
Öffne die DLL mal mit Dependency Walker, dann siehst du es sofort.
Ein guter Suchbegriff zwecks Vermeidung des Problemes wäre
extern "C"
.
-
Hallo,
bei mir sieht´s in der DLL so aus:#define stdDecl __declspec(dllexport) extern "C" { stdDecl int StartXXX(int ParameterCount, void** Parameters); } int StartXXX(int ParameterCount, void** Parameters) { return 1; }
-
Dependency Walker 2.2 schrieb:
Warning: At least one module has an unresolved import due to a missing export function in a delay-load dependent module.
Das bestätigt also, dass von der Dll Nichts exportiert wird!?
Ich frage mich ganz verzweifelt, wie mein Kollege das getestet hat, wenn die dll nichts exportiert... Muss etwas damit zu tun haben, dass er das dll-Projekt und seine Testanwendung in einer Projektgruppe und die dll statisch eingebunden hat... Kann ihn aber auch nicht fragen, er wird froh sein, dass es bei ihm irgendwie gelaufen ist...
Ich werd's herausfinden!
Also damit die Dll eine Funktion, Variable etc. nach aussen hin sichtbar hat, muss das entsprechende Teil mit "extern "C"" deklariert werden, hab' ich kapiert.
http://old.hki.uni-koeln.de/teach/ss06/PS_C++/tag23/21/kap17.htm schrieb:
Der Abschnitt extern "C" deklariert, daß es sich um einen normalen Funktionsaufruf in C handelt, so daß bei der C++-Namensanalyse nicht der Funktionsname zerrissen wird.
Wirklich viel ist darüber meinerseits noch nicht gefunden worden... aber ich suche weiter!
Danke mal wieder audacia und auch dir Hans-Martin!
Edit:
Builder-Tutorial schrieb:
extern "C" __declspec (dllexport) int AddVals(int x, int y) ) //extern "C" damit keine Ergänzung des Funktionsnamens statt findet.
Lasse sich nur keiner zu genau drüber aus
-
Lies doch bitte mal das hier.
http://bcb-tutorial.c-plusplus.net/DLL_Tutorial/artikel16.html
Vielleicht wird es dann etwas klarer.
-
Oh, da hätte ich diese Information nun wirklich am wenigsten erwartet... Jetzt ist's klar! Vielen Dank
PS: Also kann ich, wenn ich den Funktionsaufruf in der Dll im Orginal kenne, doch theoretisch auch die Funktion mit Parametern über GetProcAddress holen, oder? Statt so
...GetProcAddress(hDllLokal, "_FormShow");
in der Art
...GetProcAddress(hDllLokal, "@FormShow$qTComponent*");
? Da muss es doch irgendeine Systematik geben, wie die Parameterliste umgewandelt wird!?
Is jetzt nur Theorie, aber vielleicht gibts ja mal nen Grund, dass man extern "C" nicht nehmen will / kann!?!
-
Kolumbus schrieb:
Dependency Walker 2.2 schrieb:
Warning: At least one module has an unresolved import due to a missing export function in a delay-load dependent module.
Das bestätigt also, dass von der Dll Nichts exportiert wird!?
Nein, das kannst du getrost ignorieren. Diese Meldung erscheint, weil irgendeine DLL, die von deiner DLL referenziert wird, wiederum eine andere DLL mittels Delay-Loading bindet, die auf deinem System gar nicht existiert. Für eine Standard-C++Builder-Anwendung ergibt sich auf meinem System beispielsweise die Abhängigkeit VCL120.BPL -> SHELL32.DLL -> SHDOCVW.DLL -> MSHTML.DLL -> IEFRAME.DLL -> DWMAPI.DLL. Ich habe Internet Explorer 7 installiert, und dieser bezieht mittels Delay-Loading (d.h., die DLL wird erst geladen, wenn eine ihrer Funktionen aufgerufen wird) die DWMAPI.DLL ein, die aber nur auf Vista existiert. Solange IEFRAME.DLL nie den einen Export aus DWMAPI.DLL aufruft, ist das vollkommen unproblematisch.
Kolumbus schrieb:
Da muss es doch irgendeine Systematik geben, wie die Parameterliste umgewandelt wird!?
Freilich, die gibt es auch. So ziemlich jeder Compilerhersteller hat da seine eigene Variante. (Das ist übrigens einer der zahlreichen Gründe, warum du C++-Code verschiedener Compiler nur über eine C- oder COM-Schnittstelle interagieren lassen kannst.) In der C++Builder-RTL ist der Unmangler auch mitgeliefert; du findest ihn in $(BDS)\source\cpprtl\Source\misc\um.c oder unmangle.c:
/* C++Builder Unmangler Source Code (UM.C, UM.H) This code provides a mechanism for unmangling C++Builder linker names into a user-readable format. It is used by TDUMP, the debugger and the linker (for reporting error messages). This code can also create a standalone executable (by building with -DSTANDALONE), that takes a filename containing a list of mangled names, one per line. The main entrypoint for this code is the function "unmangle". See documentation for that function below. */
Kolumbus schrieb:
Is jetzt nur Theorie, aber vielleicht gibts ja mal nen Grund, dass man extern "C" nicht nehmen will / kann!?!
Die Dekorierung von Namen ist mindestens beim Überladen von Funktionen unerläßlich - nur so kann der Linker verschiedene Überladungen einer Funktion unterscheiden. (Entsprechend kann man auch nicht mehrere
extern "C"
-Funktionen gleichen Namens definieren.) Darüber hinaus müssen ja verschiedene Scopes (Namespaces, in Klassen verschachtelte Funktionen) und z.B. Memberfunktionen verschiedener Instantiierungen von Templates unterscheidbar sein.Praktisch reichen aber für so eine DLL-Schnittstelle ein, zwei Funktionen aus, die man getrost als extern "C" deklarieren kann. Für alles Größere benutzt man entweder statische Bindung an DLLs oder Packages oder (wenn es dynamisch sein muß) virtuelle Funktionen.
-
audacia schrieb:
Kolumbus schrieb:
Dependency Walker 2.2 schrieb:
Warning: At least one module has an unresolved import due to a missing export function in a delay-load dependent module.
Das bestätigt also, dass von der Dll Nichts exportiert wird!?
Nein, das kannst du getrost ignorieren. [...]
Ok, Danke.
audacia schrieb:
Kolumbus schrieb:
Da muss es doch irgendeine Systematik geben, wie die Parameterliste umgewandelt wird!?
Freilich, [...] In der C++Builder-RTL ist der Unmangler auch mitgeliefert; du findest ihn in $(BDS)\source\cpprtl\Source\misc\um.c oder unmangle.c:
Ja, gefunden (ist beim BDS2006 "um.c"). Sieht sogar recht nachvollziehbar aus.
audacia schrieb:
Kolumbus schrieb:
Is jetzt nur Theorie, aber vielleicht gibts ja mal nen Grund, dass man extern "C" nicht nehmen will / kann!?!
[...]Praktisch reichen [...] für so eine DLL-Schnittstelle ein, zwei Funktionen aus, die man getrost als extern "C" deklarieren kann. Für alles Größere benutzt man entweder statische Bindung an DLLs oder Packages oder (wenn es dynamisch sein muß) virtuelle Funktionen.
Praktisch reicht es in meinem Fall tatsächlich aus, eine Funktion mit extern "C" zu deklarieren. Damit wäre die Dll dann erfolgreich dynamisch eingebunden!
Vielen Dank an alle Helfer!