第15天 将动态加载DLL的功能封装到自定义类中

今天要学习的案例对应的源代码目录:src/chapter03/ks03_04。本案例不依赖第三方类库。程序运行效果如图3-4所示。

图3-4 第15天案例程序运行效果

今天的目标是掌握如下内容。

  • 将动态加载DLL功能封装到自定义类中。
  • 使用该自定义类加载DLL并调用其中的接口。

第14天的学习内容中介绍了可动态加载DLL的开发技术,演示了在Windows系统、Linux系统中如何实现动态加载DLL并调用其中的接口。在ks03_03项目中,需要利用操作系统宏定义来区分不同的系统以便调用不同的接口,这个方案在实际应用过程中不太方便。为了更加方便,可以把加载DLL以及查找DLL中接口等的相关代码封装到自定义类中,在应用中只需要调用该类的功能即可。

1.将动态加载DLL的功能封装到自定义类

首先,将动态加载DLL的功能封装到自定义类CLibrary,将该类添加到basedll项目。该类的定义见代码清单3-19。

代码清单3-19

在代码清单3-19中,如标号①处所示,将CLibrary置于命名空间ns_train中,这样便于管理。在标号②处,对CLibraryData进行前置声明,以便用来定义CLibrary的私有成员m_pLibraryData,前置声明的目的是通知编译器CLibraryData已在别处定义。在标号③、标号④、标号⑤处定义了3个接口分别用来加载DLL、卸载DLL、查找DLL中的接口。从第13天的学习内容中可以知道,实现这几个功能需要调用的接口在Windows系统、Linux系统中是不同的,因此需要针对不同的操作系统为CLibrary类提供不同的实现。CLibrary在Windows系统中的实现如代码清单3-20所示。结构体CLibraryData的完整定义如标号①处所示。在标号②处,为DLL文件名添加Windows系统中的后缀。

代码清单3-20

CLibrary在Linux系统中的实现如代码清单3-21所示。结构体CLibraryData的完整定义如标号①处所示。在标号②处至标号③处,组织完整的DLL文件名。如果pszDLLName=aaa,那么完整的DLL文件名应该为libaaa.so.1。

代码清单3-21

2.使用该自定义类加载DLL并调用其中的接口

将CLibrary封装完成后,就可以使用该类加载DLL并调用其中的接口了。使用该类的代码如代码清单3-22所示。在标号①处,定义CLibrary类型的对象lib,此处代码采用了ns_train::CLibrary的写法。在标号②处,加载指定的DLL。在标号③、标号④处,查找DLL中指定接口,然后调用。在标号⑤处,当不再使用DLL时,卸载该DLL。

代码清单3-22

注意:因为本案例的EXE项目中,不再涉及UNICODE问题,所以本案例EXE的pro中无须配置“DEFINES -= UNICODE”。