(Tips) Understanding DLLs – Building them and Allowing External Calls to their Functions
Understanding DLLs – Building them and Allowing External Calls to their Functions
Introduction
In a generic sense of the term, a library is a collection of modules, each
of which contains one or more functions or procedures which are packaged
together so that they can be reused easily when needed and not used when not
needed. There are application DLLs and system DLLs. Many system DLLs are called
key system components (kernel32.dll, advapi32.dll, ntdll.dll, hal.dll,
user32.dll, gdi32.dll, and so forth). If you have ever programmed in the C
language, then you would know that unlike any object-oriented programming
language, the basic unit of organization is the function; that C is a function,
or procedural (not object) oriented language. The compiler will contain
directives (included header files atop the body of the source code) that contain
the prototypes of the predefined functions. The name of the header file is based
on the type of those semantically-related functions defined in that header file.
These header files link together to form a static, not dynamic, library. The C
compiler translates the human-readable source code into machine language. The
output is a resource, or object, or module file. But even though the definitions
of the functions are not included in the main body of the source code, the C
compiler cannot generate the address of a function that it is not seeing. You
pass the static library as input to the linker and the linker searches for all
of the unresolved externals. This is why it is important to keep your source
code files in the same working directory as the directory that contains the
library (that contains the header definitions of the predefined functions).
DLLs, on the other hand, differ. There is a separate link step for the DLL
itself. When the DLL is linked, it will generate an import library. This import
library enumerates by name (or sometimes number) all of the functions that are
contained in that library.
Assume you have a graphical application and you call CreateWindow to put a
window on the screen. When the compiler is generating that module, it doesn't
know where CreateWindow is. So we build our application and we pass it our
import library for user32.dll. There is no the implementation of a function in
this import library. The import library communicates back to the call, stating
that CreateWindow is the needed function and it lives in user32.dll. Rather than
resolve CreateWindow to an absolute (relative) address, the compiler and linker
create a slot in an import address table which is the location where later on,
the loader will patch with the address of CreateWindow. So when your built
application is loaded, Windows sees that you have some functions that depend on
user32.dll. So it loads user32.dll in the process address space (where the code
and data are mapped to both represent an instance of and run your application).
Note that only pieces of the DLL are "virtually loaded": not the entire DLL.
This can be a misunderstanding: a loaded executable means that only pieces of it
are loaded, not the entire image. Only the needed pieces of are loaded. As more
features are used in application, then more pieces of are loaded, as well as the
appropriate DLLs. This is part of the Windows Memory Management mechanism – any
memory that can be shared will be shared. Once Windows loads user32.dll into
your address space, it knows where the address of CreateWindow is. It then goes
to import address table to realize that it must resolve the address for
CreateWindow, and it patches it at that point.
Read
full article..
Courtesy : Codeproject.com
- guru's blog
- Login or register to post comments

