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.