INF: Windows Exit Procedure (WEP) for a Dynamic-Link Library

ID Number: Q66360

3.00 3.10

WINDOWS

docerr

Summary:

The Windows Exit Procedure (WEP) is designed to be the last function

called in the last reference to a dynamic-link library (DLL) before

the DLL is removed from memory. WEPs were introduced in version 3.0 to

allow each DLL that hooked interrupts and/or modified I/O ports to

clean up when the DLL was unloaded. Under Windows version 3.0, this

cleanup should be the WEP's only task.

In Windows version 3.0, some details regarding the WEP are not completely

documented. This article addresses issues and provides guidance for

using a WEP.

More Information:

In Windows version 3.0, the WEP is called on a Kernel stack that is too

small to process almost any Windows API call. These calls must be

avoided in the WEP. The prohibition includes calls to the global memory

routines. MS-DOS calls go through a Kernel intercept and can also

overflow the stack.

In some low memory situations, the WEP can be called before the

library initialization routine and before the library's DGROUP has

been created. WEP code that relies on the library initialization

function should verify that the initialization has been called. Also,

WEP code that relies on the DGROUP being valid needs to check for

this. The following three-step procedure is recommended for this type

of situation:

1. Verify that the DS is present by issuing a LAR instruction and

checking the present bit. This will indicate that the DS has been

loaded (the DS register will always contain a valid selector).

2. Add code in the library initialization code to set a flag in the

data segment when it is executed. Once the WEP code has verified

that the DS exists, it should test this flag to determine if the

initialization code has been run.

3. A WEP must be declared in the EXPORTS section of the DEF file for

the DLL. The following is an example declaration:

WEP @1 RESIDENTNAME

The keyword RESIDENTNAME makes the name of the function (WEP)

resident at all times. It is NOT necessary to use the ordinal

reference 1. This clarifies information presented on pages 20-25

through 20-27 of the "Microsoft Windows Software Development Kit

Guide to Programming."

When it is time for the Windows Kernel to remove the DLL, it calls the

WEP function by name. In low memory situations, it is possible for the

DLL's nonresident name table to be discarded from memory. If this

happens, the Kernel must load the table to determine if a WEP function

was declared for the DLL. Under low memory conditions, this may fail

and cause the system to FatalExit (also known as a RIP). Using the

RESIDENTNAME option forces Windows to keep the name entry for the WEP

in memory at all times that the DLL is in use.

Similarly, the WEP must be placed in a fixed code segment. If,

instead, it is placed in a discardable segment, in low memory

situations, Windows must load the WEP segment back from disk so that

the WEP function can be called before the DLL is discarded. Under

certain low memory conditions, attempting to load the segment

containing the WEP may cause the system to RIP. This would not happen

if the WEP is in a fixed segment. One word of warning, since fixed DLL

code is also page locked, keep the amount of fixed code to a minimum.

The following is the proper declaration of a WEP in a DLL:

int FAR PASCAL WEP (int iParam)

{

return 1;

}

In the "Microsoft Windows Software Development Kit Guide to

Programming," the WEP declarations in section 20.3.1 on page 20-20 and

section 20.6.3 on page 20-41 are incorrect. Change "VOID" to "int" and

each WEP procedure returns the value of 1.

If a DLL is explicitly loaded by the LoadLibrary function, its WEP will

be called when the DLL is freed, by the FreeLibrary function. If the DLL

is implicitly loaded, the WEP will be called; however, CodeView for

Windows (CVW) will indicate that the application has been terminated

before the WEP is called.

However, if an application that uses a DLL closes properly, and leaves

Windows in an unstable state, there may be a problem with the way the

WEP is declared. As stated above, the WEP should be placed in a fixed code

segment. If the WEP is discarded under low memory conditions, the

application may fail with an unrecoverable application error (UAE).

In the DEF file for the DLL, the name listed in the LIBRARY statement

must be in uppercase letters and must match the name of the DLL file.

No assumptions may be made concerning the order in which the WEPs of

dependent DLLs are called. It is unlikely to be either the order in

which the DLLs were loaded or the reverse of this. It is completely

dependent upon the order in which the DLLs usage counts go to zero.

In summary, DLLs for Windows version 3.0 require that a WEP be present.

Not providing a WEP may cause the DLL to function improperly under

certain low memory situations.

In Windows version 3.1, the WEP will be called on the stack of the

application that is terminating. This will allow the WEP access to

Windows APIs. However, it is still necessary to place the WEP in a

fixed segment.

Additional reference words: 3.00 3.10 3.x