GetProcAddress 与 __declspec(dllimport)
GetProcAddress vs __declspec( dllimport )
两者有什么区别?
即用于查找 Nt___ 或 Zw___
等函数
GetProcAddress()
可让您在运行时查找函数。它对于可选的导入或诸如可以动态加载的插件之类的东西很有用。它的另一个用途是导出但没有头文件或库文件的未记录函数。
使用 __declspec( dllimport )
将函数添加到您的导入 table 中,因此它会随您的 executable 自动加载。
在 MS Windos 中,隐式链接和显式链接是有区别的。
隐式链接
可执行文件链接到随附的库(.lib
文件),该库提供从 DLL 导出的符号。 (导入的函数用__declspec(dllimport)
注释。)隐式链接的DLL加载可执行文件。
显式链接
程序载入一个显式调用 LoadLibrary()
的 DLL。要调用 DLL 的函数,必须使用 GetProcAddress()
.
确定其地址
但是,GetProcAddress()
也可用于来自隐式链接 DLL 的函数。如果意外地在多个 DLL 中使用相同的符号(例如,如果使用了链接到不同运行时 DLL 的 DLL),这会很有帮助。
有时,提供的 DLL 没有导入库。一个众所周知的例子是 OpenGL,微软在 1.2 版中停止了对它的支持。然而,如果有足够的 H/W 和 up-to-date 驱动程序,当前 OpenGL 版本的所有功能都可能可用(并且可以在 run-time 处使用 GetProcAdress()
加载)。
一段OpenGL绑定的示例代码MyGL.cc
:
// version 2.0
glAttachShader
= (PFNGLATTACHSHADERPROC)wglGetProcAddress(
"glAttachShader");
glCompileShader
= (PFNGLCOMPILESHADERPROC)wglGetProcAddress(
"glCompileShader");
glCreateProgram
= (PFNGLCREATEPROGRAMPROC)wglGetProcAddress(
"glCreateProgram");
glCreateShader
= (PFNGLCREATESHADERPROC)wglGetProcAddress(
"glCreateShader");
glDeleteProgram
= (PFNGLDELETEPROGRAMPROC)wglGetProcAddress(
"glDeleteProgram");
glDeleteShader
= (PFNGLDELETESHADERPROC)wglGetProcAddress(
"glDeleteShader");
与 MyGL.h
:
// Version 2.0
extern MY_GL_API PFNGLATTACHSHADERPROC glAttachShader;
extern MY_GL_API PFNGLCOMPILESHADERPROC glCompileShader;
extern MY_GL_API PFNGLCREATEPROGRAMPROC glCreateProgram;
extern MY_GL_API PFNGLCREATESHADERPROC glCreateShader;
extern MY_GL_API PFNGLDELETEPROGRAMPROC glDeleteProgram;
extern MY_GL_API PFNGLDELETESHADERPROC glDeleteShader;
其中 MY_GL_API
在编译 MyGL.dll
时定义为 __declspec(dllexport)
,否则 __declspec(dllimport)
。 (所以,实际上 __declspec(dllimport)
和 GetProcAddress()
而不是 vs. 因为函数指针本身是 dllexport
ed但初始化为 run-time unsing GetProcAddress()
。)
(PFNGL
宏扩展为具有适当签名的函数指针类型。它们包含在 kronos.org 提供的 header 中。)
GetProcAddress()
的另一个重要用途是用于可能不存在于特定版本 Windows 之前的函数(或其他可能在 DLL 中可用或不可用的函数)。因此,当 GetProcAddress()
无法实现预期功能时,可以向后兼容地编写应用程序,提供替代方案 fall-back。
MSDN 上为 GetProcAddress()
提供的示例:
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);
} else {
GetSystemInfo(&si);
}
两者有什么区别?
即用于查找 Nt___ 或 Zw___
等函数GetProcAddress()
可让您在运行时查找函数。它对于可选的导入或诸如可以动态加载的插件之类的东西很有用。它的另一个用途是导出但没有头文件或库文件的未记录函数。
使用 __declspec( dllimport )
将函数添加到您的导入 table 中,因此它会随您的 executable 自动加载。
在 MS Windos 中,隐式链接和显式链接是有区别的。
隐式链接
可执行文件链接到随附的库(.lib
文件),该库提供从 DLL 导出的符号。 (导入的函数用__declspec(dllimport)
注释。)隐式链接的DLL加载可执行文件。
显式链接
程序载入一个显式调用 LoadLibrary()
的 DLL。要调用 DLL 的函数,必须使用 GetProcAddress()
.
但是,GetProcAddress()
也可用于来自隐式链接 DLL 的函数。如果意外地在多个 DLL 中使用相同的符号(例如,如果使用了链接到不同运行时 DLL 的 DLL),这会很有帮助。
有时,提供的 DLL 没有导入库。一个众所周知的例子是 OpenGL,微软在 1.2 版中停止了对它的支持。然而,如果有足够的 H/W 和 up-to-date 驱动程序,当前 OpenGL 版本的所有功能都可能可用(并且可以在 run-time 处使用 GetProcAdress()
加载)。
一段OpenGL绑定的示例代码MyGL.cc
:
// version 2.0
glAttachShader
= (PFNGLATTACHSHADERPROC)wglGetProcAddress(
"glAttachShader");
glCompileShader
= (PFNGLCOMPILESHADERPROC)wglGetProcAddress(
"glCompileShader");
glCreateProgram
= (PFNGLCREATEPROGRAMPROC)wglGetProcAddress(
"glCreateProgram");
glCreateShader
= (PFNGLCREATESHADERPROC)wglGetProcAddress(
"glCreateShader");
glDeleteProgram
= (PFNGLDELETEPROGRAMPROC)wglGetProcAddress(
"glDeleteProgram");
glDeleteShader
= (PFNGLDELETESHADERPROC)wglGetProcAddress(
"glDeleteShader");
与 MyGL.h
:
// Version 2.0
extern MY_GL_API PFNGLATTACHSHADERPROC glAttachShader;
extern MY_GL_API PFNGLCOMPILESHADERPROC glCompileShader;
extern MY_GL_API PFNGLCREATEPROGRAMPROC glCreateProgram;
extern MY_GL_API PFNGLCREATESHADERPROC glCreateShader;
extern MY_GL_API PFNGLDELETEPROGRAMPROC glDeleteProgram;
extern MY_GL_API PFNGLDELETESHADERPROC glDeleteShader;
其中 MY_GL_API
在编译 MyGL.dll
时定义为 __declspec(dllexport)
,否则 __declspec(dllimport)
。 (所以,实际上 __declspec(dllimport)
和 GetProcAddress()
而不是 vs. 因为函数指针本身是 dllexport
ed但初始化为 run-time unsing GetProcAddress()
。)
(PFNGL
宏扩展为具有适当签名的函数指针类型。它们包含在 kronos.org 提供的 header 中。)
GetProcAddress()
的另一个重要用途是用于可能不存在于特定版本 Windows 之前的函数(或其他可能在 DLL 中可用或不可用的函数)。因此,当 GetProcAddress()
无法实现预期功能时,可以向后兼容地编写应用程序,提供替代方案 fall-back。
MSDN 上为 GetProcAddress()
提供的示例:
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);
} else {
GetSystemInfo(&si);
}