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 动态链接库编程的更多相关文章

  1. Windows Socket 编程_单个服务器对多个客户端简单通讯

    单个服务器对多个客户端程序: 一.简要说明 二.查看效果 三.编写思路 四.程序源代码 五.存在问题 一.简要说明: 程序名为:TcpSocketOneServerToMulClient 程序功能:实 ...

  2. 【Windows】windows核心编程整理(下)

    windows核心编程整理(上) windows核心编程整理(下) 线程的堆栈 每当创建一个线程时,系统就会为线程的堆栈(每个线程有他自己的堆栈)保留一个堆栈空间区域,并将一些物理存储器提交给这个以保 ...

  3. 《windows核心编程系列》十七谈谈dll

    DLL全称dynamic linking library.即动态链接库.广泛应用与windows及其他系统中.因此对dll的深刻了解,对计算机软件开发专业人员来说非常重要. windows中所有API ...

  4. Ligg.EasyWinApp-000: 一款Windows应用编程框架介绍

        本框架(解决方案)是一个Windows应用编程框架和UI库,通过该框架,不需任何代码,通过XML配置文件,搭建任意复杂的Windows应用界面,以类似Execel公式的方式实现基本的过程控制( ...

  5. windows多线程编程星球(一)

    以前在学校的时候,多线程这一部分是属于那种充满好奇但是又感觉很难掌握的部分.原因嘛我觉得是这玩意儿和编程语言无关,主要和操作系统的有关,所以这部分内容主要出现在讲原理的操作系统书的某一章,看完原理是懂 ...

  6. windows核心编程 - 线程同步机制

    线程同步机制 常用的线程同步机制有很多种,主要分为用户模式和内核对象两类:其中 用户模式包括:原子操作.关键代码段 内核对象包括:时间内核对象(Event).等待定时器内核对象(WaitableTim ...

  7. windows核心编程---第九章 同步设备IO与异步设备IO之同步IO

    同步设备IO 所谓同步IO是指线程在发起IO请求后会被挂起,IO完成后继续执行. 异步IO是指:线程发起IO请求后并不会挂起而是继续执行.IO完毕后会得到设备的通知.而IO完成端口就是实现这种通知的很 ...

  8. windows核心编程---第八章 使用内核对象进行线程同步

    使用内核对象进行线程同步. 前面我们介绍了用户模式下线程同步的几种方式.在用户模式下进行线程同步的最大好处就是速度非常快.因此当需要使用线程同步时用户模式下的线程同步是首选. 但是用户模式下的线程同步 ...

  9. storysnail的Windows串口编程笔记

    storysnail的Windows串口编程笔记 作者 He YiJun – storysnail<at>gmail.com 团队 ls 版权 转载请保留本声明! 本文档包含的原创代码根据 ...

随机推荐

  1. 将TinyXml快速入门的接口面向对象化(转载)

    作者:朱金灿 来源:http://www.cnblogs.com/clever101 在TinyXml快速入门的系列文章中(详情见本博客),我只是将tinyxml类库解析xml文件的类封装为API接口 ...

  2. [国嵌笔记][010][TFTP与NFS服务器配置]

    交叉开发 嵌入式软件产生的平台称为宿主机,运行嵌入式软件的平台称为目标机 宿主机一般通过串口.网络.USB.JTAG等方式将软件下载到目标机 网络下载 一般有TFTP和NFS两种方式 tftp服务器 ...

  3. django入门基础

    首先要说的是django与其他的框架不同,django是一个封装的及其完善的框架,我们使用django也不会像之前写学生系统那样,django操作数据库使用自带的ORM来进行操作,Torando与Fl ...

  4. 使用layui在规定的期限内选择日期

    这几天碰到了layui中的日期与时间这个,本以为很简单的,可是又一个需求是这样的,有两个日期选择框,第一个日期选择框要求最小日期不得小于当前日期,第二个日期选择框要求最小日期为第一个日期选择框的选中日 ...

  5. line-height相关总结

    line-height http://cindylu520.iteye.com/blog/670512 四个boxes containing boxes inline boxes 匿名inline b ...

  6. 修改织梦默认栏目页、文章页URL命名规则,简化目录结构

    版权声明:本文为博主原创文章,未经博主允许不得转载. 用织梦Dedecms建站,建议优化系统默认的URL结构,这样能简化网站目录深度,利于搜索引擎收录. 现在织梦的默认文章命名规则是 {typedir ...

  7. dedecms幻灯片调用图片模糊的解决办法

    dedecms幻灯片调用的是缩略图,如果图片尺寸比例和幻灯片的大小相差太大的话,图片就会自动拉伸模糊,比较影响美观和用户体验,下面就有常用的2个方法来解决这个图片模糊的问题. 第一种:手动制图 我们用 ...

  8. element-ui中upload组件如何传递文件及其他参数

    最近项目用到了vuethink,里面集成了element-ui,之前一直用的是bootstrap框架,对js也是一知半解,然后也用过vue.js,但也是学的不通透的,然后就各种入坑. 下面就分析一下我 ...

  9. Python 3 利用机器学习模型 进行手写体数字识别

    0.引言 介绍了如何生成数据,提取特征,利用sklearn的几种机器学习模型建模,进行手写体数字1-9识别. 用到的四种模型: 1. LR回归模型,Logistic Regression 2. SGD ...

  10. 使用VSCode和VS2017编译调试STM32程序

    近两年,微软越来越拥抱开源支持跨平台,win10搭载Linux子系统,开源VSCode作为跨平台编辑器,VS2017官方支持了Linux和嵌入式开发功能. ST也是,近两年开发的软件工具基本都是跨平台 ...