栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

Windows动态链接库(dll)浅析 - 2

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Windows动态链接库(dll)浅析 - 2

Windows动态链接库(dll)浅析 - 2
  • Windows动态链接库(dll)浅析 - 1
  • Windows动态链接库(dll)浅析 - 3
5. DLL的编写 5.1 一个简单的dll项目

上面用静态链接库的方式提供了add函数接口,下来我们看看用动态链接库的方式如何实现同样的功能。
  首先,在VS中创建一个“动态链接库”项目DllAdd。

  然后,为项目添加lib.cpp及lib.h文件,源码如下:

lib.cpp:
#include "lib.h"

int add(int x, int y)
{
	return x + y;
}
lib.h:
#ifndef __LIB_H__
#define __LIB_H__

#ifdef DLLADD_EXPORTS

extern "C" _declspec(dllexport)
int add(int x, int y);

#else

extern "C" _declspec(dllimport)
int add(int x, int y);

#endif

#endif

最后,在项目属性页中“C/C++ -> 预处理器 -> 预处理器定义”中增加“DLLADD_EXPORTS”。编译生成项目,可以得到DllAdd.lib。

  
  分析上述代码,DllAdd工程中的lib.cpp 文件与前一节静态链接库版本完全相同,不同在于lib.h 对函数add的声明前面添加了LIB_API宏的定义。当“DLLADD_EXPORTS”这个宏有定义时,这个语句的含义是声明函数add为DLL的“extern"C" __declspec(dllexport)”导出函数,否则为”extern"C" __declspec(dllimport)”导入函数。我们通过项目属性页为DllAdd工程增加预处理器DLLADD_EXPORTS,这样这个工程内时,add就被定义成导出函数了,当lib.h文件给调用者使用时,由于调用者的工程中没有该宏的定义,所以它的add函数就被定义成了导入函数。

5.2 dll导出函数

dll中导出函数的声明方式有两种:一种是像上一个小节给出的示例一样,在函数声明上加上“_declspec(dllexport)”;另一种方法是采用“模块定义(.def)”文件声明,“.def”文件为链接器提供了有关被链接程序的导出、属性等方面的信息。
  
  下面给出一个.def文件示例

; lib.def : 导出DLL函数
LIBRARY DllAdd
EXPORTS
add @ 1
  • 说明:
  • LIBRARY语句说明.def文件相应的DLL;
  • EXPORTS语句后列出要导出函数的名称;
  • 在.def文件中的导出函数名后加@n,表示要导出函数的序号为n(在后面进行显示函数调用时,这个序号将发挥其作用);
5.3 dll的调用方式

动态链接库的调用方法包括两种:隐式调用和显示调用。

5.3.1 隐式调用(静态调用)

隐式调用也称为静态调用,是由编译系统完成对dll的加载和应用程序结束时卸载。当调用某个DLL的程序结束时,若系统中还有其他程序使用该dll,则Windows对dll的应用记录减1,直到所有使用该dll的程序都结束时才释放它。静态调用方式同静态链接库的调用方式相同,特点也是简单实用,但不如动态调用方式灵活。
  下面我们新建一个Windows控制台程序DllCallStatic,并修改DllCallStatic.cpp如下:

#include "stdafx.h"
#include 

#include "../../DllAdd/DllAdd/lib.h"

#pragma comment(lib, "../../DllAdd/Debug/DllAdd.lib")

int main(int argc, char*argv[])
{
	int result = add(2048, 52);

	printf("%dn", result);

	return 0;
}

注意:
  (1)将DllAdd.dll复制到DllCallStatic项目的工作目录;
  (2)在DllCallStatic工程中没有对DLLADD_EXPORTS宏的定义,故add在lib.h头文件中已经被定义称为了extern"C" __declspec(dllimport)导入函数。

编译并运行,查看结果。

5.3.2 显式调用(动态调用)

显式调用是指使用由“LoadLibrary - GetProcAddress - FreeLibrary”系统API提供的三位一体“DLL加载 - DLL函数地址获取 - DLL释放”方式,这种调用方式也被称为DLL的动态调用。动态调用方式的特点是完全由编程者用API函数加载和卸载DLL,程序员可以决定DLL文件何时加载或不加载,显式链接在运行时决定加载哪个DLL文件。
  
  新建一个Windows控制台程序DllCallDynamic,并修改DllCallDynamic.cpp如下:

#include "stdafx.h"
#include
#include

typedef int(*lpAddFun)(int, int); //宏定义函数指针类型

int main(int argc, char*argv[])
{
	HINSTANCE hDll;//DLL句柄
	lpAddFun addFun;//函数指针

	hDll = LoadLibrary(L"..//..//DllAdd//Debug//DllAdd.dll");

	if (hDll != NULL)
	{
		addFun = (lpAddFun)GetProcAddress(hDll, "add");

		if (addFun != NULL)
		{
			int result = addFun(72, 28);
			printf("result:%dn", result);
		}

		FreeLibrary(hDll);
	}

	return 0;
}

编译并运行,查看结果。

5.3.3 dll查找顺序

为了使需要动态链接库的应用程序可以运行,需要将DLL文件放在操作系统能够找到的地方。Windows操作系统查找DLL的目录顺序为:

  1. 应用程序的可执行文件(*.exe)所在的目录

  2. 进程的当前工作目录

  3. Windows系统目录:Windows操作系统安装目录的系统子目录,如C:Windows System32。可用GetSystemDirectory函数检索此目录的路径。

  4. Windows目录:Windows操作系统安装目录,如C:Windows。可用GetWindowsDirectory函数检索此目录的路径。

  5. 搜索目录:Path环境变量中所包含的自动搜索路径目录,一般包含C:Windows和C:WindowsSystem32等目录。可在命令行用Path命令来查看和设置,也可以通过(在“我的电脑”右键菜单中选“属性”菜单项)“系统属性”中的环境变量,来查看或编辑“Path”系统变量和“Path”用户变量。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1018209.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号