COM编程之五 动静态链接
【1】静态链接
静态链接是指由链接器在链接时将库的内容加入到可执行程序中的做法。
链接器是一个独立程序,将一个或多个库或目标文件(先前由编译器或汇编器生成)链接到一块生成可执行程序。
函数和数据被编译进一个二进制文件(通常扩展名为.LIB)。
在使用静态库的情况下,在编译链接可执行文件时,链接器从库中复制这些函数和数据并把它们和应用程序的其它模块
组合起来创建最终的可执行文件(.EXE文件)。
具体实例步骤如下:
第一步:打开VS2010-->文件-->新建-->工程-->WIN32控制台项目-->确定(名称Static)-->静态库选项-->预编译头文件不选-->Finish
第二步:在这个空项目中,添加一个lib.h文件和一个lib.cpp文件
首先添加 lib.h 声明文件
// Static Project
// lib.h
// 声明函数 #ifndef LIB_H
#define LIB_H extern "C" int Add(int a, int b);
extern "C" int Sub(int a, int b); #endif
再添加 lib.cpp 实现文件
// Static project
// lib.cpp
// 实现函数逻辑 #include "lib.h" int Add(int a, int b)
{
return a + b;
}
int Sub(int a, int b)
{
return a - b;
}
第三步:保证添加正确后编译整个工程,确保编译成功
第四步:在工程Debug文件夹下寻找生成的Static.lib文件,这个文件正是我们需要的静态链接库
第五步:在目前的工程下,新建空项目TestLib。用以测试静态链接库的使用效果:
(1)实现方式一
a. 将Static项目下的lib.h和Static.lib这两个文件复制到TestLib项目的目录下
b. 在工程目录中添加已存在的lib.h文件
c. 再新建一个Test.cpp文件。如下:
// TestLib project
// Test.cpp
// 测试静态链接库 #include "lib.h"
#include <stdlib.h>
#include <stdio.h> #pragma comment(lib,"Static.lib") void main()
{
printf("%d\n", Add(, ));
printf("%d\n", Sub(, ));
system("pause");
}
说明:#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
// DLL project
// DLL.h
// 声明导出函数 #ifndef DLL_H
#define DLL_H extern "C" __declspec(dllexport) int add(int x, int y); #endif
b. dll.cpp
// DLL project
// DLL.cpp
// DLL 函数实现
#include "stdafx.h"
#include "dll.h" int add(int x, int y)
{
return x + y;
}
编译整个DLL项目,工程Debug目录下会生成DLL.lib和DLL.dll文件。装入时动态链接必需二者。
第三步:在目前的工程下,新建空项目TestDLL。用以测试装入时动态链接库的效果:
将DLL项目Debug目录下的DLL.dll和DLL.lib这两个文件复制到TestDLL项目的目录下。
再新建一个TestDll.cpp文件。如下:
//ps:该文件属于TestDll项目,与DLL项目同属于一个工程
// TestDll project
// TestDll.cpp
// 静态调用DLL实现 #include<stdio.h> #pragma comment(lib,"dll.lib")
extern "C" __declspec(dllimport) int add(int x, int y); void main( )
{
int result = add(, );
printf("%d", result);
}
第四步:编译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. 如下两句的作用:
extern "C" __declspec(dllexport) int add(int x, int y);
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
// DLL.cpp
// 实现文件 #include "stdafx.h" int add(int a, int b)
{
return a + b;
}
b. dll.def
; Dll.def : 导出DLL函数
LIBRARY DLL
EXPORTS
add @
编译整个DLL项目,工程Debug目录下会生成DLL.lib和DLL.dll文件。装入时动态链接必需二者。
如果VS2010环境下只有.dll文件没有生成.lib文件
需要在项目-->属性-->连接器-->输入-->模块定义文件中添加指定模块定义文件
第三步:在目前的工程下,新建空项目TestDLL。用以测试装入时动态链接库的效果:
新建一个TestDll.cpp文件。如下:
// TestDLL project
// TestDLL.cpp 测试动态链接 #include <stdio.h>
#include <Windows.h>
using namespace std; typedef int(*lpAddFun)(int, int); //宏定义函数指针类型 int main(int argc, char *argv[])
{
HINSTANCE hDll; //DLL句柄
lpAddFun addFun; //函数指针
wchar_t wchar[] = L"..\\Debug\\DLL.dll";
hDll = LoadLibrary(wchar);
if (hDll != NULL)
{
addFun = (lpAddFun)GetProcAddress(hDll, "add");
if (addFun != NULL)
{
int result = addFun(, );
printf("%d\n", result);
}
FreeLibrary(hDll);
}
return ;
}
第四步:编译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编程之五 动静态链接的更多相关文章
- C语言动静态链接库使用(笔记)
看了视频一直没空写........... C静态链接库不用说了跟你写在cpp文件里的函数一样不会有单独的模块 不再赘述生活中用的比较少 例子 .h文件 int Plus(int x, int y); ...
- xbmc的静态链接办法
XBMC是一个相当酷的音频/视频播放器,号称家庭影视中心. 我是希望静态将一些库链接进可执行程序的,这样我用的ArchLinux就不用天天在更新一些东西了 但XBMC试了很多次,编译成功后,总是在运行 ...
- App开发流程之数据持久化和编译静态链接库
先记录数据持久化. iOS客户端提供的常用数据持久化方案:NSUserDefaults代表的用户设置,NSKeydArchiver代表的归档,plist文件存储,SQLite数据库(包括上层使用的Co ...
- [CSAPP-II] 链接[符号解析和重定位] 静态链接 动态链接 动态链接接口
1 平台 转http://blog.csdn.net/misskissc/article/details/43063419 1.1 硬件 Table 1. 硬件(lscpu) Architecture ...
- 利用CMake生成动态或静态链接库工程
install解释: TARGETS版本的install命令 install(TARGETS targets... [EXPORT <export-name>] [[ARCHIVE|LIB ...
- linux c静态链接库与动态链接库
库函数是我们编程的时候经常用到的,我们协作编程的时候可以将常用的函数封装成库供大家使用,这样能够提高大家的工作效率.对于库函数,它分为动态链接库和静态链接库.对于静态链接库我们必须是连接到可执行文件中 ...
- 动态链接库dll,静态链接库lib, 导入库lib
转载地址:http://www.cnblogs.com/chio/archive/2008/08/05/1261296.html 目前以lib后缀的库有两种,一种为静态链接库(Static Libar ...
- 动态链接库dll,导入库lib,静态链接库lib
目前以lib后缀的库有两种,一种为静态链接库(Static Libary,以下简称“静态库”),另一种为动态连接库(DLL,以下简称“动态库”)的导入库(Import Libary,以下简称“导入库” ...
- gcc使用及动静态库制作
一. GCC的使用 1. GCC的编译过程 (1)预处理(cpp)gcc -E(输出问价通常以 .i 结尾),将头文件展开,宏替换等操作: (2)编译器(gcc)gcc -S(输出问价以 .s 结尾) ...
随机推荐
- 使用nmcli创建网络连接
使用nmcli创建一个新的网络连接时,首先需要清楚几个概念 设备即接口 连接是供设备使用的配置,其由一组设置组成. 同一个设备可能存在多个连接,但是一次只能有一个保持活动状态 在创建新的连接时,参数的 ...
- Linux下设置网卡静态ip
Linux下设置网卡静态ip 如果是服务器版,没有图形界面只用用命令行修改配置文件 如果是客户端版本,可以用图形界面 配置的前提是要在root用户下才能重启网卡服务 图形界面: system-conf ...
- APICloud请你看英特尔智能硬件大赛决赛直播
英特尔智能硬件大赛由英特尔硬享公社(CCE)发起,联合了全国各地50余家产业链优秀合作伙伴,旨在集合全国硬创资源,携手寻找中国最具代表性的硬件创业项目,并通过技术支持.资源对接.产品推广等方式助力项目 ...
- 30天,APP创业从0到1【7.25上海站】
活动概况 时间:2015年7月25日13:30-16:30 地点:太库•上海孵化器(张江金科路2889号长泰广场c座12楼) 主办:APICloud.诸葛.圣诺资讯 联合主办:微链.太库•上海孵化器 ...
- javascript学习笔记之DOM与表单
DOM(文档对象模型),猫叔了一个层次化的节点树 一.DOM NODE相关公共属性与方法 DOM中所有节点都实现了NODE接口,该接口的公共属性和方法如下: 1.节点基本属性 1)NodeType 节 ...
- Hadoop学习笔记: 安装配置Hadoop
安装前的一些环境配置: 1. 给用户添加sudo权限,输入su - 进入root账号,然后输入visudo,进入编辑模式,找到这一行:"root ALL=(ALL) ALL"在下面 ...
- nsstring打印结构体
// // main.m // 09-常用结构体 // // Created by apple on 14-3-20. // Copyright (c) 2014年 apple. All ri ...
- ios-控件的frame_center_bounds简单介绍
frame 例如一个button按钮控件的frame frame是一个结构体,frame表示了button在它的父控件view中的位置---origin 以及---size origin也是一个结构体 ...
- HttpwebClient的四种请求方式
最近悟出来一个道理,在这儿分享给大家:学历代表你的过去,能力代表你的现在,学习代表你的将来. 十年河东十年河西,莫欺少年穷. 本文旨在发布代码,供自己参考,也供大家参考,谢谢. 正题: Ht ...
- c# 排序算法总结
/// <summary> /// 冒泡排序法1 /// </summary> /// <param name="list"></para ...