本篇主要讲述动态库的开发、动态库的测试与调用、添加log日志记录的应用。
动态库原理浅析
1. 动态库是什么,它有什么作用? |
Windows系统平台上提供了一种完全不同的较有效的编程和运行环境,你可以将独立的程序模块创建为较小的DLL(Dynamic Linkable Library)文件,并可对它们单独编译和测试。在运行时,只有当EXE程序确实要调用这些DLL模块的情况下,系统才会将它们装载到内存空间中。这种方式不仅减少了EXE文件的大小和对内存空间的需求,而且使这些DLL模块可以同时被多个应用程序使用。详见文档《Win32环境下动态链接库(DLL)编程原理》。 |
|
2. 动态库的导出 |
动态库的导出有两种方法: (1) __declspec(dllexport)intMyFunction(int n); 这样就可以将动态库中的函数MyFunction()导出了。 (2) 需要一个Des文件,通过该文件来导出动态库。 (Master没细说这种方法,不过说了这两种方法都较常用) 说明:在后面的例程中将使用第一种导出方法,并且将__declspec(dllexport)int放到宏定义中去。 |
|
3. 与DLL模块建立链接(应用程序加载动态库) |
与DLL模块建立链接也有两种方法: (1) 隐式链接方式 程序员在建立一个DLL文件时,链接程序会自动生成一个与之对应的LIB导入文件。该文件包含了每一个DLL导出函数的符号名和可选的标识号,但是并不含有实际的代码。LIB文件作为DLL的替代文件被编译到应用程序项目中。具体操作方法会在后面提到。 (2) 显式链接方式(动态加载) 显式链接方式对于集成化的开发语言(例如VB)比较适合。
说明:在后面的例程中将使用第一种链接方法。 |
|
4. 应用程序(exe文件)怎样找到动态库? |
(Master)这对于不同的系统版本,其方式不一样,如在XP、win7、win8系统下都不一样。例如在XP系统下,应用程序是优先到C:\Windows\System32路径下去找,完了之后再到对应目录下去找。 |
动态库的调用
先不说如何开发动态库,先来感受一下动态库是如何被使用的。
Step1:复制所需文件到指定位置 |
这里需要三个文件,socketclient.dll、socketclient.lib、socketclientdll.h,将这三个文件复制到项目目录下,如下图所示。然后再将头文件socketclientdll.h添加到工程里。 |
|
dll和lib文件打不开,这里就只展示socketclientdll.h文件了。 |
|
|
Step2:链接lib文件 |
右击工程名→properties,弹出如下对话框,
将socketclient.lib文件的文件名复制到图中所示位置,完了如下图。 |
|
|
Step3:新建源文件,编写调用动态库的代码。 |
main.c文件 |
|
上面的例程是已经定义了一套socket客户端发送报文、接受报文的api接口,并且发送、接收等函数都已经写好了,封装在库文件中(lib文件),我们只需调用即可。那么这些动态库库究竟是如何生成的呢?这些库文件(这里其实就是dll和lib文件)里面装的是什么呢?这在后面会详细讲到。 |
前面一节是讲述如何使用已经创建好的动态库,这一节则是讲述如何开发动态库。这里就以实现前一节的动态库功能为例来讲述实际工程开发中是如何实现动态库的创建与开发的。
动态库的建立
Step1:新建工程 |
第一步和之前的新建工程一样,如下图所示。
接下来的一步和之前略有不同,如下图所示。 |
|
Step2:添加头文件itcast_comm.h。头文件内容如下。 |
|
|
Step3:新建源文件MySocketLib.c |
接下来就是在要在文件MySocketLib.c里编辑自己的库函数了。我们就以master给的第一套api接口为例来编写这些函数的具体源代码。 这里先打桩,然后再编写个动态库测试程序来看看有木有成功,若成功了则继续往下编写动态库函数。 |
|
一般的函数是像上述这样定义的,可是动态库开发不一样,这里需要将各个函数的返回类型用itcast_comm.h头文件中的宏定义ITCAST_FUNC_EXPORT(returnType)来替换,完了如下所示。 |
|
|
Step4:编译生成动态库文件,如下所示。 |
动态库测试程序的建立
类似动态库调用那一节,需要添加lib文件到测试工程的链接器。
Step1:新建测试工程 |
新建一个工程,这个工程是用来测试刚刚开发的动态库的。注意这时候就是新建一个普通的工程,与新建动态库开发环境有所不同,不同点如下图所示。 |
|
Step2:复制所需文件到指定位置 |
如“同动态库的调用”一节所述,这里也需要三个文件。 将在动态库开发中生成的两个文件MySocketLib.dll、MySocketLib.lib和socketclientdll.h共三个文件复制到指定位置,如下图所示。然后再将头文件socketclientdll.h添加到工程里。 |
|
Step3:链接lib文件 |
同样是右击工程名→properties,将MySocketLib.lib文件的文件名复制到下图所示位置。 |
|
Step4:新建源文件,编写调用动态库的代码。 |
|
|
Step5:编译调试 |
在“rv = cltSocketInit(&handle);”处设置断点,如果能够成功进入该函数(也就是进入了动态库),并成功执行该函数里面的代码,则说明动态库调用成功了。 |
编写动态库函数
当测试程序成功测试了动态库的调用后,就说明动态库已经创建成功了。接下来就是要继续完善动态库函数了。
最后动态库的源代码如下。 |
|
编译该动态库工程即可更新在对应路径下的动态库文件MySocketLib.dll和MySocketLib.lib。 |
动态库文件弄好之后,就要测试动态库中的函数是否可用,那么就要将新生成的两个库文件拷贝到之前的测试程序路径下,以替换之前的库文件。具体方法在前面已经说过了。 |
|
将动态库文件拷贝后,就要编写动态库测试程序了,以便于测试这些动态库函数是否可用,测试程序如下所示。 |
|
编译该测试工程后,就可以调试测试动态库函数是否编写成功了,如果没有则还需要到动态库开发环境中去修改库函数,然后将新生成的库文件拷贝到测试程序路径下再次测试,这样直到测试成功为止。 |
添加日志记录
工程开发中,常常需要将程序的执行状态记录下来保存到一个日志文件中去,以便于调试。
这里需要两个文件:itcastlog.h和itcastlog.c,哪里需要用到日志记录,就将这个两个文件复制到哪里,比如上一节中的动态库想要用日志来记录程序执行状态,就将这两个文件复制到动态库程序目录下,然后将头文件itcastlog.h添加到工程中。 若在MySocketLib.c文件中想要用日志记录,那么还要在MySocketLib.c中包含头文件itcastlog.h。 |
|
itcastlog.h文件如下 |
|
|
itcastlog.c |
|
|
那么再实践中是如何使用的呢?其实很简单,作为示例,下面就展示一下cltSocketInit()函数是如何调用日志显示的,如下所示。 |
执行完程序后,看C:\itcast目录下的log文件,如下图所示。 |
生成的日志是被放在了C盘根目录下的itcast文件夹里,这可以由itcastlog.c文件中的ITCAST_Error_OpenFile()函数看出来。注意是要先在C盘根目录下新建一个文件名为itcast的文件夹。 |
第二套API函数实现动态库开发
前面讲述动态库的开发是基于第一套API函数接口来实现的,接下来要用第二套API函数来实现。
其实基本原理和第一套API函数实现是一样的,只不过第二套API的部分函数的接口不一样,所以导致了函数内容有些变化。如下所示。 |
|