C语言dll文件的说明以及生成、使用方法
最近在搞一些小项目,由于要涉及到跟其它语言进行交互,动态链接库变成了不二的选择。为此也查阅了很多资料,将动态链接库的相关知识在此做一个整理。
一、动态链接库概述
动态链接库(Dynamic Link Library )是一种不可执行的二进制程序文件,它允许多个程序共享执行特殊任务所必需的代码和其他资源。Windows 中,DLL 多数情况下是带有 ".dll" 扩展名的文件,但也可能是 ".ocx"或其他扩展名;Linux系统中常常是 ".so" 的文件。动态链接提供了一种方法,使进程可以调用不属于其可执行代码的函数。函数的可执行代码位于一个 DLL 文件中,该 DLL 包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。DLL 还有助于共享数据和资源。多个应用程序可同时访问内存中单个 DLL 副本的内容。使用动态链接库可以更为容易地将更新应用于各个模块,而不会影响该程序的其他部分。是开发大型项目必不可少的部分。
二、优缺点
优点:(1)节省内存和代码重用:当多个程序使用同一个函数库时,DLL可以减少在磁盘和物理内存中加载代码的重复量,且有助于代码的重用。
(2)模块化:DLL有助于促进模块式程序开发。模块化允许仅仅更改几个应用程序共享使用的一个DLL中的代码和数据而不需要更改应用程序自身。适用于大规模的软件开发,使开发过程独立、耦合度小,便于不同开发者和开发组织之间进行开发和测试。这种模块化的基本形式允许如Microsoft Office、Microsoft Visual Studio、甚至windows自身这样大的应用程序使用较为紧凑的补丁和服务包。
(3)扩展了应用程序的特性,使用dll文件可以使得应用程序能很方便的进行功能的扩展,很多程序的插件机制就是通过dll文件实现的。
(4)可以用多种语言来编译和调用,由于各种语言都有自己独特的开发优势,在处理某类事务方面具有着独特的优势,所以在多种语言编程的过程中,可以利用dll文件作为桥梁,可以发挥多种语言的优点。
缺点:DLL Hell:即DLL地狱,指几个应用程序在使用同一个共享的DLL库时发生版本冲突。
究其原因,八个字:成也共用,败也共用。因为DLL Hell正是由于动态链接库可与其他程序共用函数、资源所导致。
主要有两种情况:
设想这样一个场景:程序A会使用1.0版本的动态链接库X,则在程序A安装到系统时,会同时安装该1.0版本的动态链接库X。假设另一个程序B也会使用到动态链接库X,那么程序B直接复制到硬盘中即可正常运行,因为动态链接库已经存在于系统中。然而有一天,另一程序C也要使用动态链接库X,但是由于程序C开发的时间较晚,其需要较新版本---2.0版本的动态链接库X。则在程序C被安装到系统时,2.0版本的动态链接库X 也必须随之安装到系统中,此时系统中1.0版本的动态链接库将被2.0版本所取代(替换)。
情况1:新版本的动态链接库不兼容旧版本。如,A何B需要X所提供的功能,在升级到2.0后,新版本的X竟然把此功能取消了(很难想象吧,呵呵但有时候就是如此....)。则此时虽然C能正常运行,但A和B均无法工作了。
情况2:新版本的动态链接库兼容旧版本,但是存在一个bug。
三、入口点
就跟应用程序的main函数一样,dll文件也有入口函数,叫做DllMain(),它的原型是这样的:
BOOL APIENTRY DllMain(
HANDLE hModule, // DLL模块的句柄
DWORD ul_reason_for_call, // 调用本函数的原因
LPVOID lpReserved // 保留
) {
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
//进程正在加载本DLL
break;
case DLL_THREAD_ATTACH:
//一个线程被创建
break;
case DLL_THREAD_DETACH:
//一个线程正常退出
break;
case DLL_PROCESS_DETACH:
//进程正在卸载本DLL
break;
}
return TRUE; //返回TRUE,表示成功执行本函数
}
入口点函数只应执行简单的初始化任务,不应调用任何其他 DLL 加载函数或终止函数。例如,在入口点函数中,不应直接或间接调用 LoadLibrary 函数或LoadLibraryEx 函数。此外,不应在进程终止时调用 FreeLibrary函数。
四、生成DLL文件
下面来生成一个DLL文件,为方便起见,只定义一个简单函数。
生成DLL文件需要用到两个文件,一个头文件,dll_add.h,和一个源文件,dll_add.c
头文件内容:
#ifndef _DLL_DEMO_H_
#define _DLL_DEMO_H_
#ifdef DLLDEMO_EXPORTS
#define DLL_DEMO _declspec( dllexport )
#else
#define DLL_DEMO _declspec(dllimport)
#endif
extern "C" DLL_DEMO int Add(int a, int b);
#endif
源文件内容:
#include "dll_demo.h" int Add(int a, int b)
{
return (a + b);
}
这里因为不需要对函数载入与卸载作特殊处理,所以可以不使用入口函数。
使用的是vs2015,在debug模式或者release模式下调试后会在相应目录下生成dll文件,即可使用。
五、调用DLL文件
生成DLL自然是为了调用,调用DLL有两种方式。
静态调用:使用.h+.lib+.dll
#include <windows.h>
#include <iostream>
#include "DLL_DEMO.h"
using namespace std;
#pragma comment(lib, "DLL_DEMO.lib") extern "C" _declspec(dllimport) int Add(int a, int b);
int main(int argc, char *argv[])
{
cout << Add(, ) << endl;
system("pause");
return ;
}
把头文件和lib文件、dll文件都放到跟源文件同一目录下即可使用。当然,路径可以重新设置。
动态调用:仅使用dll文件
#include <windows.h>
#include <iostream>
using namespace std;
typedef int (*AddFunc)(int a, int b);
int main(int argc, char *argv[])
{
HMODULE hDll = LoadLibrary(L"DLL_DEMO.dll");
if (hDll != NULL)
{
AddFunc add = (AddFunc)GetProcAddress(hDll, "Add");
if (add != NULL)
{
cout<<add(, )<<endl;
}
FreeLibrary(hDll);
}
}
在字符串前加一个L作用: unicode字符集是两个字节组成的。L告示编译器使用两个字节的 unicode 字符集。
也可以使用dll来实现类和变量的共享,还可以实现内存共享,因为研究不多,所以这里暂不介绍。
C语言dll文件的说明以及生成、使用方法的更多相关文章
- C# -- 使用反射(Reflect)获取dll文件中的类型并调用方法
使用反射(Reflect)获取dll文件中的类型并调用方法 需引用:System.Reflection; 1. 使用反射(Reflect)获取dll文件中的类型并调用方法(入门案例) static v ...
- XML序列化 判断是否是手机 字符操作普通帮助类 验证数据帮助类 IO帮助类 c# Lambda操作类封装 C# -- 使用反射(Reflect)获取dll文件中的类型并调用方法 C# -- 文件的压缩与解压(GZipStream)
XML序列化 #region 序列化 /// <summary> /// XML序列化 /// </summary> /// <param name="ob ...
- Core文件简单介绍及生成设置方法
Core文件简单介绍及生成设置方法 Core文件其实就是内存的映像,当程序崩溃时,存储内存的相应信息,主用用于对程序进行调试.当程序崩溃时便会产生core文件,其实准确的应该说是core dump 文 ...
- FPGA工程中用C语言对文件进行处理_生成mif文件
本博客中有用verilog处理文件数据的代码,本博文采用C 处理文件中的数据. 有时候要生成一个mif文件—— altera memory initial file.本次工程中我得到的是一个大型的数 ...
- C语言复制文件的两种简单的方法【从根本解决问题】
网上的方法大致有这样几种: 1.使用操作系统提供的复制文件的API 2.使用C语言本身提供的复制文件的函数 3.直接读写文件,从文件角度来操作,从而直接将一个文件复制 这里我们使用的就是这第三种. 复 ...
- WPF调用C++生成的dll文件(示例)
注:笔者使用的VS版本为2019.1.打开VS2019,选择文件 -> 新建 -> 项目 2.选择项目 新建项目时选择C++“控制台应用”语言:C++平台:Windows项目类型:空项目 ...
- vs工程生成dll文件及其调用方法
转载:https://blog.csdn.net/weixin_44536482/article/details/91519413 vs工程生成dll文件及其调用方法 ...
- 如何生成带注释的DLL文件
背景: 实际上并不是生成带有注释的DLL文件,而是同时生成一个XML文件,用来显示注释. 为什么要使用DLL文件,在C#编程的过程中,一直在使用DLL文件,如System.dll 方法: 1,创建类库 ...
- LabVIEW如何方便地调用DLL文件
转自:http://bbs.elecfans.com/jishu_469502_1_1.html LabVIEW调用DLL文件 LabVIEW支持通过调用DLL文件的方式与其它编程语言混合使用.比 ...
随机推荐
- 为什么使用Junit Test而不用普通java main方法来完成测试?
因为在程序里边,一个接口对应一个实现方法,而在接口中常常会定义相关的很多方法,所以在测试的时候,如果都在main方法里边进行测试,main方法就会显得臃肿,而且不便于以后其他人测试以及查看测试数据,用 ...
- Maven之安装与简单入门一
Maven 是一个项目管理和构建自动化工具,我们最关心的是它的项目构建功能.Maven 使用惯例优于配置的原则. 1,下载安装包,并根据文档说明安装: http://maven.apache.org/ ...
- Hamilton四元数群的表示
Hamilton四元数群$Q_8=\mathbb H=\{\pm e,\pm i,\pm j,\pm k\}$满足如下运算法则: $e$为单位元且同号得正.异号得负,此外$e=i^2=j^2=k^2, ...
- PHP socket上传文件图片
最近了解了下下socket方面的东西,想做一个socket上传文件的例子. 在网上搜了搜代码执行后,图片数据传输了一半,图片的下半部分是灰色的.然后就自己仿着搜来的代码和php.net 中socket ...
- oracle sql 执行计划分析
转自http://itindex.net/detail/45962-oracle-sql-%E8%AE%A1%E5%88%92 一.首先创建表 SQL> show user USER is &q ...
- 重置VS设置
用VS开发项目的时候, 偶发智能提示消失.关键字.类名不变色的情况. 如果你也遇到过,那么这样做: 新建txt,打开并输入以下内容: start "" "C:\Progr ...
- ORACLE中常见SET指令
1 SET TIMING ON 说明:显示SQL语句的运行时间.默认值为OFF. 在SQLPLUS中使用,时间精确到0.01秒.也就是10毫秒. 在PL/SQL DEVELOPER 中 ...
- The specified type member 'Date' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties
出现这个错误提示可以用 DbFunctions.TruncateTime 将Linq中entity的DateTime转化一下再使用,如下所示: var anyCalls = _db.CallLogs. ...
- JavaScript DOM节点和文档类型
以下的例子以此HTML文档结构为例: <!DOCTYPE html> <html lang="en"> <head> <meta char ...
- Nginx+FastCGI运行原理
Nginx不支持对外部程序的直接调用或者解析,所有的外部程序(包括PHP)必须通过FastCGI接口来调用.FastCGI接口在Linux下是socket(这个socket可以是文件socket,也可 ...