MODULE BB
DYNAMIC LINK LIBRARY - DLL
Part 1: STORY
What do we have in this Module?
-
Dynamic-Link Library and C Run-Time Story
-
Differences Between Applications and DLLs
-
Advantages of Using DLLs
-
Type of DLLs
-
Linking an Executable to a DLL
-
Using Linking Implicitly
-
Using Linking Explicitly
-
Determining Which Linking Method to Use
-
Implicit Linking
-
Explicit Linking
-
Creating a Resource-Only DLL
-
Importing and Exporting
-
Using a .DEF file
-
Using __declspec
-
Importing into an Application Using __declspec(dllimport)
-
Exporting from a DLL
-
Exporting from a DLL Using __declspec(dllexport)
-
Initializing a DLL
-
Initializing Extension DLLs (For MFC programs)
-
Initializing Non-MFC DLLs
-
Run-Time Library Behavior
My Training Period: xx
hours.
Before
you begin, read some
instruction here.
The Windows
MFC programming (GUI programming) for DLL can be found at
MFC GUI Programming Step-by-step Tutorial.
Abilities that supposed to be acquired:
-
Able to understand, build and run the dynamic-link library programs.
-
Able to appreciate the beneficial of using DLLs compared to normal applications.
-
Able to collect information from MSDN documentation in order to understand and use DLL.
|
Dynamic-Link Library and C Run-Time Story
Note:
This Module is a general MSDN documentation that covers the C/C++ Run-Time
Library and MFC on Visual C++. Let get the big picture first!
A dynamic-link library (DLL) is an executable file that acts as a shared
library of functions. Dynamic linking provides a way for a process to
call a function that is not part of its executable code. The executable
code for the function is located in a DLL, which contains one or more
functions that are compiled, linked, and stored separately from the
processes that use them. DLLs also facilitate the sharing of data and
resources. Multiple applications can simultaneously access the contents
of a single copy of a DLL in memory. Dynamic linking differs from static
linking in that it allows an executable module (either a
.dll
or
.exe
file) to include only the information needed at run time to locate the
executable code for a DLL function. In static linking, the linker gets
all of the referenced functions from the static link library and places
it with your code into your executable. Using dynamic linking instead
of static linking offers several advantages. DLLs save memory, reduce
swapping, save disk space, upgrade easier, provide after-market support,
provide a mechanism to extend the MFC library classes, support multi
language programs, and ease the creation of international versions.
Differences Between Applications and DLLs
Even though DLLs and applications are both executable program modules, they
differ in several ways. To the end-user, the most obvious difference
is that DLLs are not programs that can be directly executed. From the
system's point of view, there are two fundamental differences between
applications and DLLs:
Advantages of Using DLLs
Dynamic linking has the following advantages:
A potential disadvantage to using DLLs is that the application is not self-contained;
it depends on the existence of a separate DLL module.
|
Type of DLLs
Using Visual C++, you can build:
-
Win32 DLLs in C or C++ that do not use the Microsoft Foundation Class Library (MFC).
-
You can create a non-MFC DLL project with the Win32 Application Wizard.
-
The MFC library itself is available, in either static link libraries or in a number of DLLs, with the MFC DLL Wizard. If your DLL is using MFC, Visual C++ supports three different DLL development scenarios:
Building a regular DLL that statically links MFC. Building a regular DLL that dynamically links MFC. Building an MFC extension DLL. These always dynamically link MFC.
Linking an Executable to a DLL
An executable file links to (or loads) a DLL in one of two ways:
-
Implicit linking.
-
Explicit linking.
Implicit linking
is sometimes referred to as static load
or load-time dynamic linking.
Explicit linking is sometimes referred to as
dynamic load or
run-time dynamic linking. With implicit
linking, the executable using the DLL links to an import library (.LIB
file) provided by the maker of the DLL. The operating system loads the DLL when
the executable using it is loaded. The client executable calls the DLL's exported
functions just as if the functions were contained within the executable.
With explicit linking, the
executable using the DLL must make function calls to explicitly load and unload
the DLL, and to access the DLL's exported functions. The client executable must
call the exported functions through a function pointer. An executable can use
the same DLL with either linking method. Furthermore, these mechanisms are not
mutually exclusive, as one executable can implicitly link to a DLL and another
can attach to it explicitly.
Using Linking Implicitly
To implicitly link to a DLL, executables must obtain the following from
the provider of the DLL:
-
A header file (.H file) containing the declarations of the exported functions and/or C++ classes.
-
An import library (.LIB files) to link with. The linker creates the import library when the DLL is built.
-
The actual DLL (.DLL file).
Executables using the DLL must include the
header file containing the exported functions (or C++ classes)
in each source file that contains calls to the exported functions. From a coding
perspective, the function calls to the exported functions are just like any
other function call. To build the calling executable file, you must link with
the import library. If you are using an external makefile, specify the file
name of the import library where you list other object (.OBJ)
files or libraries that you are linking with. The operating system must be able
to locate the
.DLL file when
it loads the calling executable.
Using Linking Explicitly
With explicit linking, applications must make a function call to explicitly
load the DLL at run time. To explicitly link to a DLL, an application must:
-
Call LoadLibrary() (or a similar function) to load the DLL and obtain a module handle.
-
Call GetProcAddress() to obtain a function pointer to each exported function that the application wants to call. Because applications are calling the DLL's functions through a pointer, the compiler does not generate external references, so there is no need to link with an import library.
-
Call FreeLibrary() when done with the DLL.
For example:
typedef UINT (CALLBACK* LPFNDLLFUNC1)(DWORD, UINT);...HINSTANCE hDLL; // Handle to DLLLPFNDLLFUNC1 lpfnDllFunc1; // Function pointerDWORD dwParam1;UINT uParam2, uReturnVal;hDLL = LoadLibrary("MyDLL");if (hDLL != NULL){lpfnDllFunc1 = (LPFNDLLFUNC1)GetProcAddress(hDLL, "DLLFunc1");if (!lpfnDllFunc1){// handle the errorFreeLibrary(hDLL);return SOME_ERROR_CODE;}else{// call the functionuReturnVal = lpfnDllFunc1(dwParam1, uParam2);}}
Determining Which Linking Method to Use
Implicit Linking
Implicit linking occurs when an application's code calls an exported DLL
function. When the source code for the calling executable is compiled or assembled,
the DLL function call generates an external function reference in the object
code. To resolve this external reference, the application must link with the
import library (.LIB
file) provided by the maker of the DLL. The import library only contains code
to load the DLL and to implement calls to functions in the DLL. Finding an external
function in an import library informs the linker that the code for that function
is in a DLL. To resolve external references to DLLs, the linker simply adds
information to the executable file that tells the system where to find the DLL
code when the process starts up.
When the system starts a program that contains dynamically linked references,
it uses the information in the program's executable file to locate the required
DLLs. If it cannot locate the DLL, the system terminates the process and displays
a dialog box that reports the error or if you are in the process of building
an application, the following error message may be output:
testdll.obj : error LNK2019: unresolved external symbol "int __cdecl mydll(char *)" (?mydll@@YAHPAD@Z) referenced in function _mainDebug/mydlltest.exe : fatal error LNK1120: 1 unresolved externals
Otherwise, the system maps the DLL modules into the process's address space.
If any of the DLLs has an entry-point function (for initialization and termination
code), the operating system calls the function. One of the parameters passed
to the entry-point function specifies a code that indicates the DLL is attaching
to the process. If the entry-point function does not return TRUE, the system
terminates the process and reports the error.
Finally, the system modifies the executable code of the process to provide
starting addresses for the DLL functions. Like the rest of a program's code,
DLL code is mapped into the address space of the process when the process starts
up and it is loaded into memory only when
needed. As a result, the
PRELOAD and
LOADONCALL
code attributes used by
.DEF files to
control loading in previous versions of Windows no longer have meaning.
Explicit Linking
Most applications use implicit linking because it is the easiest linking
method to use. However, there are times when explicit linking is necessary.
Here are some common reasons to use explicit linking:
-
The application does not know the name of a DLL that it will have to load until run time. For example, the application might need to obtain the name of the DLL and the exported functions from a configuration file.
-
A process using implicit linking is terminated by the operating system if the DLL is not found at process startup. A process using explicit linking is not terminated in this situation and can attempt to recover from the error. For example, the process could notify the user of the error and have the user specify another path to the DLL.
-
A process using implicit linking is also terminated if any of the DLLs it is linked to have a DllMain() function that fails. A process using explicit linking is not terminated in this situation.
-
An application that implicitly links to many DLLs can be slow to start because Windows loads all of the DLLs when the application loads. To improve startup performance, an application can implicitly link to those DLLs needed immediately after loading and wait to explicitly link to the other DLLs when they are needed.
-
Explicit linking eliminates the need to link the application with an import library. If changes in the DLL cause the export ordinals to change, applications using explicit linking do not have to re-link (assuming they are calling GetProcAddress() with a name of a function and not with an ordinal value), whereas applications using implicit linking must re-link to the new import library.
Here are two hazards of explicit linking to be aware of:
-
If the DLL has a DllMain() entry point function, the operating system calls the function in the context of the thread that called LoadLibrary(). The entry-point function is not called if the DLL is already attached to the process because of a previous call to LoadLibrary() with no corresponding call to the FreeLibrary() function. Explicit linking can cause problems if the DLL is using a DllMain() function to perform initialization for each thread of a process because threads existing when LoadLibrary() (or AfxLoadLibrary()) is called will not be initialized.
-
If a DLL declares static-extent data as __declspec(thread), it can cause a protection fault if explicitly linked. After the DLL is loaded with LoadLibrary(), it causes a protection fault whenever the code references this data. (Static-extent data includes both global and local static items.) Therefore, when you create a DLL, you should either avoid using thread-local storage, or inform DLL users about potential pitfalls (in case they attempt dynamic loading).
Creating a Resource-Only DLL
A resource-only DLL is a DLL that contains nothing but resources, such as
icons, bitmaps, strings, and dialog boxes. Using a resource-only DLL is a good
way to share the same set of resources among multiple programs. It is also a
good way to provide an application with resources localized for multiple languages.
To create a resource-only DLL, you create a new Win32 DLL (non-MFC) project
and add your resources to the project.
-
Select Win32 Project in the New Project dialog box and specify a DLL project type in the Win32 Project Wizard.
-
Create a new resource script that contains the resources (such as a string or a menu) for the DLL and save the .rc file.
-
On the Project menu, click Add Existing Item and insert the new .rc file into the project.
-
Specify the /NOENTRY linker option. /NOENTRY prevents the linker from linking a reference to _main into the DLL; this option is required to create a resource-only DLL.
-
Build the DLL.
The application that uses the resource-only DLL should call
LoadLibrary()
to explicitly link to the DLL. To access the resources, call the generic functions
FindResource()
and
LoadResource(),
which work on any kind of resource, or call one of the following resource-specific
functions:
-
FormatMessage()
-
LoadAccelerators()
-
LoadBitmap()
-
LoadCursor()
-
LoadIcon()
-
LoadMenu()
-
LoadString()
The application should call
FreeLibrary()
when it is finished using the resources.
Importing and Exporting
You can import public symbols into an
application or export functions
from a DLL using two methods:
-
Use a module definition (.DEF) file when building the DLL.
-
Use the keywords __declspec(dllimport) or __declspec(dllexport) in a function definition in the main application.
Using a .DEF file
A module-definition (.DEF)
file is a text file containing one or more module statements that describe various
attributes of a DLL. If you do not use
__declspec(dllimport)
or
__declspec(dllexport)
to export a DLL's functions, the DLL requires a
.DEF file. You
can use
.DEF files to
import into an application or to export from a DLL.
Using __declspec
The 32-bit edition of Visual C++ uses
__declspec(dllimport)
and
__declspec(dllexport)
to replace the
__export keyword
previously used in 16-bit versions of Visual C++. You do not need to use
__declspec(dllimport)
for your code to compile correctly, but doing so allows the compiler to generate
better code. The compiler is able to generate better code because it knows for
sure whether a function exists in a DLL or not, so the compiler can produce
code that skips a level of indirection that would normally be present in a function
call that crossed a DLL boundary. However, you must use
__declspec(dllimport)
in order to import variables used in a DLL. With the proper
.DEF
file
EXPORTS section,
__declspec(dllexport)
is not required.
__declspec(dllexport)
was added to provide an easy way to export functions from an
.EXE
or
.DLL without
using a
.DEF file. The
Win32
Portable Executable
(PE) format is designed to minimize the number of pages that must be touched
to fix imports. To do this, it places all of the import addresses for any program
in one place called the Import Address Table.
This allows the loader to modify
only one or two pages when accessing these imports.
Importing into an Application Using __declspec(dllimport)
A program that uses public symbols defined by a DLL is said to import them.
When you create header files for applications that use your DLLs to build with,
use
__declspec(dllimport)
on the declarations of the public symbols. The keyword
__declspec(dllimport)
works whether you export with
.DEF files or
with the
__declspec(dllexport)
keyword. To make your code more readable, define a macro for
__declspec(dllimport)
and then use the macro to declare each imported symbol:
#define DllImport __declspec(dllimport)DllImport int j;DllImport void func();
Using
__declspec(dllimport) is optional on function
declarations, but the compiler produces more efficient code if you use this
keyword. However, you must use
__declspec(dllimport) in order for the importing
executable to access the DLL's public data symbols and objects. Note that the
users of your DLL still need to link with an import library. You can use the
same header file for both the DLL and the client application. To do this, use
a special preprocessor symbol which indicates whether you are building the DLL
or building the client application. For example:
|
Exporting from a DLL
A
.DLL file has
a layout very similar to an
.EXE file, with
one important difference: a DLL file contains an
exports table. The exports table contains
the name of every function that the DLL exports to other executables. These
functions are the entry points
into the DLL; only the functions in the exports table can be accessed by other
executables. Any other functions in the DLL are private to the DLL. The exports
table of a DLL can be viewed by using the
DUMPBIN tool
(comes with your Visual Studio or you can try more powerful tool,
PEBrowser) with the
/EXPORTS
option.
You can export functions from a DLL using two methods:
-
Create a module definition (.DEF) file and use the .DEF file when building the DLL. Use this approach if you want to export functions from your DLL by ordinal rather than by name.
-
Use the keyword __declspec(dllexport) in the function's definition.
When exporting functions with either method, make sure to use the
__stdcall calling
convention. A module-definition (.DEF)
file is a text file containing one or more module statements that describe various
attributes of a DLL. If you are not using the __declspec(dllexport) keyword to export
the DLL's functions, the DLL requires a
.DEF file. A minimal
.DEF
file must contain the following module-definition statements:
-
The first statement in the file must be the LIBRARY statement. This statement identifies the .DEF file as belonging to a DLL. The LIBRARY statement is followed by the name of the DLL. The linker places this name in the DLL's import library.
-
The EXPORTS statement lists the names and, optionally, the ordinal values of the functions exported by the DLL. You assign the function an ordinal value by following the function's name with an at sign (@) and a number. When you specify ordinal values, they must be in the range 1 through N, where N is the number of functions exported by the DLL.
For example, a DLL that contains the code to implement a binary search tree
might look like the following:
LIBRARY BTREEEXPORTSInsert @1Delete @2Member @3Min @4
If you use the MFC DLL Wizard to create an MFC DLL, the wizard creates a
skeleton
.DEF file for you and automatically adds
it to your project. Add the names of the functions to be exported to this file.
For non-MFC DLLs, you must create the
.DEF file yourself
and add it to your project. If you are exporting functions in a C++ file, you
will have to either place the decorated names in the
.DEF
file or define your exported functions with standard C linkage by using extern
"C".
If you need to place the decorated names
in the
.DEF file, you
can obtain them by using the
DUMPBIN tool
or by using the linker
/MAP option.
Note that the decorated names produced by the compiler are compiler specific.
If you place the decorated names produced by the Visual C++ compiler into a
.DEF
file, applications that link to your DLL must also be built using the same version
of Visual C++ so that the decorated names in the calling application match the
exported names in the DLL's
.DEF file. If
you are building an extension DLL (MFC), and exporting using a
.DEF
file, place the following code at the beginning and end of your header files
that contain the exported classes:
#undef AFX_DATA#define AFX_DATA AFX_EXT_DATA// <body of your header file>#undef AFX_DATA#define AFX_DATA
These lines ensure that MFC variables that are used internally or that are
added to your classes are exported (or imported) from your extension DLL. For
example, when deriving a class using
DECLARE_DYNAMIC,
the macro expands to add a
CRuntimeClass
member variable to your class. Leaving out these four lines may cause your DLL
to compile or link incorrectly or cause an error when the client application
links to the DLL.
When building the DLL, the linker uses the
.DEF
file to create an export (.EXP) file and an import library (.LIB)
file. The linker then uses the export file to build the
.DLL
file. Executables that implicitly link to the DLL link to the import library
when they are built. Note that MFC itself uses
.DEF files to
export functions and classes from the
MFCx0.DLL.
Exporting from a DLL Using __declspec(dllexport)
Microsoft introduced
__export in
the 16-bit compiler version of Visual C++ to allow the compiler to generate
the export names automatically and place them in a
.LIB file. This
.LIB
file could then be used just like a static
.LIB to link
with a DLL. In the 32-bit compiler version, you can
export data,
functions,
classes, or
class member functions from a DLL using the
__declspec(dllexport)
keyword.
__declspec(dllexport)
adds the export directive to the object file so you don't need to use a .DEF
file. This convenience is most apparent when trying to export decorated C++
function names. There is no standard specification for name decoration, so the
name of an exported function may change between compiler versions. If you use
__declspec(dllexport),
recompiling the DLL and dependent
.EXE files is
necessary only to account for any naming convention changes. Many export directives,
such as ordinals,
NONAME,
and
PRIVATE, can be made only in a
.DEF
file, and there is no way to specify these attributes without a
.DEF
file. However, using
__declspec(dllexport)
in addition to using a
.DEF file does
not cause build errors. To export functions, the
__declspec(dllexport)
keyword must appear to the left of the calling-convention keyword, if a keyword
is specified. For example:
__declspec(dllexport) void __stdcall WilBeExportedFunctionName(void);
And the real one may look something like this:
__declspec(dllexport) int mydll(LPTSTR lpszMsg)
To export all of the public data members and member functions in a class,
the keyword must appear to the left of the class name as follows:
class __declspec(dllexport) CExampleExport : public CObject{ ... class definition ... };
When building your DLL, you typically create a header file that contains
the function prototypes and/or classes you are exporting, and add
__declspec(dllexport)
to the declarations in the header file. To make your code more readable, define
a macro for
__declspec(dllexport)
and use the macro with each symbol you are exporting:
#define DllExport __declspec(dllexport)
__declspec(dllexport) stores
function names in the DLL's export table.
Initializing a DLL
Typically, your DLL has initialization code (such as allocating memory)
that must execute when your DLL loads. When using Visual C++, where you add
code to initialize your DLL depends on the kind of DLL you are building. If
you don't need to add initialization or termination code, there's nothing special
you have to do when building your DLL. If you need to initialize your DLL, the
following table describes where to add your code.
Type of DLL
|
Where to add initialization and termination code
|
Regular DLL
|
In the DLL's
CWinApp()
object's
InitInstance()
and
ExitInstance().
|
Extension DLL
|
In the
DllMain()
function generated by the MFC DLL Wizard.
|
Non-MFC DLL
|
In a function called
DllMain()
that you provide.
|
Table 1.
|
In Win32, all DLLs may contain an optional
entry-point function (usually called
DllMain()) that
is called for both initialization and termination. This gives you an opportunity
to allocate or release additional resources as needed. Windows calls the entry-point
function in four situations: process attach, process detach, thread attach,
and thread detach. The C run-time library provides an entry-point function called
_DllMainCRTStartup(),
and it calls
DllMain(). Depending
on the kind of DLL, either you should have a function called
DllMain()
in your source code or you should use the
DllMain() provided
in the MFC library.
Initializing Extension DLLs (For MFC programs)
Because extension DLLs do not have a
CWinApp-derived
object (as do regular DLLs), you should add your initialization and termination
code to the
DllMain() function
that the MFC DLL Wizard generates. The wizard provides the following
code for extension DLLs. In the code portion below,
PROJNAME is
a placeholder for the name of your project.
#include "stdafx.h"#include <afxdllx.h>#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endifstatic AFX_EXTENSION_MODULE PROJNAMEDLL = { NULL, NULL };extern "C" int APIENTRYDllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved){if (dwReason == DLL_PROCESS_ATTACH){TRACE0("PROJNAME.DLL Initializing!\n");// Extension DLL one-time initializationAfxInitExtensionModule(PROJNAMEDLL, hInstance);// Insert this DLL into the resource chainnew CDynLinkLibrary(Dll3DLL);}else if (dwReason == DLL_PROCESS_DETACH){TRACE0("PROJNAME.DLL Terminating!\n");}return 1; // ok}
Creating a new
CDynLinkLibrary
object during initialization allows the extension DLL to export
CRuntimeClass
objects or resources to the client application. If you are going to use your
extension DLL from one or more regular DLLs, you must export an initialization
function that creates a
CDynLinkLibrary
object. That function must be called from each of the regular DLLs that use
the extension DLL. An appropriate place to call this initialization function
is in the
InitInstance()
member function of the regular DLL's CWinApp-derived object before using any
of the extension DLL's exported classes or functions.
In the
DllMain() that the MFC DLL Wizard generates,
the call to
AfxInitExtensionModule
captures the module's run-time classes (CRuntimeClass structures) as well as
its object factories (COleObjectFactory
objects) for use when the
CDynLinkLibrary object is created. You should
check the return value of
AfxInitExtensionModule; if a zero value is
returned from
AfxInitExtensionModule,
return zero from your
DllMain() function.
If your extension DLL will be explicitly linked to an executable (meaning the
executable calls
AfxLoadLibrary to link to the DLL), you should
add a call to
AfxTermExtensionModule
on
DLL_PROCESS_DETACH.
This function allows MFC to clean up the extension DLL when each process detaches
from the extension DLL (which happens when the process exits, or when the DLL
is unloaded as a result of a
AfxFreeLibrary
call). If your extension DLL will be linked implicitly to the application, the
call to
AfxTermExtensionModule
is not necessary. Applications that explicitly link to extension DLLs must call
AfxTermExtensionModule
when freeing the DLL. They should also use
AfxLoadLibrary
and
AfxFreeLibrary
(instead of the Win32 functions
LoadLibrary()
and
FreeLibrary())
if the application uses multiple threads. Using
AfxLoadLibrary
and
AfxFreeLibrary
ensures that the startup and shutdown code that executes when the extension
DLL is loaded and unloaded does not corrupt the global MFC state.
Because the
MFCx0.DLL
is fully initialized by the time DllMain
is called, you can allocate memory and call MFC functions within DllMain
(unlike the 16-bit version of MFC).
Extension DLLs can take care of multithreading by handling the
DLL_THREAD_ATTACH
and
DLL_THREAD_DETACH
cases in the
DllMain()
function. These cases are passed to
DllMain()
when threads attach and detach from the DLL. Calling
TlsAlloc()
when a DLL is attaching allows the DLL to maintain thread local storage
(TLS) indexes for every thread attached to the DLL.
Note that the header file
AFXDLLX.H
contains special definitions for structures used in extension DLLs,
such as the definition for
AFX_EXTENSION_MODULE
and
CDynLinkLibrary.
You should include this header file in your extension DLL. Note that
it is important that you neither define nor undefine any of the
_AFX_NO_XXX
macros in
stdafx.h.
Note that the sample contains an entry-point function called
LibMain(),
but you should name this function
DllMain()
so that it works with the MFC and C run-time libraries.
|
Initializing Non-MFC DLLs
To initialize non-MFC DLLs, your DLL source code must contain a function
called
DllMain(). The following code presents a
basic skeleton showing what the definition of
DllMain() might
look like:
BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved){switch(ul_reason_for_call){case DLL_PROCESS_ATTACH:...case DLL_THREAD_ATTACH:...case DLL_THREAD_DETACH:...case DLL_PROCESS_DETACH:...}return TRUE;}
Run-Time Library Behavior
The C/C++ run-time library code performs the DLL startup sequence, eliminating
the need to link with a separate module as was necessary in Windows 3.x. Included
in the C/C++ run-time library code is the DLL entry-point function called
_DllMainCRTStartup(). The
_DllMainCRTStartup()
function does several things, including calling
_CRT_INIT, which
initializes the C/C++ run-time library and invokes C++ constructors on static,
non-local variables. Without this function, the run-time library would be left
in an uninitialized state. _CRT_INIT is available
for both a statically-linked CRT, or linking to the CRT DLL
msvcrt.dll, from a user DLL.
While it is possible to specify another entry-point function using the
/ENTRY: linker
option, it is not recommended because your entry-point function would have to
duplicate everything that
_DllMainCRTStartup()
does. When building DLLs in Visual C++,
_DllMainCRTStartup() is linked in automatically
and you do not need to specify an entry-point function using the /ENTRY: linker
option.
In addition to initializing the C run-time library,
_DllMainCRTStartup()
calls a function called
DllMain(). Depending
on the kind of DLL you are building, Visual C++ provides
DllMain()
for you and it gets linked in so that
_DllMainCRTStartup()
always has something to call. In this way, if you do not need to initialize
your DLL, there's nothing special you have to do when building your DLL. If
you need to initialize your DLL, where you add your code depends on the kind
of DLL you are writing.
The C/C++ run-time library code calls constructors and destructors on static,
non-local variables. For example, in the following DLL source code,
Equus and
Sugar
are two static, non-local objects of class
CHorse, defined
in
HORSES.H. There
is no function in source code that contains calls to a constructor function
for
CHorse or to
the destructor function because these objects are defined outside of any function.
Therefore, calls to these constructors and destructors must be performed by
the run-time code. The run-time library code for applications also performs
this function.
#include "horses.h"CHorse Equus(ARABIAN, MALE);CHorse Sugar(THOROUGHBRED, FEMALE);BOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)...
Each time a new process attempts to use the DLL, the operating system creates
a separate copy of the DLL's data: this is called "process attach." The run-time
library code for the DLL calls the constructors for all of the global objects,
if any, and then calls the
DllMain() function with process attach selected. The opposite
situation is process detach: the run-time library code calls
DllMain()
with process detach selected and then calls a list of termination functions,
including atexit() functions, destructors for the global objects, and destructors
for the static objects. Note that the order of events in process attach is the
reverse of that in process detach.
The run-time library code is also called during thread attach and thread
detach, but the run-time code does no initialization or termination on its own.
------------------------------------End
C Run –Time & Dynamic Link Library Part 1------------------------------------