C++ DLL zur Laufzeit auslesen

mr_bandit

Grünschnabel
Sehr geehrtes Forum,

ich bin gerade dabei eine Grundstruktur für eine größere Appplikation zu planen, die inviduell skalierbar sein wird. Ich habe mich daher für ein PlugIn-Framework entschieden, das auf der Windows-Plattform mit DLL's arbeiten wird und auf der Linux-Plattform mit SO-Bibliotheken. Zur Zeit teste ich mein Vorhaben auf technische Machbarkeit.
Das PlugIn-Framework selbst habe ich in der Hauptapplikation in seiner Grundstruktur bereits implementiert.

Hier meine bisherige Idee:
Es soll für alle zukünftigen DLL's immer eine exportierte Standardschnittstelle "init_plugin()" geben, die die Namen sämtlicher Funktionen, Variablen u.s.w. über sich selbst an den Aufrufer zur Laufzeit zurückliefert.
Die Namen der Funktionen selbst werden mir z.B. auch über ein char*-Array ebenfalls korrekt übergeben. Jedoch will ich jetzt aus diesen Namen anschliessend Funktionspointer bzw. Funktionalitäten in der Hauptapplikation damit verknüpfen.
Über "GetProcAddress(DLL,"NAME_DER_FUNKTION" )" kann ich zwar selbst Funktionspointer zur Entwicklungszeit damit erstellen, d.h. ich muss vor dem Kompilieren meiner Hauptapplikation schon den Namen der Funktionen u.s.w. wissen.
Verwende ich zur Laufzeit der Hauptapplikation mit GetProcAddress(..) den String eines Funktionsnamens, den ich zuvor über init_plugin() ausgelesen habe, bekomme ich beim Kompilieren der Hauptapplikation gleich einen fetten Compiler-Fehler.

Meine Frage ist: Ist es überhaupt möglich, mit dieser Methode Funktionspointer zur Laufzeit zu erstellen und diese z.B. mit einem entsprechenden Namen in einer Menüleiste hinzuzufügen? Oder ist es immer erforderlich, alle exportierten Funktionen mit Typkennungen vorher zu kennen? Beispiele habe ich schon zu genüge bei codeguru pp. gesichtet, jedoch lösen diese mein Problem nicht.

Für Eure Hilfe bin ich sehr dankbar! :)
 
moin


Verwende ich zur Laufzeit der Hauptapplikation mit GetProcAddress(..) den String eines Funktionsnamens, den ich zuvor über init_plugin() ausgelesen habe, bekomme ich beim Kompilieren der Hauptapplikation gleich einen fetten Compiler-Fehler.
Da wirst du schon Code zeigen müssen wenn du dazu ne Lösung willst.


mfg
umbrasaxum
 
Code:
#include "stdafx.h"
#include <stdio.h>
#include <windows.h>
#include <iostream.h>

int main(int argc, char* argv[])
{
	typedef char* (*PFUNC_charp)(void);
	typedef void (*PFUNC_void)(void);

	int dll_count=0;
	char *dll_fp;
	HMODULE hm = LoadLibrary("testdll1.dll");
    if (!hm)
    {
      printf("Konnte DLL testdll1.dll nicht laden!\n");
    }
 
PFUNC_charp init_plugin = (PFUNC_charp)GetProcAddress((HINSTANCE)hm, "init_plugin");    

	if (init_plugin != NULL)
    {
		printf ("init_plugin existiert!\n"); 
		dll_fp=init_plugin(); 
		
		LPCSTR func_name = dll_fp;
				PFUNC_void function2 = (PFUNC_charp)GetProcAddress((HINSTANCE)hm, func_name);    // hier kracht es!

		cout << dll_fp << endl;
    }
	else
		printf("init_plugin() nicht gefunden!\n"); 

	FreeLibrary((HMODULE)hm);
	return 0;
}

Das ist mein bisheriger grober Rumpf des PlugIn-Loaders.
 
Müsste schon gehen, dass du Funktionspointer innerhalb der DLL über eine bestimmte Funktion bekannt gibst.
Notfalls könntest du auch eine universelle Funktion machen, die z.b. ein Array an void pointer annimmt oder eine spezielle Klasse die halt das entsprechende Abbildet (Funktionsnamen, IN-OUT parameter in einem Container etc)
 
Gute Idee. Man könnte ja einfach eine Klasse, die immer den gleichen Namen hat, z.B. plugin nach außen hin exportieren, eine Art Proxy-Parttern. Das sollte möglich sein, oder?
 
Was war denn falsch?
Du hast Doch aber immer noch das Problem, daß Du den Typ der Funktion schon zur Kompilierzeit kennen mußt. Ist das immer der Fall?
Wenn nicht, dann könntest du es ja evtl. so machen, daß du nur eine exportierte Funktion 'int execute(char* cp_Command, ...)' in Deiner Dll hast, der Du einfach sagst, was intern getan werden soll. Die kannst Du ja mit variablen Parametern anlegen (wie z.B. bei printf).
 
jokey2 hat gesagt.:
Was war denn falsch?
Du hast Doch aber immer noch das Problem, daß Du den Typ der Funktion schon zur Kompilierzeit kennen mußt. Ist das immer der Fall?
Wenn nicht, dann könntest du es ja evtl. so machen, daß du nur eine exportierte Funktion 'int execute(char* cp_Command, ...)' in Deiner Dll hast, der Du einfach sagst, was intern getan werden soll. Die kannst Du ja mit variablen Parametern anlegen (wie z.B. bei printf).

Normal ja. Es geht aber auch folgendermaßen:
Ich habe einen virtuellen Struct als feste Schnittstelle in der DLL und im PlugIn-Loader deklariert. Anschliessend habe ich eine Funktion exportiert, die einen Pointer auf eine zuvor auf der Schnittstelle abgeleiteten und instanzierten Klasse an den externen Aufrufer zurückgibt. Das ganze konvertiere ich noch wieder zurück in einen Funktionspointer und schon kann ich mit dem Pointer auf die Klasse in der DLL arbeiten. In C++ sieht das Ganze so aus:

// Gemeinsame Schnittstelle
Code:
struct  plugin_interface
{
    virtual ~plugin_interface() { }                                                  
    virtual void Init() = 0;     
    virtual void Print( const char* chars) = 0;

};

Code in DLL:
Code:
// Simple Testklasse
class CTest: public plugin_interface
{
public:
    CTest() { }        
    ~Ctest() { }       

    void Init() { } 
    
    void Print(const char* chars)
    {
        cout << chars << endl;  
    }
};

// Standard Export-Funktion für DLL-Plugin
extern "C" __declspec(dllexport) void GetPlugin(plugin_interface** ppPlugin)
{
    *ppPlugin = new CTest;
}

Code im Testprogramm:
Code:
typedef void (*pPlugin)(plugin_interface**);
	
HINSTANCE hm = LoadLibrary( "dll2.dll" );
pPlugin LoadPlugin = (pPlugin)GetProcAddress(hm,"GetPlugin");	

plugin_interface* plugin_a = 0;
LoadPlugin(&plugin_a);
	
plugin_a->Print("TEST!");

Eine Frage habe ich aber trotzdem noch. Ich bin jetzt gerade dabei, QT-Dialoge in DLL's bzw. SO mit zuverpacken. Dies sollte doch ohne großartigem Mehraufwand möglich sein, oder? Dies ist nämlich ein sehr wichtiger Bestandteil bei meiner Applikation, die ich gerade plane bzw. auf technische Machbarkeit teste.

Gruss,
Michael
 
Zuletzt bearbeitet:
Das sollte schon gehen. Allerdings wirst Du die entsprechenden Bibliotheken statisch in Deine DLL mit einbinden müssen. Das ist aber nur eine Vermutung. Ich habe noch nie mit QT gearbeitet.
 
Zurück