1、一个程序从源文件编译生成可执行文件的步骤:
预编译 -->  编译 -->  汇编 --> 链接
(1)预编译,即预处理,主要处理在源代码文件中以“#”开始的预编译指令,如宏展开、处理条件编译指令、处理#include指令等。
(2)编译过程就是把预处理完的文件进行一系列词法分析、语法分析、语义分析以及优化后生成相应的汇编代码文件。
(3)汇编是将汇编代码转变成二进制文件。
(4)链接将二进制文件链接成一个可执行的命令,主要是把分散的数据和代码收集并合成一个单一的可加载并可执行的的文件。链接可以发生在代码静态编译、程序被加载时以及程序执行时。链接过程的主要工作是符号解析和重定位。
2、库
库是一组目标文件的包,就是一些最常用的代码编译成目标文件后打包存放。而最常见的库就是运行时库(Runtime Library),如C运行库CRT.
库一般分为两种:静态库(.a 、.lib)动态库(.so 、.dll )所谓静态、动态是指链接过程。

3、静态库与动态库
静态库:
函数和数据被编译进一个二进制文件(通常扩展名为.LIB)。在使用静态库的情况下,在编译链接可执行文件时,链接器从库中复制这些函数和数据并把它们和应用程序的其它模块组合起来创建最终的可执行文件(.EXE文件)。
静态库有两个重大缺点:
1)空间浪费
2)静态链接对程序的更新、部署和发布会带来很多麻烦。一旦程序中有任何模块更新,整个程序就要重新链接,发布给用户。
 
动态库:
把程序按照模块拆分成各个相对独立的部分,在程序运行时才将它们链接在一起形成一个完整的程序,而不是想静态链接一样把所有的程序模块都链接成一个单独的可执行文件。
在使用动态库的时候,往往提供两个文件:一个引入库和一个DLL。
引入库包含被DLL导出的函数和变量的符号名,DLL包含实际的函数和数据。在编译链接可执行文件时,只需要链接引入库,DLL中的函数代码和数据并不复制到可执行文件中,在运行的时候,再去加载DLL,访问DLL中导出的函数。
特点:
1)代码共享,所有引用该动态库的可执行目标文件共享一份相同的代码与数据。
2)程序升级方便,应用程序不需要重新链接新版本的动态库来升级,理论上只要简单地将旧的目标文件覆盖掉。
3)在运行时可以动态地选择加载各种应用程序模块
区别:
(1)lib是编译时用到的,dll是运行时用到的。如果要完成源代码的编译,只需要lib;如果要使动态链接的程序运行起来,只需要dll。
(2)如果有dll文件,那么lib一般是一些索引信息,记录了dll中函数的入口和位置,dll中是函数的具体内容;如果只有lib文件,那么这个lib文件是静态编译出来的,索引和实现都在其中。使用静态编译的lib文件,在运行程序时不需要再挂动态库,缺点是导致应用程序比较大,而且失去了动态库的灵活性,发布新版本时要发布新的应用程序才行。
(3)动态链接的情况下,有两个文件:一个是LIB文件,一个是DLL文件。LIB包含被DLL导出的函数名称和位置,DLL包含实际的函数和数据,应用程序使用LIB文件链接到DLL文件。在应用程序的可执行文件中,存放的不是被调用的函数代码,而是DLL中相应函数代码的地址,从而节省了内存资源。DLL和LIB文件必须随应用程序一起发行,否则应用程序会产生错误。如果不想用lib文件或者没有lib文件,可以用WIN32 API函数LoadLibrary、GetProcAddress装载。
 
下面重点介绍Windows下动态链接库DLL.
DLL即动态链接库(Dynamic-Link Libaray)的缩写,相当于Linux下的共享对象。
Windows系统中大量采用了DLL机制,甚至内核的结构很大程度依赖与DLL机制。
Windows下的DLL文件和EXE文件实际上是一个概念,都是PE格式的二进制文件。一般的动态库程序有lib文件和dll文件,lib文件是编译时期连接到应用程序中的,而dll文件是运行时才会被调用的。
为了更好的理解DLL,首先介绍一下导出和导入的概念。
(1)导出与导入
在ELF(Linux下动态库的格式),共享库中所有的全局函数和变量在默认情况下都可以被其他模块使用,即ELF默认导出所有的全局符号。DLL不同,需要显式地“告诉”编译器需要导出某个符号,否则编译器默认所有的符号都不导出。
程序使用DLL的过程其实是引用DLL中导出函数和符号的过程,即导入过程。
对于从其他DLL导入的符号,需要使用“__declspec(dllimport)”显式声明某个符号为导入符号。在ELF中,使用外部符号时,不需要额外声明该符号是从其他共享对象导入的。
指定符号的导入导出一般有如下两种方法:
1)MSVC编译器提供了一系列C/C++的扩展来指定符号的导入导出,即__declspec属性关键字。
__declspec(dllexport) 表示该符号是从本DLL导出的
__declspec(dllimport) 表示该符号是从别的DLL中导入的
2)使用“.def”文件来声明导入到导出符号,详细参考《程序员的自我修养--链接、装载与库》。
 
4、DLL创建
新建一个Win32项目,命名为myDll--->选择DLL类型,完成后项目结构如下:

修改myDll.h

// 下列 ifdef 块是创建使从 DLL 导出更简单的
// 宏的标准方法。此 DLL 中的所有文件都是用命令行上定义的 MYDLL_EXPORTS
// 符号编译的。在使用此 DLL 的
// 任何其他项目上不应定义此符号。这样,源文件中包含此文件的任何其他项目都会将
// MYDLL_API 函数视为是从 DLL 导入的,而此 DLL 则将用此宏定义的
// 符号视为是被导出的。
#ifdef MYDLL_EXPORTS
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endif // 此类是从 myDll.dll 导出的
class __declspec(dllexport) CmyDll {
public:
CmyDll(void);
// TODO: 在此添加您的方法。
}; extern __declspec(dllexport) int nmyDll; __declspec(dllexport) int fnmyDll(void); extern "C" __declspec(dllexport) double seekArea(int r, int h);

myDll.cpp

// myDll.cpp : 定义 DLL 应用程序的导出函数。
// #include "stdafx.h"
#include "myDll.h"
#include "stdio.h" // 这是导出变量的一个示例
__declspec(dllexport) int nmyDll = ; // 这是导出函数的一个示例。
__declspec(dllexport) int fnmyDll(void)
{
return ;
} // 这是已导出类的构造函数。
// 有关类定义的信息,请参阅 myDll.h
CmyDll::CmyDll()
{
return;
} void show()
{
printf("Call the library function.\n");
printf("***************************\n");
}
double area(int r)
{
return 3.14*r*r;
}
__declspec(dllexport) double seekArea(int r, int h)
{
show();
double under = 3.14*r*r;
double v = under*h;
return v;
}

编译就会生成对应的dll文件,同时也会生成对应的lib文件。

注意:a.DLL中导出函数的声明有两种方式:在函数声明中加上__declspec(dllexport);采用模块定义(.def)文件声明。详见:http://www.cnblogs.com/enterBeijingThreetimes/archive/2010/08/04/1792099.html   b.对于C文件创建dll时或者想使用C编译器创建dll时,建议使用 extern “C” 标志

5.DLL的隐式调用
隐式链接采用静态加载的方式,比较简单,需要.h、.lib、.dll三件套。新建“控制台应用程序”或“空项目”。配置如下:
项目->属性->配置属性->VC++ 目录-> 在“包含目录”里添加头文件testdll.h所在的目录
项目->属性->配置属性->VC++ 目录-> 在“库目录”里添加头文件testdll.lib所在的目录

项目->属性->配置属性->链接器->输入-> 在“附加依赖项”里添加“testdll.lib”(若有多个 lib 则以空格隔开)。//也可以在项目属性中设置库的链接,#pragma comment(lib, "DLLSample.lib")

项目结构:

CallMyDll.cpp

// CallmyDll.cpp : 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include "stdlib.h"
#include "myDll.h" #pragma comment(lib, "myDll.lib") extern "C" _declspec(dllimport) double seekArea(int r, int h); int _tmain(int argc, _TCHAR* argv[])
{
int r = , h = ;
double area = seekArea(r, h);
printf("Area is:%f\n", area);
system("pause");
return ;
}

运行前:将动态库文件myDll.dll拷贝到可执行文件目录下,否则会报错。运行结果:

原文:https://blog.csdn.net/zhangfuliang123/article/details/71515796

 

windows 动态库的封装以及调用的更多相关文章

  1. C#调用C/C++动态库,封装各种复杂结构体

    C#调用C/C++动态库,封装各种复杂结构体. 标签: c++结构内存typedefc# 2014-07-05 12:10 6571人阅读 评论(1) 收藏 举报  分类: C(8)  C#(6)  ...

  2. Windows下动态库的编译以及调用

    1.MFC下生成动态库 1>显式调用 在.cpp文件里添加接口函数 int sum(int a,int b) { return a + b; } int sub(int a,int b) { r ...

  3. 【转】分析Linux和windows动态库

    原文地址:http://www.cnblogs.com/chio/archive/2008/11/13/1333119.html 摘要:动态链接库技术实现和设计程序常用的技术,在Windows和Lin ...

  4. Linux和windows动态库

    转载:http://www.cnblogs.com/chio/archive/2008/11/13/1333119.html 态链接库技术实现和设计程序常用的技术,在Windows和Linux系 统中 ...

  5. Windows动态库学习心得

    最近在工作中需要给项目组其他成员提供调用函数,决心抛弃以前“拷贝头文件/源文件”的简陋方法,采用动态库的方式对自己开发的接口进行模块化管理.因之前一直没有机会从事Windows动态库的开发,现借助这个 ...

  6. windows动态库与Linux动态库

    Linux动态库和windows动态库的目的是基本一致的,但由于操作系统的不同,他们在许多方面还是不尽相同.但是尽管有差异Linux动态库的windows动态库还是可以移植的,有一些规则以及经验是必须 ...

  7. linux和windows动态库加载路径区别

    # linux和windows动态库加载路径区别 ### 简介------------------------------ linux加载动态库的路径是系统目录/lib和/usr/lib.- wind ...

  8. Windows 动态库创建和使用 part 2

    一.Windows动态库的创建: 1.先选择 "DLL" 和 “控项目” 2.添加一个头文件,一个源文件  CppDll.h,CppDll.cpp,一个模块定义文件 CppDll. ...

  9. Windows下动态库的隐式调用

    多年的工作经验告诉我Windows下使用动态库最简单的方法:使用def导出函数,然后隐式调用. 具体做法如下: (1)首先使用visual studio 创建“Win32项目”,如下图: (2)然后在 ...

随机推荐

  1. router-link 绑定事件的方式

    实现方法如下  使用.native 实现原生事件 <router-link to="" @click.native="dialogWithdraw=true&quo ...

  2. element-ui中 table表格hover 修改背景色

    增加样式级别就行啦   .el-table--enable-row-hover .el-table__body tr:hover>td{ background-color: #212e3e !i ...

  3. 【PHP快速入门】 第二节 php基本语法

    1.什么地方能写PHP代码? php代码需要写在php标识符内,就是这个东西: 在我们编写一个php程序时,必须要在这个文件里面写上 2.PHP语句要不要加分号? 有的地方要加,有的地方不要加.(似乎 ...

  4. [C#] LINQ之GroupBy

    声明:本文为www.cnc6.cn原创,转载时请注明出处,谢谢! 本文作者文采欠佳,文字表达等方面不是很好,但实际的代码例子是非常实用的,请作参考. 一.先准备要使用的类: 1.Person类: cl ...

  5. mysql触发器,视图,游标

    什么事触发器: 触发器是一中特殊的存储过程,主要是通过事件来触发而被执行的.它可以强化约束,来维护数据的完整性和一致性,可以跟踪数据库内的操作从而不允许未经许可的更新和变化.可以联级运算.如,某表上的 ...

  6. ajax相关问题

    1.contentType和dataType contentType 主要设置你发送给服务器的数据格式 dataType设置你收到服务器数据的格式(如text,json等),最常用的为json. 2. ...

  7. rest-framework解析器,url控制,分页,响应器,渲染器,版本控制

    解析器 1.json解析器 发一个json格式的post请求.后台打印: request_data---> {'title': '北京折叠'} request.POST---> <Q ...

  8. Django的模板语言

      Django模板系统 官方文档 常用语法 只需要记两种特殊符号: {{  }}和 {% %} 变量相关的用{{}},逻辑相关的用{%%}. 变量 {{ 变量名 }} 变量名由字母数字和下划线组成. ...

  9. VO和DO转换(二) BeanUtils

    VO和DO转换(一) 工具汇总 VO和DO转换(二) BeanUtils VO和DO转换(三) Dozer VO和DO转换(四) MapStruct BeanUtils是Spring提供的,通常项目都 ...

  10. JavaScript修改DOM节点时,样式优先级的问题

    通过element.style.xxx设置或者读取的xxx样式属性,都是属于行间样式(<p style="color=red"></p>),并不是 使用li ...