Verwendung von __declspec(dllimport)
-
Hallo,
ich habe bisher immer DEF-Files benutzt, um Funktionen aus einer DLL zu exportieren.
Nun habe ich versucht selbiges mit dem
__declspec(dllexport)
-Schlüsselwort zu tun.
Das ganze sieht (beispielhaft) so aus:
// DLL.h #ifdef DLL_EXPORTS #define DLL_API __declspec(dllexport) #else #define DLL_API __declspec(dllimport) #endif DLL_API VOID MyFunc(int, int) {};
Diese Funktion möchte ich nun in meinem Program aufrufen:
// main.cpp char* lpDLLPath = "DLL PATH"; HMODULE hDLL = LoadLibrary(lpDLLPath); __try { LP_MY_FUNC lpMyFunc = reinterpret_cast<LP_MY_FUNC>(GetProcAddress(hDLL, "MyFunc")); lpMyFunc(77, 99); } __finally { FreeLibrary(hDLL); }
Nur leider ist lpMyFunc "NULL". Wenn ich wieder mein Modul Definitions File benutze, funktioniert es ...
Wie genau benutzt man
__declspec(dllexport)
also? Danke für die Hilfe, schon mal im voraus.
-
Willst du die DLL denn wirklich dynamisch laden?
Wenn nicht: einfach Header-File inkludieren, und die Funktion aufrufen. Und mit dem .LIB File der DLL linken -> fertig.Ansonsten brauchst du den "Decorated Name" der Funktion.
Oder du könntest die Funktion natürlich als
extern "C"
deklarieren.// DLL.h #ifdef DLL_EXPORTS #define DLL_API __declspec(dllexport) #else #define DLL_API __declspec(dllimport) #endif extern "C" { DLL_API VOID MyFunc(int, int) {}; // ... weitere exportierte funktionen ... } // extern "C"
Wenn ich mich richtig erinnere müsste dann "MyFunc" als name passen. (Wenn "MyFunc" nicht geht, probier "_MyFunc")
-
hustbaer schrieb:
Wenn ich mich richtig erinnere müsste dann "MyFunc" als name passen. (Wenn "MyFunc" nicht geht, probier "_MyFunc")
Danke für die Hilfe. Ich habe noch nie mit __declspec(dllimport/dllexport) gearbeitet. Ich werde es dann aber gleich mal ausprobieren.
Darf ich auch noch fragen, warum sich dass bei dem DEF-File anders verhält?
EDIT:
Okay, ich habe es nun als extern "C" in der DLL deklariert ... kein Erfolg. Immer noch liefert GetProcAddress NULL zurück. Auch mit dem Underscore davor.Woran kann dass noch liegen?
-
FrEEzE2046 schrieb:
ich habe bisher immer DEF-Files benutzt, um Funktionen aus einer DLL zu exportieren.
Sehr gut! Warum willst Du davon weg?
FrEEzE2046 schrieb:
Nun habe ich versucht selbiges mit dem
__declspec(dllexport)
-Schlüsselwort zu tun
....
Nur leider ist lpMyFunc "NULL".Das ist so korrekt. Du solltest Dir mal die erzeugte DLL mit www.dependencywalker.com anschauen... dann siehst Du auch warum
Ganz einfach: Das "Name-Mangeling" ist anders... wenn Du es via DEF-File machst, dann wird genau der Namen exportiert den Du angegeben hast. Per dllexport sieht der Namen anders aus... wenn Du zusätzlich extern "C" verwendest, sieht er zwar immerhin besser aus, aber auch nicht so wie Du willst...
Also mein Tipp: Wenn Du Funktionen via "String-Name" ansprechen willst/musst, dann kommst Du um eine DEF-Datei nicht drum rum.
Nur: Warum willst Du das? Verwendet doch die Import-Lib...
-
Also,
ich will eigentlich gar nicht davon weg. Ich wollte mir nur die Funktion von __declspec(dllexport) anschauen und wissen wie es funktioniert.
Welcher Vorteil liegt denn dann überhaupt bei der Verwendung davon? Es muss doch einen Grund geben, warum man es anstatt des DEF-Files benutzt.
-
Es ist einfacher, da Du nicht zwei Dinge Pflegen musst (Source-Code und DEF-Datei). Macht aber, wie Du gesehen hast, nur Sinn, wenn Du auch die Import-Lib verwendest
Und Du kannst auch ganze Klassen exportieren, ohne dass Du Dir den Finger brichst...
-
Jochen Kalmbach schrieb:
Es ist einfacher, da Du nicht zwei Dinge Pflegen musst (Source-Code und DEF-Datei). Macht aber, wie Du gesehen hast, nur Sinn, wenn Du auch die Import-Lib verwendest
Und Du kannst auch ganze Klassen exportieren, ohne dass Du Dir den Finger brichst...
Okay, dass ist natürlich logisch und ein Grund. Vielen Dank.
-
Hier mal ein kleines Beispiel:
Du hast bespielsweise eine Klasse für Physikberechnungen. Diese soll in eine DLL ausgelagert werden. Später soll ein Programm diese Klasse benutzen können.Also erstmal Header schreiben.
//Physic.h #pragma once //Klasse in DLL exportieren #ifdef PHYSIC_EXPORTS #define PHYSIC_API __declspec(dllexport) #else #define PHYSIC_API __declspec(dllimport) #pragma comment(lib, "Physic.dll") //<- Linkt das Programm automatisch mit der Lib, um die DLL bei der Ausführung zu laden #endif //Klasse für Physikberechnungen class PHYSIC_API CollisionsTester { private: //Liste aller Objekte, die kollidieren können std::list<BasePhysicObject>* pObjectList; public: //Init und Exit CollisionsTester(); ~CollisionsTester(); //Bewegen und auf Kollision testen void Update(); //Neues Objekt hinzufügen void AddObject(BasePhysicObject* pNewObject); } //Singleton Collisionstester erstellen //So wird es zwar eigentlich nicht gemacht, aber so exportiert man Funktionen in DLLs CollosionsTester* PHYSIC_API GetSingletonCollisionsTester();
Dazu noch die passende Implementierung
//Physic.cpp #include"Physic.h" CollosionsTester::CollosionsTester() { pObjectList= new std::list<BasePhysicObject>; //... //Was ein Konstruktor eben so macht ;) } CollosionsTester::~CollosionsTester() { delete pObjectList; //... //Was ein Destruktor eben so macht ;) } void CollosionsTester::Update() { //... } void CollosionsTester::AddObject(BasePhysicObject* pNewObject) { //... } CollosionsTester* PHYSIC_API GetSingletonCollisionsTester() { static CollisionsTester TheOnlyOne; return(&TheOnlyOne); }
Alles kompilieren und zur DLL linken.
Jetzt brauchen wir nur noch das Programm, welches die DLL benutzen soll.
Dafür kopiert man die entstandene DLL und die gleichnamige Lib und die Header in den Ordner des Programms, welches die DLL benutzen soll.Das sieht dann so aus:
//Main.h #include"Physic.h" //Das wars, mehr muss dann vom Programm nicht mehr gemacht werden, um die DLL zu laden int main() { //... CollisionsTester* pTester= GetSingletonCollisionsTester(); BasePhysicObject* pBox1, pMesh2; //Box und Mesh sind von BasePhysicObject abgeleitet pBox1= new Box(Position1, Velocity1, Rotation1, RotationVelocity1); pMesh2= new Mesh(Vertices2, Indices2, Position2, Velocity2, Rotation2, RotationVelocity2); //... pTester->AddObject(pBox1); pTester->AddObject(pMesh2); //... pTester->Update(); //... delete pBox1; delete pMesh2; return(0); }
Das wars eigntlich.
Wenn du dich noch mehr dafür interessierst, such bei google nach DLL Tutorial C++, da findest du massig
-
Ich muss den Thread nochmal aus der Versenkung holen. Ich habe jetzt mal folgende Beispielimplementation gemacht:
//C++Library.h #ifndef _CLIBRARY_H_ #define _CLIBRARY_H_ #ifdef CLIBRARY_EXPORTS # define CLIBRARY_API __declspec(dllexport) #else # define CLIBRARY_API __declspec(dllimport) #endif extern "C" { CLIBRARY_API unsigned long ShowMessage( const char* // message ); } #endif
//C++Library.cpp // C++Library.cpp : Defines the exported functions for the DLL application. // #include "stdafx.h" ULONG ShowMessage(LPCSTR lpszMessage) { MessageBox(NULL, lpszMessage, "Message", 0); return strlen(lpszMessage); }
Ich möchte die Funktion nun in einem anderen Projekt benutzen:
//main.cpp #pragma comment( lib, "..\\..\\C++Library\\Release\\C++Library.lib" ) #include <iostream> #include "..\\..\\C++Library\\C++Library\\C++Library.h" using namespace std; int main( int argc, char** argv ) { cout << ShowMessage("Dies ist ein Test") << endl; return 0; }
Da bekomme ich nur die Nachricht:
Error 1 error LNK2019: unresolved external symbol "__declspec(dllimport) unsigned long __cdecl ShowMessage(char const *)" (__imp_?ShowMessage@@YAKPBD@Z) referenced in function _main main.obj
Wenn ich die Headerinkludierung weglasse und folgende Deklaration in main.cpp implementiere, dann geht es:
//extern unsigned long ShowMessage(const char*);
1. Was ist oben der Fehler? Warum unresolved external symbol?
2. Warum geht es, wenn ich die Funktion neu deklariere? Und muss ich da extern angeben?Wenn Ihr mir weiterhelfen könntet, wäre das echt super. Danke im voraus.
-
zuersteinmal wäre es sinnvoll wenn die library.cpp auch die library.h einbindet
-
eingebundener einband schrieb:
zuersteinmal wäre es sinnvoll wenn die library.cpp auch die library.h einbindet
oh weia ...