GetModuleHandle与包含头之间的区别

时间:2010-08-16 13:02:52

标签: c++ c winapi

也许是愚蠢的问题,但我不知道答案。使用GetModuleHandle或LoadLibrary加载DLL(然后使用该DLL的功能)并直接包含所需的标头有什么区别。例如,使用GetModuleHandle:

typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO);

// Call GetNativeSystemInfo if supported or GetSystemInfo otherwise.

PGNSI pGNSI;
SYSTEM_INFO si;

ZeroMemory(&si, sizeof(SYSTEM_INFO));

pGNSI = (PGNSI) GetProcAddress(
  GetModuleHandle(TEXT("kernel32.dll")), 
  "GetNativeSystemInfo");
if(NULL != pGNSI)
  pGNSI(&si);  //calling function through pointer
else GetSystemInfo(&si);

但我可以包含windows.h标头直接从我的代码中调用该函数:

#include <windows.h>

SYSTEM_INFO si;
ZeroMemory(&si, sizeof(SYSTEM_INFO));
GetNativeSystemInfo(&si);

这同样适用于opengl32.dll,我不知道在我的项目中包含opengl函数的头文件或者使用Getmodulehandle和GetProcAdress来调用所需的函数是否更好。有什么不同?第一种方法是以某种方式使用getmodulehandle的好处吗?谢谢你的回答。

5 个答案:

答案 0 :(得分:6)

首先,请确保您了解GetModuleHandleLoadLibrary并不完全等效。但由于这不是你问题的直接部分,我将给出一个重要的解释,并建议你确保理解这两个链接中的文档。


要直接使用dll函数,就像它与任何其他函数一样,您不只是包含标题。除了标题之外,在项目的某个地方,它被告知要链接到相应的lib文件。在您的示例中,它将是kernel32.lib。这可以通过各种方式完成,例如项目中的链接器设置或文件中有#pragma comment (lib, ...)

当程序像这样构建时,编译器会编写代码以在程序启动时加载该DLL。如果在实际尝试运行程序时找不到有问题的DLL,则它将失败并显示错误消息。您无法编写代码来捕获失败并采取其他替代操作。

对于属于操作系统的dll(如kernel32.dll)或至少通常提供的dll,这种立即加载行为不是问题,因为您可以安全地假设dll将始终存在。另一方面,如果你要构建一个通常不存在的dll,那么你会有更多的担忧。要么你必须确保这样的dll与你的程序一起分发,要么以某种方式尝试确保用户安装其他任何必要的软件包以在他们的系统上获得该dll。

此外,如果dll加载但是你试图从该dll中使用的任何函数实际上都不存在,那么它将立即失败并显示错误消息。 (它不会等到你的程序试图调用该函数。它会在程序启动时发现这种差异然后中止。)如果世界上存在不同版本的dll,这可能是一个问题。

现在,当您使用LoadLibrary / GetProcAddress时,您要求在您选择时加载dll并要求查找该dll提供的特定函数。如果其中任何一个步骤失败,您就可以编写代码以合理的方式处理它。

这可用于各种目的。例如,您可以创建一个插件机制,程序在其中搜索并动态从某个特定文件夹加载插件dll。由于程序不知道哪个插件会出现,LoadLibrary是唯一的方法。

LoadLibrary / GetProcAddress可以使用的另一件事是加载一个DLL并从中调用一个函数,即使你没有正确的头文件和lib文件。如果您知道dll的名称,函数的名称以及函数的确切签名(参数类型,返回类型,调用约定),那么您就足以编写代码来加载该DLL并成功调用该函数。偶尔这可能很有用。例如,这是人们能够使用Windows dll提供的某些“未记录的”功能的一种方式。

最后,LoadLibrary / GetModuleHandle / GetProcAddress可用于让您使用不一定存在于您要支持的所有操作系统上的功能。这似乎是您调用GetNativeSystemInfoGetSystemInfo的代码段的原因。前者仅在WinXP / 2003上可用,而后者在Win2000上可用。如果代码刚刚被编写为对GetNativeSystemInfo的直接调用,那么程序将无法在Windows 2000上运行。但是,你在那里检查当前操作系统上是否存在GetNativeSystemInfo,如果是,则仅使用它,否则它会回到更广泛支持的GetSystemInfo。

因此,对于您的示例,您选择调用该函数的技术取决于您打算支持的操作系统。如果你的软件不需要在Windows 2000上运行,那么只需直接调用GetNativeSystemInfo就容易多了(而且很可能是最好的方法)。

答案 1 :(得分:4)

旧版Windows中不存在某些功能,当您直接调用函数时,该函数最终会出现在程序的导入表中。如果Windows无法在导入表中找到其中一个函数,则该程序根本不会运行。

在您的具体示例中,在Windows XP中添加了GetNativeSystemInfo,如果您直接调用它,那么您的程序将无法在Windows 2000或更早版本上运行。

如果您想支持第三方插件等,

LoadLibrary也很有用。

答案 2 :(得分:1)

GetModuleHandle使您可以动态加载dll,例如可用于实现插件或按需加载某些资源。 在下面,两个方法之间没有区别 - 你链接的静态库只包含在程序启动时进行动态链接的代码(在C中)。

答案 3 :(得分:1)

这取决于,在这种情况下,我会说它被使用,以便如果系统(kernel32.dll等)没有二进制<的导出,dll / exe将不会从Windows LDR加载错误strong>可能使用,onr的一个很好的例子是Windows XP的DEP功能,它只存在于SP 2+中,但强制所需的SP不是一个好主意,因为它可以减少可用性该计划的观众。 OpenGL使用相同的sorta原则,因为无法预测API支持(和扩展),因此必须检查它,然后导入它或使用wglGetProcAddress的替代

另一个更“便宜”的原因是,人们不必链接到某些库并包含某些标题,特别是如果你使用的只是一个非常大的SDK中的1个函数,这可以防止其他开发人员浪费获得巨大SDK的时间(他们将需要二进制文件来输出)

答案 4 :(得分:0)

LoadLibraryGetModulehandle两者都适用于相同的东西,即;他们会在运行时将模块映射到进程,但是在LoadLibrary的情况下,它会增加内核透视图中的引用计数,而后者则不会这样做。