2010-08-16 28 views
1

也许是个愚蠢的问题,但我不知道答案。使用GetModuleHandle或LoadLibrary加载dll(然后使用该dll的函数)并直接包含所需的标题有什么区别?例如,使用的GetModuleHandle: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好处的第一种方法?感谢您的回答。

+0

GetNativeSystemInfo()是特殊的,它不可用在早期版本的Windows中。你真的应该使用GetProcAddress。这不适用于opengl。 – 2010-08-16 14:29:53

+0

GetNativeSystemInfo()只是一个例子,但正如我现在看到的,这是一个很好的例子,现在我明白了,谢谢 – sanjuro 2010-08-17 14:13:26

回答

6

首先,确保你明白,GetModuleHandleLoadLibrary不完全等同

调用LoadLibrary也很有用。但是,由于这不是你问题的直接部分,所以我会留下一个大的解释,并建议你确保理解这两个链接中的文档。


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

当一个程序是这样构建的时,编译器编写代码来在程序启动时加载该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就容易多了(最有可能的是最好的方法)。

+0

thx为您详尽的解释 – sanjuro 2010-08-17 14:10:52

1

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

+0

当我包含头文件和可选的#pragma注释(lib,“opengl32.lib”)我指定库它意味着我静态链接? – sanjuro 2010-08-16 13:19:03

+0

不,(lib,)只是显示链接器在哪里查找库;的确我不认为将dll链接为静态库是可能的。 – mbq 2010-08-16 13:26:23

+0

@san:有区别,当你连接到opengl32.lib时不需要使用GetProcAddress。这真的是你想要的,在opengl上使用GPA会非常痛苦。不必要的。 – 2010-08-16 14:28:34

1

这取决于,在这种情况下,我会说它正在使用,以便dll/exe不会从窗口LDR加载错误,如果系统(kernel32.dll等)没有导出的二进制文件可能使用,onr很好的例子是Windows XP的DEP功能,它只存在于SP 2+中,但它不是一个强制强制所需SP的好主意,因为它可以减少程序的可用观众。 OpenGL的使用相同的几分原理,由于这一事实,一个不能预测的API支持(和扩展),因此必须检查它,然后将其导入或与wglGetProcAddress

另一个原因,这是更可替代'廉价'是这样的,人们不必链接到某些库并包含某些头文件,特别是如果您使用从一个非常大的SDK只说1个函数,这可以防止其他开发人员浪费时间来获得巨大的SDK(他们ofc将需要二进制连续导出)

3

某些函数不存在于旧版本的Windows中,并且当您直接调用某个函数时,该函数将以您的程序的导入表结尾。如果Windows无法在导入表中找到其中一个功能,则该程序根本无法运行。如果你想支持第三方插件等

0

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