MFC下的DLL编程学习

1、DLL库与LIB库对比:

静态链接库Lib(Static Link Library),是在编译的链接阶段将库函数嵌入到应用程序的内部。如果系统中运行的多个应用程序都包含所用到的公共库函数,则必然造成很大的浪费。这样即增加了链接器的负担,也增大了可执行程序的大小,还加大了内存的消耗。Lib的好处是应用程序可以独立运行,而不需要在操作系统中另外安装对应的DLL。

而DLL采用动态链接,对公用的库函数,系统只有一个拷贝(一般是位于系统目录的*.DLL文件),而且只有在应用程序真正运行阶段调用时,才加载到内存。在内存中的库函数,也只有一个拷贝,可供所有运行的程序调用。当再也没有程序需要调用它时,系统会自动将其卸载,并释放其所占用的内存空间。DLL的缺点是应用程序不能独立运行,需要在操作系统中另外安装对应的DLL。例如,如果你的MFC项目被设置成“在共享DLL中使用MFC”的,则虽然生成的可执行程序很小,但是在其他没有安装Visual C++(运行环境)的机器上是不能直接运行的,需要另外安装MFC的动态链接库(如mfc90.dll)。

2、DLL库与LIB库区别:

(1)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装载。

3、DLL库与LIB库的调用方法:

使用LIB库的方法:
静态lib中,一个lib文件实际上是任意个obj文件的集合,obj文件是cpp文件编译生成的。在编译这种静态库工程时,根本不会遇到链接错误;即使有错,也只会在使用这个lib的EXT文件或者DLL工程里暴露出来。
在VC中新建一个static library类型的工程Lib,加入test.cpp文件和test.h文件(头文件内包括函数声明),然后编译,就生成了Lib.lib文件。
别的工程要使用这个lib有两种方式:
(1)在project->link->Object/Library Module中加入Lib.lib文件(先查询工程目录,再查询系统Lib目录);或者在源代码中加入指令#pragma comment(lib, “Lib.lib”)。
(2)将Lib.lib拷入工程所在目录,或者执行文件生成的目录,或者系统Lib目录中。
(3)加入相应的头文件test.h。

使用DLL库的方法:
使用动态链接中的lib,不是obj文件的集合,即里面不会有实际的实现,它只是提供动态链接到DLL所需要的信息(包括DLL响应函数的信息、地址等),这种lib可以在编译一个DLL工程时由编译器自动生成。
(1)隐式链接
第 一种方法是:通过project->link->Object/Library Module中加入.lib文件(或者在源代码中加入指令#pragma comment(lib, “Lib.lib”)),并将.dll文件置入工程所在目录,然后添加对应的.h头文件。

#include "stdafx.h"
#include "DLLSample.h"

#pragma comment(lib, "DLLSample.lib")    //你也可以在项目属性中设置库的链接

int main()
{
        TestDLL(123);   //dll中的函数,在DllSample.h中声明
        return(1);
}

(2)显式链接
需要函数指针和WIN32 API函数LoadLibrary、GetProcAddress装载,使用这种载入方法,不需要.lib文件和.h头文件,只需要.dll文件即可(将.dll文件置入工程目录中)。

#include <</span>iostream>
#include <</span>windows.h>         //使用函数和某些特殊变量
typedef void (*DLLFunc)(int);
int main()
{
        DLLFunc dllFunc;
        HINSTANCE hInstLibrary = LoadLibrary("DLLSample.dll");//率先在当前可执行程序目录下寻找DLL库文件

        if (hInstLibrary == NULL)
        {
          FreeLibrary(hInstLibrary);
        }
        dllFunc = (DLLFunc)GetProcAddress(hInstLibrary, "TestDLL");
        if (dllFunc == NULL)
        {
          FreeLibrary(hInstLibrary);
        }
        dllFunc(123);
        std::cin.get();
        FreeLibrary(hInstLibrary);
        return(1);
}
LoadLibrary函数利用一个名称作为参数,获得DLL的实例(HINSTANCE类型是实例的句柄),通常调用该函数后需要查看一下函数返回是否成功,如果不成功则返回NULL(句柄无效),此时调用函数FreeLibrary释放DLL获得的内存。GetProcAddress函数利用DLL的句柄和函数的名称作为参数,返回相应的函数指针,同时必须使用强转;判断函数指针是否为NULL,如果是则调用函数FreeLibrary释放DLL获得的内存。此后,可以使用函数指针来调用实际的函数。最后要记得使用FreeLibrary函数释放内存。

4、MFC中DLL中函数的导出方法

使用MFC创建DLL时,从项目中导出(export)函数到DLL文件的方法有:

(1) 使用模块定义文件(.def)。

(2)使用__declspec(dllexport)关键字或其替代宏AFX_EXT_CLASS。

这两种方法是互斥的,对每个函数只需用一种方法即可。另外,DEF文件只能用来导出函数,不能用于导出整个类。导出C++类,必须用__declspec(dllexport)关键字或其替代宏AFX_EXT_CLASS。

DEF文件

模块定义(module definition)文件(.def)是包含一个或多个描述DLL各种属性的模块语句的文本文件。DEF文件必须至少包含下列模块定义语句:

文件中的第一个语句必须是LIBRARY语句。此语句将.def文件标识为属于DLL。LIBRARY语句的后面是DLL的名称(缺省为DLL项目名)。链接器将此名称放到DLL的导入库中。

EXPORTS语句列出名称,可能的话还会列出DLL导出函数的序号值。通过在函数名的后面加上@符和一个数字,给函数分配序号值。当指定序号值时,序号值的范围必须是从1到N,其中N是DLL导出函数的个数。

即,DEF文件的格式为:(在这两个语句之间,还可以加上可选的描述语句:DESCRIPTION "库描述串"。分号;后的文本内容行为注释)

库名.def

LIBRARY 库名

EXPORTS

函数名1 @1

函数名2 @2

……

函数名n @n

在使用MFC DLL向导创建MFC DLL项目时,VC会自动创建一个与项目同名但没有任何函数导出项的DEF文件(项目名.def),格式为:

项目名.def : 声明 DLL 的模块参数。

LIBRARY      "项目名"

EXPORTS

。。。

例如,项目名为RegDll的DEF文件(RegDll.def)的内容为:

; RegDll.def : 声明 DLL 的模块参数。

LIBRARY      "RegDll"

EXPORTS

。。。

当生成DLL时,链接器使用.def文件创建导出(.exp)文件和导入库(.lib)文件。然后,链接器使用导出文件生成DLL文件。隐式链接到DLL的可执行文件在生成时链接到导入库。请注意,MFC本身就是使用.def文件从MFCx0.dll导出函数和类的。

关键字或宏

除了使用DEF文件来导出函数外,还可以在源程序中使用__declspec(dllexport)关键字或其替代宏AFX_EXT_CLASS:

#define AFX_EXT_CLASS  AFX_CLASS_EXPORT (定义在头文件afxv_dll.h中)

#define AFX_CLASS_EXPORT  __declspec(dllexport) (定义在头文件afxver_.h中)

来导出函数和整个C++类。

具体的格式为:

导出整个类:

class AFX_EXT_CLASS 类名[ : public基类]

{

……

}

导出类的成员函数:

class 类名[ : public基类]

{

AFX_EXT_CLASS 返回类型 函数名1(……) ;

AFX_EXT_CLASS 返回类型 函数名2(……) ;

……

}

导出外部C格式的(全局)函数:

extern "C" __declspec(dllexport) 返回类型 函数名(……)

{

……

}

如果希望用MFC(C++)编写的规则DLL中的函数,也能够被非MFC程序来调用,需要为函数声明指定extern "C"。不然,C++编译器会使用C++类型安全命名约定(也称作名称修饰)和C++调用约定(使用此调用约定从C调用会很困难)。

为了使用方便,可以定义宏:

#define DllExport extern "C" __declspec(dllexport)

然后再使用它,例如:

DllExport int Add(int d1, int d2) {……}

5、VC查找DLL及LIB库的目录优先顺序

为了使需要动态链接库的应用程序可以运行,需要将库文件放在操作系统能够找到的地方。Windows操作系统查找库的目录顺序为:

  1. 所在目录——当前进程的可执行模块所在的目录,即应用程序的可执行文件(*.exe)所在的目录。
  2. 当前目录——进程的当前目录。
  3. 系统目录——Windows操作系统安装目录的系统子目录,如C:\Windows\ System32。可用GetSystemDirectory函数检索此目录的路径。
  4. Windows目录——Windows操作系统安装目录,如C:\Windows\。可用GetWindowsDirectory函数检索此目录的路径。
  5. 搜索目录——PATH环境变量中所包含的自动搜索路径目录,一般包含C:\Windows\和C:\Windows\System32\等目录。可在命令行用Path命令来查看和设置,也可以通过(在“我的电脑”右键菜单中选“属性”菜单项)“系统属性”中的环境变量,来查看或编辑“Path”系统变量和“PATH”用户变量。

参考:https://www.cnblogs.com/405845829qq/p/4108450.html

参考:https://www.cnblogs.com/19910101zj/p/4611695.html

原文地址:https://www.cnblogs.com/cjy15639731813/p/10549771.html

时间: 2024-10-29 19:05:39

MFC下的DLL编程学习的相关文章

深入Delphi下的DLL编程

深入Delphi下的DLL编程 作者:岑心 引 言 相信有些计算机知识的朋友都应该听说过“DLL”.尤其是那些使用过windows操作系统的人,都应该有过多次重装系统的“悲惨”经历——无论再怎样小心,没有驱动损坏,没有病毒侵扰,仍然在使用(安装)了一段时间软件后,发现windows系统越来越庞大,操作越来越慢,还不时的出现曾经能使用的软件无法使用的情况,导致最终不得不重装系统.这种情况常常是由于dll文件的大量安装和冲突造成的.这一方面说明DLL的不足,另一方面也说明DLL的重要地位,以至我们无

Windows平台VC++ 6.0 下的网络编程学习 - 简单的测试winsock.h头文件

最近学习数据结构和算法学得有点累了(貌似也没那么累...)...找了本网络编程翻了翻当做打一个小基础吧,打算一边继续学习数据结构一边也看看网络编程相关的... 简单的第一次尝试,就大致梳理一下看书+自己理解的东西. 1.首先是对Winsock的一点介绍:Winsock是一种标准的API(应用程序编程接口),主要用于网络中的数据通信,它允许两个应用程序在同一台机器上或通过网络相互通信.需要注意的是Winsock和协议无关,使用Winsock编程接口,应用程序可通过普通网络协议如:TCP/IP(网络

MFC下的aero效果学习笔记

最近想在MFC中用下aero 首先参考了 http://blog.csdn.net/polytechnic/article/details/5696797 中的一系列的步骤,进行了初步学习 但是对于其中按钮效果不是特别满意,文中的按钮解决是通过将窗口改为层窗口,设定透明色为别的颜色解决的,我期望找到可不用层属性的解决方案 后来参考了 http://blog.csdn.net/cometnet/article/details/6547504 对dwm有了更进一步的了解,知道了一些更丰富的内容 但是

推荐在线编程学习网站

今天主要跟大家分享一下三个编程在线学习网址,下面三个我都用过,感觉还不错,有些不仅仅适用于小白,还适用像我一样的菜鸟.当然了,高手也是适用的. 虽然是国外的,但是不得不承认,人家确实做得挺不错的,这一点我们还是可以借鉴学习的. 至于全部是英文的,这一点确实有点麻烦,不过我想现在Google浏览器或者一些超强的翻译工具,对于英文我想各位程序员们或者有志于在IT界发展的朋友应该不算是很难的事情. 当然了,最近我也在补补英语,主要以应用英语为主,其实的话,平时面对的是英文开发环境不知不觉,一天下来还是

MFC下DLL编程(图解)

DLL(Dynamic Link Library,动态链接库)是微软公司为Windows和OS/2操作系统设计一种供应用程序在运行时调用的共享函数库.DLL是应用程序的一种扩展,也是软件共享和重用的传统方法. DLL除了可同时被多个应用程序共享外,还可以在不改变调用接口(从而不需修改使用它的应用程序)的情况下,改进和升级里面的库函数.而且DLL与编写它的语言无关,例如,用VC生成的规则DLL,可以被VB.Delphi等生成的应用程序使用. DLL可以用多种语言和工具编写,我们这里只介绍如何使用M

在Windows下进行的编程人员,你真的需要学习下Linux

从业几年,发现好多编程人员,严重依赖UI工具.对一些命令操作,十分的反感.尤其是从事Windows系统中的程序开发的人员.由于微软对开发工具,编程套件的极限优化.开发出更多的 面向UI的开发工具.从VB6.0 到VC6.0的经典MFC编程.越来越多的Windows开发人员,包括后来的从业者,越发的不能理解那种古老的在命令行下进行代码编程的方式和思维. 从.Net诞生后,微软开发的新一代IDE工具,Visual Studio,越来越华丽,功能越来越强大.所有的操作都是面向UI.不需要进行命令的控制

MFC下CSocket编程详解

MFC下CSocket编程详解 分类: C/C++2008-03-13 09:01 34465人阅读 评论(34) 收藏 举报 mfc编程socket服务器socketsstream MFC下CSocket编程详解: 1. 常用的函数和注意事项(详细的函数接口说明请查看MSDN): CSocket::Create 初始化(一般写服务器程序都不要用为好,用下面的 CSocket::Socket 初始化) CSocket::Socket初始化 CSocket::SetSockOpt 设置socket

C语言/C+游戏编程学习之简单 DLL 劫持,就是这么任性

C语言面向过程编程的语言:C++面向对象编程的语言. 两者有本质的区别,其实是完全不同的两种语言,只不过C++兼容C语言而已. 其中C++则一般看作是对C语言的扩展.因为C语言没有面向对象的语法结构,而当时业界又迫切需要面向对象的编程特性,所以贝尔实验室的开发者就为C语言添加了面向对象的结构.现在C++已经不只是C语言的扩展了,它已经完全可以被看作一种新的编程语言.虽然C语言的特性以及库函数仍然被C++支持,不过C++拥有自己的独立的类库体系,功能相当强大. C/C++的优点在于与底层比较接近,

linux下的bash编程简要学习

linux下的bash编程简要学习     1.bash是什么: linux运行时系统只会运行系统运行所需要的运行脚本即系统守护进程,一般根据用户自己需求设定和实现的服务需要手动启动,这种服务进程通常由bash启动,脚本中的命令通常被按照一定规则被bash读取视作参数,因此在脚本头部要申明运行的bash类型,bash命令分为内建命令及外部命令,外部命令通过PATH进行依次查找. bash读取命令后将其启动(fork)成为一个进程,依次启动服务     2.bash控制语句:         本地