首页 > 系统相关 >windows DLL技术-可执行文件的链接

windows DLL技术-可执行文件的链接

时间:2024-10-28 23:16:28浏览次数:6  
标签:可执行文件 调用 windows DLL 显式 链接 加载

可执行文件通过以下两种方式之一链接到(或加载)DLL:

  • 隐式链接,其中操作系统会与使用 DLL 的可执行文件同时加载它。 客户端可执行文件调用 DLL 的导出函数的方式与函数进行静态链接并包含在可执行文件中时的方式相同。 隐式链接有时称为静态加载或加载时动态链接;

  • 显式链接,其中操作系统会在运行时按需加载 DLL。 通过显式链接使用 DLL 的可执行文件必须显式加载和卸载 DLL。 它还必须设置函数指针,用于访问它从 DLL 使用的每个函数。 与静态链接的库或隐式链接 DLL 中的函数调用不同,客户端可执行文件必须通过函数指针调用显式链接 DLL 中的导出函数。 显式链接有时称为动态加载或运行时动态链接;

可执行文件可以使用任一链接方法链接到同一个 DLL。 而且,这些方法并不相互排斥;一个可执行文件可以隐式链接到 DLL,另一个可执行文件可以显式附加到它。

隐式链接

当应用程序的代码调用导出 DLL 函数时,会进行隐式链接。 当编译或汇编调用可执行文件的源代码时,DLL 函数调用会在对象代码中生成外部函数引用。 若要解析此外部引用,应用程序必须与 DLL 创建者提供的导入库(.lib 文件)链接。

导入库包含的代码仅用于加载 DLL 和实现对 DLL 中函数的调用。 在导入库中查找外部函数会告知链接器该函数的代码处于 DLL 中。 若要解析对 DLL 的外部引用,链接器只需将信息添加到可执行文件,告知系统在进程启动时查找 DLL 代码的位置。

当系统启动包含动态链接引用的程序时,它将使用该程序可执行文件中的信息查找所需 DLL。 如果找不到 DLL,则系统将终止进程,并显示报告错误的对话框。 否则,系统会将 DLL 模块映射到进程地址空间中。

如果任何 DLL 的初始化和终止代码(如 DllMain)有入口点函数,则操作系统将调用该函数。 传递给入口点函数的一个参数指定用于指示 DLL 附加到进程的代码。 如果入口点函数不返回 TRUE,则系统将终止进程并报告错误。

最后,系统会修改进程的可执行代码以提供 DLL 函数的起始地址。

与程序代码的其余部分一样,在进程启动时,加载程序会将 DLL 代码映射到进程的地址空间中。 操作系统仅在需要时才将它加载到内存中。 因此,.def 文件在以前 Windows 版本中用于控制加载的 PRELOAD 和 LOADONCALL 代码特性不再有意义。

显式链接

大多数应用程序使用隐式链接,因为这是可使用的最简单链接方法。 但是,有时需要显式链接。 下面是使用显式链接的一些常见原因:

  • 应用程序直到运行时才知道它所加载的 DLL 的名称。 例如,应用程序可能会在启动时从配置文件获取 DLL 的名称和导出函数;
  • 如果在使用隐式链接的进程启动时找不到 DLL,则操作系统会终止进程。 使用显式链接的进程在这种情况下不会终止,可以尝试从错误中恢复。 例如,进程可以向用户通知错误,并让用户指定 DLL 的其他路径;
  • 如果使用隐式链接的进程所链接到的任何 DLL 的 DllMain 函数失败,则进程也会终止。 使用显式链接的进程在这种情况下不会终止;
  • 隐式链接到许多 DLL 的应用程序可能会速度较慢,因为 Windows 会在应用程序加载时加载所有 DLL。 若要提高启动性能,应用程序可以只对在加载之后立即需要的 DLL 使用隐式链接。 它可以仅在需要时才使用显式链接加载其他 DLL;
  • 显式链接无需使用导入库链接应用程序。 如果 DLL 中的更改导致导出序号发生更改,则在使用函数名称而不是序号值调用 GetProcAddress 时,应用程序无需重新链接。 使用隐式链接的应用程序仍必须重新链接到更改的导入库;

下面是需要注意的显式链接方面的两个风险:

  • 如果 DLL 具有 DllMain 入口点函数,则操作系统会在调用 LoadLibrary 的线程的上下文中调用该函数。 如果 DLL 已附加到进程,则不会调用入口点函数,因为以前调用的 LoadLibrary 没有对 FreeLibrary 函数进行相应调用。 如果 DLL 使用 DllMain 函数初始化进程的每个线程,则显式链接可能会导致问题,因为调用 LoadLibrary(或 AfxLoadLibrary)时已存在的任何线程都不会进行初始化;
  • 如果 DLL 将静态范围数据声明为 __declspec(thread),则可能会在进行显式链接时导致保护错误。 在通过调用 LoadLibrary 加载 DLL 之后,每当代码引用此数据,便会导致保护错误。静态范围数据包含全局和局部静态项。这就是为什么在创建 DLL 时,应避免使用线程本地存储。 如果不能这样做,请向 DLL 用户告知动态加载 DLL 的潜在陷阱;
如何使用隐式链接

若要通过隐式链接使用 DLL,客户端可执行文件必须从 DLL 的提供程序获取以下文件:

  • 一个或多个头文件(.h 文件_,其中包含 DLL 中的导出数据、函数和 C++ 类的声明。 DLL 导出的类、函数和数据全都必须在头文件中标记为 __declspec(dllimport); 
  • 要链接到可执行文件中的导入库。 生成 DLL 时,链接器会创建导入库;
  • 实际 DLL 文件;

若要通过隐式链接使用 DLL 中的数据、函数和类,任何客户端源文件都必须包含声明它们的头文件。 从编码的角度来看,对导出函数的调用与任何其他函数调用一样。

若要生成客户端可执行文件,必须与 DLL 的导入库链接。 如果使用外部生成文件或生成系统,请将导入库与链接的其他对象文件或库一起指定。

当操作系统加载调用可执行文件时,它必须能够找到 DLL 文件。 这意味着必须在安装应用程序时部署 DLL 或验证 DLL 是否存在。

如何显式链接到 DLL

若要通过显式链接使用 DLL,应用程序必须在运行时进行函数调用以显式加载 DLL。 若要显式链接到 DLL,应用程序必须:

调用 LoadLibraryEx 或类似函数以加载 DLL 并获取模块句柄。

调用 GetProcAddress 以获取应用程序调用的每个导出函数的函数指针。 由于应用程序通过指针调用 DLL 函数,因此编译器不生成外部引用,从而不需要与导入库链接。 不过,必须有 typedef 或 using 语句,此语句定义你调用的已导出函数的调用签名。

处理完 DLL 时,调用 FreeLibrary。

例如,此示例函数调用 LoadLibrary 以加载名为“MyDLL”的 DLL,调用 GetProcAddress 以获取指向名为“DLLFunc1”的函数的指针,调用该函数并保存结果,然后调用 FreeLibrary 以卸载 DLL。

#include "windows.h"

typedef HRESULT (CALLBACK* LPFNDLLFUNC1)(DWORD,UINT*);

HRESULT LoadAndCallSomeFunction(DWORD dwParam1, UINT * puParam2)
{
    HINSTANCE hDLL;               // Handle to DLL
    LPFNDLLFUNC1 lpfnDllFunc1;    // Function pointer
    HRESULT hrReturnVal;

    hDLL = LoadLibrary("MyDLL");
    if (NULL != hDLL)
    {
        lpfnDllFunc1 = (LPFNDLLFUNC1)GetProcAddress(hDLL, "DLLFunc1");
        if (NULL != lpfnDllFunc1)
        {
            // call the function
            hrReturnVal = lpfnDllFunc1(dwParam1, puParam2);
        }
        else
        {
            // report the error
            hrReturnVal = ERROR_DELAY_LOAD_FAILED;
        }
        FreeLibrary(hDLL);
    }
    else
    {
        hrReturnVal = ERROR_DELAY_LOAD_FAILED;
    }
    return hrReturnVal;
}

标签:可执行文件,调用,windows,DLL,显式,链接,加载
From: https://blog.csdn.net/m0_72813396/article/details/143316216

相关文章

  • MaskGCT,AI语音克隆大模型本地部署(Windows11),基于Python3.11,TTS,文字转语音
    前几天,又一款非自回归的文字转语音的AI模型:MaskGCT,开放了源码,和同样非自回归的F5-TTS模型一样,MaskGCT模型也是基于10万小时数据集Emilia训练而来的,精通中英日韩法德6种语言的跨语种合成。数据集Emilia是全球最大且最为多样的高质量多语种语音数据集之一。本次分享一下如何在本地......
  • 边境游戏遭遇d3dx9_43.dll缺失危机?揭秘边境游戏d3dx9_43.dll缺失的真正原因与解决方案
    当你在享受《边境》这款游戏的精彩内容时,突然弹出一个错误提示:“d3dx9_43.dll缺失”。这个提示可能会让你感到困惑和沮丧,但不必过于担心,本文将为你揭秘d3dx9_43.dll缺失的真正原因,并提供有效的解决方案。d3dx9_43.dll文件的重要性d3dx9_43.dll是DirectX9的一个关键组件,是Wi......
  • vba6.dll缺失怎么办?解决vba6.dll缺失问题详细修复步骤
    在使用MicrosoftOffice或相关应用程序时,有时可能会遇到“vba6.dll缺失”的错误提示。这个动态链接库(DLL)文件对于VisualBasicforApplications(VBA)的运行至关重要,一旦缺失或损坏,可能会导致Office应用程序无法正常工作,甚至无法启动VBA代码。本文将为你提供详细的修复步骤,帮助你......
  • gdpfile.dll文件丢失/损坏?应对gdpfile.dll缺失或损坏的全面解决方案
    gdpfile.dll文件丢失或损坏是一个常见的问题,可能会影响到相关应用程序的正常运行。以下是一套全面的解决方案,旨在帮助用户解决gdpfile.dll文件缺失或损坏的困扰:一、初步检查与重启检查错误消息:当应用程序报告gdpfile.dll文件丢失或损坏时,请仔细阅读错误消息,以获取更多关......
  • 《Dead Cide Club死神俱乐部》报错大揭秘:innocallback.dll文件丢失的解决办法
    对于热爱《DeadCideClub死神俱乐部》这款游戏的玩家来说,遇到游戏报错,特别是提示“innocallback.dll文件丢失”时,无疑是一件令人沮丧的事情。然而,不必过于担心,本文将为你揭秘这一问题的原因,并提供详细的解决办法,帮助你迅速恢复游戏的正常运行。一、了解innocallback.dll文件......
  • d3dx9_43.dll缺失导致小小世界Smalland无法启动?小小世界Smalland玩家必看d3dx9_43.dll
    当d3dx9_43.dll文件缺失导致小小世界Smalland无法启动时,作为玩家,你可以采取以下紧急应对措施来解决这一问题:一、了解d3dx9_43.dll文件的重要性d3dx9_43.dll是DirectX9.0c的一个重要组件,它负责为基于DirectX技术的游戏和应用程序提供图形和声音效果的支持。如果该文件缺失或......
  • 如何在Windows 10/11中轻松实现PDF到Word的
    PDF到Word的转换在工作场所是常见需求。编辑Word文档比PDF更加方便,因为PDF是只读文件。如果你希望在与他人共享之前对文档进行一些修改,选择Word文档会更合适。本文将介绍如何在Windows10/11中将PDF转换为Word的可行方法。请继续阅读。第1部分:有关如何在W......
  • 《聆听音乐》上传资源提示DLL文件丢失:修复步骤与技巧详解
    当您在尝试使用“聆听音乐”(或其他类似的应用程序)上传资源时遇到丢失DLL文件的问题,这通常意味着应用程序缺少了运行所必需的某些系统文件。解决这类问题的一般步骤如下:确认错误信息:首先,请仔细阅读错误提示中的具体信息,了解是哪个具体的DLL文件丢失或损坏。安装DLL修复工具:......
  • 《星速磁力》软件下载电影时DLL文件找不到?简单几步帮你解决
    当星速磁力bt下载资源时提示丢失DLL文件,可以通过以下几种方法解决:重新安装星速磁力软件:卸载现有程序:通过控制面板的“程序和功能”选项彻底卸载现有的星速磁力软件。在卸载过程中,注意勾选“删除相关配置文件”等选项,以确保卸载干净。清理残留文件:卸载完成后,手动删......
  • 《超级幻影猫:光痕》游戏启动时DLL文件丢失?简单几步帮你解决
    当《超级幻影猫:光痕》游戏启动时出现黑屏并提示丢失DLL文件,这通常意味着游戏运行所必需的某个动态链接库文件缺失或损坏。以下是一些可能的解决方法:1.重新安装游戏卸载当前的游戏。从官方商店(如AppStore、GooglePlay或者其他平台)下载最新版本的游戏。确保在安装过程中......