Windows 动态链接库编程
Windows 动态链接库编程
1、介绍
Windows操作系统是应用最关的操作系统,因此动态链接库也为程序员所熟悉,即使对于普通的使用者来说,很多时候也会碰到.dll结尾的文件,这就是动态链接库文件。Windows下的动态链接库可以通过参考头文件和.lib库文件进行编译,从而使得动态链接库隐式地被使用;也可以使用LoadLibrary、GetProcAddress等函数来显式调用动态链接库。
2、语法、导入导出
在Windows编程中,对于要使用或被使用的函数或者变量,需要使用 __declspec 关键字来声明,以告诉编译器该变量或函数不是普通的变量或函数,而是一个动态链接库的接口属性。
如果定义一个要被其他代码使用的函数,可以写成:
__declspec( dllexport ) int add(int a, int b);
如果在该代码中,打算使用另外一个程序中的变量,则可以写成:
__declspec( dllimport ) char *name;
动态链接库通常包含一系列供其他程序使用函数,因此 declspec( dllexport ) 语法形式最为常用。如果动态库需要其他程序中的定义的全局变量,则需要在其他程序中使用导出该变量,在动态链接库中则需要使用 extern declspec( dllexport ) 将该变量声明为外部变量以便使用。
3、链接方式
可以以下列两种方式之一链接到(或加载)DLL:
隐式链接
显式链接
隐式链接有时称为静态加载或加载时动态链接。显式链接有时称为动态加载或运行时动态链接。在隐式链接下,使用 DLL 的可执行文件链接到该 DLL 的创建者所提供的导入库(.lib 文件)。使用 DLL 的可执行文件加载时,操作系统加载此 DLL。客户端可执行文件调用 DLL 的导出函数,就好像这些函数包含在可执行文件内一样。
在显式链接下,使用 DLL 的可执行文件必须进行函数调用以显式加载和卸载该 DLL,并访问该 DLL 的导出函数。客户端可执行文件必须通过函数指针调用导出函数。可执行文件对两种链接方法可以使用同一个 DLL。另外,由于一个可执行文件可隐式链接到某个 DLL,而另一个可显式附加到此 DLL,故这些机制不是互斥的。
4、隐式链接
隐式链接动态链接库比较简单,不予详述。
5、显式链接API函数
显式链接主要涉及到3个API函数( LoadLibrary , GetProcAddress 和 FreeLibrary ),要使用这些函数包含windows.h头文件即可。
(1)HINSTANCE LoadLibrary(LPCSTR lpLibFileName);
该函数用来加载指定动态库文件,并且返回句柄。
参数lpLibFileName为动态链接库的名称。Windows 首先搜索“已知 DLL”,如 Kernel32.dll 和 User32.dll。然后按下列顺序搜索 DLL:
1、当前进程的可执行模块所在的目录。
2、当前目录。
3、Windows 系统目录。GetSystemDirectory 函数检索此目录的路径。
4、Windows 目录。GetWindowsDirectory 函数检索此目录的路径。
5、PATH 环境变量中列出的目录。
(2)FARPROC GetProcAddress (HMODULE hModule, LPCSTR lpProcName);
函数GetProcAddress 用来获取 DLL 导出函数的地址。返回由lpProcName指定的变量或函数指针。
参数hModule为已经加载的动态库文件的句柄。
参数lpProcName为要调用的变量或函数名称。
(3)BOOL FreeLibrary(HMODULE hModule);
从内存中释放hModule所代表的动态链接库。
(4)如果发生错误,可以调用GetLastError()函数或去错误代码。
6、显示链接举例
(1)动态库文件代码:dll_demo.c
#include <stdio.h>
__declspec( dllexport ) int add(int a, int b)
{
printf("calling add\n");
return a + b;
}
该文件中的add()函数计算两个整数之和,并且返回之前打印提示字符串。函数使用 __declspec( dllexport ) 语法来说明函数add(int a, int b)要被导出。
(2)客户端事例代码:main.c
#include <stdio.h>
#include <windows.h>
int main (int argc, char *argv[])
{
int a = 10, b = 20;
int c = 0;
HINSTANCE hInstLibrary = NULL;
int (*add)();
printf ("Load DLL file\n");
if ((hInstLibrary = LoadLibrary(L"dll_demo.dll")) == NULL)
{
printf ("***LoadLibrary ERROR: %d.\n", GetLastError());
return 1;
}
if((add = (int (*)())GetProcAddress(hInstLibrary, "add")) == NULL) {
printf ("***GetProcAddress ERROR: %d.\n", GetLastError());
return 1;
}
c = add(a, b);
printf("%d + %d = %d\n", a, b, c);
FreeLibrary(hInstLibrary);
return 0;
}
程序利用LoadLibrary函数加载动态链接dll_demo.dll,利用FreeLibrary关闭句柄,利用GetLastError()获取错误代码,利用GetProcAddress定位共享库中的add函数,然后调用该函数执行加法计算,并打印结果。
(3)编译与运行
编译共享库:
在VS.Net中创建一个动态链接库项目,名称为dll_demo,加入文件dll_demo.c,编译后生成dll_demo.dll文件。
编译事例程序:
在VS.Net中创建一个动态链接库项目,名称为dll_main,加入文件main.c,编译后生成dll_main.exe可以执行文件。
运行:
将 dll_demo.dll 和 dll_main.exe 放在同一个目录下,然后双击运行 dll_main.exe。
输出:
Load DLL file
calling add
10 + 20 = 30
7、调用动态链接库中的变量
也可以使用动态链接库中的变量。例如,在动态链接库中定义:
__declspec( dllexport ) int num = 100;
那么可以在事例程序中这样调用:
int *d;
d = (int *)GetProcAddress(hInstLibrary, "num");
printf("num = %d\n", *d);
Windows 动态链接库编程的更多相关文章
- Windows Socket 编程_单个服务器对多个客户端简单通讯
单个服务器对多个客户端程序: 一.简要说明 二.查看效果 三.编写思路 四.程序源代码 五.存在问题 一.简要说明: 程序名为:TcpSocketOneServerToMulClient 程序功能:实 ...
- 【Windows】windows核心编程整理(下)
windows核心编程整理(上) windows核心编程整理(下) 线程的堆栈 每当创建一个线程时,系统就会为线程的堆栈(每个线程有他自己的堆栈)保留一个堆栈空间区域,并将一些物理存储器提交给这个以保 ...
- 《windows核心编程系列》十七谈谈dll
DLL全称dynamic linking library.即动态链接库.广泛应用与windows及其他系统中.因此对dll的深刻了解,对计算机软件开发专业人员来说非常重要. windows中所有API ...
- Ligg.EasyWinApp-000: 一款Windows应用编程框架介绍
本框架(解决方案)是一个Windows应用编程框架和UI库,通过该框架,不需任何代码,通过XML配置文件,搭建任意复杂的Windows应用界面,以类似Execel公式的方式实现基本的过程控制( ...
- windows多线程编程星球(一)
以前在学校的时候,多线程这一部分是属于那种充满好奇但是又感觉很难掌握的部分.原因嘛我觉得是这玩意儿和编程语言无关,主要和操作系统的有关,所以这部分内容主要出现在讲原理的操作系统书的某一章,看完原理是懂 ...
- windows核心编程 - 线程同步机制
线程同步机制 常用的线程同步机制有很多种,主要分为用户模式和内核对象两类:其中 用户模式包括:原子操作.关键代码段 内核对象包括:时间内核对象(Event).等待定时器内核对象(WaitableTim ...
- windows核心编程---第九章 同步设备IO与异步设备IO之同步IO
同步设备IO 所谓同步IO是指线程在发起IO请求后会被挂起,IO完成后继续执行. 异步IO是指:线程发起IO请求后并不会挂起而是继续执行.IO完毕后会得到设备的通知.而IO完成端口就是实现这种通知的很 ...
- windows核心编程---第八章 使用内核对象进行线程同步
使用内核对象进行线程同步. 前面我们介绍了用户模式下线程同步的几种方式.在用户模式下进行线程同步的最大好处就是速度非常快.因此当需要使用线程同步时用户模式下的线程同步是首选. 但是用户模式下的线程同步 ...
- storysnail的Windows串口编程笔记
storysnail的Windows串口编程笔记 作者 He YiJun – storysnail<at>gmail.com 团队 ls 版权 转载请保留本声明! 本文档包含的原创代码根据 ...
随机推荐
- Nginx安装手册
前提是搭建yum安装环境,见前面的教程资料 Nginx安装手册1 nginx安装环境 nginx是C语言开发,建议在linux上运行,本教程使用Centos6.5作为安装环境. gcc 安装ngin ...
- 如何开发由Create-React-App 引导的应用(一)
此文章是翻译How to develop apps bootstrapped with Create React App 官方文档 系列文章 如何开发由Create-React-App 引导的应用 如 ...
- input[type=file]中使用ajaxSubmit来图片上传
今天在使用input[type=file]上传图片到服务器时,因为项目要求,并不是像常见的通过按钮来提交表单事件,而是图片上传后就自动执行表单提交事件,将上传的图片信息传给服务器. 刚开始我是这样执行 ...
- es6语法部分浏览器支持引发的坑
es2015部分浏览器支持踩的坑 自从es2015出现以来,以其更丰富的api和简介的语法,使得js功能越来越丰富写起来也更便捷.比较早先的时候,浏览器是完全不支持的,我们使用的时候,必须要使用bab ...
- TP5使用phpmailer实现邮件发送
1.从github下载PHPMailer,在vendor目录中新建文件夹phpmailer,将压缩包中的class.phpmailer.php和class.smtp.php复制到phpmailer中, ...
- Nginx的启动(start),停止(stop)命令
http://blog.csdn.net/u010739551/article/details/51654859 查看Nginx的版本号:nginx -V 启动Nginx:start nginx 快速 ...
- WinSCP怎么导入filezilla中的站点?
WinSCP是一款优秀的图形界面,远程文件管理工具,其出色的图形化界面与windows完美集成,是运用在windows上与远程服务器安全传输文件的软件之一 工具/原料 winscp 方法/步骤 下载. ...
- beetl 配置多视图解析器
如下配置,指定了三个视图解析器,一个用于beetl页面渲染,一个用于cms,采用了beetl技术,另外一个一些遗留的页面采用jsp <bean name="beetlConfig&qu ...
- c语言统计一个文件中的单词,字符和行数
body, table{font-family: 微软雅黑; font-size: 10pt} table{border-collapse: collapse; border: solid gray; ...
- scrapy_cookie禁用_延迟下载_自定义爬虫setting
如何设置禁止cookie? 在setting中 添加字段: COOKIE_ENABLED = False # False关闭cookie,True ...