DLL´s dynamisch verwenden funktioniert nicht



  • Ich habe ein Porblem und zwar will ich eine DLL dynamisch zur Laufzeit in mein Programm laden und dann die Funktionen der DLL verwenden. Das Laden der DLL funktioniert auch einwandfrei, jedoch funktioniert der Funktionsaufruf nicht.

    Ich nutze Microsoft Visual Studio 2013 Express. Beim Debuggen dieses Programms bekomme ich beim Auslesen der Funktionsadresse aus der DLL mit dem Befehl

    GetProcAddress
    

    einen Fehler von Visual Studio angezeigt der so aussieht:

    Ausnahmefehler bei 0x751ECB49 in LoadDLL.exe: 0xC0000005: Zugriffsverletzung beim Ausführen an Position 0x00000000

    Das Problem ist, dass das so sogar bei MSDN funktioniert, nur bei mir nicht. Ich weiß zwar mit der Fehlermeldun etwas anzufangen, jedoch sehe ich keine andere Möglichkeit dynamisch eine DLL zu verwenden.

    Hier ist der Code der DLL:

    #define TEST_API_E __declspec(dllexport)
    #include <Windows.h>
    #include <iostream>
    
    BOOL APIENTRY DllMain(HMODULE hModule,
    	DWORD dwReasonForCall,
    	LPVOID pReserved)
    {
    	switch (dwReasonForCall)
    	{
    	case DLL_PROCESS_ATTACH:
    		std::cout << "Ich wurde geladen!\n";
    		break;
    	case DLL_PROCESS_DETACH:
    		break;
    	}
    
    	return TRUE;
    }
    
    void TEST_API_E Message (int a) {
    	std::cout << "Irgend eine Nachricht!\n\n" << "Übergebener Parameter: " << a << std::endl;
    }
    

    Und der Code der Anwendung zum verwenden der DLL:

    #include <Windows.h>
    #include <iostream>
    
    typedef void (CALLBACK* DLLFunction)(int);
    
    HMODULE hDLL;
    DLLFunction dllFunc;
    
    int main() {
    	hDLL = LoadLibrary(TEXT("TestDLL.dll"));
    	if (hDLL != nullptr) {
    		dllFunc = (DLLFunction(GetProcAddress(hDLL,"Message")));
    			dllFunc(123);
    	}
    	else {
    		std::cout << "Fehler beim Laden der DLL!\n";
    		system("PAUSE");
    		return 1;
    	}
    }
    

    Um das kurz zu erklären:

    hDLL
    

    ist die Instanz der DLL die ich mit

    LoadLibrary
    

    lade.

    dllFunc
    

    ist ein Zeiger auf die Funktion

    Message
    

    in der DLL der mit

    GetProcAddress
    

    initialisiert wird. Und genau da kommt die Fehlermeldung.

    Ich hoffe ihr könnt mir helfen!



  • Bist du sicher, dass die gesuchte Funktion "MEssage" heist?
    Und prüf mal den Rückgabewert von getProcAddress gegen 0...



  • Erstmal:

    void TEST_API_E Message (int a)
    

    Diese Funktion hat normalerweise die Callingconvention "cdecl" während

    typedef void (CALLBACK* DLLFunction)(int);
    

    Die Funktion als "stdcall" aufruft. Kann das das Problem sein ?

    Du scheinst den Code jetzt editiert zu haben, du musst natürlich prüfen ob die Funktion gefunden wurde oder ob die zurückgegebene Adresse null ist.
    Zwecks Umgehung von Problem was das angeht würde ich die Funktion als "extern C" markieren und "cdecl" nutzen. Stichwort "Namedecoration", zumindest hab ich mit Funktionen die als "stdcall" markiert sind jedesmal Probleme mit dem Namemangeling.



  • Es ist uebrigens nicht gerade hilfreich, wenn man nicht den richtigen Code kopiert und ihn erst spaeter hineditiert. Deine Urpsurngsfassung hatte diese Pruefung naemlich drin und hat ohne Crash eine Fehlermeldung ausgegeben...

    Egal, dein Problem ist wohl das Name Mangling und ggf. koennten auch unterschiedliche Funktions-ABIs zum Problem werden.
    Zum Name-Mangling: In C++ werden die Funktionsnamen beim exportieren so umbenannt, dass die Parameterinformationen mit enthalten, z.B. um Ueberladung zu ermoeglichen.
    Aus deinem void Message(int) wird ?Message@@YAXH@Z , was du auch so importieren muesstest mit GetProcAdress . Die bessere Moeglichkeit waere den Compiler zu zwingen das Name Mangling zu deaktivieren, erweiter dein Define fuer __declspec(dllexport) auf extern "C" __declspec(dllexport) .
    Zum ABI: Du hast bei deiner Definition von DLLFunction CALLBACK mit drin, was im Prinzip einen Zeiger auf folgende Signatur ergeben wuerde: void CALLBACK foo(int); , wobei CALLBACK nur ein Define auf __stdcall ist, am Ende kommt also void __stdcall foo(int); .
    Bei der Definition von Message seh ich aber nix von __stdcall und sofern du nicht das implizite ABI in den Projektoptionen umgestellt hast, wovon ich nicht ausgehe, hast du eine void __cdecl Message(int); definiert und exportiert.
    Bei einem Parameter koennte das sogar funktionieren, bei mehreren ists wahrscheinlich, dass es Probleme gibt, da die Argumente bei den Calling Conventions in anderer Reihenfolge auf den Stack gelegt werden.

    Immernoch Lust auf DLLs? :>



  • Vielen Dank für eure Tipps, ich hatte die Überprüfung nur rasugenommen weil ich sonst auch keine Fehlermeldung vom Debugger bekommen, diese jedoch sind oft sehr hilfreich.

    Ich werde das ganze jetzt gleich nochmal ausporbieren und mich dann zurückmelden!



  • Jetzt wo ich die Funktion mit

    ?Message@@YAXH@Z
    

    auslese geht es. Doch wie bist du auf diesen Funktionsnamen gekommen??
    Und kannst du bitte mal genauer erklären wie ich mein

    declspec(dllexport)
    

    mit

    extern "C"
    

    erweitere??

    Mein Ansatz war jetzt folgendes:

    #define extern "C" TEST_API_E declspec(dllexport)
    

    Jedoch gibts da nur Trillionen Fehler von Visual Studio.



  • Max schrieb:

    Mein Ansatz war jetzt folgendes:

    #define extern "C" TEST_API_E declspec(dllexport)
    

    Jedoch gibts da nur Trillionen Fehler von Visual Studio.

    Ergibt ja auch keinen Sinn, der Name (TEST_API_E) muss natürlich am Anfang stehen...

    So wie es jetzt ist Existiert eine Definierte Variable mit dem Namen

    extern
    

    und dem Wert

    "C" TEST_API_E declspec(dllexport)
    


  • Gut, habs jetzt hinbekommen!

    Vielen Dank euch allen für die Hilfe!


Anmelden zum Antworten