[笔记]Windows核心编程《十九》DLL基础(一)

简介: [笔记]Windows核心编程《十九》DLL基础

前言

常用DLL

Windows API中的所有函数都包含在 D L L中。3个最重要的 D L L是:

  • Kernel32.dll:它包含用于管理内存、进程和线程的各个函数;
  • User32.dll:它包含用于执行用户界面任务(如窗口的创建和消息的传送)的各个函数;
  • GDI32.dll,它包含用于画图和显示文本的各个函数。

其他:

  • AdvAPI32. dll 包含用于实现对象安全性、注册表操作和事件记录的函数;
  • ComDlg32.dll 包含常用对话框(如File Open和File Save);
  • ComCtl32.dll 则支持所有的常用窗口控件。

使用DLL的一些原因

优点:

  • 它们扩展了应用程序的特性。 由于 DLL能够动态地装入进程的地址空间,因此应用程序能够在运行时确定需要执行什么操作,然后装入相应的代码,以便根据需要执行这些操作。
  • 它们可以用许多种编程语言来编写。 可以选择手头拥有的最好的语言来编写 D L L。系统允许Visual Basic程序加载C++ DLL、Cobol DLL和Fortran DLL等。
  • 它们简化了软件项目的管理。 项目小组分工可以使用DLL,项目管理会容易一些。但是过多的DLL会使程序加载时间过长。
  • 它们有助于节省内存。 如果两个或多个应用程序使用同一个 D L L,那么该D L L的页面只要放入R A M一次,所有的应用程序都可以共享它的各个页面。 C/C++运行期库就是个极好的例子。许多应用程序都使用这个库。如果所有的应用程序都链接到这个静态库,那么sprintf、strcpy和malloc等函数的代码就要多次存在于内存中。但是,如果所有这些应用程序链接到DLL C/C++运行期库,那么这些函数的代码就只需要放入内存一次,这意味着内存的使用将更加有效。
  • 它们有助于资源的共享。 DLL可以包含对话框模板、字符串、图标和位图等资源。多个应用程序能够使用DLL来共享这些资源。
  • 它们有助于应用程序的本地化。 应用程序常常使用 D L L对自己进行本地化。例如,只包含代码而不包含用户界面组件的应用程序可以加载包含本地化用户界面组件的 D L L。
  • 它们有助于解决平台差异。 它们有助于解决平台差异。不同版本的 Wi d n o w s配有不同的函数。开发人员常常想要调用新的函数(如果它们存在于主机的 Wi n d o w s版本上的话)。但是,如果你的源代码包含了对一个新函数的调用,而你的应用程序将要在不能提供该函数的 Wi n d o w s版本上运行,那么操作系统的加载程序将拒绝运行你的进程。即使你实际上从不调用该函数,情况也是这样。如果将这些新函数保存在 D L L中,那么应用程序就能够将它们加载到 Windows的老版本上。当然,你仍然可以成功地调用该函数。
  • 它们可以用于一些特殊的目的。 Wi n d o w s使得某些特性只能为 D L L所用。例如,只有当D L L中包含某个挂钩通知函数的时候,才能安装某些挂钩(使用 SetWindowsHookEx和SetWinEventHook来进行安装)。可以通过创建必须在DLL中生存的COM对象来扩展Windows Explorer的外壳程序。对于可以由We b浏览器加载的、用于创建内容丰富的 Web页的ActiveX控件来说,情况也是一样.

缺点:

  • 过多的DLL会使程序加载时间过长。

一、DLL与进程的地址空间

DLL特点:

  • DLL仅包含一组应用程序可以使用的自主函数。在DLL中通常没有用来处理消息循环或创建窗口的支持代码。

应用程序(或另一个D L L)能够调用D L L中的函数条件:

  • DLL文件 映像必须被映射到调用进程的地址空间中。

D L L映射到调用进程的地址空间的方式:

  • 加载时的隐含链接
  • 运行期的显式链接

DLL文件映射完后,就会像在进程的地址空间中的额外代码和数据一样:

  1. DLL函数查看线程堆栈,检索所传递的参数。
  2. 使用线程的堆栈初始化DLL函数需要的局部变量

注意:

  • exe加载dll时也会加载dll的全局变量和静态变量的实例 到静态区

关于跨DLL释放 解释

单个地址空间是由一个可执行模块和若干个 D L L模块组成的。

一般三种情况的模块:

  • 链接到静态版本的 C/C++运行期库的模块
  • 链接到一个DLL版本的 C/C++ 运行期库的模块
  • 不需要C/C++运行期库的模块

静态运行时库(MT): 编译时会包含一些C/C++运行时库,但是使用多个模块的大型软件来说,如果每个模块均选择静态链接C或C++运行库,程序运行时就会存在多个运行库。在链接时也会出现重复定义的问题。

动态运行时库 (MD): 程序在运行时动态的加载对应的DLL。程序体积变小,但一个很大的问题就是一旦找不到对应DLL,程序将无法运行(比如所要移植的电脑没有安装VC++)。

假设使用VC6.0并选择使用MD选项构建,那么当用户使用VC2005来使用这个DLL时很可能出现找不到MSVCRT.DLL或MSVCP60.DLL的情况。

终于理解了什么是c/c++运行时库,以及libcmt msvcrt等内容

请看下面的代码:

vOID EXEFunc( ) 
{
  PvOID pv = DLLFunc( );
  //Access the storage pointed to by pv. ..
  //Assumes that pv is in EXE's C/C++ run-time heap
  free(pv) ;
}
PVOID DLLFunc( ) 
{
  //A11ocate block from DLL's C/C++ run-time heap
  return(ma11oc(100 ));
}
  • 上面这个代码能够正确运行吗?
  • D L L函数分配的内存块是由EXE的函数释放的吗?

两种可能:

  • 如果EXE和DLL都链接到DLL的C/C++运行期库(MD),那么上面的代码将能够很好地运行。
  • 但是,如果两个模块中的一个或者两个都链接到静态C/C + +运行期库(MT),那么对free函数的调用就会失败。

解决方案就是:

当一个模块提供一个用于分配内存块的函数时,该模块也必须提供释放内存的函数。(谁申请内存 谁就去释放内存)、

VOID EXEFunc( ) 
{
  PVOID pv = DLLFunc( ) ;
  //Access the storage pointed to by pv.. .
  //Makes no assumptions about C/C++ run-time heap
  DLLFreeFunc(pv);
}
PVOID DLLFunc( )
{
  //A11ocate b1ock from DLL's C/C++ run-time heap
  PVOID pv = ma11oc(100) ;
  return(pv);
}
B00L DLLFreeFunc( PVOID pv) 
{
 //Free block from DLL's C/C++ run-time heap
 return( free(pv ) );
)

这个代码是正确的,它始终都能正确地运行。

当你编写一个模块时,不要忘记其他模块中的函数也许没有使用C/C + +来编写,因此可能无法使用malloc和free函数进行内存的分配。

二、 DLL的总体运行情况

本节重点介绍可执行模块和 DLL模块之间是如何隐含地互相链接。

当一个模块(比如一个可执行文件)使用DLL中的函数或变量时,将有若干个文件和组件参与发挥作用。如下图:

创造DLL:

1)建立带有输出原型/结构/符号的头文件。

2)建立实现输出函数/变量的C/C++源文件。

3)编译器为每个C/C++源文件生成 .obj模块 。

4)链接程序将生成DLL的 .obj模块链接起来

5)如果至少输出一个函数/变量,那么链接程序也生成lib 文件。

创造EXE:

6) 建立带有输入原型/结构/符号的头文件。

7) 建立引用输入函数/变量的C/C++源文件。

8) 编译器为每个C/C++源文件生成 .obj源文件。

9) 链接程序将各个 .obj模块链接起来,产生一个 .exe文件(它包含了所需要DLL模块的名字和输入符号的列表)。

运行应用程序:

10) 加载程序为 .exe 创建地址空间。

11) 加载程序将需要的DLL加载到地址空间中进程的主线程开始执行;应用程序启动运行。

几个文件解释

.h文件:一般是函数的声明,或者记录要导出函数的文件。

.cpp文件:一般就是函数的实现,一般不导出,只用于生成.obj文件。

.obj文件:cpp文件的编译后的产物。

.lib:列出所有已输出函数和变量的符号名。

.dll:记录函数的实现。

.exe :

  • 执行文件的所有二进制代码和全局/静态变量。
  • 输入节,列出可执行文件需要的所有DLL模块名以及所引用的函数和变量符号。

简单的来说就是编译链接运行的过程:

  1. 编译:把cpp编译成.obj。
  2. 链接:就是链接所有.obj到一个文件(dll/exe)中。
  3. 运行:为exe创建地址空间,加载dll到地址空间执行。


相关文章
|
6月前
|
XML C# 数据格式
掌握了在Windows平台上查看DLL依赖的方法
掌握了在Windows平台上查看DLL依赖的方法
843 4
|
6月前
|
监控 Ubuntu Linux
视频监控笔记(五):Ubuntu和windows时区同步问题-your clock is behind
这篇文章介绍了如何在Ubuntu和Windows系统中通过设置相同的时区并使用ntp服务来解决时间同步问题。
152 4
视频监控笔记(五):Ubuntu和windows时区同步问题-your clock is behind
|
7月前
|
网络协议 API Windows
MASM32编程调用 API函数RtlIpv6AddressToString,windows 10 容易,Windows 7 折腾
MASM32编程调用 API函数RtlIpv6AddressToString,windows 10 容易,Windows 7 折腾
|
7月前
|
Windows
[原创]用MASM32编程获取windows类型
[原创]用MASM32编程获取windows类型
|
7月前
|
JavaScript 前端开发 API
MASM32编程通过WMI获取Windows计划任务
MASM32编程通过WMI获取Windows计划任务
|
7月前
|
API Windows
MASM32编程获取Windows当前桌面主题名
MASM32编程获取Windows当前桌面主题名
|
8月前
|
数据库 Windows
超详细步骤解析:从零开始,手把手教你使用 Visual Studio 打造你的第一个 Windows Forms 应用程序,菜鸟也能轻松上手的编程入门指南来了!
【8月更文挑战第31天】创建你的第一个Windows Forms (WinForms) 应用程序是一个激动人心的过程,尤其适合编程新手。本指南将带你逐步完成一个简单WinForms 应用的开发。首先,在Visual Studio 中创建一个“Windows Forms App (.NET)”项目,命名为“我的第一个WinForms 应用”。接着,在空白窗体中添加一个按钮和一个标签控件,并设置按钮文本为“点击我”。然后,为按钮添加点击事件处理程序`button1_Click`,实现点击按钮后更新标签文本为“你好,你刚刚点击了按钮!”。
783 0
|
Windows 数据安全/隐私保护 网络协议
|
1月前
|
Unix 虚拟化 Windows
Windows Server 2025 中文版、英文版下载 (2025 年 3 月更新)
Windows Server 2025 中文版、英文版下载 (2025 年 3 月更新)
103 4
Windows Server 2025 中文版、英文版下载 (2025 年 3 月更新)
|
1月前
|
安全 数据安全/隐私保护 虚拟化
Windows Server 2022 中文版、英文版下载 (2025 年 3 月更新)
Windows Server 2022 中文版、英文版下载 (2025 年 3 月更新)
96 4
Windows Server 2022 中文版、英文版下载 (2025 年 3 月更新)
下一篇
oss创建bucket