COM编程之五 动静态链接
【1】静态链接
静态链接是指由链接器在链接时将库的内容加入到可执行程序中的做法。
链接器是一个独立程序,将一个或多个库或目标文件(先前由编译器或汇编器生成)链接到一块生成可执行程序。
函数和数据被编译进一个二进制文件(通常扩展名为.LIB)。
在使用静态库的情况下,在编译链接可执行文件时,链接器从库中复制这些函数和数据并把它们和应用程序的其它模块
组合起来创建最终的可执行文件(.EXE文件)。
具体实例步骤如下:
第一步:打开VS2010-->文件-->新建-->工程-->WIN32控制台项目-->确定(名称Static)-->静态库选项-->预编译头文件不选-->Finish
第二步:在这个空项目中,添加一个lib.h文件和一个lib.cpp文件
首先添加 lib.h 声明文件
1 // Static Project 2 // lib.h 3 // 声明函数 4 5 #ifndef LIB_H 6 #define LIB_H 7 8 extern "C" int Add(int a, int b); 9 extern "C" int Sub(int a, int b); 10 11 #endif
再添加 lib.cpp 实现文件
1 // Static project 2 // lib.cpp 3 // 实现函数逻辑 4 5 #include "lib.h" 6 7 int Add(int a, int b) 8 { 9 return a + b; 10 } 11 int Sub(int a, int b) 12 { 13 return a - b; 14 }
第三步:保证添加正确后编译整个工程,确保编译成功
第四步:在工程Debug文件夹下寻找生成的Static.lib文件,这个文件正是我们需要的静态链接库
第五步:在目前的工程下,新建空项目TestLib。用以测试静态链接库的使用效果:
(1)实现方式一
a. 将Static项目下的lib.h和Static.lib这两个文件复制到TestLib项目的目录下
b. 在工程目录中添加已存在的lib.h文件
c. 再新建一个Test.cpp文件。如下:
1 // TestLib project 2 // Test.cpp 3 // 测试静态链接库 4 5 #include "lib.h" 6 #include <stdlib.h> 7 #include <stdio.h> 8 9 #pragma comment(lib,"Static.lib") 10 11 void main() 12 { 13 printf("%d\n", Add(1, 2)); 14 printf("%d\n", Sub(4, 3)); 15 system("pause"); 16 }
说明:#pragma comment( lib, "Static.lib" ),这一句是显式的导入静态链接库。
(2)实现方式二
a. 将Static项目下的lib.h文件复制到TestLib项目的目录下
b. 在工程目录中添加已存在的lib.h文件
c. 工程-->属性-->链接器-->输入-->附加依赖项输入“Static.lib”
d. 再新建一个Test.cpp文件。如上。
不论使用那种方式。最终编译 运行的结果都应该是正确链接并调用到两个函数。执行结果不做赘述。
【2】静态链接过程详解
静态链接即就是把被链接项目的.h文件和.cpp文件
首先编译成为一个静态链接库文件.lib
然后在链接项目的源文件目录添加
编译生成的静态链接库文件.lib 以及 被链接项目的.h文件
最后在链接项目的源文件中引入.h文件 并显式导入静态链接库
即可成功执行链接项目调用被链接项目的接口功能
其实形象理解如下:
即就是别人把它的产品零件(.h和.cpp文件)
通过车床(静态链接库工程)
进行加工 (编译)
生成一个机器产品 (debug文件)
抛弃生成的不必要成分 (debug中除过.lib的其他文件)
提取对客户有用的核心部分 (debug中的.lib文件)
当然这个核心的部分是独一无二的(别人拥有版权的权利)
为了人性化的推销使用他们的产品,他们要把产品说明书(.h文件)附加
送给我们,以便于我们的正确高效使用!
【3】动态链接
动态链接库链接分为两种方式:
(1)载入时动态链接
即是:编译之前已经明确知道要调用DLL中的哪几个函数并且编译时在目标文件中只保留必要的链接信息,而不含DLL函数的代码。
当程序执行时,利用链接信息加载DLL函数代码并在内存中将其链接入调用程序的执行空间中,其主要目的是便于代码共享。
实例如下:
第一步:打开VS2010-->文件-->新建-->工程-->WIN32控制台项目-->确定(名称DLL)-->DLL选项->Finish
第二步:查看新建项目是否存在dllmain.cpp文件,确保为DLL项目。然后在项目中添加以下文件:
a. dll.h
1 // DLL project 2 // DLL.h 3 // 声明导出函数 4 5 #ifndef DLL_H 6 #define DLL_H 7 8 extern "C" __declspec(dllexport) int add(int x, int y); 9 10 #endif
b. dll.cpp
1 // DLL project 2 // DLL.cpp 3 // DLL 函数实现 4 #include "stdafx.h" 5 #include "dll.h" 6 7 int add(int x, int y) 8 { 9 return x + y; 10 }
编译整个DLL项目,工程Debug目录下会生成DLL.lib和DLL.dll文件。装入时动态链接必需二者。
第三步:在目前的工程下,新建空项目TestDLL。用以测试装入时动态链接库的效果:
将DLL项目Debug目录下的DLL.dll和DLL.lib这两个文件复制到TestDLL项目的目录下。
再新建一个TestDll.cpp文件。如下:
1 //ps:该文件属于TestDll项目,与DLL项目同属于一个工程 2 // TestDll project 3 // TestDll.cpp 4 // 静态调用DLL实现 5 6 #include<stdio.h> 7 8 #pragma comment(lib,"dll.lib") 9 extern "C" __declspec(dllimport) int add(int x, int y); 10 11 void main( ) 12 { 13 int result = add(20, 30); 14 printf("%d", result); 15 }
第四步:编译TestDLL项目。执行结果应该正确调用add函数功能。
过程进行完毕,但是过程中存在很多疑问。且听分析:
1. .lib文件详解
.lib 文件为Windows系统中的库文件,相当于Linux中的.a 或 .o、.so文件
lib有 静态lib 和 动态lib之分
a: 静态lib将导出声明和实现都放在lib中。编译后所有代码都嵌入到宿主程序。(如上静态链接模块中编译后得到的lib文件)
b: 动态lib相当于一个.h文件,是对实现部分(.dll文件)的导出部分的声明。
编译后只是将导出声明部分编译到宿主程序中,运行时候需要相应的dll文件支持。
一个lib文件是obj文件的集合。
当然,其中还夹杂着其他一些辅助信息,目的是为了让编译器能够准确找到对应的obj文件。
2. 如下两句的作用:
1 extern "C" __declspec(dllexport) int add(int x, int y); 2 extern "C" __declspec(dllimport) int add(int x, int y);
在动态链接库中__declspec(dllexport)作用是导出声明,__declspec(dllimport)作用是导入声明。
关于导出导入声明还有另外一种方式即采用模块定义文件(.def),下面将示例。
3. #pragma comment(lib,"dllTest.lib")作用是告诉编译器与DLL相对应的.lib文件所在的路径及文件名。
程序员在建立一个DLL文件时,连接器会自动为其生成一个对应的.lib文件。
该文件包含了DLL导出函数的符号名及序号(并不含有实际的代码)。
在应用程序里,.lib文件将作为DLL的替代文件参与编译。
总而言之,静态链接方式编译生成应用程序时,应用程序中调用的与.lib文件中导出符号相匹配的函数符号将进入到生成的EXE文件中,.lib文件中所包含的与之对应
的DLL文件的文件名也被编译器存储在EXE文件内部。
当应用程序运行过程中需要加载DLL文件时,Windows将根据这些信息发现并加载DLL,然后通过符号名实现对DLL函数的动态链接。
这样,EXE将能直接通过函数名调用DLL的输出函数,就像调用程序内部的其它函数一样。
(2)运行时动态链接
即是:编译之前并不知道将会调用哪些DLL函数,完全是在运行过程中根据需要决定应调用哪个函数,并用LoadLibrary和GetProcAddress动态获得DLL函数的入口地址。
实例如下:
第一步:打开VS2010-->文件-->新建-->工程-->WIN32控制台项目-->确定(名称DLL)-->DLL选项->Finish
第二步:查看新建项目是否存在dllmain.cpp文件,确保为DLL项目。然后在项目中添加以下文件:
a. dll.cpp
1 // DLL.cpp 2 // 实现文件 3 4 #include "stdafx.h" 5 6 int add(int a, int b) 7 { 8 return a + b; 9 }
b. dll.def
1 ; Dll.def : 导出DLL函数 2 LIBRARY DLL 3 EXPORTS 4 add @ 1
编译整个DLL项目,工程Debug目录下会生成DLL.lib和DLL.dll文件。装入时动态链接必需二者。
如果VS2010环境下只有.dll文件没有生成.lib文件
需要在项目-->属性-->连接器-->输入-->模块定义文件中添加指定模块定义文件
第三步:在目前的工程下,新建空项目TestDLL。用以测试装入时动态链接库的效果:
新建一个TestDll.cpp文件。如下:
1 // TestDLL project 2 // TestDLL.cpp 测试动态链接 3 4 #include <stdio.h> 5 #include <Windows.h> 6 using namespace std; 7 8 typedef int(*lpAddFun)(int, int); //宏定义函数指针类型 9 10 int main(int argc, char *argv[]) 11 { 12 HINSTANCE hDll; //DLL句柄 13 lpAddFun addFun; //函数指针 14 wchar_t wchar[] = L"..\\Debug\\DLL.dll"; 15 hDll = LoadLibrary(wchar); 16 if (hDll != NULL) 17 { 18 addFun = (lpAddFun)GetProcAddress(hDll, "add"); 19 if (addFun != NULL) 20 { 21 int result = addFun(20, 30); 22 printf("%d\n", result); 23 } 24 FreeLibrary(hDll); 25 } 26 return 0; 27 }
第四步:编译TestDLL项目。执行结果应该正确调用add函数功能。
1. def文件
a: 模块定义 (.def) 文件为衔接器提供有关被链接程序的导出、属性及其他方面的信息。生成 DLL 时,.def 文件最有用。
b: .def文件的规则为:
(1) LIBRARY语句说明.def文件相应的DLL;
(2) EXPORTS语句后列出要导出函数的名称。可以在.def文件中的导出函数名后加@n,表示要导出函数的序号为n(在进行函数调用时,这个序号将发挥其作用);
(3) .def 文件中的注释由每个注释行开始处的分号 (;) 指定,且注释不能与语句共享一行。
2. LoadLibrary 加载动态库; GetProcAddress 获取DLL函数的地址; FreeLibrary 释放动态库。
【4】动态链接分析
相比静态链接,动态链接有几个优点:
1.多个进程在同一基地址装载相同DLL,只需要一个共享DLL即可,它在物理地址空间内共享。
2.DLL内的函数变化,只要其输入输入参数、调用格式没有变,应用程序自身不必重新编译。静态链接需要重新编译。
3.DLL提供异步支持。比如应用程序装载DLL时,用DLL支持一个无效设备。
4.不同语言编写的应用程序可以用约定的调用格式调用DLL函数。
潜在缺点是应用程序不是相对独立的。
启动装载动态链接时,DLL不存在,程序不被装载。
运行装载时,如果DLL不存在,由程序处理。
【5】静态链接 与 动态链接 总结
静态链接是在生成可执行程序的时候就把库中的内容加入到程序中。
载入时动态链接是在将功能模块读入内存时把动态库中调用到的相关模块的内容载入内存。
运行时动态链接是在执行程序调用到模块内容时再将动态库中的相应模块载入到内存。
这里有两个时间问题。一是载入时间,二是执行时间。
静态链接由于是在一开始就把所有模块都加载进入内存,所以如果模块很多的话效率就会被大大拉低。
载入时动态链接是分别载入,当把一个模块载入内存时检查有调用关系的模块载入,比静态链接节省了许多开销。
运行时动态链接则是把当前模块调用的模块推迟到调用的时候再载入。
三者之间的关系就像是机枪,冲锋枪和shou枪
机枪在一开始就把所有子弹装好,开枪的时候很快,但也很笨重。
冲锋枪则是将子弹分弹夹存好,轻便了许多,但是会有一段装填时间。
shou枪就更加轻便了,但是弹夹容量更小,装填的频率又变高了。
【6】组件与动态链接库
动态链接库简称为DLL。一个组件实际上并不是一个DLL。
DLL只是一个组件服务器。或者说是一种发行组件的方式。
组件实质上应看成是在DLL中所实现的接口集。
DLL只是一种形式,而组件才是实质。
而组件需要放入DLL中,在客户获取某个组件接口指针时:
它必须先将相应的DLL装载到其进程空间并创建此组件。
CreateInstance可以建立一个组件实例并给客户返回一个IUnknown接口指针。
CreateInstance是DLL中唯一需要客户显式链接的函数。
而客户对于组件所需的所有函数通过一个接口指针而访问到。
Good Good Study, Day Day Up.
顺序 选择 循环 总结
COM编程之五 动静态链接相关推荐
- Linux gcc 制作动/静态链接库
gcc 静态链接库 以 math.c为例 gcc -c math.c ar rcs libmath.a math.o ar命令 将多个文件打包成一个备份文件 参数r:用来替换库中已有的目标文件,或加入 ...
- c语言之动静态链接库
静态链接库.a 出于版权保护行为,将源文件编译但不链接生成.o文件,再用ar工具将多个.o文件归档成.a文件,该.a文件就被称为静态链接库.再发布.a和.h文件,h文件显示有.o中函数声明.用户即可知 ...
- gcc/gdb/make/动/静态链接库介绍
gcc是一个编译工具,我们平时写的c/c++代码要想变成可执行文件,必须要经过预处理.编译.汇编.连接等步骤.gcc工具就完成这些动作. 一gcc编译过程 二.gcc常用参数 1.编译过程常用参数 参 ...
- 【Linux】磁盘结构/文件系统/软硬链接/动静态库
文章目录 前言 一.磁盘结构 1.磁盘的物理结构 2.磁盘的存储结构 3.磁盘的逻辑结构 二.文件系统 1.对 IO 单位的优化 2.磁盘分区与分组 3.对分组的具体管理方法 4.文件操作 三.软硬链 ...
- OSG_64位动态链接库+静态链接库的使用
前言 最近看了FreeSouth的几个视频对于他用的链接库导出类还是挺感兴趣的然后我就实现了下简单的Dll动态库操作+静态库,博主自己用的是vs2017编译的话用的x64位编译的.,自己之前找了半天都 ...
- 学习系统编程No.15【深入动静态库】
引言: 北京时间:2023/4/5/11:04,天空阴沉,非常符合今天清明节的身份,不知道是大部分学校都放假一天,还是就我们学校,反正清明节回不了家,昨天上了一个中国优秀传统文化的课,老师给我们讲了李 ...
- Linux下的静态链接库和动态链接库编程
Linux下的静态链接库和动态链接库编程 参考: Linux下的静态链接库和动态链接库编程 - Histring - 博客园 Mac下静态库和动态库的创建和使用_C/C++_vincent2610的专 ...
- linux文件编程(2)——系统文件描述符、动静态文件、块设备介绍
参考:linux文件编程(2)--文件操作原理简述之文件描述符.动静态文件.块设备 作者:丶PURSUING 发布时间: 2021-04-09 11:14:12 网址:https://blog.csd ...
- Linux系统编程25:基础IO之亲自实现一个动静态库
本文接:Linux系统编程24:基础IO之在Linux下深刻理解C语言中的动静态库以及头文件和库的关系 文章目录 A:说明 B:实现静态库 C:实现动态库 A:说明 前面说过,库其实就是头文件和和.a ...
最新文章
- 我艹,MySQL数据量大时,delete操作无法命中索引。
- 第三章:3.0 本章内容介绍
- 释疑の舍入参数文件介绍
- maven jar包冲突的发现与解决[工具篇]
- 苹果手机其他占内存很大去哪删除_Iphone内存总是不够用?原来这才是正确清理垃圾的方法,长见识了...
- 前端怎么携带cookie发送php,PHP如何执行传递cookie的http请求并将结果保存到字符串...
- Go语言学习笔记(八)
- Android 进程的五种生命周期学习
- xlsx文件怎么打开
- 8_7.网络安全协议
- Alexa 世界网站排名研究(上)(转)
- 什么是PLC?可编程控制器的结构和工作原理介绍
- hdu 5294 Tricks Device 最短路建图+最小割
- 群雄混战的短视频,繁荣背后存在的短板
- web项目js调用斑马打印机打印二维码
- 夏令营一部分数学试题
- transact-sql的语法规则
- EditPlus格式化xml文档
- 解决办法: Cannot resolve the collation conflict between Japanese_CI_AS and SQL_...
- .xb文件腾讯云备份恢复