赞
踩
8种机械键盘轴体对比
本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选?
静态链接库和动态链接库
1) 静态库
函数和数据被编译进一个二进制文件(通常扩展名为.LIB)。在使用静态库的情况下, 在编译链接可执行文件时,链接器从库中复制这些函数和数据并把它们和应用程序的其他模块组合起来创建最终的可执行文件(.EXE文件)。++当发布产品时,只需要发布这个可执行文件,并不需要发布被使用的静态库。++
2) 动态库
在使用动态库的时候,往往提供两个文件:一个引入库(.lib)文件和一个DLL (.dll) 文件。虽然引入库的后缀名也是“lib”,但是,动态库的引入库文件和静态库文件有着本质上的区别,++对一个DLL来说,其引入库文件(.lib)包含该DLL导出的函数和变量的符号名,而.dll文件包含该DLL实际的函数和数据++。在使用动态库的情况下,在编译链接可执行文件时,只需要链接该DLL的引入库文件,该DLL中的函数代码和数据并不复制到可执行文件中,++直到可执行程序运行时,才去加载所需的DLL++,将该DLL映射到进程的地址空间中,然后访问DLL中导出的函数。++这时,在发布产品时,除了发布可执行文件以外,同时还要发布该程序将要调用的动态链接库。++
第一个demohModule 表示本DLL程序的句柄。
ul_reason_for_call 表示DLL当前所处的状态,例如DLL_PROCESS_ATTACH表示DLL刚刚被加载到一个进程中,DLL_PROCESS_DETACH表示DLL刚刚从一个进程中卸载。
lpReserved 表示一个保留参数,目前已经很少使用。
DllMain() 函数在DLL程序载入和卸载时执行,可以用来做一些初始化和清理的工作,++如果仅仅是向外暴露函数,就可以省略 DllMain() 函数++。但是如果有 DllMain() 函数,就一定要 #include 或 #include 。首先利用VC6.0新建一个 Win32 Dynamic-Link Library 类型的工程,工程取名为 dllDemo,并选择“An empty Dll project”选项,即创建一个空的动态链接库工程。然后,为该工程添加 一个C源文件 main.c,并在其中编写完成加法运算和减法运算的函数,代码如下所示:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include // 也可以 #include
#include
_declspec(dllexport) int add(int a, int b){
return a+b;
}
_declspec(dllexport)int sub(int a, int b){
return a-b;
}
BOOL APIENTRY DllMain(
HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
){
if(ul_reason_for_call == DLL_PROCESS_ATTACH){
printf("Congratulations! DLL is loaded!");
}
}
查看一个DLL中有哪些导出函数VC98bin目录下,批处理文件VCVARS32.bat,该文件的作用是用来建立VC6.0使用的环境信息。该文件所设置的环境信息只是在当前命令行窗口生效。如果关闭该窗口。
Dumpbin.exe文件位于VC6.0安装目录下的VC98bin目录下,用于查看dll文件的导出函数:1
2dumpbin -exports 文件名
dumpbin -exports dllDemo.dll
动态链接库DLL的加载:隐式加载(载入时加载)和显式加载(运行时加载)动态链接库有两种加载方式:隐式加载和显示加载。隐式加载又叫载入时加载,++指在主程序载入内存时搜索DLL,并将DLL载入内存++。隐式加载也会有静态链接库的问题,如果程序稍大,加载时间就会过长,用户不能接受。
显式加载又叫运行时加载,++指主程序在运行过程中需要DLL中的函数时再加载++。显式加载是将较大的程序分开加载的,程序运行时只需要将主程序载入内存,软件打开速度快,用户体验好。
隐式加载#pragma comment(lib, “dllDemo.lib”) 手动导包1
2
3
4
5
6
7
8
9#include
extern int add(int, int); // 也可以是 _declspec(dllimport) int add(int, int);
extern int sub(int, int); // 也可以是 _declspec(dllimport) int sub(int, int);
int main(){
int a=10, b=5;
printf("a+b=%dn", add(a, b));
printf("a-b=%dn", sub(a, b));
return 0;
}
另一种写法1
2
3
4
5
6
7[dllDemo.h]
#ifndef _DLLDEMO_H
#define _DLLDEMO_H
#pragma comment(lib, "dllDemo.lib")
_declspec(dllexport) int add(int, int);
_declspec(dllexport) int sub(int, int);
#endif1
2
3
4
5
6
7
8
9
10
11[demo.c]
#include
#pragma comment(lib, "dllDemo.lib")
_declspec(dllimport) int add(int, int);
_declspec(dllimport) int sub(int, int);
int main(){
int a=10, b=5;
printf("a+b=%dn", add(a, b));
printf("a-b=%dn", sub(a, b));
return 0;
}
显式加载将 debug 目录下的 dllDemo.dll 复制到当前工程目录下。注意,++只需要 dllDemo.dll,不需要 dllDemo.lib++。
LoadLibrary() 函数该函数的作用是将指定的可执行模块映射到调用进程的地址空间1
2
3HMODULE LoadLibrary(LPCTSTR 1pFileName);
//1pFileName: 调用对象;dll和exe
//HMODULE: 返回调用对象的句柄对象
GetProcAddress()函数获取该动态链接库中导出函数的地址1
2
3FARPROC GetProcAddress(HMODULE hModule, LPCSTR 1pProcName);
//hModule:指定动态链接库模块的句柄,即 LoadLibrary() 函数的返回值。
//1pProcName:字符串指针,表示DLL中函数的名字。
例子1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22#include
#include
#include // 必须包含 windows.h
typedef int (*FUNADDR)(); // 指向函数的指针
int main(){
int a=10, b=5;
HINSTANCE dllDemo = LoadLibrary("dllDemo.dll");
FUNADDR add, sub;
if(dllDemo){
add = (FUNADDR)GetProcAddress(dllDemo, "add");
sub = (FUNADDR)GetProcAddress(dllDemo, "sub");
}else{
printf("Fail to load DLL!n");
system("pause");
exit(1);
}
printf("a+b=%dn", add(a, b));
printf("a-b=%dn", sub(a, b));
system("pause");
return 0;
}
参考文件
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。