What Does _Declspec(Dllimport) Really Mean

what does __declspec(dllimport) really mean?

__declspec is a Microsoft-specific attribute that allows you to specify storage-class information.

(Nitpicker's Corner: However, a number of other compiler vendors—e.g. GCC—now support this language extension for compatibility with the installed base of code that was written targeting Microsoft's compilers. Some even provide additional storage-class attributes.)

Two of those storage-class attributes that can be specified are dllimport and dllexport. These indicate to the compiler that a function or object is imported or exported (respectively) from a DLL.

More specifically, they define the DLL's interface to the client without requiring a module-definition (.DEF) file. Most people find it much easier to use these language extensions than to create DEF files.

For obvious reasons, __declspec(dllimport) and __declspec(dllexport) are generally paired with one another. You use dllexport to mark a symbol as exported from a DLL, and you use dllimport to import that exported symbol in another file.

Because of this, and because the same header file is generally used both when compiling the DLL and in client code that consumes the DLL's interface, it is a common pattern to define a macro that automatically resolves to the appropriate attribute specifier at compile-time. For example:

#if COMPILING_DLL
#define DLLEXPORT __declspec(dllexport)
#else
#define DLLEXPORT __declspec(dllimport)
#endif

And then marking all of the symbols that should be exported with DLLEXPORT.

Presumably, that is what the Q_CORE_EXPORT macro does, resolving to either Q_DECL_IMPORT or Q_DECL_EXPORT.

how does __declspec(dllimport) actually work?

When you use test() in your code the resulting object file is marked as requiring the symbol for test.

You then supply the .lib file for your dll to the linker, the lib contains the symbol for test and contains the required code for loading your dll which includes the name of the dll.

You could supply a different .lib file which also contains the test symbol which would load a different dll.

Why/when is __declspec( dllimport ) not needed?

It isn't required. It is an optimization, a hint to the compiler that the DLL is going to export the function pointer directly rather than just an entry in the IAT of the DLL. The exported function pointer for a function named foo() will be __imp_foo. Which allows it to generate better code, saving a function pointer load from the IAT and an indirect jump. It is a time optimization, not space.

This blog post has the details.

What is the difference between __declspec( dllimport ) extern C AND extern C __declspec( dllimport )

extern "C" and __declspec(dllimport) are totally orthogonal.

  • extern "C" means that C linkage should be used for that symbol. I.e. no C++ name mangling will be applied. It also limits functions' interfaces to C-compatible things: built-in types, trivial structs, and pointers. Essentially, it tells the compiler and linker that a symbol should be found in the "C way" rather than the "C++ way". extern "C" is generally used for either calling C functions from C++ code or creating a C-compatible interface to C++ code.
  • __declspec(dllimport) tells the linker that a symbol will be loaded dynamically at runtime from a DLL.

The two can be combined as well. A function marked extern "C" __declspec(dllimport) will be dynamically linked and use C-style linkage.

What is the difference between dllexport and dllimport?

  • __declspec(dllexport) tells the linker that you want this object to be made available for other DLL's to import. It is used when creating a DLL that others can link to.

  • __declspec(dllimport) imports the implementation from a DLL so your application can use it.

I'm only a novice C/C++ developer, so perhaps someone's got a better explanation than I.

GetProcAddress vs __declspec( dllimport )

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

__declspec(dllexport) and __declspec(dllimport) in C++

The Windows-exclusive __declspec(dllexport) is used when you need to call a function from a Dll (by exporting it) , that can be accessed from an application.

Example This is a dll called "fun.dll" :


// Dll.h :

#include <windows.h>

extern "C" {

__declspec(dllexport) int fun(int a); // Function "fun" is the function that will be exported

}

// Dll.cpp :

#include "Dll.h"

int fun(int a){
return a + 1;
}

You can now access the "fun" from "fun.dll" from any application :

#include <windows.h>

typedef int (fun)(int a); // Defining function pointer type

int call_fun(int a){
int result = 0;

HMODULE fundll = LoadLibrary("fun.dll"); // Calling into the dll

if(fundll){
fun* call_fun = (fun*) GetProcAddress(fundll, "fun"); // Getting exported function
if(call_fun){
result = call_fun(a); // Calling the exported fun with function pointer
}
}
return result;
}


Related Topics



Leave a reply



Submit