Lib和Dll的那点事

2024-05-10 18:58
文章标签 lib dll 那点

本文主要是介绍Lib和Dll的那点事,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

转载自 http://www.cppfans.org/1394.html

搞程序开发的朋友应该对LibDll很熟悉,对于这两个东西,可谓是几家欢喜几家忧,喜欢的人觉得它可以封装代码,避免别人剽窃,不喜欢的人觉得它很麻烦,干嘛不直接用源文件。而特别是新手对于LibDll的关系和使用完全搞不清楚。

Lib称为静态链接库(static link library),是在编译的链接期间使用的,他里面其实就是源文件的函数实现。

Dll成为动态链接库(Dynamic link library),是在程序运行时动态调用的,runtime时使用,它里面包含了源文件的函数实现、DllMain入口函数和.def文件。

先说说Lib库吧,相对来说大家对它比dll熟悉一些。

Lib库

Lib库有两种,一种就是常见的普通Lib(static Lib),还有一种大家经常下载的开源代码编译后,会产生Lib和dll,其中Lib只是Dll的附带品,是DLL导出的函数列表文件而已,暂且称之为Dynamic Lib

两者都是二进制文件,两者都是在链接是调用的,使用static lib的exe可直接运行,使用dynamic lib的exe需要对应的dll才能运行。下来我们来看如何产生并使用一个static lib文件。

这里假设我们的工具是VS2005(包含)以上的版本,其他的工具都是大同小异的,就不做介绍了。

1.建立win32控制台工程

2.在应用程序设置的步骤,选择”静态库 static Library”

3.完成即可 (这里只是针对最简单的Dll,Win32 Application的方式稍有不同)

这样一个静态Lib库的工程就建好了。代码如下:

//
// Function.h
//void Print();

//
// Function.cpp
//
#include "Function.h"void Print()
{std::cout << "Hello world!" << std::endl;
}

编译会生成一个以工程名作为名称的Lib文件。

在你的项目工程属性中包含这个Lib文件的头文件目录和Lib文件目录。

头目录包含方法:项目属性(Alt + F7) -> 配置属性 -> C/C++ -> 常规 -> 附加包含目录,里面包含你的Lib库的头文件,你可以使用绝对路径,也可以使用VS中宏表示的相对路径,建议使用相对路径。

Lib文件包含方法:项目属性(Alt + F7) -> 配置属性 -> 链接器 -> 常规 -> 附加库目录,在这里面填写你Lib文件的路径。项目属性(Alt + F7) -> 配置属性 -> 链接器 -> 常规 -> 输入,在这里面填写你Lib文件的名称,例如: Function.lib

这样你在你的代码里就可以这样使用了:


#include <stdio.h>
#include <stdlib.h>
#include "Function.h"int _tmain(int argc, _TCHAR* argv[])
{Print();system("pause");return 0;
}


这样就是一个完整生成并使用Lib库的例子。

当然了,你还可以使用#pragma comment(Lib, “LibPath”)的方法来调用Lib文件。

==============================================================

Dynamic Lib的调用方法与Static lib完全一致,唯一的区别就是使用Dynamic Lib编译出来的程序,运行时需要其对应的Dll文件。前面我们已经说过了。

DLL

下来我们好好谈谈Dll的问题,相对于Lib来说,Dll使用的频率应该是非常高的了,因为你的程序运行,系统运行等等都靠它,MS也是因为这个才导致操作系统封装的越来越好了。

Dll其实和Exe是几乎完全一样的,唯一的不一样就是Exe的入口函数式WinMain函数(console程序是main函数),而Dll是DllMain函数,其他完全是一样的。所以有人也戏称Dll是不能自己运行的Exe。

Dll创建的过程也比较简单,唯一麻烦的就是需要定义导出函数接口。

创建Dll工程过程很简单,建立win32控制台工程,在应用程序设置的步骤,选择”动态库 Dynamic Library”,完成即可。(这里只是针对最简单的Dll,Win32 Application的方式稍有不同)

定义导出函数接口有两种方式:

1.使用__declspec宏

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "stdafx.h"BOOL APIENTRY DllMain( HMODULE hModule,DWORD  ul_reason_for_call,LPVOID lpReserved)
{switch (ul_reason_for_call){case DLL_PROCESS_ATTACH:case DLL_THREAD_ATTACH:case DLL_THREAD_DETACH:case DLL_PROCESS_DETACH:break;}return TRUE;
}


//
// Fucntion.h
//extern "C" __declspec(dllexport) void Print(void);


//
// Function.cpp
//
#include "Function.h"void Print(void)
{std::cout << "[Dll] Hello world!" << std::endl;
}


这里假设我们的工程名叫Function,那么 编译后会生成一个Function.dll和一个Function.lib(Dynamic lib),Dynamic lib前面已经说过,此处不再赘述了。

Function.h头文件中的

extern "C" __declspec(dllexport) void Print(void);

我们只需要清楚其中函数的名称,返回值,参数就可以了。

extern “C”表示我们要按照C语言的方式编译该函数,防止在C++工程中编译出现函数名错误,因为C++中有函数重载,所以函数名编译后可能会出现Print@1的形式;而且这样也可以让C调用C++的动态链接库;__declspec(dllexport)表示下来的函数是dll的导出函数接口。

2.使用def文件,类似于声明导出接口的方式,不过却不需要声明了,因为它专门定义了一个def文件来说明

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "stdafx.h"BOOL APIENTRY DllMain( HMODULE hModule,DWORD  ul_reason_for_call,LPVOID lpReserved)
{switch (ul_reason_for_call){case DLL_PROCESS_ATTACH:case DLL_THREAD_ATTACH:case DLL_THREAD_DETACH:case DLL_PROCESS_DETACH:break;}return TRUE;
}


//
// Fucntion.h
//void Print(void);


//
// Function.cpp
//
#include "Function.h"void Print(void)
{std::cout << "[Dll] Hello world!" << std::endl;
}


//
// Fucntion.def
//EXPORTSPrint

同样,类似于 Static Lib的显式调用方法,dll也可以显式调用,前提是我们很清楚函数名、返回值、参数列表。

#include <stdlib.h>
#include "Function.h"
#include <windows.h>int _tmain(int argc, _TCHAR* argv[])
{HINSTANCE hInstance  = LoadLibrary("Function.dll");typedef void(*_Print)(void);_Print printFunction;if (hInstance != NULL){printFunction = (_Print)GetProcAddress(hInstance, "Print");}printFunction();FreeLibrary(hInstance);system("pause");return 0;
}

当然了,有显式自然还有隐式调用了,这个时候Function.dll的伴生产物Function.lib就可以派上用场了,其使用方法和静态lib完全相同。

DLL调用的两种方法各有利弊:采用寻找DLL中函数地址的方法,优点是只要函数形参没变化,那么修改了函数实现也没关系,不需要重新编译Exe,只需要将新的DLL文件拷贝过来即可,大型项目上使用比较灵活;缺点是比较麻烦,需要定义实例,函数指针,加载DLL,释放DLL等过程。而采用Dynamic Lib的方法,优点是容易理解和接受(因为他跟静态库的调用方法类似);缺点是修改了DLL工程的任何东西都需要使用最新的Dynamic Lib重新能编译Exe。

 

总结:

DLL和Lib是各有千秋,使用的情况也是各不相同,不过最终还是需要大家在项目中实践到底哪种方法好,到底采用哪种类型的库,总之,一切都要按需求最优。

这篇关于Lib和Dll的那点事的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/977283

相关文章

springboot将lib和jar分离的操作方法

《springboot将lib和jar分离的操作方法》本文介绍了如何通过优化pom.xml配置来减小SpringBoot项目的jar包大小,主要通过使用spring-boot-maven-plugin... 遇到一个问题,就是每次maven package或者maven install后target中的ja

配置springboot项目动静分离打包分离lib方式

《配置springboot项目动静分离打包分离lib方式》本文介绍了如何将SpringBoot工程中的静态资源和配置文件分离出来,以减少jar包大小,方便修改配置文件,通过在jar包同级目录创建co... 目录前言1、分离配置文件原理2、pom文件配置3、使用package命令打包4、总结前言默认情况下,

【LabVIEW学习篇 - 21】:DLL与API的调用

文章目录 DLL与API调用DLLAPIDLL的调用 DLL与API调用 LabVIEW虽然已经足够强大,但不同的语言在不同领域都有着自己的优势,为了强强联合,LabVIEW提供了强大的外部程序接口能力,包括DLL、CIN(C语言接口)、ActiveX、.NET、MATLAB等等。通过DLL可以使用户很方便地调用C、C++、C#、VB等编程语言写的程序以及windows自带的大

PHP7扩展开发之函数方式使用lib库

前言 首先说下什么是lib库。lib库就是一个提供特定功能的一个文件。可以把它看成是PHP的一个文件,这个文件提供一些函数方法。只是这个lib库是用c或者c++写的。 使用lib库的场景。一些软件已经提供了lib库,我们就没必要再重复实现一次。如,原先的mysql扩展,就是使用mysql官方的lib库进行的封装。 在本文,我们将建立一个简单的lib库,并在扩展中进行封装调用。 代码 基础

PHP7扩展开发之对象方式使用lib库

前言 上一篇文章,我们使用的是函数方式调用lib库。这篇文章我们将使用对象的方式调用lib库。调用代码如下: <?php $hello = new hello(); $result = $hello->get(); var_dump($result); ?> 我们将在扩展中实现hello类。hello类中将依赖lib库。 代码 基础代码 这个扩展,我们将在say扩展上增加相关代码。sa

什么是Lib

概念 LIB有两种: 一种是静态库,比如C-Runtime库,这种LIB中有函数的实现代码,一般用在静态连编上,它是将LIB中的代码加入目标模块(EXE或者DLL)文件中,所以链接好了之后,LIB文件就没有用了。一种LIB是和DLL配合使用的,里面没有代码,代码在DLL中,这种LIB是用在静态调用DLL上的,所以起的作用也是链接作用,链接完成了,LIB也没用了。至于动态调用DLL的话,根本用不

什么是dll

DLL的概念        DLL(Dynamic Link Library)文件为动态链接库文件,又称“应用程序拓展”,是软件文件类型。在Windows中,许多应用程序并不是一个完整的可执行文件,它们被分割成一些相对独立的动态链接库,即DLL文件,放置于系统中。当我们执行某一个程序时,相应的DLL文件就会被调用。一个应用程序可使用多个DLL文件,一个DLL文件也可能被不同的应用程序使

用VB创建开始菜单快捷方式(无需其他DLL)

Option Explicit   Private Sub Command1_Click()   CreateProgManGroup Me, "测试", "test.grp"   CreateProgManItem Me, "d:\ghost.exe", "Ghost"   CreateProgManItem Me, "d:\setupQQ.exe", "QQ"   End

编译和链接那点事下

http://www.0xffffff.org/?p=357 上回书我们说到了链接以前,今天我们来研究最后的链接问题。         链接这个话题延伸之后完全可以跑到九霄云外去,为了避免本文牵扯到过多的话题导致言之泛泛,我们先设定本文涉及的范围。我们今天讨论只链接进行的大致步骤及其规则、静态链接库与动态链接库的创建和使用这两大块的问题。至于可执行文件的加载、可执行文件的运行时