zoukankan      html  css  js  c++  java
  • 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函数方式->导出类方式。

  • 相关阅读:
    Python3之random模块常用方法
    Go语言学习笔记(九)之数组
    Go语言学习笔记之简单的几个排序
    Go语言学习笔记(八)
    Python3之logging模块
    Go语言学习笔记(六)
    123. Best Time to Buy and Sell Stock III(js)
    122. Best Time to Buy and Sell Stock II(js)
    121. Best Time to Buy and Sell Stock(js)
    120. Triangle(js)
  • 原文地址:https://www.cnblogs.com/h2zZhou/p/5306695.html
Copyright © 2011-2022 走看看