C++: le chargement dynamique de classes à partir de dll
Pour mon projet actuel, je veux être en mesure de charger des classes à partir d'une dll (qui n'est pas toujours la même, et peut même ne pas exister lorsque mon application est compilée). Il peut aussi y avoir plusieurs alternatives de dll pour une catégorie donnée (par exemple une mise en œuvre pour Direct3D9 et un pour OpenGL), mais un seul de la dll sera chargé/utilisé à tout moment.
J'ai un ensemble de classes de base qui définissent l'interface ainsi que quelques méthodes de base/membres (c'est à dire ceux pour la refrence de comptage) des classes que je veux charger, ce qui la dll projets dérivent ensuite lors de la création, il y a de classes.
//in namespace base
class Sprite : public RefCounted//void AddRef(), void Release() and unsigned refCnt
{
public:
virtual base::Texture *GetTexture()=0;
virtual unsigned GetWidth()=0;
virtual unsigned GetHeight()=0;
virtual float GetCentreX()=0;
virtual float GetCentreY()=0;
virtual void SetCentre(float x, float y)=0;
virtual void Draw(float x, float y)=0;
virtual void Draw(float x, float y, float angle)=0;
virtual void Draw(float x, float y, float scaleX, flota scaleY)=0;
virtual void Draw(float x, float y, float scaleX, flota scaleY, float angle)=0;
};
Le truc c'est que je ne suis pas sûr de savoir comment tout faire pour que le fichier exécutable et autres dll peuvent charger et utiliser ces classes depuis le ive jamais utilisé dll, où il n'y avait qu'une dll et j'ai pu avoir les Visual Studio linker le tri à l'aide de l' .fichier lib que j'ai quand compileing dll.
Je n'ai pas l'esprit à l'aide de méthodes de fabrique pour l'instanciation des classes, beaucoup d'entre eux le font déjà par la conception (c'est à dire une classe sprite est créé par le principal de la classe Graphics, par exemple, des Graphiques->CreateSpriteFromTexture(base::Texture*)
EDIT:
Quand j'ai besoin de l'écrire en c++ dll pour une utilisation en python, j'ai utilisé une bibliothèque appelée pyCxx. Le résultant dll essentiellement exportés uniquement une méthode, qui a créé une instance de la "Module" de la classe, qui pourrait contenir de l'usine de méthodes pour créer d'autres classes, etc.
L'résultant dll peuvent être importés en python juste avec "import [dllname]".
//dll compiled as cpputill.pyd
extern "C" void initcpputill()//only exported method
{
static CppUtill* cpputill = new CppUtill;
}
class CppUtill : public Py::ExtensionModule<CppUtill>
{
public:
CppUtill()
: Py::ExtensionModule<CppUtill>("cpputill")
{
ExampleClass::init_type();
add_varargs_method("ExampleClass",&CppUtill::ExampleClassFactory, "ExampleClass(), create instance of ExampleClass");
add_varargs_method("HelloWorld", &CppUtill::HelloWorld, "HelloWorld(), print Hello World to console");
initialize("C Plus Plus module");
}
...
class ExampleClass
...
static void init_type()
{
behaviors().name("ExampleClass");
behaviors().doc ("example class");
behaviors().supportGetattr();
add_varargs_method("Random", &ExampleClass::Random, "Random(), get float in range 0<=x<1");
}
Exactement comment cela fonctionne, et pourrais-je l'utiliser dans un but purement c++ de l'environnement afin de résoudre mon problème ici?
Vous devez vous connecter pour publier un commentaire.
Meilleure façon de le faire, à mon humble avis, est d'avoir un simple C une fonction qui retourne un pointeur vers une interface décrit par ailleurs. Alors votre application, pouvez appeler toutes les fonctions de cette interface, sans vraiment savoir dans quelle classe il est à l'aide.
Edit: Voici un exemple simple.
Dans le code de l'application, vous créez un en-tête de l'interface:
Principal de l'application est codée pour utiliser l'interface ci-dessus, sans plus de détails sur la mise en œuvre effective de l'interface.
Maintenant, les modules de la DLL effectivement implémentations de cette interface, et les classes n'ont même pas à être exportés -
__declspec (dllexport)
n'est pas nécessaire. La seule exigence pour les modules est d'exporter une fonction unique, qui permettrait de créer et de retourner une implémentation de l'interface:remarque: la vérification des erreurs laissées vous feriez habituellement à vérifier, si de nouveaux renvoyé le bon pointeur et vous devriez vous protéger contre les exceptions qui peuvent être jetés dans le constructeur de la
ActualModule
classe.Puis, dans votre application, tout ce que vous devez faire est simplement de charger le module (
LoadLibrary
fonction) et de trouver la fonctionCreateModule
(GetProcAddr
fonction). Ensuite, vous utilisez la classe par le biais de l'interface.Edit 2: votre RefCount (classe de base de l'interface), peuvent être mises en œuvre (et exportés à partir de) l'application principale. Alors tous vos module aurait besoin d'un lien vers le fichier lib de l'application principale (oui! Les fichiers EXE peuvent avoir LIB fichiers comme les fichiers DLL!) Et cela devrait être suffisant.
Vous ré-inventer COM. Votre classe RefCounted est IUnknown. Votre classe abstraite est une interface. Un serveur COM dans une DLL a un point d'entrée nommé DllGetClassObject(), c'est une fabrique de classe. Il y a beaucoup de documentation disponible auprès de Microsoft en sur COM, fouiner un peu pour voir comment ils ont fait.
[Edit: pendant que j'était en train de composer tout cela, Paulius Maruška édité son commentaire à-dire essentiellement la même. Alors, toutes mes excuses pour le double emploi. Mais je suppose que vous avez maintenant en ai un de rechange :)]
Sur le dessus de ma tête, et en supposant que Visual C++...
Vous devez utiliser la fonction LoadLibrary de charger une DLL dans dynamiquement, puis utilisez GetProcAddress pour rechercher l'adresse d'une fonction qui va créer la classe dérivée que le code de la DLL met en œuvre. Comment vous décidez de faire cette précision est à vous (les Dll doivent trouver, à la manière de l'exposer leurs besoins en fonctionnalités de la spécification, etc.) donc pour l'instant, supposons que les plugins ne fournit de nouvelles Sprite implémentations.
Pour ce faire, décider sur la signature de la fonction dans la DLL que le programme principal appelle à créer un de ces nouveaux sprites. Celui-ci semble adapté:
Puis, à partir du programme principal, vous aurez à charger une DLL (encore une fois, comment vous trouver cette DLL est jusqu'à vous) et obtenir le sprite de la création de la fonction d'elle. J'ai décidé que le sprite de la création de la fonction sera appelée "CreateSprite":
Ensuite pour créer l'un de ces, il suffit d'appeler la fonction:
Une fois que vous avez terminé avec la DLL et il n'existe pas de gauche objets qui ont été créés par elle, vous pouvez alors l'utiliser FreeLibrary pour se débarrasser d'elle:
Pour créer une DLL que le sport cette interface, d'écrire le code de la classe dérivée et ainsi de suite, alors quelque part dans le code de la DLL fournir les CreateSprite fonction que le programme appelant besoins, à l'aide de la signature:
La dllexport chose signifie que vous pouvez utiliser GetProcAddress pour prendre cette fonction par le nom, et la extern "C" permet de s'assurer que le nom est unmangled et ne finissent pas comme "CreateSprite@4" ou quelque chose du genre.
Deux autres notes:
Peut-être que vous voulez regarder dans les DLL Délai de Chargement (http://www.codeproject.com/KB/DLL/Delay_Loading_Dll.aspx) - cela va vous donner ce que vous voulez sans avoir à travailler trop dur pour elle