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 版权 转载请保留本声明! 本文档包含的原创代码根据 ...
随机推荐
- 读书笔记——《C++ Concurrency IN ACTION》
=================================版权声明================================= 版权声明:原创文章 禁止转载 请通过右侧公告中的“联系邮 ...
- nxlog4go 简介 - 基于log4go的下一代go语言日志系统
nxlog4go的项目网址: https://github.com/ccpaging/nxlog4go 项目历史 ccpaging's log4go forked from https://githu ...
- label+input实现开关切换效果
Document 主要使用label+input来实现改变left的值,下面是核心代码,意思就是选中的input的兄弟节点.box下的.switch-btn元素的left会变成0px(原来是-37px ...
- Angular19 自定义表单控件
1 需求 当开发者需要一个特定的表单控件时就需要自己开发一个和默认提供的表单控件用法相似的控件来作为表单控件:自定义的表单控件必须考虑模型和视图之间的数据怎么进行交互 2 官方文档 -> 点击前 ...
- mysql-冗余和重复索引
mysql允许在相同列上创建多个索引,无论是有意还是无意,mysql需要单独维护重复的索引,并且优化器在优化查询的时候也需要逐个地进行考虑,这会影响性能. 重复索引是指的在相同的列上按照相同的顺序创建 ...
- python_开发规范
对于python有哪些开发规范? 1. 每行代码不超过80字符 2. 不要在逗号, 分号, 冒号前加空格, 应该之后加空格 3. 列表, 索引,切片的左括号前不加空格 4. 比较运算前后 加一个空格 ...
- 流API--使用并行流
这篇博客一起来研究下使用并行流.借组多核处理器并行执行代码可以显著提高性能,但是并行编程可能十分复杂且容易出错,流API提供的好处之一是能够轻松可靠的并行执行一些操作.请求并行处理流,首先要获得一个并 ...
- 在 ios 中的日期格式
var d="2017-1-1" ; new Date(d) //生成一个日期对象 这样写在 Android 中没有问题,但是在 ios 中,d 的格式不对,应该设为 2017- ...
- 【转】awk数组操作
转自:http://blog.csdn.net/wangran51/article/details/9168361 用awk进行文本处理,少不了就是它的数组处理.那么awk数组有那些特点,一般常见运算 ...
- CentsOS7无网情况下安装mysql5.7
1.需求就不用讲了,客户现场,政府环境,银行环境,大多是没网的,所以无网安装是很有必要的 mysql下载路径:https://dev.mysql.com/downloads/mysql/ 查看自己Li ...