[笔记]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到地址空间执行。


相关文章
|
21天前
|
编解码 5G Linux
FFmpeg开发笔记(二十一)Windows环境给FFmpeg集成AVS3解码器
AVS3是中国首个8K及5G视频编码标准,相比AVS2和HEVC性能提升约30%。解码器libuavs3d支持8K/60P视频实时解码,兼容多种平台。《FFmpeg开发实战》书中介绍了在Windows环境下如何集成libuavs3d到FFmpeg。集成步骤包括下载源码、使用Visual Studio 2022编译、调整配置、安装库文件和头文件,以及重新配置和编译FFmpeg以启用libuavs3d。
36 0
FFmpeg开发笔记(二十一)Windows环境给FFmpeg集成AVS3解码器
|
1月前
|
算法 Linux Windows
FFmpeg开发笔记(十七)Windows环境给FFmpeg集成字幕库libass
在Windows环境下为FFmpeg集成字幕渲染库libass涉及多个步骤,包括安装freetype、libxml2、gperf、fontconfig、fribidi、harfbuzz和libass。每个库的安装都需要下载源码、配置、编译和安装,并更新PKG_CONFIG_PATH环境变量。最后,重新配置并编译FFmpeg以启用libass及相关依赖。完成上述步骤后,通过`ffmpeg -version`确认libass已成功集成。
41 1
FFmpeg开发笔记(十七)Windows环境给FFmpeg集成字幕库libass
|
1月前
|
编解码 Linux Windows
FFmpeg开发笔记(十三)Windows环境给FFmpeg集成libopus和libvpx
本文档介绍了在Windows环境下如何为FFmpeg集成libopus和libvpx库。首先,详细阐述了安装libopus的步骤,包括下载源码、配置、编译和安装,并更新环境变量。接着,同样详细说明了libvpx的安装过程,注意需启用--enable-pic选项以避免编译错误。最后,介绍了重新配置并编译FFmpeg以启用这两个库,通过`ffmpeg -version`检查是否成功集成。整个过程参照了《FFmpeg开发实战:从零基础到短视频上线》一书的相关章节。
51 0
FFmpeg开发笔记(十三)Windows环境给FFmpeg集成libopus和libvpx
|
1月前
|
Rust 前端开发 Windows
blog-engine-06-pelican 静态网站生成 windows11 安装实战笔记
这篇内容是一个关于在Windows 11上安装和使用静态网站生成器的教程,主要包括对多个博客引擎(如Jekyll、Hugo、Hexo等)的简介和对比,以及详细步骤教你如何在Windows环境下安装Python、Pelican、Rust和Cargo。作者首先介绍了Python和Pelican的安装,然后在遇到依赖问题时,引导读者安装Rust和Cargo来解决。最后,通过`pelican-quickstart`创建项目,编写Markdown文章并生成、预览站点。
|
1月前
|
编解码 Linux Windows
FFmpeg开发笔记(十一)Windows环境给FFmpeg集成vorbis和amr
在Windows环境下,为FFmpeg集成音频编解码库,包括libogg、libvorbis和opencore-amr,涉及下载源码、配置、编译和安装步骤。首先,安装libogg,通过配置、make和make install命令完成,并更新PKG_CONFIG_PATH。接着,安装libvorbis,同样配置、编译和安装,并修改pkgconfig文件。之后,安装opencore-amr。最后,重新配置并编译FFmpeg,启用ogg和amr支持,通过ffmpeg -version检查是否成功。整个过程需确保环境变量设置正确,并根据路径添加相应库。
41 1
FFmpeg开发笔记(十一)Windows环境给FFmpeg集成vorbis和amr
|
1月前
|
API C++ Windows
windows编程入门_链接错误的配置
windows编程入门_链接错误的配置
22 0
|
1月前
|
机器学习/深度学习 安全 数据安全/隐私保护
Windows系统安装Jupyter Notebook并实现公网访问内网笔记服务
Windows系统安装Jupyter Notebook并实现公网访问内网笔记服务
|
1月前
|
Linux 编译器 C语言
FFmpeg开发笔记(二)搭建Windows系统的开发环境
在Windows上学习FFmpeg通常较困难,但通过安装预编译的FFmpeg开发包可以简化流程。首先需要安装MSYS2来模拟Linux环境。下载并执行MSYS2安装包,然后修改msys2_shell.cmd以继承Windows的Path变量。使用pacman安装必要的编译工具。接着,下载预编译的FFmpeg Windows包,解压并配置系统Path。最后,在MSYS2环境中运行`ffmpeg -version`确认安装成功。欲深入学习FFmpeg开发,推荐阅读《FFmpeg开发实战:从零基础到短视频上线》。
48 4
FFmpeg开发笔记(二)搭建Windows系统的开发环境
|
1月前
|
Windows
火山中文编程 -- 第一个windows程序
火山中文编程 -- 第一个windows程序
17 0
|
Windows 数据安全/隐私保护 网络协议