当前位置: 首页 > 编程日记 > 正文

dll的概念、dll导出类(转)


1、 DLL的概念

DLL(Dynamic Linkable Library),动态链接库,可以向程序提供一些函数、变量或类。这些可以直接拿来使用。

静态链接库与动态链接库的区别:

(1)静态链接库与动态链接库都是共享代码的方式。静态链接库把最后的指令都包含在最终生成的EXE文件中了;动态链接库不必被包含在最终EXE文件中,EXE文件执行时可以“动态”地引用和卸载这个与EXE独立的DLL文件。

(2)静态链接库中不能再包含其他的动态链接库或者静态库,而在动态链接库中还可以再包含其他的动态或静态链接库。

动态链接库的分类:Visual C++支持三种DLL,它们分别是:

(1)Non-MFC DLL(非MFC动态库)

非MFC动态库不采用MFC类库结构,其导出函数为标准的C接口,能被非MFC或MFC编写的应用程序所调用;

(2)MFC Regular DLL(MFC规则DLL)

MFC规则DLL 包含一个继承自CWinApp的类,但其无消息循环;

(3)MFC Extension DLL(MFC扩展DLL):MFC扩展DLL采用MFC的动态链接版本创建,它只能被用MFC类库所编写的应用程序所调用。

2、 创建一个DLL

2.1 非MFC的DLL

2.1.1声明导出函数:

extern “C” __declspec(dllexport) int add(int a, int b);

其中 extern “C”为声明为C编译。由于C++编译器在编译的时候会造成其函数名的该变,在其他应用程序中导致函数不可调用,而C编译器则不会在编译后改变其函数名。这样如果用C编译的程序来调用该dll中的函数时,可能会造成找不到该函数。

__declspec(dllexport)表示该函数为DLL输出函数,即其他应用程序可以调用该函数

从dll中声明输出函数有两种方式:
(1) 用模块定义(.def) 文件声明,.def文件为链接器提供了有关被链接程序的导出、属性及其他方面的信息。
(2) 用__declspec(dllexport)来声明函数

如果使用Visual C++来创建dll,对于同样用VC创建的exe来说,调用dll没有什么问题。

而如果用其他工具来创建的exe来调用dll,就会出现问题。因为即使你不用C++编译器,Microsoft C编译器也会损害C函数。

当用__stdcall将函数输出时,C编译器会将函数改为_func@1的形式。在这里需要在.def文件中加入EXPORTS节来输出函数:

EXPORTS
func
这样,dll将用func函数名来输出函数。

另一种方式是用#pragma (linker, “/exports:func=_func@1”),告诉编译器输出函数func,这种方式没有前一种好。

如果通过VC++编写的DLL欲被其他语言编写的程序调用应将函数的调用方式声明为__stdcall方式。

WINAPI都采用这种方式,而C/C++ 缺省的调用方式却为__cdecl。__stdcall方式与__cdecl对函数名最终生成符号的方式不同。

若采用C编译方式(在C++中需将函数声明为extern "C"),__stdcall调用约定在输出函数名前面加下划线,后面加“@”符号和参数的字节数,

形如_functionname@number;而__cdecl调用约定仅在输出函数名前面加下划线,形如_functionname。

lib.def : 导出DLL函数
LIBRARY dllTest
EXPORTS
add @ 1
.def文件的规则为:
   (1)LIBRARY语句说明.def文件相应的DLL;
   (2)EXPORTS语句后列出要导出函数的名称。可以在.def文件中的导出函数名后加@n,表示要导出函数的序号为n

(在进行函数调用时,这个序号将发挥其作用);

   (3).def 文件中的注释由每个注释行开始处的分号 (;) 指定,且注释不能与语句共享一行。
   由此可以看出,例子中lib.def文件的含义为生成名为“dllTest”的动态链接库,导出其中的add函数,并指定add函数的序号为1。

2.1.2 Dll的调用方式: 

DLL的调用分为两种方式:动态和静态显示动态链接隐式动态链接)

(1) 动态调用(显示动态链接):

typedef int(*lpAddFun)(int, int); //宏定义函数指针类型

lpAddFun add;//函数指针
HINSTANCE hDll=LoadLibrary(“path”);
add=(lpAddFun)GetProcAddress(hDll, "add");//获得dll中的add函数指针
FreeLibrary(hDll);

在从dll调用中返回的函数、指针或者类都是以指针的方式的,即返回的是函数、变量或类的地址。这里一定要注意,不能简单的用函数名来赋值。

(2) 静态调用(隐式动态链接):

将生成的.dll和.lib文件拷入到调用dll的工程中,用命令

#pragma comment(lib,"dllTest.lib"),实现静态调用,即把该dll在编译的时候也编译到exe文件中去,而后在工程中调用时用下面的代码:

#pragma comment(lib,"dllTest.lib")//.lib文件中仅仅是关于其对应DLL文件中函数的重定位信息
extern "C" __declspec(dllimport) add(int x,int y);
int main(int argc, char* argv[])
{
int result = add(2,3);
printf("%d",result);
return 0;
}

   由上述代码可以看出,静态调用方式的顺利进行需要完成两个动作:
   (1) 告诉编译器与DLL相对应的.lib文件所在的路径及文件名,#pragma comment(lib,"dllTest.lib")就是起这个作用。程序员在 建立一个DLL文件时,连接器会自动为其生成一个对应的.lib文件,该文件包含了DLL 导出函数的符号名及序号(并不含有实际的代码)。在应用程序 里,.lib文件将作为DLL的替代文件参与编译。另外一种显式调用的方式是设置vc中的目录和includefiles来实现

   (2) 声明导入函数,extern "C" __declspec(dllimport) add(int x,int y)语句中的__declspec(dllimport)发挥这个作 用。静态调用方式不再需要使用系统API来加载、卸载DLL以及获取DLL中导出函数的地址。这是因为,当程序员通过静态链接方式编译生成应用程序时,应 用程序中调用的与.lib文件中导出符号相匹配的函数符号将进入到生成的EXE 文件中,.lib文件中所包含的与之对应的DLL文件的文件名也被编译器存储在 EXE文件内部。当应用程序运行过程中需要加载DLL文件时,Windows将根据这些信息发现并加载DLL,然后通过符号名实现对DLL 函数的动态链接。这 样,EXE将能直接通过函数名调用DLL的输出函数,就象调用程序内部的其他函数一样。

2.1.3 DllMain函数

Windows在加载dll的时候,会首先需要一个入口函数DllMain。当在dll中不定义DllMain的时候,windows会从其他运行库中调用一个不做任何操作的DllMain函数,直接返回true。DllMain是dll内部的函数,这意味着在调用dll的程序中不能显式的调用。它是在 dll被调用时自动被调用的。

BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)

{
switch (ul_reason_for_call)
{
case: DLL_PROCESS_ATTACH:
break;
case: DLL_THREAD_ATTACH:
break;
case: DLL_THREAD_DETACH:
break;
case: DLL_PROCESS_DETACH:
break;
return TRUE;
}

2.2 在dll中导出变量
1、在dll中定义变量 extern int global;
2、在.def中定义输出 EXPORTS:
global DATA
3、 在应用程序中调用:#pragma comment(lib,"dllTest.lib")
extern int global;
注意在此引入的变量global,是一个地址,在使用时需要强制转化为指针后再用,才能得到其值。
(int *)global=10;

在应用工程中引用DLL中全局变量的一个更好方法是:

extern int _declspec(dllimport) global; //用_declspec(dllimport)导入
通过_declspec(dllimport)方式导入的就是DLL中全局变量本身而不再是其地址了,建议在一切可能的情况下使用这种方式。

2.3 dll导出类
在定义的时候用

class _declspec(dllexport) classname{

}

在类中引用的时候用加入类定义头文件:

#include “classname.h”

Class _declspec(dllimport) classname 来导入类

3、 MFC规则Dll
MFC规则DLL的概念体现在两方面:
   (1) 它是MFC的
   “是MFC的” 意味着可以在这种DLL的内部使用MFC;
(2) 它是规则的
“是规则的”意味着它不同于MFC扩展DLL,在MFC规则DLL的内部虽然可以使用MFC,但是其与应用程序的接口不能是MFC。而MFC扩展DLL与应用程序的接口 可以是MFC,可以从MFC扩展DLL中导出一个MFC类的派生类。
   Regular DLL能够被所有支持DLL技术的语言所编写的应用程序调用,当然也包括使用MFC的应用程序。在这种动态连接库中,包含一个从CWinApp继承下 来的类,DllMain函数则由MFC自动提供。

(1)静态链接到MFC 的规则DLL
   静态链接到MFC的规则DLL与MFC库(包括MFC扩展 DLL)静态链接,将MFC库的代码直接生成在.dll文件中。在调用这种DLL的接口时,MFC使用DLL的资 源。因此,在静态链接到MFC 的规则DLL中不需要进行模块状态的切换。使用这种方法生成的规则DLL其程序较大,也可能包含重复的代码。
(2)动态链接到MFC 的规则DLL
   动态链接到MFC 的规则DLL 可以和使用它的可执行文件同时动态链接到 MFC DLL 和任何MFC扩展 DLL。在使用了MFC共享库的时候,默认情况下,MFC 使用主应用程序的资源句柄来加载资源模板。这样,当DLL和应用程序中存在相同ID的资源时(即所谓的资源重复问题),系统可能不能获得正确的资源。因此,对于共 享MFC DLL的规则DLL,我们必须进行模块切换以使得MFC能够找到正确的资源模板。

我们可以在Visual C++中设置MFC规则DLL是静态链接到MFC DLL还是动态链接到MFC DLL。如图8,依次选择Visual C++的project -> Settings -> General菜单或选项,在Microsoft Foundation Classes中进行设置。

3.1规则DLL的创建;

与非MFCdll不同的是,在其定义里面可以引入MFC类,其他与非MFC一样

3.2规则DLL的调用

(1)显示方式LoadLibrary , GetProcAdress , FreeLibrary

(2)我们照样可以在EXE程序中隐式调用MFC规则DLL,只需要将DLL工程生成的.lib文件和.dll文件拷入当前工程所在的目录,并在cpp文件顶部添加:
#pragma comment(lib,"RegularDll.lib")

3.3共享MFC DLL的规则DLL的模块切换

应用程序进程本身及其调用的每个DLL模块都具有一个全局唯一的HINSTANCE句柄,它们代表了DLL或EXE模块在进程虚拟空间中的起始地址进程本身的模块句柄一般为0x400000而DLL模块的缺省句柄为0x10000000如果程序同时加载了多个DLL,则每个DLL模块都会有不同的 HINSTANCE应用程序在加载DLL时对其进行了重定位。
  共享MFC DLL(或MFC扩展DLL)的规则DLL涉及到HINSTANCE句柄问题,HINSTANCE句柄对于加载资源特别重要。EXE和DLL都有其自己的资源,而且这些资源的ID可能重复,应用程序需要通过资源模块的切换来找到正确的资源。如果应用程序需要来自于DLL的资源,就应将资源模块句柄指定为 DLL的模块句柄;如果需要EXE文件中包含的资源,就应将资源模块句柄指定为EXE的模块句柄。

模块的切换有三种方式:
(1)在DLL函数中调用:AFX_MANAGE_STATE(AfxGetStaticModuleState());(推荐使用,最简单)
void ShowDlg(void)
{
//方法1:在函数开始处变更,在函数结束时恢复
//将AFX_MANAGE_STATE(AfxGetStaticModuleState());作为接口函数的第一//条语句进行模块状态切换
AFX_MANAGE_STATE(AfxGetStaticModuleState());
CDialog dlg(IDD_DLL_DIALOG);//打开ID为2000的对话框
dlg.DoModal();
}
(2)在DLL函数中调用AfxGetResourceHandle();
AfxSetResourceHandle(HINSTANCE xxx);
(3)由应用程序自身切换(不推荐,最麻烦)

4、扩展MFCDLL

MFC扩展DLL的内涵为MFC的扩展,用户使用MFC扩展DLL就像使用MFC本身的DLL一样。除了可以在MFC扩展DLL的内部使用MFC以外, MFC扩展DLL与应用程序的接口部分也可以是MFC。我们一般使用MFC扩展DLL来包含一些MFC的增强功能,譬如扩展MFC的CStatic、 CButton等类使之具备更强大的能力。
导出一个类,直接在类声明头文件中使用AFX_EXT_CLASS即可,最后别忘了在调用dll的程序中加入class的头文件

5、总结:
综上所述:以上几种dll主要由以下几种区别:

1、动态链接库是将exe程序在程序执行的时候动态加载的,而静态链接库是在编译的时 将其编译在代码之中的

2、动态链接库可以输出变量、函数和类。其中每种输出的方式与调用方式不尽相同:

(1)变量:在dll中定义 extern int global;
在.def文件中输出 EXPORTS
global DATA
或extern _declspec(dllexport)int global(不用输出文件了)
在程序中调用:
静态调用:

#pragma comment(lib,"dllTest.lib")

extern int _declspec(dllimport) global;
动态调用:

(2)函数:在dll中定义

extern “C” __declspec(dllexport) int add(int a, int b);
也可以在.def文件中输出该函数
EXPORTS
add @ 1
在程序中调用:
静态调用:
#pragma comment(lib,"dllTest.lib")
extern "C" __declspec(dllimport) add(int x,int y);
动态调用:
typedef int(*lpAddFun)(int, int); //宏定义函数指针类型
lpAddFun add;//函数指针
HINSTANCE hDll=LoadLibrary(“path”);
add=(lpAddFun)GetProcAddress(hDll, "add");//获得dll中的add函数指针
FreeLibrary(hDll);
在从dll调用中返回的函数、指针或者类都是以指针的方式会的,即返回的是函数、变量或类的地址。这里一定要注意,不能简单的用函数名来赋值。
(3)类:在dll中定义:
在定义的时候用 class _declspec(dllexport) classname{
}
在类中引用的时候用
加入类定义头文件:#include “classname.h”
Class _declspec(dllimport) classname 来导入类
3、除了扩展MFC的dll外,其他的dll均可被其他语言编写的应用程序来调用。

转载于:https://www.cnblogs.com/whiteyun/archive/2011/07/22/2113668.html

相关文章:

墨奇科技汤林鹏:如何用 AI 技术颠覆指纹识别?

受访者 | 墨奇科技联合创始人& CTO 汤林鹏 记者 | Aholiab,编辑 | Carol 出品 | AI科技大本营(ID:rgznai100) 随着深度学习等AI技术的成熟,生物识别成为了关注度较高的领域,指纹、人脸、虹膜等识别技术…

ASP.Net ViewState的实现

选择自 timmy3310 的 Blog ViewState是.Net中提出的状态保存的一种新途径(实际上也是老瓶装新酒);我们知道,传统的Web程序保存状态的方式有这样几种:1、Application 这是Web应用程序生命期中的全局保存区&#xff0c…

【51CTO学院三周年】遇到

作为一名二流学校的大学生,因为学校的一门嵌入式Linux应用程序开发而喜欢上了嵌入式,但是学校却是只上了一学期的课,无奈只能自己找教程继续学习。在3个月前,无意中找到了朱有鹏老师的嵌入式学习基础视频,通过老师视频…

ASP.NET图象处理详解

作者:未知 请与本人联系在使用ASP的时候,我们时常要借助第三方控件来实现一些图象功能。而现在,ASP.NET的推出,我们已经没有必要再使用第三方控件来实现,因为ASP.NET 已经具有强大的功能来实现一些图象处理。现在&…

IT工作者,你们的爱情是这样的吗?

今天在博客里看到了这篇文章,看完这个视频我随笔写了点自己的感受和看法, 视频链接在下方: http://leidu.blog.51cto.com/3245712/622534 很感谢90 男孩提供,建议IT人员看一下,看完写一下你们的感受吧!…

平头哥玄铁处理器Linux新版本,5大亮点速览

来源 | 芯片开放社区为了便于 CPU 评估,系统集成,快速上手玄铁处理器 Linux 操作系统,平头哥更新了玄铁处理器 linux 版本,结合 gitlab 开源 CI/CD 系统,对已发布到开源社区的玄铁架构 CPU 相关的生态软件形成持续保障…

费用保险单,如何失焦时自动补零

费用,如何失焦时自动补零转载于:https://www.cnblogs.com/maojiayan/p/5606247.html

腾讯AI种番茄双丰收:参赛AI全胜专家,辽宁试点净利增千元

6月9日,腾讯宣布了两项AI农业领域进展。在研究侧,腾讯 AI Lab 与荷兰瓦赫宁根大学(下称WUR)联办的“第二届国际智慧温室种植挑战赛”(下称比赛)落幕。在全球疫情肆虐之时,复赛的五支队伍挑战用 …

在ASP.NET中值得注意的两个地方

在ASP.NET中ASPX页面的Page_Load事件有两个让人奇怪的地方,你应该记住它们: a.有时Page_Load事件在你的ASP.NET页面里会发生多次。这种情况发生的一个可能的原因是你把ASPX页面的AutoEvenWireup值设置成了True。如果是这样,那么在“Sub Page…

yii 级联删除

alter table 外键表 add constraint 级联删除名 foreign key (外键字段) references 主表名(主表字段)ON delete CASCADE go 转载于:https://blog.51cto.com/dasangshu/624605

iOS--优秀博客记录

感谢唐巧整理,我又加了一些备注。原地址:https://github.com/tangqiaoboy/iOSBlogCN 博客地址RSS地址psOneVs Denhttp://onevcat.com/atom.xml 一只魔法师的工坊http://blog.ibireme.com/feed/图片处理、YYKit破船之家http://beyondvincent.com/atom.xml…

linux环境下和网络服务相关的配置文件含义及如何配置

要建立一个安全Linux服务器就首先要了解Linux环境下和网络服务相关的配置文件的含义及如何进行安全的配置。那天查看服务器的eth0地址,后来想了一些问题,到家里就翻了翻以前的文档,无意中看到了这个,现在发布出来,希望…

ASP.NET保持用户状态的九种选择

2003-06-10 ■陶刚编译 ■yesky摘要:ASP.NET为保持用户请求之间的数据提供了多种不同的途径。你可以使用Application对象、cookie、hidden fields、Sessions或Cache对象,以及它们的大量的方法。决定什么时候使用它们有时很困难。本文将介绍了上述的技术&…

Python 图像处理 | 图像平滑之均值滤波、方框滤波、高斯滤波及中值滤波

作者 | 杨秀璋,责编 | 夕颜 题图 | 视觉中国出品 | CSDN博客本篇文章主要讲解Python调用OpenCV实现图像平滑,包括四个算法:均值滤波、方框滤波、高斯滤波和中值滤波。全文均是基础知识,希望对您有所帮助。知识点如下:…

Laravel Lumen之Eloquent ORM使用速查-基础部分

使用Eloquent [eləkwənt] 时&#xff0c;数据库查询构造器的方法对模型类也是也用的&#xff0c;使用上只是省略了DB::table(表名)部分。 在模型中使用protected成员变量$table指定绑定的表名。<?php namespace App;use Illuminate\Database\Eloquent\Model;class Flight…

数据库连接字在Web.config里的用法

作者&#xff1a;未知 请速与本人联系在asp.net中的WEB程序的设置中我们必须用到Web.config来存储数据库连接字.事实上这是个很好的做法,因为可以省去我们很多的麻烦还可以帮助我们避免不必要的错位,是的很多情况下我就是这样做.它通过XML来记录这些信息.具体的是在....这个标…

重构ncnn,腾讯优图开源新一代移动端推理框架TNN

来源 | 腾讯优图从学界到工业界&#xff0c;“开源”已经成为AI领域的一个关键词。一方面&#xff0c;它以“授人以渔”的方式为AI构建了一个开放共进的生态环境&#xff0c;帮助行业加速AI应用落地&#xff1b;另一方面&#xff0c;在解决行业实际问题时持续更新和迭代&#x…

java读取文件

1 java8读取文本文件2 3 4 public static void java8ReadFileLines(String fileName) throws IOException {5 List lineList Files.readAllLines(Paths.get(fileName), StandardCharsets.UTF_8);6 7 for(String line:lineList){8 Sys…

常见 Datagrid 错误

Marcie Robillard DatagridGirl.comDatagrid 控件是 Microsoft ASP.NET 中功能最强、用途最广的 Web 控件之一&#xff0c;这一点已经得到了 ASP.NET 权威人士的认同。虽然 Datagrid 控件易于使用&#xff0c;但同样易于给使用者带来麻烦。以下是许多人所犯的一些错误&#xff…

干货!3 个重要因素,带你看透 AI 技术架构方案的可行性!

作者 | 房磊责编 | Carol出品 | AI 科技大本营&#xff08;ID&#xff1a;rgznai100&#xff09;人工智能这几年发展的如火如荼&#xff0c;不仅在计算机视觉和自然语言处理领域发生了翻天覆地的变革&#xff0c;在其他领域也掀起了技术革新的浪潮。无论是在新业务上的尝试&…

mysql从另一张获取数据的方法

方法一 CREATE TABLE tmp AS SELECT a.id FROM t_user t JOIN temp a ON t.email a.email; 方法二 INSERT INTO t_user (id,username,PASSWORD,email,user_type,STATUS) SELECT id,REPLACE(email,,_),PASSWORD,email,0,0 FROM temp; 这两个sql都是从另外一张中获取的数据插入…

手动创建Spring项目 Spring framework

之前学习框架一直是看的视频教程&#xff0c;并且在都配套有项目源码&#xff0c;跟着视频敲代码总是很简单&#xff0c;现在想深入了解&#xff0c;自己从官网下载文件手动搭建&#xff0c;就遇到了很多问题记载如下。 首先熟悉一下spring的官方网站&#xff1a;http://spring…

使用 ASP+ DataGrid 控件来创建主视图/详细资料视图

Nikhil Kothari Microsoft Corporation 2000年8月简介 Microsoft Visual Studio.NET 的下一发行版包括 DataGrid Web 控件 (作为服务器控件的 Active Server Page (ASP) 套件的一部分)。 该控件提供用以根据数据源的内容来表示 HTML 的功能。 DataGrid 控件可以用于若干个只…

如何将广告始终定位到网页右下角

body{margin:0;border:0;height:100%;overflow-y:auto;}#test{display:block; bottom:3px; right:3px; width:130px; position:fixed;}/* 以下是写给IE6的 */* html #test{position:absolute;right:18px} * html{overflow-x:auto; overflow-y:hidden;}转载于:https://www.cnblo…

如何用 Python 将 Excel 表格转成可视化图形?| 原力计划

作者 | Waao666责编 | 王晓曼出品 | CSDN 博客前言大家知道&#xff0c;考研很大一部分也是考信息收集能力。每年往往有很多人就是在这上面栽跟头了&#xff0c;不能正确分析各大院校往年的录取信息&#xff0c;进而没能选择合适的报考院校。至于很多院校的录取信息是以 PDF 形…

Mac OS X 下mysql配置备忘

从windows过渡到os x确实需要适应&#xff0c;对于开发人员来讲更是这样。从官网下载目前最新版本的mysql 5.7.13&#xff0c;下载地址&#xff1a;http://dev.mysql.com/downloads/mysql/刚开始非常顺利的安装完mysql&#xff0c;这时候我还没有意识到密码的问题&#xff0c;直…

为 ASP.NET Datagrid 创建自定义列

Marcie Robillard DatagridGirl.com 2003 年 9 月 简介 不得不承认&#xff0c;为 Microsoft ASP.NET 编写 Datagrid 代码包括大量的重复工作。尽管我深受该控件的困扰&#xff0c;但我还是不断寻找简化这类任务的捷径。谁都不愿意做重复的工作&#xff0c;对不对&#xff1…

不怕面试被问了!二叉树算法大盘点

作者 | BoCong-Deng题图 | 视觉中国出品 | CSDN博客树结构对于程序员来说应该不陌生&#xff0c;特别是二叉树&#xff0c;基本只要接触算法这一类的都一定会碰到的&#xff0c;所以我打算通过一篇文章&#xff0c;对二叉树结构的相关算法进行总结汇总&#xff0c;思路和代码实…

Field types

2019独角兽企业重金招聘Python工程师标准>>> Field types The generated Form class will have a form field for every model field. Each model field has a corresponding default form field. For example, a CharField on a model is represented as a CharFie…

【51CTO学院三周年】我的职业生涯有贵人相助--小强老师

个人认为功能测试做到一定年限之后&#xff0c;自然会遇到职业生涯中最大瓶颈——转型。对此&#xff0c;我的经历是这样的。话说那还是两年前&#xff0c;在搜索某问题的时候发现了51CTO&#xff0c;从中看到了很多大牛的博文和视频课程&#xff0c;顿时感觉自己找到宝了&…