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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 协程(coroutine)简介

    协程(coroutine)简介Acoroutineisafunctionthatcansuspendexecutiontoberesumedlater.协程不是系统级线程,很多时候协程被称为“轻量级线程”

    2022年6月30日
    24
  • java List去除重复数据的五种方式

    java List去除重复数据的五种方式以下介绍五种-不同的方法去除Java中ArrayList中的重复数据1.使用LinkedHashSet删除arraylist中的重复数据LinkedHashSet是在一个ArrayList删除重复数据的最佳方法。LinkedHashSet在内部完成两件事:删除重复数据 保持添加到其中的数据的顺序Java示例使用LinkedHashSet删除arraylist中的重复项。在…

    2022年5月26日
    39
  • Haar特征提取算法的实现

    Haar特征提取算法的实现自己动手 丰衣食足 系列 nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp Haar 特征是一种很早就被提出的图像特征提取算法 后面还经过了几次改进 Haar 特征能够很好地运用于人脸识别技术 当然很多目标检测技术中对目标图像的特征提取也可以使用 Haar 特征 当我们使用 opencv 自带的 cascade 分类器时可以选择 Haar 特征作为训练样本数据的特征描述子 然后将特征描述子作为样本数据送入 cascade 分类器中 就可以通过 Adab

    2025年7月10日
    4
  • Exchange 2010 重建OWA报错

    Exchange 2010 重建OWA报错

    2021年8月15日
    47
  • spi,i2c,uart三种总线的区别(vga接口是干嘛用的)

    一SPII2CUART通信速率比较二串行和并行同步和异步的区别三I2C接口与串行接口的区别四总线接口UARTI2CSPIUSB的异同点五串口通信UARTSPII2C区别UART通用异步收发器I2CUART总结一、SPII2CUART通信速率比较:SPI&gt;I2C&gt;UART1、同步通信&gt;异步通信;2、同步通信…

    2022年4月14日
    384
  • realsense深度图像保存方法[通俗易懂]

    realsense深度图像保存方法[通俗易懂]一般使用realsense时会保存视频序列,当保存深度图像时,需要注意保存的图像矩阵的格式,不然可能造成深度值的丢失。在众多图像库中,一般会使用opencv中的imwrite()函数进行深度图像的保存。一般深度图像中深度值的单位是mm,因此一般使用np.uint16作为最终数据格式保存。例子:importnumpyasnpimportcv2deffun1(…

    2022年4月25日
    31

发表回复

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

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