随手笔记之VC++(四)
来源:互联网 发布:重庆seo入门基础教程 编辑:程序博客网 时间:2024/04/30 13:45
DLL : 动态链接库( Dynamic Link Library)
动态链接库 (DLL) 是作为共享函数库的可执行文件。
一般来说,DLL是一种磁盘文件,以.dll、.DRV、.FON、.SYS和许多以.EXE为扩展名的系统文件都可以是DLL。
动态链接库的调用可以分为两种:一种是隐式调用,一种是显示调用。
在操作系统中使用动态链接库(DLL)有很多优点,最主要的一点是多个应用程序、甚至是不同语言编写的应用程序可以共享一个DLL文件,真正实现了资源"共享",大大缩小了应用程序的执行代码,更加有效地利用了内存;使用DLL的另一个优点是DLL文件作为一个单独的程序模块,封装性、独立性好,在软件需要升级的时候,开发人员只需要修改相应的DLL文件就可以了,而且,当DLL中的函数改变后,如果没有修改参数,程序代码并不需要重新编译。这在编程时十分有用,大大提高了软件开发和维护的效率。
我们在Windows目录下的system32文件夹中会看到kernel32.dll、user32.dll和gdi32.dll,windows的大多数API都包含在这些DLL中。kernel32.dll中的函数主要处理内存管理和进程调度;user32.dll中的函数主要控制用户界面;gdi32.dll中的函数则负责图形方面的操作。
一般的程序员都用过类似MessageBox的函数,其实它就包含在user32.dll这个动态链接库中。由此可见DLL对我们来说其实并不陌生。
动态链接库中的导出接口可以使用Visual C++的Depends工具进行查看。
/* 文件名:lib.h */
#ifndef LIB_H
#define LIB_H
extern "C" int __declspec(dllexport)add(int x, int y);
#endif
/* 文件名:lib.cpp */
#include "lib.h"
int add(int x, int y)
{
`return x+y;
}
#include <stdio.h>
#include <windows.h>
typedef int(*lpAddFun)(int, int); //+])
{
HINSTANCE hDll; //DLL句柄
lpAddFun addFun; //函数指针
hDll = LoadLibrary("..\\Debug\\dllTest.dll");
if (hDll != NULL)
{
addFun = (lpAddFun)GetProcAddress(hDll, "add");
if (addFun != NULL)
{
int result = addFun(2, 3);
printf("%d", result);
}
FreeLibrary(hDll);
}
return 0;
}
add的声明前面添加了__declspec(dllexport)语句, 。这个语句的含义是声明函数add为DLL的导出函数.
DLL内的函数分为两种:
(1) DLL导出函数,可供应用程序调用;
(2) DLL内部函数,只能在DLL程序使用,应用程序无法调用它们。
DLL中导出函数的声明有两种方式:
1. __declspec(dllexport)
2. 采用模块定义(.def) 文件声明,.def文件为链接器提供了有关被链接程序的导出、属性及其他方面的信息。
“DLL加载-DLL函数地址获取-DLL释放,这种调用方式称为DLL的动态调用。
动态调用方式的特点是完全由编程者用 API 函数加载和卸载 DLL,程序员可以决定 DLL 文件何时加载或不加载,显式链接在运行时决定加载哪个 DLL 文件。
静态调用方式的特点是由编译系统完成对DLL的加载和应用程序结束时 DLL 的卸载。当调用某DLL的应用程序结束时,若系统中还有其它程序使用该 DLL,则Windows对DLL的应用记录减1,直到所有使用该DLL的程序都结束时才释放它。静态调用方式简单实用,但不如动态调用方式灵活。
静态调用的例子:
#pragma comment(lib,"dllTest.lib") //.lib文件中仅仅是关于其对应DLL文件中函数的重定位信息
extern "C" __declspec(dllimport) add(int x,int y);
int main(int argc, char* argv[])
{
int result = add(2,3);
printf("%d",result);
return 0;
}
由上述代码可以看出,静态调用方式的顺利进行需要完成两个动作:
1.告诉编译器与DLL相对应的.lib文件所在的路径及文件名,
#pragma comment(lib,"dllTest.lib")就是起这个作用。
程序员在建立一个DLL文件时,连接器会自动为其生成一个对应的.lib文件,该文件包含了DLL 导出函数的符号名及序号(并不含有实际的代码)。在应用程序里,.lib文件将作为DLL的替代文件参与编译。
2声明导入函数,extern "C" __declspec(dllimport) add(int x,int y)语句中的__declspec(dllimport)发挥这个作用。
_stdcall约定:
__stdcall,它意味着这个函数以标准Pascal的方式进行调用,也就是WINAPI方式;
如果通过VC++编写的DLL欲被其他语言编写的程序调用,应将函数的调用方式声明为__stdcall方式,WINAPI都采用这种方式,而C/C++缺省的调用方式却为__cdecl。__stdcall方式与__cdecl对函数名最终生成符号的方式不同。若采用C编译方式(在C++中需将函数声明为extern "C"),__stdcall调用约定在输出函数名前面加下划线,后面加“@”符号和参数的字节数,形如_functionname@number;而__cdecl调用约定仅在输出函数名前面加下划线,形如_functionname。
在lib.h中,应这样声明add函数:
int __stdcall add(int x, int y);
在应用工程中函数指针类型应定义为:
typedef int(__stdcall *lpAddFun)(int, int);
- 随手笔记之VC++(四)
- 随手笔记之VC++(三)
- 随手笔记之VC++(五)
- 随手笔记之VC++(八)
- 随手笔记之VC++(六)
- 随手笔记之VC++ (七)
- VC笔记(四)
- VC编程练习之API笔记(四)
- 随手笔记之Effective C++
- 数据结构随手笔记之哈希表
- VC入门笔记(四)
- VC++学习笔记(四)
- 孙鑫VC++笔记(四)
- VC++深入详解--之复习笔记(四)
- Java 并发编程之线程安全(随手笔记)
- VC之GDI(四)
- hadoop随手笔记(3)
- java随手笔记(二)
- java实现ireport动态报表导出与国际化
- C# Stopwatch类用法
- 一步一步学android之布局管理器——FrameLayout
- bootmem allocator分析
- KMP算法详解
- 随手笔记之VC++(四)
- 设计模式2 观察者模式
- 外在化应用参数的配置 spring <context:property-placeholder location="" />
- iOS 的 IAP 教程
- Android 桌面插件
- Quagga通信详解
- Android开发点点滴滴——LayoutInflater及inflate方法
- Storyboard全解析-第二部分
- Hibernate 对象的三种状态