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 版权 转载请保留本声明! 本文档包含的原创代码根据 ...
随机推荐
- 将TinyXml快速入门的接口面向对象化(转载)
作者:朱金灿 来源:http://www.cnblogs.com/clever101 在TinyXml快速入门的系列文章中(详情见本博客),我只是将tinyxml类库解析xml文件的类封装为API接口 ...
- [国嵌笔记][010][TFTP与NFS服务器配置]
交叉开发 嵌入式软件产生的平台称为宿主机,运行嵌入式软件的平台称为目标机 宿主机一般通过串口.网络.USB.JTAG等方式将软件下载到目标机 网络下载 一般有TFTP和NFS两种方式 tftp服务器 ...
- django入门基础
首先要说的是django与其他的框架不同,django是一个封装的及其完善的框架,我们使用django也不会像之前写学生系统那样,django操作数据库使用自带的ORM来进行操作,Torando与Fl ...
- 使用layui在规定的期限内选择日期
这几天碰到了layui中的日期与时间这个,本以为很简单的,可是又一个需求是这样的,有两个日期选择框,第一个日期选择框要求最小日期不得小于当前日期,第二个日期选择框要求最小日期为第一个日期选择框的选中日 ...
- line-height相关总结
line-height http://cindylu520.iteye.com/blog/670512 四个boxes containing boxes inline boxes 匿名inline b ...
- 修改织梦默认栏目页、文章页URL命名规则,简化目录结构
版权声明:本文为博主原创文章,未经博主允许不得转载. 用织梦Dedecms建站,建议优化系统默认的URL结构,这样能简化网站目录深度,利于搜索引擎收录. 现在织梦的默认文章命名规则是 {typedir ...
- dedecms幻灯片调用图片模糊的解决办法
dedecms幻灯片调用的是缩略图,如果图片尺寸比例和幻灯片的大小相差太大的话,图片就会自动拉伸模糊,比较影响美观和用户体验,下面就有常用的2个方法来解决这个图片模糊的问题. 第一种:手动制图 我们用 ...
- element-ui中upload组件如何传递文件及其他参数
最近项目用到了vuethink,里面集成了element-ui,之前一直用的是bootstrap框架,对js也是一知半解,然后也用过vue.js,但也是学的不通透的,然后就各种入坑. 下面就分析一下我 ...
- Python 3 利用机器学习模型 进行手写体数字识别
0.引言 介绍了如何生成数据,提取特征,利用sklearn的几种机器学习模型建模,进行手写体数字1-9识别. 用到的四种模型: 1. LR回归模型,Logistic Regression 2. SGD ...
- 使用VSCode和VS2017编译调试STM32程序
近两年,微软越来越拥抱开源支持跨平台,win10搭载Linux子系统,开源VSCode作为跨平台编辑器,VS2017官方支持了Linux和嵌入式开发功能. ST也是,近两年开发的软件工具基本都是跨平台 ...