文章目录


前言

常用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++运行库,程序运行时就会存在多个运行库。在链接时也会出现重复定义的问题。
[笔记]Windows核心编程《十九》DLL基础_microsoft
动态运行时库 (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++运行期库,那么上面的代码将能够很好地运行。
  • 但是,如果两个模块中的一个或者两个都链接到静态C/C + +运行期库,那么对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的总体运行情况

三、 创建D L L模块

3.1 输出的真正含义是什么

3.2 创建用于非Visual C++工具的D L L

四、创建可执行模块

五、运行可执行模块

总结

1.为什么静态C/C++ 运行时库(MT)被其他模块释放内存 不会报错?