DLL Remains in Memory After Calling Application Terminates

ID Number: Q68320

3.00

WINDOWS

Summary:

Every time a Windows application loads a DLL, the module usage count

for that DLL is incremented by 1. As long as the module usage count is

greater than zero, the DLL will remain in memory. Windows decrements

this count when FreeLibrary() is called, and determines whether the

library should be discarded.

If a DLL remains in memory after all the calling applications

terminate, the system will experience problems when one of the calling

applications is loaded for a second time.

More Information:

When a DLL remains in memory after its calling applications have

terminated, it is likely that one of the following situations has

occurred:

1. The library name in the module definition (DEF) file contains

lowercase letters.

2. FreeLibrary() is not called.

3. FreeLibrary() is called from a windows exit procedure (WEP).

If the problem is caused by the first situation, convert the name of

the library in the module definition file to uppercase letters.

Because of an interaction problem between LINK 5.10 and Windows 3.00,

Windows will increment the lock count of the DLL twice, rather than

once, when the library is loaded into memory. Thus, when FreeLibrary()

is called to decrement the lock count of the DLL, the lock count is

not decremented to zero. For more information on this interaction,

query on the following words:

prod(winsdk) and DLL and unload

If the library name in the module definition file is in uppercase

letters, you will have to investigate the situation further. One

approach is to conditionally compile some debugging code into the

application so that you can monitor the DLL usage count when the

application calls LoadLibrary() and FreeLibrary(), and at the

application's entry and exit points. The debugging code may resemble

the following:

#define MODULEUSAGE // Use this to compile the debugging code

#ifdef MODULEUSAGE

char szModUsageBuf[80]; // Debug output buffer

#endif

#ifdef MODULEUSAGE // Use this to monitor the reference count

wsprintf((LPSTR)szModUsageBuf,

(LPSTR)"Usage Count:%u %s\n\r\0",

GetModuleUsage(GetModuleHandle((LPSTR)<Name Of DLL>)),

(LPSTR)<Name Of DLL>);

OutputDebugString((LPSTR)szModUsageBuf);

#endif

The first piece of the above code defines the MODULEUSAGE variable so

that the debugging blocks of code will compile. The second piece

defines an output buffer for temporary use. The third piece of code

displays the usage count of the DLL on the debugging monitor. The

monitoring code should be placed into the application in the following

three points:

1. At the start of the application, if the DLL is implicitly loaded

2. Immediately after each LoadLibrary() call, if the DLL is explicitly

loaded

3. Immediately before the application terminates

The information provided by this debug code will provide evidence that

the usage count is or is not growing and shrinking by 1 (one) with

each call to LoadLibrary() and FreeLibrary().

A third situation that can cause a DLL to remain in memory after all

calling applications terminate occurs if the WEP in the DLL is used to

free the library. The WEP is designed to be the standard place where a

DLL can perform any required tasks before the DLL is removed from

memory. Unfortunately, in Windows 3.00, this standard is not fully

implemented and the WEP may or may not be called. For more information

on the WEP function, query on the following words:

prod(winsdk) and WEP

If the design of a DLL requires the WEP in the DLL to free another

DLL, the second library will not be freed if the first library's WEP

is not called. To remedy this situation, remove the FreeLibrary() call

from the WEP and place it into a termination routine. Any application

using the library can explicitly call the termination routine to

ensure that the correct FreeLibrary() call is made.