上文我简单的介绍了如何建立一个简单DLL,下面再我简单的介绍一下如何使用一个DLL。当一个DLL被生成后,它创建了一个.dll文件和一个.lib文件;这两个都是你需要的。要使用DLL,就需要载入这个DLL。

隐式链接

这里有两个方法来载入一个DLL;一个方法是捷径另一个则相比要复杂些。捷径是只链接到你.lib 文件并将.dll文件置入你的新项目的路径中去。因此,创建一个新的空的Win32控制台项目并添加一个源文件。将你做的DLL放入你的新项目相同的目录下。

#include "stdafx.h"
#include "DLLSample.h"

#pragma comment(lib, "DLLSample.lib") //你也可以在项目属性中设置库的链接

int main()
{
        TestDLL(123);
        return(1);
}

这就是载入一个DLL的简单方法。

显式链接

难点的加载DLL的方法稍微有点复杂。你将需要函数指针和一些Windows函数。但是,通过这种载入DLLs的方法,你不需要DLL的.lib或头文件,而只需要DLL。

#include <iostream>
#include <windows.h>
typedef void (*DLLFunc)(int);
int main()
{
        DLLFunc dllFunc;
        HINSTANCE hInstLibrary = LoadLibrary("DLLSample.dll");

if (hInstLibrary == NULL)
        {
         FreeLibrary(hInstLibrary);
        }
        dllFunc = (DLLFunc)GetProcAddress(hInstLibrary, "TestDLL");
        if (dllFunc == NULL)
        {
         FreeLibrary(hInstLibrary);
        }
        dllFunc(123);
        std::cin.get();
        FreeLibrary(hInstLibrary);
        return(1);
}

首先你会注意到:这里包括进了文件“windows.h”同时移走了“DLLSample.h”。原因很简单:因为windows.h包含了一些Windows函数,当然你现在将只需要其中几个而已。它也包含了一些将会用到的Windows特定变量。你可以去掉DLL的头文件(DLLSample.h)因为-如我前面所说-当你使用这个方法载入DLL时你并不需要它。

下面你会看到:下面的一句代码:

typedef void (*DLLFunc)(int);
     
这是一个函数指针类型的定义。指向一个函数是一个int型的参数,返回值为void类型。

一个HINSTANCE是一个Windows数据类型:是一个实例的句柄;在此情况下,这个实例将是这个DLL。你可以通过使用函数LoadLibrary()获得DLL的实例,它获得一个名称作为参数。在调用LoadLibrary函数后,你必需查看一下函数返回是否成功。你可以通过检查HINSTANCE是否等于NULL(在Windows.h中定义为0或Windows.h包含的一个头文件)来查看其是否成功。如果其等于NULL,该句柄将是无效的,并且你必需释放这个库。换句话说,你必需释放DLL获得的内存。如果函数返回成功,你的HINSTANCE就包含了指向DLL的句柄。

一旦你获得了指向DLL的句柄,你现在可以从DLL中重新获得函数。为了这样作,你必须使用函数GetProcAddress(),它将DLL的句柄(你可以使用HINSTANCE)和函数的名称作为参数。你可以让函数指针获得由GetProcAddress()返回的值,同时你必需将GetProcAddress()转换为那个函数定义的函数指针。举个例子,对于Add()函数,你必需将GetProcAddress()转换为AddFunc;这就是它知道参数及返回值的原因。现在,最好先确定函数指针是否等于NULL以及它们拥有DLL的函数。这只是一个简单的if语句;如果其中一个等于NULL,你必需如前所述释放库。

一旦函数指针拥有DLL的函数,你现在就可以使用它们了,但是这里有一个需要注意的地方:你不能使用函数的实际名称;你必需使用函数指针来调用它们。在那以后,所有你需要做的是释放库如此而已。

模块句柄

进程中的每个DLL模块被全局唯一的32字节的HINSTANCE句柄标识。进程自己还有一个HINSTANCE句柄。所有这些模块句柄都只有在特定的进程内部有效,它们代表了DLL或EXE模块在进程虚拟空间中的起始地址。在Win32中,HINSTANCE和HMODULE的值是相同的,这个两种类型可以替换使用。进程模块句柄几乎总是等于0x400000,而DLL模块的加载地址的缺省句柄是0x10000000。如果程序同时使用了几个DLL模块,每一个都会有不同的HINSTANCE值。这是因为在创建DLL文件时指定了不同的基地址,或者是因为加载程序对DLL代码进行了重定位。
模块句柄对于加载资源特别重要。Win32 的FindResource函数中带有一个HINSTANCE参数。EXE和DLL都有其自己的资源。如果应用程序需要来自于DLL的资源,就将此参数指定为DLL的模块句柄。如果需要EXE文件中包含的资源,就指定EXE的模块句柄。
但是在使用这些句柄之前存在一个问题,你怎样得到它们呢?如果需要得到EXE模块句柄,调用带有Null参数的Win32函数GetModuleHandle;如果需要DLL模块句柄,就调用以DLL文件名为参数的Win32函数GetModuleHandle。

应用程序怎样找到DLL文件

如果应用程序使用LoadLibrary显式链接,那么在这个函数的参数中可以指定DLL文件的完整路径。如果不指定路径,或是进行隐式链接,Windows将遵循下面的搜索顺序来定位DLL:
1. 包含EXE文件的目录,
2. 进程的当前工作目录,
3. Windows系统目录,
4. Windows目录,
5. 列在Path环境变量中的一系列目录。
这里有一个很容易发生错误的陷阱。如果你使用VC++进行项目开发,并且为DLL模块专门创建了一个项目,然后将生成的DLL文件拷贝到系统目录下,从应用程序中调用DLL模块。到目前为止,一切正常。接下来对DLL模块做了一些修改后重新生成了新的DLL文件,但你忘记将新的DLL文件拷贝到系统目录下。下一次当你运行应用程序时,它仍加载了老版本的DLL文件,这可要当心!

调试DLL程序

Microsoft 的VC++是开发和测试DLL的有效工具,只需从DLL项目中运行调试程序即可。当你第一次这样操作时,调试程序会向你询问EXE文件的路径。此后每次在调试程序中运行DLL时,调试程序会自动加载该EXE文件。然后该EXE文件用上面的搜索序列发现DLL文件,这意味着你必须设置Path环境变量让其包含DLL文件的磁盘路径,或者也可以将DLL文件拷贝到搜索序列中的目录路径下。
或者当你调试EXE程序时,在Project Setting中,将Debug选项卡中的Category设置为Additional DLLs。就可以同时调试EXE和它调用的DLL(当然,你需要有DLL的源代码)了。

DLL入门浅析(2)——如何使用DLL相关推荐

  1. DLL入门浅析(5)——使用DLL在进程间共享数据

    在Win16环境中,DLL的全局数据对每个载入它的进程来说都是相同的,因为所有的进程用的都收同一块地址空间:而在Win32环境中,情况却发生了变化,每个进程都有了它自己的地址空间,DLL函数中的代码所 ...

  2. DLL入门浅析(1)——如何建立DLL

    初学DLL,结合教程,总结一下自己的所得,希望对DLL初学者们有所帮助. 动态链接库(DLL)是从C语言函数库和Pascal库单元的概念发展而来的.所有的C语言标准库函数都存放在某一函数库中.在链接应 ...

  3. DLL入门浅析(4)——从DLL中导出类

    前面介绍了怎么从DLL中导出函数和变量,实际上导出类的方法也是大同小异,废话就不多说了,下面给个简单例子示范一下,也就不多做解释了. DLL头文件: #ifndef _DLL_SAMPLE_H #de ...

  4. DLL入门浅析(3)——从DLL中导出变量

    前面介绍了怎么从DLL中导出函数,下面我们来看一下如何从DLL中导出变量来. 声明为导出变量时,同样有两种方法:    第一种是用__declspec进行导出声明 #ifndef _DLL_SAMPL ...

  5. Windows动态链接库(dll)浅析 - 2

    Windows动态链接库(dll)浅析 - 2 Windows动态链接库(dll)浅析 - 1 Windows动态链接库(dll)浅析 - 3 5. DLL的编写 5.1 一个简单的dll项目 上面用 ...

  6. 在IIS7里配置 ISAPI,运行dll程序,总提示下载dll

    在IIS7里配置 ISAPI,运行dll程序,总提示下载dll,只需要把对应站点应用程序池里面的高级设置里的启用32位应用程序,设为"true"即可.

  7. C++ 调用lib 和 dll的 方法 及 动态库DLL与静态库lib的区别

    C++ 调用.lib的方法: 一: 隐式的加载时链接,有三种方法 1  LIB文件直接加入到工程文件列表中 在VC中打开File View一页,选中工程名,单击鼠标右键,然后选中"Add F ...

  8. pb调用c语言dll,PB调用C#编写的Dll类库

    在c# 中编写com组件,供PB调用实例 前言:c#中写的dll直接是不能被pb调用的,只有写成com组件才可以调用,所以用c#写dll时要注意. c#中新建类库 类库类型为通用类库,项目名为AddC ...

  9. c++ dll继续使用然后强制删除dll文件_Windows 10系统安全风险,近300个系统执行文件容易遭受劫持攻击...

    一个简单的VBScript足以让用户获得管理权限并完全绕过Windows 10上的UAC. 在普华永道英国安全研究人员Wietze Beukema的最新报告中,我们了解到将近300个Windows 1 ...

最新文章

  1. WeeklyBlogging_20100722
  2. 安卓 spinner下拉框 做模糊查询_如何用一张图来做全年/去年的部门离职率动态对比...
  3. 【PAT乙级】1045 快速排序 (25 分)
  4. 视觉盛宴篇!推荐 12 个好用的 CSS 的开源项目,YYDS !
  5. 第九十四期:GitHub 发布 2019 年年度报告
  6. BZOJ 2768 [JLOI2010]冠军调查
  7. (四)使用Jenkins工作流链接MLOps管道
  8. Quartz 2.x 任务调度使用(CronTrigger)
  9. Oracle 11g vs 12c 内存、优化器等默认参数对比
  10. 道路车辆 盲区监测(bsd)系统性能要求及试验方法_LKA、BSD国标出炉,狩猎和绞杀即将开始...
  11. HTTP长连接与短连接、长轮询与短轮询及长轮询的实现概述
  12. 两种方法,word文件转换成PDF文件
  13. 主流的工业以太网简介及比较(EPA , EtherCAT , Ethernet Powerlink , PROFINET, Ethernet/IP, SERCOS III)
  14. Pandoc 安装与使用
  15. 500~1000元价位有哪些新手入门吉他推荐?saga萨伽、VEAZEN费森和雅马哈这几个品牌怎么样?
  16. linux可以玩什么游戏_为什么我们要在Linux上玩游戏,与Icculus聊天等等
  17. 为什么打不开jar文件?
  18. DOM+CSS3实现小游戏SwingCopters
  19. AI Security3-通用漏洞披露(CVE: Common Vulnerabilities and Exposures)
  20. jflash烧录教程_使用J-Flash 对ARM烧录HEX程序

热门文章

  1. 数据库-左外连接-右外连接
  2. Request_获取请求参数通用方式演示
  3. 为什么说 Java 是按值传递的?
  4. Shiro使用redis作为缓存(解决shiro频繁访问Redis)
  5. 从构建分布式秒杀系统聊聊WebSocket推送通知
  6. ASP.NET Core MVC 模型绑定用法及原理
  7. SpringJdbc持久层封装,Spring jdbcTemplate封装,springJdbc泛型Dao,Spring baseDao封装
  8. 使用ToughMySQL为ToughRADIUS系统提供数据存储
  9. spring MVC 工作原理
  10. [转]深入理解G1垃圾收集器