12、动态链接库,dll

12、动态链接库,dll

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

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

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

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

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

2、静态库与动态库:

静态库:

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

动态库:

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

wps_clip_image-28821

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

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

3Dumpbin命令

应用程序如果想要访问某个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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Java面试宝典:42个面试题总结!

    Java面试宝典:42个面试题总结!本文我们将要讨论Java面试中的各种不同类型的面试题,它们可以让雇主测试应聘者的Java和通用的面向对象编程的能力。下面的章节分为上下两篇,第一篇将要讨论面向对象编程和它的特点,关于Java和它的功能的常见问题,Java的集合类,垃圾收集器,第二篇主要讨论异常处理,Java小应用程序,Swing,JDBC,远程方法调用(RMI),Servlet和JSP。开始!目录面向对象编

    2022年7月7日
    17
  • Android Studio 中Intel HAXM安装与模拟器创建「建议收藏」

    Android Studio 中Intel HAXM安装与模拟器创建「建议收藏」AndroidStudio中IntelHAXM安装与模拟器创建

    2022年4月19日
    35
  • checkbox选中和不选中 jqu_jquery checkbox 选中不选中

    checkbox选中和不选中 jqu_jquery checkbox 选中不选中展开全部$(function(){//动态绑定默认状态//$(“#ck”).attr(“checked”,true)//选中//$(“#ck”).attr(“checked”,false)//未选中//点击判断选中还是未选中$(“#ck”).click(function(){if($(this).is(“:checked”)){alert(“选中”);}else{alert…

    2022年6月30日
    20
  • 光纤交换机配置zone[通俗易懂]

    光纤交换机配置zone[通俗易懂]B系列SAN交换机-Zoning配置信息型本文档提供了BrocadeSAN交换机zoning配置的分步骤指南。详细信息新建zone配置:a. 新建一个zoning配置,用cfgcreate命令。格式:cfgcreate“cfgname”,“zonename1;zonename2;…”举例:cfgcreate“cfg1”,“zone1;zone2”b. 新建一个zone,用zonecreate命令。格式:zonecreate“zone

    2022年5月22日
    34
  • 渗透之——使用reaver傻瓜式破解wifi之利用路由器WPS漏洞

    渗透之——使用reaver傻瓜式破解wifi之利用路由器WPS漏洞跟这篇破解教程一样,网上破解教程多是基于路由器的WPS漏洞破解,但是这样的路由器只占少数。一般wifi是依据WPA/WPA2加密的,因此想要破解一般的wifi,还得破解这个协议,虽然近期这个协议也被破解了,不过也是很不容易的。刚入门破解,不是很熟悉,在网上找各种破解资料,终于破解成功了临近工作室的wifi,沾沾自喜~本文破解wifi针对一些路由器的WPS(Wi-fiprotectedset…

    2022年5月16日
    50
  • 如何生成“年月日_时分秒”命名的文件

    如何生成“年月日_时分秒”命名的文件

    2021年9月1日
    86

发表回复

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

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