Dll LoadLibrary()
-
Hallo zusammen,
ich habe eine Dialog Applikation mit einer DLL erstellt.
Befindet sich meine DLL nicht im App Ordner so wird ein starten der App durch Windows selber mit der Meldung "Dll xxx konnte nicht gefunden werden" beendet.Wie kann ich das abschalten und die DLL selber mit LoadLibrary laden?
-
naja halt LoadLibrary benutzen^^. In der MSDN gibst ein schönes Beispiel dazu.
Du könntest z.B. im Konstrukor deines Dialoges die DLL laden und im Destruktor wieder freigeben. Anhand der Handle-Rückgabe weist du ja, obs geklappt hat oder nicht.
Dann brauchst du natürlich Funktionszeiger, um an die Funktionen in der DLL heranzukommen.
-
Die DLL sollte aber nur "einfache" Funktionen exportieren und keine Klassen... (dafür ist das LoadLibrary/GetProcAddress nicht vorgesehen; es gibt zwar ansätze dies zu machen aber eine 100%ig Lösung hab ich noch nicht gefunden).
-
Hallo, ich habe mich jetzt auch erstmals mit LoadLibrary befasst.
Ich habe jetzt eine Funktion aufrufen können die innerhalb meiner
DLL liegt, aber wie kann ich z.B. einen CString zur Verarbeitung
an meine DLL übergeben?In meiner MFC-EXE:
FARPROC pFunc; HMODULE hMod = LoadLibrary("beispiel.dll"); pFunc = GetProcAddress(hMod, "testfunktion"); //???? (*pFunc)();
In meiner MFC-DLL:
__declspec (dllexport) CString testfunktion(CString master) { CString hellodll; hellodll=master; MessageBox(NULL, hellodll, "der übergeben wert lautet",MB_OK); return hellodll; }
In der DLL scheint ja alles zu stimmen oder?
Ich muss doch aber der EXE nun noch sagen welchen CString
sie an die Funktion "testfunktion" übergeben soll.
Und genau da komme ich nicht weiter.
Soll ich da etwas wie testfunktion(\"meinstring\") reinschreiben?
Ist doch auch unfug oder?
-
bekomme immer von GetProcAdress NULL zurück :-(. Ohne dieses Load Library geraffel kann ich über die Header Datei und der Lib darauf zu greifen.
DLL.h
#define DLLEXPORT __declspec(dllexport) DLLEXPORT bool test( void );
DLL.cpp
bool test( void ) { return true; }
App.cpp
typedef bool (*DllTest) ( void ); DllTest TheProc; HINSTANCE hInst = AfxLoadLibrary((LPCTSTR) "My.dll"); if( hInst != NULL ) { // Gibt immer NULL zurück :-( TheProc = (DllTest)GetProcAddress( hInst, "test" ); }
-
@TimTulpe: Schau doch mal bitte mittels dependecy walkter (http://www.dependencywalker.com/) wie der Namen der Funktion in der DLL wirklich heisst. So wie es ausschaust verwendest Du C++ und da wird ein dekorierter Name in die DLL geschrieben. Ich würde Dir empfehlen: Mach die Funktion als
extern "C"
.
@Snudo: Du musst natürlich den Pointer auf die Funktion, welche Du mit GetProcAddress holst genauso machen wie die, welche Du exportierst:
typedef CString (*tTestFunktion)(CString master); tTestfunktion pTestFunktion = (tTestFunktion) GetProcAddres(...);
Ich Rate Dir aber dazu: Verwende einfache Schnittstellen (also hier kein CString, sondern LPCTSTR und einen Buffer der Du noch (mit größe) übergibst für den Rückgabewert). Wenn Du CRT oder MFC/ATL Sachen von der EXE in die DLL gibst um sie dort zu ändern (oder anders herum), dann *musst* Du in beiden Projekten die sharead CRT/MFC verwenden, da dies sonst nicht geht!
-
@Jochen Kalmbach:
Hi ich habe da doch erhebliche VerständnisproblemeBislang funktionierte der beschriebene Aufruf ganz gut.
Allerdings habe ich halt noch nie einen Wert aus der
Anwendung in die DLL zur Berechnung o.ä. übergeben.Deine Zeile:
typedef CString (*tTestFunktion)(CString master);
Entspricht doch im Grunde meiner, die ich in der .h der
DLL angelegt habe, oder?#define PLUG_API __declspec(dllexport) Extern "C" PLUG_API CString (testfunktion)(CString master);
Warum ist es dann über den gezeigten Codeausschnitt nicht möglich
mittels dem definiertenpFunc = GetProcAddress(hMod, "testfunktion");//Zuweisung der Funktion (*pFunc)();//Aufruf der Funktion,hier für void ohne Werte
einen Wert einzubinden? Praktisch so wie ich es in meinem normalen
Projekt innerhalb einer Klasse auch machen würde:zurufendefunktion("meinstring");
Die Kommunikation mit einer DLL rüttelt an meinem Weltbild
-
Snudo schrieb:
Deine Zeile:
typedef CString (*tTestFunktion)(CString master);
Entspricht doch im Grunde meiner, die ich in der .h der
DLL angelegt habe, oder?
#define PLUG_API __declspec(dllexport) Extern "C" PLUG_API CString (testfunktion)(CString master);
Ja, sonst würde es ja gar nicht gehen...
Snudo schrieb:
Warum ist es dann über den gezeigten Codeausschnitt nicht möglich mittels dem definierten
pFunc = GetProcAddress(hMod, "testfunktion");//Zuweisung der Funktion (*pFunc)();//Aufruf der Funktion,hier für void ohne Werte
einen Wert einzubinden?
Du definierst ja die "pFunc" ohne Parameter, warum solltest Du dann einen übergeben können?
Mach es so wie ich es gezeigt habe...
-
Ok, ich habe den Teil für den Aufruf jetzt so eingebunden.
Allerdings stellt sich mir nun noch die Frage, wie ich im Vorweg
prüfen kann, ob die DLL da ist bzw. die zu rufende Funktion in
dieser DLL überhaupt vorhanden ist.typedef CString (*tTestFunktion)(CString master); tTestFunktion pTestFunktion = (tTestFunktion) GetProcAddress(hMod,"test"); CString jux="hallo welt!!!"; pTestFunktion(jux)
-
Wenn LoadLibrary fehlschlägt (also NULL zurückliefert) ist die DLL nicht da und wenn GetProcAddress NULL zurückliefert hat er die Funktion nicht gefunden (aber ein wenig Doku könntest Du schon selber lesen!)
-
Aller best. Da hast du recht
-
Ich habe wie Snudo vor mit meinem Plugin System ein String rein verarbeiten und dan n geb ich nen String zurück
Original habe ich in meinem Sourcecode folgendes
webserverdlg.h
typedef int (*PFUNC)(void); //fürs Plugin-System
webserverdlg.cpp
// ************ for debug only ...... if(m_dwa2.count("plug1.plx")==TRUE) { //Find a function and use it PFUNC pFunc = (PFUNC)GetProcAddress((HINSTANCE)m_dwa2["plug1.plx"], _T("fnPlug1")); if (pFunc != NULL) { int n = pFunc(); CString answer ; answer.Format("Das Plugin antwortet mit %d", n); MessageBox(answer); } } //PLUGIN System ENDE.............................
das würde ich abändern zu
webserverdlg.h
typedef CString (*PFUNC)(CString master); //fürs Plugin-System
webserverdlg.cpp
// ************ for debug only ...... if(m_dwa2.count("plug1.plx")==TRUE) { //Find a function and use it PFUNC pFunc = (PFUNC) GetProcAddress((HINSTANCE)m_dwa2["plug1.plx"], _T("fnPlug1")); if (pFunc != NULL) { CString parameter="viewtopic.html"; CString answer = pFunc(parameter); MessageBox(answer); }
}
und die dll selbst hätte ich folgende änderungen vorgenommen
wobei mich vorallem interessiert warum bei eurem code "fnPlug1" in Klammern steht und bei mir nichtplug1.h
extern "C" PLUG1_API int fnPlug1(void);
plug1.cpp
PLUG1_API int fnPlug1(void)
abgeändert zu
plug1.h
extern "C" PLUG1_API CString (fnPlug1)(CString master);
plug1.cpp
PLUG1_API CString (fnPlug1)(CString master)
-
Und wo ist jetzt die Frage?
PS: Du musst dann aber die shared CRT/MFC verwenden!
-
also funktionieren tats der originalcode schon original bekamm ich bei der dll einfach ne zahl zurück um zu sehen obs läuft
wollte erstens einfach wissen ob ich das so richtig verstanden hatte
weil ich z.b. nicht verstehe warum bei mir
extern "C" PLUG1_API int fnPlug1(void);
und bei euch
extern "C" PLUG1_API int (fnPlug1)(void);
stehen würde
geschweige denn wo bei mir das "_T" in
PFUNC pFunc = (PFUNC)GetProcAddress((HINSTANCE)m_dwa2["plug1.plx"], _T("fnPlug1"));
herkommt
und aufgrund der unterschiede wollt ich fragen obs richtig ist kann es leider nicht testen da der code noch von der Sourcecodeverwaltung gesperrt ist weil nen Kumpel mir hilft nen anderes Problem zu finden
-
Skippy schrieb:
weil ich z.b. nicht verstehe warum bei mir
extern "C" PLUG1_API int fnPlug1(void);
und bei euch
extern "C" PLUG1_API int (fnPlug1)(void);
stehen würde
Da hast Du was falsch verstanden...
Das was Du hier machst ist eine Funktion in die DLL exportieren.
Wenn Du diese Funktion nun via GetProcAddress verwenden willst, dann benötigst Du noch eine separate deklaration der Funktion (also in meinem Beispiel mit "typedef ...").Skippy schrieb:
geschweige denn wo bei mir das "_T" in
PFUNC pFunc = (PFUNC)GetProcAddress((HINSTANCE)m_dwa2["plug1.plx"], _T("fnPlug1"));
herkommt
Das _T wird dazu verwendet dass man mit dem gleichen Source einmal für ANSI und auch für UNICODE compilieren kann. Es ist einfach ein Makro entweder auf *nix* oder auf L(x). Drück doch einfach mal F12, dann siehst Du es...
-
ich hab das Plugin nun Versucht zu ändern und zu Kompilieren
extern "C" PLUG1_API CString fnPlug1(CString master);
aber ich bekomme jetzt fehlermeldungen
error C2146: Syntaxfehler: Fehlendes ';' vor Bezeichner 'fnPlug1'
error C2146: Syntaxfehler: Fehlendes ')' vor Bezeichner 'master'
error C2501: 'fnPlug1': Fehlende Speicherklasse oder Typspezifiziererkönnt des was mit CString zu tun haben fehlt vielleicht nen include?
habe nur die #include <windows.h> ioncludiert und wenn ja welche fehlt denn oder was muss andernfalls ändern
-
Irgendwas von den MFC Headern brauchst Du natürlich noch!
Z.B afx.h (hab die Hilfe aber auf meinem PDA gerade nicht zur Hand)
-
hast recht hab das grad eben gelesen die beispiel dll verwendet keine MFC
also klappt das gar net oder??
hab aber noch ein anderes beispiel was die MFC verwendet mal sehen obs klappt
-
wenn du MFC-KLassen benutzt, vergiss nicht das Makro in die Exportfunktionen am Anfang zu schreiben/kopieren, was nötig ist. Steht in dem Kommentar der CPP-Datei zur DLL, wwnn du ein DLL-Projekt mit dem Assistenten anlegst.
-
Vielen Dank Jochen, das war es.
Ein Problem hab ich aber noch. Die exportierten Funktionen haben laut Dependency Walker alle den richtigen Namen bis auf meine CALLBACK funktionen.
Alle diese Funtkionen haben ein "_" vor dem Namen. Kann ich den auch weg bekommen ?
-
Hm also Klassen Exportieren geht auch. Ich mach das in meinem 3D Editor so um die 3D Engine vom Editor zu trennen.
Mal ne kleine Erklärung ie ich das machen:
Ich erstelle eine LIB und eine DLL.
In die Lib kommt eine Interfaceklasse. In die DLL kommt eine von der Interfaceklasse abgeleitete Version.Nun exportiere ich zwei Funktionen aus der DLL die ich immer gleich nenne. In einer Funktion instanziere ich Dynamisch ein Objekt der abgeleiteten Klasse und gib ein gecasteten Zeiger in den Typ der Interfaceklasse zurück. Dadurch erhalte ich dann den Zugriff.
Die zweite Funktion löscht einfach die Instanz des Objekts wieder.