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 结尾) ...
随机推荐
- PySe-004-Se-WebDriver 启动浏览器之二 - Chrome
上篇文章简略讲述了 WebDriver 启动 firefox 浏览器的示例脚本源码,具体请参阅: PySe-003-Se-WebDriver 启动浏览器之一 - Firefox 此文主要讲述在 Mac ...
- MVC4怎么设置@Html.TextBoxFor这样的输入框的css样式
在传统webForm中,输入框的这样的: <input id="userName" name="userName" type="text&quo ...
- 【转】ViewPager实现一个页面多个Item的显示
转自:http://billyyuan.iteye.com/blog/1941538 ViewPager实现一个页面多个Item的显示 博客分类: android 代码在: https://cod ...
- MySQL一些常用的时间函数
https://my.oschina.net/sallency/blog/470370
- The include feature of SQL Server Index
1. Why we need the index 'include' feature? For SQLServer , the length of all the index key have a l ...
- extjs form.load()加载服务端数据
formPanel.getForm().load({ url: 'getApproveRefundInf?refundIdDetail=${refundIdDetail}', waitMsg: '请稍 ...
- OC中@property属性关键字的使用(assign/weak/strong/copy)
OC中@property属性关键字的使用(assign/weak/strong/copy) 一.assign 用于 ‘基本数据类型’.‘枚举’.‘结构体’ 等非OC对象类型 eg:int.bool等 ...
- Virtualbox+UbuntuServer+Xshell搭建Linux开发环境
需求背景 嵌入式开发环境以编译服务器(Linux系统)为核心, 开发人员较多使用Windows系统, 通过若干工具, 可以实现开发人员使用Windows的开发工具,编写代码,然后在Linux系统上编译 ...
- 【转】DataSource高级应用
我们知道 DataSource能提供最高性能的对数据库的并发访问,但是,对DataSource的引用,也还有很多知识要弄清楚,获取Connection的方式是数据库性能最相关的技术,而对DataSou ...
- Effective C++ 1.让自己习惯C++
//条款01:视C++为一个语言联邦 // 1:C++主要包含的语言为: // A:C.说到底C++仍然以C为基础.区块(blocks).语句.预处理器.内置数据类型.数组.指针等均来自于C.许多时候 ...