C ++:从dll动态加载类 [英] C++: Dynamically loading classes from dlls

查看:182
本文介绍了C ++:从dll动态加载类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于我当前的项目,我想能够从dll(这不总是相同,甚至可能不存在,当我的应用程序编译时)加载一些类。对于给定类也可能有几个可选的dll(例如Direct3D9的实现和OpenGL的实现),但只有一个dll将被加载/使用在任何一个时间。



我有一组定义接口的基类,以及一些我想加载的类的基本方法/成员(即refrence counting的成员),然后dll工程从中创建类。 / p>

  // in namespace base 
class Sprite:public RefCounted // void AddRef 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;
};

事情是我不知道如何做,所以可执行文件和其他dll加载和使用这些类,因为ive只使用dlls,其中只有一个dll,我可以有Visual Studio链接器使用我在编译DLL时得到的.lib文件排序。



我不介意使用工厂方法来实例化类,其中许多已经通过设计(即一个sprite类是由主Graphics类创建的,例如Graphics-> CreateSpriteFromTexture(base :: Texture *)

编辑:
当我需要编写一些c ++ dll在python中使用时,我使用了一个名为pyCxx的库,所得的dll基本上只导出一个方法,



生成的dll可以通过import [dllname]导入到python中, 。

  // dll编译为cpputill.pyd 
externCvoid initcpputill方法
{
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模块);
}
...
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);
}

它如何工作,我可以在纯粹的c ++环境在这里解决我的问题?

解决方案

最简单的做法是,一个简单的C函数返回一个指针到其他地方描述的接口。然后你的应用程序,可以调用该接口的所有函数,而不知道它正在使用什么类。



编辑:这是一个简单的例子。 b
$ b

在您的主应用程序代码中,您将为界面创建一个标题:

  class IModule 
{
public:
virtual〜IModule(); //< = important!
virtual void doStuff()= 0;
};

主应用程序被编码为使用上面的界面,没有关于实际实现接口的任何细节。

  class ActualModule:public IModule 
{
/ * implementation * /
};

现在,模块 - DLL具有该接口的实际实现,甚至必须导出 - __ declspec(dllexport)是不需要的。模块的唯一要求是导出单个函数,创建并返回一个接口的实现:

  __ declspec dllexport)IModule * CreateModule()
{
//调用实际实现的构造函数
IModule * module = new ActualModule();
//返回创建的函数
return module;
}

注意:错误检查将被忽略 - 您通常需要检查new返回正确的指针,你应该保护自己免受可能在 ActualModule 类的构造函数中抛出的异常。



然后,在你的主要应用程序中,所有你需要的是简单地加载模块( LoadLibrary function),并找到函数 CreateModule GetProcAddr 函数)。



编辑2:您的RefCount(接口的基类),可以在主应用程序中实现(和导出) 。然后所有的模块都需要链接到主应用程序的lib文件(是的!EXE文件可以有LIB文件就像DLL文件!)这应该就够了。


For my current project I want to be able to load some classes from a dll (which is not always the same, and may not even exist when my app is compiled). There may also be several alternative dll's for a given class (eg an implementation for Direct3D9 and one for OpenGL), but only one of the dlls will be loaded/used at any one time.

I have a set of base classes that define the interface plus some basic methods/members (ie the ones for refrence counting) of the classes I want to load, which the dll projects then derive from when creating there 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;
};

The thing is I'm not sure how to do it all so that the executable and other dlls can load and use these classes since ive only ever used dlls where there was only one dll and I could have the Visual Studio linker sort it all out using the .lib file I get when compileing dll's.

I dont mind using factory methods for instancing the classes, many of them do already by design (Ie a sprite class is created by the main Graphics class, eg Graphics->CreateSpriteFromTexture(base::Texture*)

EDIT: When I needed to write some c++ dlls for use in python I used a library called pyCxx. The resulting dll basicly only exported one method, which created an instance of the "Module" class, which could then contain factory methods to create other classes etc.

The resulting dll could be imported in python just with "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");
    }

How exactly does that work, and could I use it in a purely c++ enviroment to solve my problem here?

解决方案

Easiest way to do this, IMHO, is to have a simple C function that returns a pointer to an interface described elsewhere. Then your app, can call all of the functions of that interface, without actually knowing what class it is using.

Edit: Here's a simple example.

In your main app code, you create a header for the interface:

class IModule
{
public:
    virtual ~IModule(); // <= important!
    virtual void doStuff() = 0;
};

Main app is coded to use the interface above, without any details on the actual implementation of the interface.

class ActualModule: public IModule
{
/* implementation */
};

Now, the modules - the DLL's have the actual implementations of that interface, and those classes don't even have to be exported - __declspec (dllexport) isn't needed. The only requirement for the modules is to export a single function, that would create and return an implementation of the interface:

__declspec (dllexport) IModule* CreateModule()
{
    // call the constructor of the actual implementation
    IModule * module = new ActualModule();
    // return the created function
    return module;
}

note: error checking left out - you'd usually want to check, if new returned the correct pointer and you should protect yourself from the exceptions that might be thrown in the constructor of the ActualModule class.

Then, in your main app, all you need is to simply load the module (LoadLibrary function) and find the function CreateModule (GetProcAddr function). Then, you use the class through the interface.

Edit 2: your RefCount (base class of the interface), can be implemented in (and exported from) the main app. Then all your module would need to link to the lib file of the main app (yes! EXE files can have LIB files just like DLL files!) And that should be enough.

这篇关于C ++:从dll动态加载类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆