C++中模块(Dll)对外暴露接口的几种方式
2012-11-24 15:00
686 查看
C++中模块(Dll)对外暴露接口的几种方式
总结下C++中模块(Dll)对外暴露接口的方式:
(1)导出API函数的方式
这种方式是Windows中调用DLL接口的最基本方式,GDI32.dll, User32.dll都是用这种方式对外暴露系统API的。
这种方式的优点是导出函数没有语言限制,什么语言都能调用;
缺点是这种方式是面向过程的,外部如果要支持多实例等不是很方便,另外它要求的回调函数(callback)只能是普通C函数,C++中我们通常用类静态成员函数,很不方便。
当然,我们通过封装其实也可以让这种方式支持多实例,通过一个抽象句柄HComponent, 比如支持导出函数HComponent CreateInstance(); VOID DeleteInstance(HComponent h);然后内部的其他导出函数的第一个参数都是实例句柄,类似INT SendMessage(HComponent h, ...), 用这种方式可以模拟出面向对象的效果。
另外如果用动态加载(LoadLibrary, GetProcAddress)的方式调用它的导出函数,即使导出函数内部实现修改了,外部程序也不用重新编译,仍然可用。
导出函数方式一个比较优秀的例子是GDI+的实现,整个GdiPlus.dll对外提供的都是普通导出函数,但是它却可以方便的给面向对象的语言使用,因为一方面它用Handle的方式在DLL内部封装了对象,另一方面它在DLL外围又用C++类的方式封装了头文件直接提供给用户, 所以C++程序可以直接以面向对象的方式调用。
(2)导出类方式
导出类的方式就是把整个C++类对外导出, MFC42.dll就是这种方式。
这种方式的优点是直接面向对象。
缺点是只能给C++用,而且最好编译器都要一致,另外DLL一变动, 外部程序需要重新编译, 而且外部程序可以通过头文件看到你类的内部实现,
所以这种方式是最不建议使用的方式。
(3)COM方式
COM方式实际上导出了几个固定函数(DllGetClassObject, DllCanUnloadNow, DllRegisterServer, DllUnregisterServer), 然后以这几个函数为入口,调用组件内部‘实现的接口。
COM方式综合了上面2种方法的所有优点,没有语言限制,面向对象,多实例,只能看到接口,动态升级等。
当然COM因为其复杂性和对注册表的依赖,很多时候我们在封装模块时不愿意严格按照COM标准来实现,但是我们可以按照COM思想来提供接口。
比如我们可以让我们模块只提供一个导出函数CreateFactory, 然后外部可以调用该接口来创建工厂,最后通过工厂创建出各种类型的对象,这些对象实现了某些接口,外部只需要这些接口的头文件即可调用对象的方法。
现在越来越多的组件以这种方式对外提供接口,比如D2D对外的导出接口就是D2D1CreateFactory, 然后就可以通过该工厂来创建其他的对象,比如pD2DFactory->CreateHwndRenderTarget(...),最后可以直接调用对象实现的接口:pRenderTarget->DrawRectangle(D2D1::RectF(100.f,
100.f,
500.f,
500.f),
pBlackBrush);
当然,上面几种DLL对外暴露接口的方式本质上没有区别,都是利用PE文件的导出节来导出数据和函数,但是根据它们使用方式的不同,对外部模块来说还是有很大的区别,我们的推荐次序依次是:COM方式->导出API函数方式->导出类方式。
总结下C++中模块(Dll)对外暴露接口的方式:
(1)导出API函数的方式
这种方式是Windows中调用DLL接口的最基本方式,GDI32.dll, User32.dll都是用这种方式对外暴露系统API的。
这种方式的优点是导出函数没有语言限制,什么语言都能调用;
缺点是这种方式是面向过程的,外部如果要支持多实例等不是很方便,另外它要求的回调函数(callback)只能是普通C函数,C++中我们通常用类静态成员函数,很不方便。
当然,我们通过封装其实也可以让这种方式支持多实例,通过一个抽象句柄HComponent, 比如支持导出函数HComponent CreateInstance(); VOID DeleteInstance(HComponent h);然后内部的其他导出函数的第一个参数都是实例句柄,类似INT SendMessage(HComponent h, ...), 用这种方式可以模拟出面向对象的效果。
另外如果用动态加载(LoadLibrary, GetProcAddress)的方式调用它的导出函数,即使导出函数内部实现修改了,外部程序也不用重新编译,仍然可用。
导出函数方式一个比较优秀的例子是GDI+的实现,整个GdiPlus.dll对外提供的都是普通导出函数,但是它却可以方便的给面向对象的语言使用,因为一方面它用Handle的方式在DLL内部封装了对象,另一方面它在DLL外围又用C++类的方式封装了头文件直接提供给用户, 所以C++程序可以直接以面向对象的方式调用。
(2)导出类方式
导出类的方式就是把整个C++类对外导出, MFC42.dll就是这种方式。
这种方式的优点是直接面向对象。
缺点是只能给C++用,而且最好编译器都要一致,另外DLL一变动, 外部程序需要重新编译, 而且外部程序可以通过头文件看到你类的内部实现,
所以这种方式是最不建议使用的方式。
(3)COM方式
COM方式实际上导出了几个固定函数(DllGetClassObject, DllCanUnloadNow, DllRegisterServer, DllUnregisterServer), 然后以这几个函数为入口,调用组件内部‘实现的接口。
COM方式综合了上面2种方法的所有优点,没有语言限制,面向对象,多实例,只能看到接口,动态升级等。
当然COM因为其复杂性和对注册表的依赖,很多时候我们在封装模块时不愿意严格按照COM标准来实现,但是我们可以按照COM思想来提供接口。
比如我们可以让我们模块只提供一个导出函数CreateFactory, 然后外部可以调用该接口来创建工厂,最后通过工厂创建出各种类型的对象,这些对象实现了某些接口,外部只需要这些接口的头文件即可调用对象的方法。
现在越来越多的组件以这种方式对外提供接口,比如D2D对外的导出接口就是D2D1CreateFactory, 然后就可以通过该工厂来创建其他的对象,比如pD2DFactory->CreateHwndRenderTarget(...),最后可以直接调用对象实现的接口:pRenderTarget->DrawRectangle(D2D1::RectF(100.f,
100.f,
500.f,
500.f),
pBlackBrush);
当然,上面几种DLL对外暴露接口的方式本质上没有区别,都是利用PE文件的导出节来导出数据和函数,但是根据它们使用方式的不同,对外部模块来说还是有很大的区别,我们的推荐次序依次是:COM方式->导出API函数方式->导出类方式。
相关文章推荐
- C++中模块(DLL)对外暴露接口的几种方式
- C++中模块(Dll)对外暴露接口的方式
- 问题:C++编写的核心模块如何暴露给外部HTTP Web服务接口???
- 【C++码农】VC环境下DLL接口申明的三种方式
- Unreal Engine 4 C++ FString操作的几种方式
- 快速得知ArcGIS Engine接口所属命名空间的几种方式
- [C/C++] 几种常见的字符串输入输出方式
- c++多线程创建的几种方式
- C++与matlab用dll或者Lib的方式混编方法
- 使用dubbo对外暴露接口,实现类同时实现两个接口后 @Autowire失败,提示expected single matching bean but found 2解决方案
- VC环境下DLL接口申明的三种方式
- C++的几种从键盘输入方式
- VC环境下DLL接口申明的三种方式
- C#调用C++ DLL的方式
- C#调用C++的DLL 所有数据类型转换方式
- 整理MINGW编译dll使用JNI被java调用的几种方式
- 标准C++中的几种强制类型转换方式比较说明
- WPF MVVM之INotifyPropertyChanged接口的几种实现方式
- 模块及模块间的接口方式
- 文件打开的几种方式(c/c++/win32/mfc)