Windows Memory Management
Memory Management is very important for writing high-efficiency Windows programs because Windows is a multitasking system, and its memory management is very different compared to single task DOS. DOS is a single task operating system. After the application is assigned to memory, if it does not actively release it, the system will not change it for it; but Windows is not, it may have multiple applications to share memory at the same time, sometimes In order to make a task better, the Windows system may move, even delete the memory allocated by other tasks. Therefore, when we use memory in a Windows application, we must follow some of Windows memory management to try to improve the utilization of Windows memory.
Windows memory object
The Windows application can apply for allocation to be a memory block, the memory block is the unit of the application operating memory, which is also called a memory object, and operates the memory object through the memory handle in Windows. Memory objects can be divided into global memory objects and local memory objects based on the range of allocation; divided into fixed memory objects, removable memory objects, and delete memory objects depending on the nature.
Fixed memory objects, especially partial fixed memory objects, and DOS memory blocks are similar. Once it is assigned, it will not be moved or deleted unless the application actively releases it. And for local fixed memory objects, its memory handle itself is a 16-bit address of the memory object, which can be accessed directly, without having to lock in memory by locking in memory like other types of memory objects. use.
The movable memory object does not have a fixed address, and the Windows system can move them to a new address at any time. The removable memory object makes Windows effectively utilizes free memory. For example, if a movable memory object separates two free memory objects, Windows can remove the movable memory object, combine two free memory objects into a large free memory object, and implement the merger of memory and fragmentation.
Removable memory objects are similar to the movable memory object, which can be moved by Windows, and when Windows requires large memory space to meet new tasks, it can delete the length of the memory object to 0, discard the memory object. data.
The removable memory object and the delete memory object must be locked using a memory plock function before accessing, and the locked memory object cannot be moved and deleted. Therefore, the application will unlock as quickly as possible after using the memory object. Memory needs to lock and unlock the programmer's burden, but it greatly improves the efficiency of Windows memory utilization, so Windows encourages the use of removable and delete memory objects, and requires applications not use fixed when it is not necessary. Memory object.
Different types of objects are different in the memory in its memory, Figure 6.2 illustrates the location of the memory object in the heap: fixed object is located at the bottom of the heap; the movable object is located on the fixed object; can delete objects The top of the heap began allocation.
Figure 6.1 Memory object allocation location diagram
6.1.2 Local memory object management
The local memory object is allocated in a local heap, and the local heap is the free memory of the application, which can only be accessed by the application's specific instance. The local heap is built in the application's data segment, so the maximum memory space of the user-assigned local memory object cannot exceed 64K. The local stack is applied by the Windows application in the module definition file, and Heapsize specifies the initial spatial size of the local heap in bytes. Windows provides a range of functions to operate local memory objects.
6.1.2.1 Assign partial memory objects
The LOCALALLOC function is used to assign partial memory, which allocates a memory block in the application branch, and returns the handle of the memory block. The LOCALALLOC function can specify the size and characteristics of the memory object, where the main feature has a fixed (LMEM_FIXED), the movable (LMEM_MOVEABLE), and deleteable (LMEM_Discardable). If the application is not assigned in the partial heap, the LOCALALLOC function returns NULL. The following code is used to assign a fixed memory object because the object handle of the local fixed memory object is itself a 16-bit memory near address, so it can be accessed directly by the application. The code is as follows: char Near * pClocalObject;
IF (PCLocalObject = Localalloc (LMEM_FIXED, 32)) {
/ * Use PClocalObject As the Near Address of the Locally Allocated Object, IT IS Not Necessary To Lock
And UNLOCK The Fixed Local Object * /
......
}
Else {
/ * The 32 bytes cannot be allocated .reat accordingly. * /
}
6.1.2.2 Plugging and Unlock
The fixed local memory object assigned by the above program segment can be accessed directly by the application, but Windows does not encourage the use of fixed memory objects. Therefore, when using removable and delete memory objects, it is often used to use the lock and unlocking of the memory object.
Whether it is a removable object or a delete object, it is constant in the memory object after it assigns it. However, the application cannot access memory objects through the memory handle, and the application must access the memory object and must obtain its near address, which is implemented by calling the locallock function. The LOCALLOCK function is temporarily fixed to a part of the local stack and returns the near address value of the address. This address is available for application access memory objects, which is valid before the application calls the localunlock function. . How to lock and unlock the movable memory object, please see the following code:
Hlocal hlocalobject;
Char Near * PClocalObject;
IF (HlocalObject = Localalloc (LMEM_MOVEABLE, 32)) {
IF (PCLocalobject = Locallock (HlocalObject)) {
/ * Use PClocalObject As the Near Address of the Locally Allocated Object * /
......
Localunlock (Hlocalobject);
}
Else {
/ * The Lock Failed. React Accordingly. * /
}
}
Else {
/ * The 32 bytes cannot be allocated. React accountingly. * /
}
After using the memory object, you should unlock it as early as possible, because Windows cannot move the memory object being locked. When the application is to assign other memory, Windows cannot use the area that is locked, can only be seen around it, which reduces the efficiency of Windows Memory Management.
6.1.2.3 Changing the local memory object
After local memory object assignment, you can call the LocalRealloc function to modify. The LocalRealloc function can change the size of the local memory object without damaging its content: Regional content. In addition, the localRealloc function can also change the properties of the object, such as change the property from LMEM_MOVEABLE to LMEM_DISCARDABLE, or in turn, you must specify the LMEM_MODIFY option at this time. However, the LocalRealloc function cannot change the size and properties of the memory object at the same time, and cannot change the memory object with the LMEM_FIXED property and change the memory objects of other properties to the LMEM_FIXED attribute. How to change a movable memory object to be delete, please see the example below: HlocalObject = Localalloc (32, LMEM_MOVEABLE);
......
HlocalObject = localRealloc (Hlocalobject, 32, LMEM_MODIFY | LMEM_KISCARDABLE);
6.1.2.4 Release and Delete
Assigned local memory objects can be deleted and released using the localdiscard and localfree functions, delete and release only if the memory object is not locked.
The localfree function is used to release the local memory object, and when a local memory object is released, the content is removed from a local heap, and its handle is also removed from a valid local memory table, the original memory handle is not available. The localdiscard function is used to delete local memory objects, which only removes the contents of the object, and keep its handle to be valid, and the user can use this memory handle to reassign a memory with the localRealloc function with the LOCALREALLOC function.
In addition, Windows also provides functions localsize to detect space occupied by objects; function localflags is used to detect whether memory objects can be deleted, whether it has been deleted, and its lock count value; function localcompact is used to determine the available memory of local stacks.
6.1.3 Global Memory Object Management
The global memory object is allocated in the global heap, and the global stack includes all system memory. In general, the application performs large memory allocation in the global heap (about 1 kB), which can also be assigned a giant memory greater than 64K in the global heap, which will be introduced later.
6.1.3.1 Assign global memory objects
Global memory objects are allocated using the GlobalAlloc function, which is similar to the local memory objects with Localalloc allocation. Examples of using GlobalLoc we will give it to Globalock.
6.1.3.2 Plugging and Unlock
Global memory objects are locked using the Globalock function, and all global memory objects must be locked before access. GLOBALLOCK locks objects in the memory fixed position and returns a far pointer, which is valid before calling GlobalUnlock.
GlobalLock and Locallock are slightly different, because global memory objects may be used by multiple tasks, so the object may have been locked when using GlobalLock to lock a global memory object, in order to handle this, Windows adds a lock counter. When using GLOBALLOCK to lock the global memory object, the lock counter adds 1; when using the GLOBALUNLOCK to unlock the object, the lock counter minus 1, only when the lock counter is 0, Windows really unlocked this object. The use of Globalalloc and GlobalLock is as follows:
Hglobal HglobalObject; Char Far * lpglobalObject;
IF (HglobalObject = GlobalAlloc (GMEM_MOVEABLE, 1024)) {
IF (lpglobalobject = Globalock (HglobalObject)) {
/ * Use lpglobalObject as the far address of the global allocated object. * /
......
GlobalUnlock (HglobalObject);
}
Else {
/ * The lock failed .reat accordingly. * /
}
}
Else {
/ * The 1024 bytes cannot be allocated. React accountingly. * /
}
6.1.3.3 Modify the global memory object
Modifying global memory objects using the GlobalRealloc function, it is similar to the LocalRealloc function, and details will not be described here. Modifying the special place for global memory objects is on the modification of the giant object, this will be described later.
6.1.3.4 Memory release and other operations
The global memory object uses the GlobalFree function and GlobalDiscard to release and delete, and its role is similar to LocalFree and LocalDiscard. The globalsize function can detect memory object size; the globalflags function is used to retrieve whether the object can be deleted, whether it has been deleted; the GlobalCompact function can detect the global heap available memory size.
6.1.3.5 giant memory object
If the size of the global memory object is 64kb or more, it is a giant memory object, and the GlobalLock function is used to lock the giant memory object will return a giant pointer. Assign a 128KB giant memory object, use the following code segment:
Hglobal HglobalObject;
Char huge * hpglobalObject;
IF (hglobalobject = globalalloc (gmem_moveable, 0x20000l)) {
IF (HPGLOBALOBJECT = (char huge *) GlobalLock (HGLOBALOBJECT)) {
/ * Use HPGLOBALOBJECT As The Far Address of The Global Allocated Object. * /
...
GlobalUnlock (HglobalObject);
}
Else {
/ * The Lock Failed. React Accordingly. * /
}
}
Else {
/ * The 128k cannot be allocated. React accountingly. * /
}
The modification of the giant memory object has a certain particularity. When the object size increases and exceeds a multiple of 64K, Windows may have to return a new global handle for the redistributed memory object, so the modification of the giant memory object should be in the following form:
IF (HTEMPHUGEOBJECT = GlobalRealloc (HhugeObject, 0x20000L, GMEM_MOVEABLE)) {
HhugeObject = HTEMPOBJECT;
}
Else {
/ * The Object Could Not Be Reallocated. React Accordingly. * /
}
6.1.4
Windows uses segments concept to manage the memory, paragraphs and data segments, and one application can have multiple code segments and data segments. The number of code segments and data segments determines the memory mode of the application, and Figure 6.2 illustrates the relationship between memory mode and application code segment and data segment. Code segment number
Single-segment
Multi-segment
Data segment
Single-segment
Small memory mode
Medium memory mode
Multi-segment
Compressed memory mode
Large memory mode
Figure 6.2 Memory mode diagram
The management of the segment is very similar to the management of the global memory object, and the segment can be fixed, movable, and deleted, specified in the application's module definition file. The segment is allocated in the global memory, and Windows encourages the use of removable code segments and data segments, which can improve their memory utilization efficiency. Using the deleted code segment can further reduce the impact of the application on the memory, if the code segment is delete, Windows is deleted to meet the request for global memory when necessary. The deleted segment is monitored by Windows. When the application uses the code segment, Windows automatically reloads them.
6.1.4.1 code segment
The code segment is a machine command that does not exceed 64k bytes, which represents all or part of the application instruction. The data in the code segment is read-only, and the write operation to the code segment will cause a general purpose protection (GP) error.
There is at least one code segment for each application, such as the example of our previous chapters, only one code segment. Users can also generate applications with multiple code segments. In fact, most Windows applications have multiple code segments. By using multi-code segments, users can reduce the size of any given code segment to several instructions that completed certain tasks. This way, you can optimize the use of the application by enabling some segments to be deleted.
Both models and large-mode applications use multi-code segments, each of which is one or more source files. For multiple source files, separate them separately, name each segment belonging to the compiled code, and then connect. The properties of the segment are defined in the module definition file. Windows uses the segments statement to complete this task, as follows the code defines the properties of four segments:
Segments
Memory_main preload moveable
Memory_init loadoncall moveable discardable
Memory_WndProc Preload Moveable
Memory_about loadoncall Moveable Discardable
Users can also define default attributes for all unlvious defined code segments in the module definition file. For example, to define all segments in the segments statement as delete, available below:
Code movable discardable.
6.1.4.2 Data Section
Each application has a data segment, the data segment contains the stack, local heap, static data, and global data of the application. The length of a data segment cannot exceed 64K. The data segment can be fixed or movable, but it cannot be deleted. If the data segment is movable, Windows automatically locks the control steering application, and the mobile data segment may be Move, thus do not retain the length pointer to the variable in the data segment, and when the data segment moves, the long pointer will fail.
Define the properties of the data segment in the module definition file, the default value of the property is MoveAble and Multiple. Multiple Attributes Copy an application data segment for each instance of the application, which means that the content of the data segment in each application instance is different.
6.1.5 Memory Manager Example Memory
Application Memory examples have some memory management, which is a medium-mode Windows application that uses delete code segments. The Memory program has four C language source programs that displays four code segments in the module definition file. The corresponding module definition files and makefile files have some modifications, readers can compare the Memory programs and 5.1.2 examples. Experience the difference between them. In addition, the reader can use the Windows Heap Walker (HEAPWalk.exe) provided by Visual C to observe each segment of the Memory runtime after compiling and connecting the application Memory. // Module 1: Memory_Main
#include "windows.h"
#include "memory.h"
Handle hinst;
/ ************************************************** ***********************************
Module: Memory1.c
Function: WinMain (Handle, Handle, LPSTR, INT)
Purpose: Calls Initialization Function, Processes Message Loop
*********************************************************** ********************************** /
Int Pascal Winmain (Hinstance, Hprevinstance, LPCMDLINE, NCMDSHOW)
Handle hinstance;
Handle Hprevinstance;
LPSTR LPCMDLINE;
Int ncmdshow;
{
MSG msg;
IF (! hprevinstance)
IF (! initApplication (hinstance))
Return (False);
IF (! initinstance (hinstance, ncmdshow))
Return (False);
While (GetMessage (& MSG, NULL, NULL, NULL) {
TranslateMessage (& MSG);
DispatchMessage (& MSG);
}
Return (msg.wparam);
}
// Module 2: Memory_init
#include "windows.h"
#include "memory.h"
/ ************************************************** ***********************************
Module: Memory2.c
Function: initApplication (Handle)
Purpose: Initializes Window Data And Registers WINDOW CLASS
*********************************************************** ********************************** /
BOOL INITAPPLICATION (Hinstance)
Handle hinstance;
{
WNDCLASS WC;
wc.style = null;
Wc.lpfnwndproc = mainwndproc;
wc.cbclsextra = 0;
wc.cbWndextra = 0;
wc.hinstance = hinstance;
Wc.hicon = loading;
Wc.hcursor = loadingcursor (null, idc_arrow); wc.hbrbackground = color_window 1;
Wc.lpsz GeneNuname = "MemoryMenu";
wc.lpszclassname = "MemorywClass";
Return (RegisterClass (& WC));
}
/ ************************************************** ***********************************
Module: Memory2.c
Function: InitInstance (Handle, Int)
Purpose: Saves Instance Handle and Creates Main Window
*********************************************************** ********************************** /
Bool InitInstance (Hinstance, ncmdshow)
Handle hinstance;
Int ncmdshow;
{
Hwnd hwnd;
Hinst = hinstance;
HWnd = CREATEWINDOW ("MemoryWClass", "Memory Sample Application",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, HINSTANCE, NULL
IF (! hwnd)
Return (False);
ShowWindow (HWND, NCMDSHOW);
UpdateWindow (HWND);
Return (TRUE);
}
// Module 3: Memory_WndProc
#include "windows.h"
#include "memory.h"
/ ************************************************** ***********************************
Module: Memory3.c
Function: MainWndProc (HWND, UINT, WPARAM, LPARAM)
Purpose: Processes Messages
Messages:
WM_COMMAND - Application Menu (About Dialog Box)
WM_DESTROY - DESTROY WINDOW
*********************************************************** ********************************** /
Long Far Pascal__export mainwndproc (HWnd, Message, WParam, LPARAM)
Hwnd hwnd;
Uint Message;
WPARAM WPARAM;
LParam Lparam;
{
FarProc LPPROCABOUT;
Switch (Message) {
Case WM_COMMAND:
IF (wPARAM == IDM_ABOUT) {
LPPROCABOUT = MakeProcinstance (About, Hinst);
Dialogbox (Hinst, "AboutBox", HWnd, LPPROCABOUT;
FreeProcinstance (LPPROCABOUT);
Break;
Else
Return (DEFWINDOWPROC (HWND, MESSAGE, WPARAM, LPARAM);
Case WM_DESTROY:
PostquitMessage (0);
Break;
DEFAULT:
Return (DEFWINDOWPROC (HWND, MESSAGE, WPARAM, LPARAM);
}
Return (NULL);
}
// Module 4: Memory_about
#include "windows.h"
#include "memory.h"
/ ************************************************** ***********************************
Module: Memory4.c
Function: About (hwnd, unsigned, words, long)
Purpose: Processes Messages for "About" Dialog Box
Messages:
WM_INITDIALOG - INITIALIZE DIALOG BOX
WM_COMMAND - INPUT Received
*********************************************************** ********************************** /
Bool Far Pascal __Export About (HDLG, Message, WPARAM, LPARAM)
HWND HDLG;
unsigned message;
Word wparam;
Long lparam;
{
Switch (Message) {
Case WM_INITDIALOG:
Return (TRUE);
Case WM_COMMAND:
IF (wparam == idok || wparam == iDCancel) {
EndDialog (HDLG, TRUE);
Return (TRUE);
}
Break;
}
Return (False);
}
Below is a small segment in the module definition file, which uses the / NT option to name each segment when compiling each module.
Memory1.obj: Memory1.c $ (Memory1_DEP)
$ (Cc) $ (cflags) $ (ccreatepchflag) / c / nt membrate_main memory1.c
Memory2.obj: Memory2.c $ (Memory2_DEP)
$ (Cc) $ (cflags) $ (cusepchflag) / c / nt membrate_init memory2.c
Memory3.obj: Memory3.c $ (Memory3_DEP)
$ (Cc) $ (cflags) $ (cusepchflag) / c / nt membrate_wndproc memory3.c
Memory4.obj: Memory4.c $ (Memory4_DEP)
$ (Cc) $ (cflags) $ (cusepchflag) / c / nt memory_about memory4.c
6.2 Dynamic Connection Library DLL
Using a dynamic connection library is a very important feature of Windows, which makes multiple Windows applications to share function code, data, and hardware, which greatly improves the utilization of Windows memory.
Dynamic Library is an executable module that is included in the Windows application call execution to serve the application. It is very similar to the previous C function library we used, its main difference is that the dynamic connection library is running, the C function library (static connection library) is the connector when generating executable files (LINK) connection. The code in the static connection library has been connected to the application module after application generation, but the code in the dynamic connection library is only moving into the corresponding code in the DLL only when the application is to use the code segment. In order to allow the application to be able to transfer the correct code in the DLL during execution, Windows provides the introduction library for the dynamic connection library. Windows When connecting to generate an application, if you use a dynamic connection function, the connector does not copy any code in the DLL, which simply specifies the desired function in the DLL in the application module, when When the application is running, these positioning information establish a dynamic connection between the executable application and the dynamic connection library. The difference between the static library, the introduction library and the dynamic library is shown in Table 6.1. Table 6.1 Differences between static libraries, introduction library and dynamic libraries
Library type
Connection time
Instance library
Function example
Description
Static library
Connection
Mlibcew.lib
Strcpy
Function code
Introduction
Connection
Libw.lib
TEXTOUT
Positioning information
Dynamic library
Runtime
Gdi.exe
TEXTOUT
Function code
The DLL cannot be executed independently, nor does the message loop can be used. Each DLL has an entry point and an exit point, has its own instance handle, data segment, and local heap, but the DLL does not stack, which uses the stack of the calling program. The DLL also includes a .C file, .h file, .rc file, and .def file, in addition, the LibENTRY.OBJ file in the SDK library is usually added when connected.
6.2.1 Creating a Dynamic Library
To create a dynamic connection library, there are at least three files:
· C language source file;
· A module definition file (.def);
· Makefile file.
With these documents, you can run Microsoft's program maintenance mechanism (NMAKE), compile and connect the source code file, generate a DLL file.
6.2.1.1 Creating a C language source file
As with other C applications, dynamic connection libraries can contain multiple functions, each function to be declared with a FAR before being used by other applications or libraries, and use an Exports statement in the library's module definition file. Here is a complete C language source file:
/ ************************************************** ***********************************
Program: DLLDRAW.C
Purpose: Contains Library Routines for Drawing
*********************************************************** **************************** /
#include "windows.h"
#include "stdlib.h"
#include "dlldraw.h"
/ ************************************************** ***********************************
Function: Libmain (Handle, Word, Word, LPSTR)
Purpose: Is Called by Libentry. Libentry is Called by Windows When the DLL IS loaded.
The LibENTRY ROUTINE IS Provided in The Libentry.obj in The SDK LIBRARIES
(The Source LibENTRY.ASM is Also Provided.)
.
The libntry calls libmain. The libmain function below satisfies That Call.
.
In this Example, No Initialization Tasks Are Required. Libmain Should Return A Value of 1
If The Initialization Is Successful.
*********************************************************** **************************** /
Int Far Pascal Libmain (HMODULE, WDATASEG, CBHEAPSIZE, LPSZCMDLINE)
Handle hModule;
Word wdataseg;
Word cbheapsize;
LPSTR LPSZCMDLINE;
{
Return 1;
}
/ ************************************************** ***********************************
Function: WEP (Int)
Purpose: Performs Cleanup Tasks When the DLL IS Unloaded. WEP () IS Called
Automatically by Windows When THE DLL IS Unloaded (no remaining tasks still "
The dll loaded. It is strongly recommented That A DLL HAVE A WEP () Function,
Even if it does Nothing But Returns Success (1), AS in this Example.
*********************************************************** **************************** /
Int far pascal __export _wep (bsystemexit)
Int bsystemexit;
{
Return (1);
}
/ ************************************************** ***********************************
Function: RandRect (Rect *) - Get a Rand Rectangle Position
*********************************************************** ********************************** /
Void RandRect (RC)
Rect Far * RC;
{
RC-> TOP = RAND ()% 400;
Rc-> Left = rand ()% 600;
Rc-> bottom = rand ()% 400;
Rc-> Right = rand ()% 600;
}
/ ************************************************** ************************** Function: DrawBox (HWnd, HPEN, HBRUSH) - Draw A Box
Purpose: Draw A Box with specified pen and brush.
*********************************************************** ********************************** /
Void Far Pascal __Export DrawBox (HWnd, HPEN, HBRUSH)
Hwnd hwnd;
HPEN HPEN
Hbrush Hbrush;
{
HDC HDC;
HPEN HOLDPEN
Hbrush Holdbrush;
Rect RC;
RandRect (Rect Far *) & rc);
HDC = Getdc (hwnd);
Holdpen = SELECTOBJECT (HDC, HPEN);
Holdbrush = SELECTOBJECT (HDC, Hbrush);
Rectangle (HDC, RC.LEFT, RC.TOP, RC.right, RC.BOTTOM);
SelectObject (HDC, HoldPen);
SELECTOBJECT (HDC, HOLDBRUSH);
ReleaseDC (HWND, HDC);
}
/ ************************************************** ***********************************
Function: Drawcircle (HWND, HPEN, HBRUSH) - Draw A Circle
Purpose: Draw a circle with specified pen.
*********************************************************** ********************************** /
Void Far Pascal __Export Drawcircle (HWnd, HPEN, HBRUSH)
Hwnd hwnd;
HPEN HPEN
Hbrush Hbrush;
{
HDC HDC;
HPEN HOLDPEN
Rect RC;
RandRect (Rect Far *) & rc);
HDC = Getdc (hwnd);
Holdpen = SELECTOBJECT (HDC, HPEN);
Arc (HDC, RC.LEFT, RC.TOP, RC.right, RC.BOTTOM, RC.LEFT, RC.TOP, RC.LEFT, RC.TOP);
SelectObject (HDC, HoldPen);
ReleaseDC (HWND, HDC);
}
/ ************************************************** ***********************************
Function: Drawpie (HWnd, HPEN, HBRUSH) - Draw A Pie
PURPOSE: Draw a Pie with specified pen and brush.
*********************************************************** ********************************** /
Void Far Pascal __Export Drawpie (HWnd, HPEN, HBRUSH)
Hwnd hwnd;
HPEN HPEN
Hbrush Hbrush;
{
HDC HDC;
HPEN HOLDPEN
Hbrush Holdbrush;
Rect RC;
RANDRECT (Rect Far *) & rc); HDC = GetDC (HWND);
Holdpen = SELECTOBJECT (HDC, HPEN);
Holdbrush = SELECTOBJECT (HDC, Hbrush);
PIE (HDC, RC.LEFT, RC.TOP, RC.right, RC.BOTTOM, RC.LEFT, RC.TOP, RC.RIGHT, RC.TOP);
SelectObject (HDC, HoldPen);
SELECTOBJECT (HDC, HOLDBRUSH);
ReleaseDC (HWND, HDC);
}
In the above source code, two functions are required for the DLL source code, which is the DLL entry function libmain and the exit function WEP.
The libmain function is the entry point of the DLL, which is called by the DLL automatic initialization function libENTRY, mainly used to complete some initialization tasks. Libmain has four parameters: Hint, WDataseg, Cbheapsize and Lpszcmdline. Hinst is an instance handle of a dynamic connection library; WDATASEG is the value of the data segment (DS) register; CBHEAPSIZE is the size of the stack defined by the module definition file, and the libentry function is initialized by this value; LPSZCMDline contains information of the command line.
The WEP function is the standard exit function of the DLL, which is executed by the Windows call before the DLL is removed to complete some of the necessary clearing work. The WEP function uses only one parameter NPARAMETER, which is used to indicate the termination status.
Other functions in the source file are DLLs to provide library functions provided by the application, and the DLL designer can add the features you need, such as DRAWBOX, DRAWPIE, and DRAWCIRCLE.
6.2.1.2 Creating a DLL module definition file
Each DLL must have a module definition file that is used to provide import information for definition library properties when using a link connection. Here is a simple module definition file instance:
Library DLLDRAW
EXTYPE WINDOWS
Code Preload Moveable Discardable
Data Prelioad Single
Heapsize 1024
Exports
WEP @ 1 ResidentName
Drawbox @ 2
Drawcircle @ 3
Drawpie @ 4
Keyword library is used to identify this module is a dynamic connection library, which is later Database name DrawDLL, which must be the same as the dynamic connection library file name.
The keyword SINGLE in the DATA statement is required, it indicates that the DLL has only a single data segment regardless of the application access DLL.
Other keywords The usage is the same as the module definition file of the Windows application, which has been described earlier, see 5.1.2.3.
6.2.1.3 Compile a Makefile file
NMAKE is a Microsoft's program maintenance mechanism that controls the creation of execution files to ensure that only the necessary operations are executed. There are five tools to create a dynamic connection library:
CL Microsoft C Optimize the compiler, which compiles the C language source file into a target file .Obj. The Link Microsoft segmentation can perform a connector that generates a dynamic connection library for the target file and static library connection. There are five parameters, separated by commas: The first argument lists all the target files (.Obj) for all dynamic connection libraries, if the standard dynamic connection initialization function is used, the libentry.obj file must be included; Two parameters indicate the final executable file name, generally used .dll as the extension; the third parameter lists the introduction libraries and static libraries required to create a dynamic connection library; the fifth parameters are module definition files. Implib Microsoft introduces the library manager that creates an extension library based on the dynamic connection library module definition file. RC Microsoft Windows Resource Compiler. All dynamic connection libraries must be compiled with RC to make them compatible with Windows 3.1. Mapsym Microsoft Symbol file generator, it is an optional tool, which is only used for debug versions. The following is an instance of a Makefile file:
# Microsoft Visual C Generated Build Script - Do Not Modify
Proj = DLLDRAW
Debug = 1
Progtype = 1
Caller =
Args =
DLLS =
D_rcdefines =
R_rcdefines =
Origin = MSVC
Origin_Ver = 1.00
Projpath = D: / JDX / Winsamp / DLLDRAW /
USEMFC = 0
CC = CL
CPP = CL
CXX = CL
Ccreatepchflag =
Cppcreatepchflag =
CUSEPCHFLAG =
CPPUSEPCHFLAG =
FigSTC = SELECT.C
Firstcpp =
RC = RC
CFLAGS_D_WDLL = / NOLOGO / YX / ZP1 / OD / D "_Debug" / d "_windows" / d "_windll" / g2 / w3 / asw / fr / gd / zi
CFLAGS_R_WDLL = / NOLOGO / YX / ZP1 / OX / D "NDEBUG" / D "_Windows" / D "_windll" / g2 / w3 / asw / fr / gd / gs
LFLAGS_D_WDLL = / NOLOGO / NOD / OneRROR: NOEXE / Align: 16 / CO
LFLAGS_R_WDLL = / NOLOGO / NOD / OneRROR: Noexe / Align: 16
LIBS_D_WDLL = OldNames Libw Commdlg Shell Olecli Olesvr SDLLCEW LIBW
LIBS_R_WDLL = OldNames Libw Commdlg Shell Olecli Olesvr SDLLCEW LIBW
Rcflags = / NOLOGO
Resclags = / noLogo -t
Runflags =
Deffile = dlldraw.def
Objs_ext =
LIBS_EXT =
! IF "$ (debug) ==" 1 "
CFLAGS = $ (cflags_d_wdll) LFLAGS = $ (LFLAGS_D_WDLL)
LIBS = $ (libs_d_wdll)
MapFile = NUL
RcDefines = $ (D_RCDefines)
Else
Cflags = $ (cflags_r_wdll)
LFLAGS = $ (LFLAGS_R_WDLL)
LIBS = $ (libs_r_wdll)
MapFile = NUL
Rcdefines = $ (r_rcdefines)
! ENDIF
! IF [if exist msvc.bnd del msvc.bnd]
! ENDIF
SBRS = DLLDRAW.SBR
All: $ (proj) .dll $ (proj) .BSC
DLLDRAW.OBJ: DLLDRAW.C $ (DLLDRAW_DEP)
$ (Cc) $ (cflags) $ (cusepchflag) / c DLLDRAW.C
$ (Proj) .dll :: DLLDRAW.OBJ $ (OBJS_EXT) $ (Deffile)
Echo> NUL @ << $ (proj) .crf
DLLDRAW.OBJ
$ (Objs_ext)
$ (Proj) .dll
$ (MapFile)
D: / MSVC / LIB /
$ (LIBS)
$ (Deffile);
<<
LINK $ (LFLAGS) @ $ (proj) .crf
$ (Rc) $ (resflags) $ @
Implib / Nowep $ (Proj) .LIB $ (Proj) .dll
Run: $ (proj) .dll
$ (Proj) $ (Runflags)
$ (Proj) .BSC: $ (SBRS)
BSCMAKE @ <<
/ o $ @ $ (SBRS)
<<
6.2.2 Application Access DLL
Application To access dynamic connection library functions, it should do three things below: create a library function prototype, call library functions, and import library functions. The establishment library function prototype is generally resolved by the header file containing the dynamic connection library in the C language source file, the following is a header file instance of a dynamic connection library:
#define sl_box 1 / * Draw A Solid Border Around The Rectangle * /
#define sl_block 2 / * Draw a solid Rectangle * /
#define sl_extend 256 / * EXTEND THE CURRENT PATTERN * /
#define sl_type 0x00ff / * mask out everything but the type flags * /
#define sl_special 0xff00 / * Mask Out Everything But The Special Flags * /
Void Far Pascal __Export DrawBox (HWND, HPEN, HBRUSH);
Void Far Pascal__export drawcircle (hwnd, hpen, hbrush);
Void Far Pascal __Export Drawpie (HWND, HPEN, HBRUSH);
The header file contains the prototype statement of each library function, the purpose of the prototype statement is to define the parameters and return values of the compiler to enable the compiler to create the code of the call library function correctly. After the prototype statement is defined, the application can call a function of the dynamic connection library like calling a static connection function.
The extraction function in the application call DLL also introduces it in the application, generally three methods: (1) implicit introduction
The most commonly used simple method is implicitly introduced, this method is to list the introduction library created by the dynamic connection library in the application's connection command line, so that the application is like the DLL of the DLL is like Use the functions in the static library.
(2) Explicit introduction
As with implicit introduction, explicit introduction is also done when connected, which is completed by collecting the required function lists in the IMPORTS statement of the application's module definition file. For DLL functions that define in the module definition file, in the form of introduction function name, dynamically connect the library name, and entry serial number, such as:
Imports
Drawbox = dlldraw.2
If the DLL module definition file does not define the entry serial number of the extraction function, use the following introduction statement:
Imports
DLLDRAW.DRAWBOX
(3) Dynamic introduction
The application can dynamically connect the DLL function at runtime. When you need to call the DLL's extraction function, the application first loads the library and retrieves the desired function address directly, and then calls the function. For example, how the application is dynamically connected to the CREATEINFO function in the Windows Info.dll library, use the following code:
Hinstance hlibrary;
FarProc LPFUNC;
Hlibrary = loadingLibrary ("info.dll");
IF (HLibrary> = 32) {
LPFUNC = GetProcaddress (Hlibrary, "CreateInfo");
IF (lpfunc! = (farproc) NULL)
(* LPFUNC) ((LPSTR) Buffer, 512);
Freelibrary (HLibrary);
}