12、动态链接库,dll

12、动态链接库,dll

动态链接库通常都不能直接运行,也不能接收消息。它们是一些独立的文件,其中包含能被可执行程序或其它DLL调用来完成某项工作的函数。只有在其它模块调用动态链接库中的函数时,它才发挥作用。

1、我们可以把完成某种功能的函数放在一个动态链接库中,提供给其它函数调用。Windows API中所有的函数都包含在DLL中,其中三个最重要:

1)Kernal32.dll 包含那些用于内存管理,进程和线程的函数,如CreateThread函数。

2)User32.dll 包含执行用户界面任务,如窗口的创建和消息的传送的函数,如3)CreateWindow函数。

3)GDI32.dll 用于画图的显示文本的函数。

2、静态库与动态库:

静态库:

函数和数据被编译进一个二进制文件(通常扩展名为.LIB)。在使用静态库情况下,在编译链接可执行文件时,链接器从库中复制这些函数和数据并把它们和应用程序的其它模块组合起来创建最终的可执行文件。产品发布时不需要发布被使用的静态库。

动态库:

动态库一般提供两个文件:一个引入库(.lib),一个是DLL(.dll)文件。.lib文件中包含该DLL导出的函数和变量的符号名,而.dll文件包含该DLL实际的函数和数据。在使用动态库情况下,在编译链接可执行文件时,只需要链接该DLL的引入库文件,该DLL中的函数代码和数据并不复制到可执行文件中,直到可执行程序运行时,才去加载所需的DLL,将该DLL映射到进程的地址空间中,然后访问DLL中导出的函数。发布产品时要同时发布 DLL。

wps_clip_image-28821

图示 P703 两个进程访问同一个DLL时的情形

两种加载dll文件的方式,隐式加载和显式加载。

3、Dumpbin命令

应用程序如果想要访问某个DLL中的函数,那么该函数必须是已经被导出的函数。可以用Dumpbin查看。在使用之前可能需要通过VCVARS32.bat来建立VC使用的环境变量。

dumpbin -exports name.dll

4、导出DLL中函数

加_declspec(dllexport)于函数前面。

1)隐式加载

(1)通过extern声明外部函数。并在工程属性的链接器的命令行中输入lib符号名文件。把dll文件和lib文件放入指定目录中在工具选项的VC++目录中包含。

(2)利用_declspec(dllimport)于外部函数声明前。

为了方便dll的使用,通常都是提供一个.h文件给客户的;我们通常在头文件的函数声明按如下形式处理:


#ifdef DLL1_API
#else
#define DLL1_API _declspec(dllimport)
#endif

DLL1_API int _stdcall add(int a,int b);

而在函数定义的
.cpp
文件中,如下形式定义:


#define DLL1_API extern "C" _declspec(dllexport)
#include "Dll1.h"

#include <Windows.h>
#include <stdio.h>

int _stdcall add(int a,int b)
{
return a+b;
}

这样提供给客户时不需要额外的改动代码。

同样,可以把上面定义的DLL1加在一个类前面,或类的成员函数前面来把类或类的成员函数导出。如下所示:

class /*DLL1*/ Point
{
public:
void DLL1_API output(int x,int y);
void test();
};



2)显式加载

通过LoadLibrary来实现。LoadLibrary将指定的可执行模块映射到调用进程的地址空间,and the return value is a handle to the module。再通过GetProcAddress 来获得动态库中导出函数的地址。

HINSTANCE hInst;
hInst=LoadLibrary("Dll3.dll");
typedef int (/*_stdcall*/ *ADDPROC)(int a,int b);
//ADDPROC Add=(ADDPROC)GetProcAddress(hInst,"?add@@YAHHH@Z");
ADDPROC Add=(ADDPROC)GetProcAddress(hInst,"add");
//ADDPROC Add=(ADDPROC)GetProcAddress(hInst,MAKEINTRESOURCE(1));


The MAKEINTRESOURCE macro converts an integer value to a resource type

compatible with the resource-management functions. This macro is used in place of a

string containing the name of the resource

The DllMain function is called when the driver DLL first starts up.

使用完后,通过FreeLibrary 来减少被加载的dll的引用计数,当减到0时,该DLL模块从调用进程的地址空间卸载。

5、名字改编问题

不同的编译器在编译函数时,及采用不同的函数调用约定时,对函数的改编是不一样的。

http://www.cnblogs.com/mydomain/archive/2010/09/27/1837179.html

由此,在函数调用时会产生一些问题,如用C++编译器生成的函数通过C编译器调用时会出错。对于这种情况,可以在声明中加上extern “C”

#define DLL1_API extern “C” _declspec(dllimport)

利用extern “C”可以解决C++,C间相互调用问题,但是有一个缺陷,就是不能用于导出一个类的成员函数。,只能用于导出全局函数这种情况。

如果函数的调用约定发生了变化,如有的函数用_stdcall,有的用pascal,那么即使使用了extern “C”,名字改编仍会发生。

可以通过定义一个模块定义文件.def的方式来解决这个问题:

新建一个newname.def文件,加入工程中:


LIBRARY Dll2
EXPORTS
add
subtract

Dll2
与生成的动态链接库名相同。

EXPORTS:下面定义的符号名如果与函数名一样,则以符号名导出函数,如果不同,按下面规则导出函数:

entryname[=internalname] [@ordinal[NONAME]] [DATA] [PRIVATE]

There are three methods for exporting a definition, listed in recommended order of use:

1.The __declspec(dllexport) keyword in the source code

2.An EXPORTS statement in a .def file

3.An /EXPORT specification in a LINK command[1]

参考:

[1] http://msdn.microsoft.com/en-us/library/hyx1zcd3.aspx

[2] VC++深入详解

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/110679.html原文链接:https://javaforall.net

赞 (0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Xmind激活码(xmind破解版)

    这个方法我也是找了挺久才找到的,供个人借鉴和使用,但不能用于商业用途!本人的电脑系统是:MicrosoftWindows10家庭中文版一、安装软件压缩包解压后有一个文件“xmind-8-update9-windows.exe”,这是从官网上下载的安装包,没有任何改动,大家可以放心使用。该方法适用这个版本,更新后的版本没测试。二、打开安装路径找到XMind.ini文件用记事本等可以编辑文件的打开该文件在最后一行加上↓-javaagent:C:\ProgramFiles(x86)\XM

    2022年4月17日
  • GOD is a DJ[通俗易懂]

    GOD is a DJ[通俗易懂]先知教会我们知识,但不赐予我们力量;上帝创造我们身体,但不注入我们生命

    2022年10月8日
  • 用java web实现聊天室_java web实现简单聊天室「建议收藏」

    用java web实现聊天室_java web实现简单聊天室「建议收藏」目标servlet、jsp实现简单聊天室,用户通过浏览器登录后进入聊天室,可发送消息进行群聊,点击聊天信息框中的用户名可实现拍一拍功能。基础知识数据的存取setAttribute/getAttributerequest请求对象:有效时间短ServletContext上下文对象:一直存在于服务器,存储公有、共享数据Session会话对象:独立网站默认页面一般是index.jsp实现思路1….

    2022年6月22日
  • exec 与 exec sp_executesql 的用法及比较[通俗易懂]

    exec 与 exec sp_executesql 的用法及比较[通俗易懂]exec与exec sp_executesql 都可以用于执行动态sql。下面先介绍它们的用法,然后再对它们进行比较(下面用到的数据库表来自SQLSERVER的示例数据库AdventureWorks2008)一、exec与exec sp_executesql 用法1.动态sql(使用字符串拼接的方式)declare@FName2varchar(20)=’Ken’,  …

    2022年5月21日
  • 父子组建传值_详解Vue之父子组件传值

    父子组建传值_详解Vue之父子组件传值一、简要介绍父子组件之间的传值主要有三种:传递数值、传递方法、传递对象,主要是靠子组件的props属性来接收传值,下面分别介绍:(一)传递数值1.子组件:Header.vue{{msg}}exportdefault{data(){return{}},methods:{},//接收父类的传值props:[‘msg’]}可以看到,在子组件中的data对象里并没有msg属性,这里调…

    2022年5月17日
  • 北京2018积分落户名单[通俗易懂]

    北京2018积分落户名单[通俗易懂]北京2018积分落户名单已经公示出来了,地址在北京人力和社会保障局官网,共有6019人获得,恭喜他们,最低分为90.75分。Update:2019年的也出来了,详情请见https://blog.csdn.net/minstyrain/article/details/102642906.网站每页只能显示100页的内容,浏览起来很不方便,这里提供完整的excel表格形式的数据,详见百度网盘(…

    2022年10月6日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号