【发布时间】:2018-09-15 04:56:23
【问题描述】:
两者有什么区别?
即用于查找 Nt___ 或 Zw___ 等函数
【问题讨论】:
-
真的
__declspec(dllimport)只影响 CL 声明指向符号(函数)的指针并通过此指针调用函数(或访问数据)。全部。实际效果在构建过程中使用导入库
两者有什么区别?
即用于查找 Nt___ 或 Zw___ 等函数
【问题讨论】:
__declspec(dllimport) 只影响 CL 声明指向符号(函数)的指针并通过此指针调用函数(或访问数据)。全部。实际效果在构建过程中使用导入库
在 MS Windos 中,隐式链接和显式链接是有区别的。
隐式链接
可执行文件链接到提供从 DLL 导出的符号的随附库(.lib 文件)。 (用于导入的函数用__declspec(dllimport) 标注。)隐式链接的DLL 加载了可执行文件。
显式链接
程序加载一个显式调用LoadLibrary() 的DLL。要调用 DLL 的函数,它们的地址必须使用GetProcAddress() 来确定。
不过,GetProcAddress() 也可用于来自隐式链接 DLL 的函数。如果意外地在多个 DLL 中使用了相同的符号(例如,如果使用了链接到不同运行时 DLL 的 DLL),这可能会有所帮助。
有时,提供的 DLL 没有导入库。一个众所周知的例子是 OpenGL,MS 在 1.2 版中停止了对它的支持。但是,如果有足够的硬件和最新的驱动程序,当前 OpenGL 版本的所有功能都可能可用(并且可以在运行时使用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. 作为函数指针本身是 dllexported 但在运行时初始化 GetProcAddress()。)
(PFNGL 宏扩展为具有适当签名的函数指针类型。它们包含在kronos.org 提供的标头中。)
GetProcAddress() 的另一个重要用途是用于在某个版本的 Windows 之前可能不存在的函数(或其他可能在 DLL 中可用或不可用的函数)。因此,当GetProcAddress() 无法实现预期功能时,应用程序可以向后兼容地编写,从而提供备用回退。
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);
}
【讨论】:
GetProcAddress() 页面中有一个 C++ 示例。
GetProcAddress() 适用于不能选择隐式链接的情况。 (我举了两个例子。)
__imp_FuncName 并通过它调用函数。链接器搜索 __imp_FuncName 符号。如果在导入库中找到它 - 这里存在有关 dll 名称的信息,从哪个函数导入。他将__imp_FuncName 变量放入IAT 并在导入表中为它/dll 创建记录。加载器在加载 dll 时使用此记录为您解析函数地址
GetProcAddress() 让您可以在运行时查找函数。它对于可选导入或可以动态加载的插件之类的东西很有用。它的另一个用途是用于导出但没有头文件或库文件的未记录函数。
使用__declspec( dllimport ) 将该函数添加到您的导入表中,以便它与您的可执行文件一起自动加载。
【讨论】:
extern "C" { extern void* __imp_FuncName; } 并通过此指针调用函数。比我们需要以某种方式实现void* __imp_FuncName。可能并指导自己。但通常,当它在导入库中实现时 - 是的,链接器将此变量添加到 IAT 并在导入表中创建记录