-->

GetProcAddress vs __declspec( dllimport )

2020-02-16 01:14发布

问题:

What's the difference between the two?

i.e. for finding functions such as Nt___ or Zw___

回答1:

In MS Windos, there is a difference between implicit linking and explicit linking.

Implicit Linking

The executable is linked against the accompanying library (.lib file) which provides the symbols exported from DLL. (The functions for import are remarked with __declspec(dllimport).) Implicit linked DLLs are loaded with executable.

Explicit Linking

The program loads a DLL explicitly calling LoadLibrary(). To call functions of the DLL their address has to be determined using GetProcAddress().

However, GetProcAddress() can be used as well for functions which come from implicit linked DLLs. This can be helpful, if accidentally the same symbol is available in multiple DLLs (e.g. if DLLs have been used which are linked against different runtime DLLs).

Sometimes, DLLs are provided without import libraries. A wellknown example is OpenGL for which MS stopped support with version 1.2. However, with sufficient H/W and up-to-date drivers, all functions of the current OpenGL version might be availabe (and can be loaded with GetProcAdress() at run-time).

A piece of sample code for OpenGL binding 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");

with 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;

where MY_GL_API is defined as __declspec(dllexport) when MyGL.dll is compiled and __declspec(dllimport) otherwise. (So, actually __declspec(dllimport) and GetProcAddress() instead of vs. as function pointers themselves are dllexported but initialized at run-time unsing GetProcAddress().)

(The PFNGL macros expand to function pointer types with the appropriate signature. They are included from a header provided by kronos.org.)

Another important usage of GetProcAddress() is for functions which may exist not before a certain version of Windows (or other functions which may or may not be available in DLLs). Thus, the application can be written backwards compatible providing an alternative fall-back when GetProcAddress() fails for the intended function.

The sample provided on MSDN for 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);
   }

Further reading: MSDN: Link an executable to a DLL



回答2:

GetProcAddress() lets you find functions in runtime. It's useful for optional imports or for things like plug-ins that can be loaded dynamically. Another use for it is for undocumented functions that are exported but don't have a header file or library file.

Using __declspec( dllimport ) adds the function to your import table so it's loaded automatically with your executable.