我的编程空间,编程开发者的网络收藏夹
学习永远不晚

VisualStudio 制作Dynamic Link Library动态链接库文件的详细过程

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

VisualStudio 制作Dynamic Link Library动态链接库文件的详细过程

工具集

借助工具可以获得Dll库函数的访问地址,以下推荐两款工具以供使用:

Dependency Walker官网

Depends22_x64.zip

Dllexp-x64.zip

如何生成

__declspec(dllexport)

将一个函数声名为导出函数,就是说这个函数要被其他程序调用,即作为DLL的一个对外函数接口。

__declspec(dllexport) RETURN_TYPE FUNCTION()

extern “C”

由于在制作DLL导出函数时由于C++存在函数重载

  • 因此__declspec(dllexport) FUNCTION(int,int)在DLL会被decorate,例如: 被decorate成为function_int_int,
  • 而且不同的编译器decorate的方法不同,造成了在用GetProcAddress取得FUNCTION地址时的不便
  • 使用extern "C"时,上述的decorate不会发生,因为C没有函数重载,如此一来被extern"C"修饰的函数,就不具备重载能力
extern "C" {
  __declspec(dllexport) RETURN_TYPE FUNCTION(){
    ;
  }
}

如何使用

  • 动态载入方式是指在编译之前并不知道将会调用哪些 DLL 函数, 完全是在运行过程中根据需要决定应调用哪些函数。
  • 方法是:用 LoadLibrary 函数加载动态链接库到内存,用 GetProcAddress函数动态获得 DLL 函数的入口地址。
  • 当一个 DLL 文件用 LoadLibrary 显式加载后,在任何时刻均可以通过调用 FreeLibrary 函数显式地从内存中把它给卸载。
  • 动态调用使用的 Windows API 函数主要有 3 个, 分别是 LoadLibraryGetProcAddressFreeLibrary

声明调用

注意DLL函数调用约定,必须一致

  • __stdcall Windows API默认的函数调用协议
  • __cdecl C/C++默认的函数调用协议
  • __fastcall 适用于对性能要求较高的场合

Example

假如我有一个函数接口如下:

//@ GETCOMCHECKSUM_API是一个宏定义
//@ #define GETCOMCHECKSUM_API __declspec(dllexport)
GETCOMCHECKSUM_API int fnGetComCheckSum(
                        const unsigned char*  iCsArray,       //[In]数组
                        const unsigned int    iCsSize,        //[In]数值
                        unsigned char&        ioCsValue)      //[In/Out]数值

那么我的调用应该这么写:

//@ __cdecl * 后面函数名可以自定义
typedef int(__cdecl *GetComCheckSum)(
            unsigned char const *,
            unsigned int,
            unsigned char&);

LoadLibrary

  • [格式] function LoadLibrary(LibFileName : PChar): Thandle;
  • [功能] 加载由参数 LibFileName 指定的 DLL 文件
  • [说明] 参数 LibFileName 指定了要装载的 DLL 文件名

如果 LibFileName 没有包含一个路径,系统将按照:当前目录、Windows 目录、Windows 系统目录、包含当前任务可执行文件的目录、列在 PATH 环境变量中的目录等顺序查找文件。

如果函数操作成功,将返回装载 DLL 库模块的实例句柄,否则,将返回一个错误代码,错误代码的定义如下表所示

错误代码             含义
      0             系统内存不够,可执行文件被破坏或调用非法
      2             文件没有被发现
      3             路径没有被发现
      5             企图动态链接一个任务错误或者有一个共享或网络保护错误
      6             库需要为每个任务建立分离的数据段  
      8             没有足够的内存启动应用程序  
      10            Windows  版本不正确  
      11            可执行文件非法或不是Windows  应用程序,或在.  EXE映像中有错误  
      12            应用程序为一个不同的操作系统设计(如  OS/2)  
      13            应用程序为  MS  DOS   4. 0  设计  
      14            可执行文件的类型不知道  
      15            试图装载一个实模式应用程序(为早期Windows  版本设计)
      16            试图装载包含可写的多个数据段的可执行文件的第二个实例  
      19            试图装载一个压缩的可执行文件(文件必须被解压后才能被装载)  
      20            DLL  文件非法
      21            应用程序需要  32  位扩展

Example

//@ 定义句柄
HINSTANCE hSnKLib;

//@ 获取链接库句柄       Getchecksum为dll的文件名 即 Getchecksum.dll
//@ 系统将会在当前目录下寻找名为Getchecksum.dll的文件
//@ 至于为什么使用_T("") ,_T是一个宏,作用是让你的程序支持Unicode编码,Windows使用两种字符集ANSI和UNICODE
hSnKLib = LoadLibrary(_T("Getchecksum"))

//@ 如果未能成功获取,抛出错误
if (hSnKLib == NULL)
{
    FreeLibrary(hSnKLib);
  	printf("LoadLibrary err\n");
  	getchar();
  	return 1;
}

GetProcAddress

  • 格式:function GetProcAddress(Module:Thandle; ProcName:PChar): TfarProc;
  • 功能: 返回参数 Module 指定的模块中,由参数 ProcName 指定的过程或函数的入口地址
  • 说明: 参数 Module 包含被调用函数的 DLL 句柄,这个值由 LoadLibrary 返回,procName是指向含有函数名的以 nil 结尾的字符串指针,或者可以是函数的次序值.

大多数情况下,用函数名是一种更稳妥的选择。

如果该函数执行成功,则返回 DLL 中由参数 ProcName 指定的过程或函数的入口地址,否则返回 nil 。

Example

//前面我们在头文件中声明了下述函数
typedef int(__cdecl *GetComCheckSum)(
            unsigned char const *,
            unsigned int,
            unsigned char&);


//实例化并且获取函数地址
//fnGetComCheckSum为dll export出来的函数名,GetComCheckSum为我们引用时候声明的函数名
//这里做的工作就是将dll中函数与我们声明的联系到一块。
GetComCheckSum getcom = (GetComCheckSum)GetProcAddress(hSnKLib, "fnGetComCheckSum")

if (!getcom)
{
	FreeLibrary(hSnKLib);			//释放dll文件
	//Add your code here
}

FreeLibrary

  • 格式:procedure FreeLibrary(Module: Thandle);
  • 说明:将由参数 Module 指定的 DLL 文件从内存中卸载 1 次。
  • 说明:Module 为 DLL 库的句柄。这个值由 LoadLibrary 返回。由于 DLL 在内存中只装载一次,因此调用 FreeLibrary 首先使 DLL 的引用计数减 1,如果计数减为 0 则卸载该 DLL
  • 注意:每调用一次 LoadLibrary 函数就应调用一次 FreeLibrary 函数,以保证不会有多余的库模块在应用程序结束后仍留在内存中,否则导致内存泄漏。

Example

FreeLibrary(hSnKLib);

FAQS

Question 1: GetLastError获取错误代码127

问题描述:

  • 采用"运行期间动态链接"自己的dll文件
  • LoadLibrary成功获取dll模块句柄
  • 但是GetProcAddress(hModule, “ExportFunc”)却返回NULL,GetLastError获取错误代码127,意思是“找不到指定程序”

问题定位:

  • 用Depends工具(VS2010默认没有,需另行下载:http://www.dependencywalker.com/),查看dll的导出函数名称。
  • 发现导出函数名不再是“ExportFunc”,而根据函数的返回类型和参数进行了“decorate”,变为了“?ExportFunc@@YAXPB_W@Z”。

解决方法两种:

  • 修改GetProcAddress的第二个参数为真正的导出函数名称即可
  • 在dll工程中添加DEF文件,写入如下内容:
EXPORTS
               ExportFunc
  • 重新编译dll工程。再次用Depends工具查看导出函数名称,即为“ExportFunc”。
  • 工程–链接器–输入 的模块定义文件中,将自己的DEF文件加上

在这里插入图片描述

参考案例

GetProcAddress 使用注意事项

到此这篇关于VisualStudio 制作Dynamic Link Library动态链接库文件的文章就介绍到这了,更多相关VisualStudio动态链接库文件内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

VisualStudio 制作Dynamic Link Library动态链接库文件的详细过程

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

VisualStudio 制作Dynamic Link Library动态链接库文件的详细过程

这篇文章主要介绍了VisualStudio 制作Dynamic Link Library动态链接库文件的详细过程,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
2022-11-13

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录