ID Number: Q74796
3.00
WINDOWS
Summary:
In the Microsoft Windows graphical environment, the GlobalNotify
function works with memory allocated using the GMEM_NOTIFY and
GMEM_DISCARDABLE flags as follows:
1. The memory is allocated.
2. Windows runs low on memory, so it discards the least-recently used
(LRU) block of discardable memory.
3. If the block to be discarded was allocated with the GMEM_NOTIFY
flag set, Windows calls the appropriate notification procedure.
4. The notification procedure gives permission to discard the memory.
This article discusses these four steps and some related issues.
More Information:
The notification procedure must be in a fixed code dynamic-link
library (DLL). This ensures that the memory containing the
notification procedure will not be discarded. Although the application
allocated the memory, the application (except for the notification
procedure) is not in memory because memory is low.
The application has two methods available to instruct the notification
procedure regarding a particular block of memory:
1. Store disposition instructions at the beginning of the block of
memory. For example, if the notification should save 1000 bytes of
the block in the TEMP.VM file when the block is discarded, reserve
a fixed number of bytes at the beginning of the memory block for a
header. The header could contain the name of the file (TEMP.VM) and
the number of bytes to store.
2. Assign the job of allocating the memory to the DLL. Then, when the
notification routine is called, the DLL has the data on where to
save the contents of the memory block. This can be accomplished by
implementing the MyGlobalAlloc and MyGlobalLock functions in the
DLL.
MyGlobalAlloc allocates an appropriately sized block of discardable
memory with the notify bit set, and stores the handle returned into
a handle table (stored in the DLL's data segment). MyGlobalLock
locks the appropriate block of memory and returns a pointer to the
memory to the calling application.
The following issues must be addressed in the notification routine:
1. Open the file, save the data, and close the file upon receiving the
notification. Applications should not leave file handles open
between messages. Using a file handle that is already open can
cause disastrous results because the current program segment prefix
(PSP) may not belong to the application, and the application might
use the wrong file handle.
2. Do not call any functions that might move memory, such as
GlobalAlloc, GlobalReAlloc, or LocalAlloc, in the notification
function. If the notification procedure calls the SendMessage
function, be sure it does not start a chain reaction that could
move memory. Using PostMessage is a safer alternative.
3. The GlobalLock function fails if the memory has been discarded;
therefore, the DLL should have a MyGlobalLock function that follows
this algorithm:
if (GMEM_DISCARDED & GlobalFlags(hMem))
{
hMem = GlobalReAlloc(hMem, lSize,
GMEM_DISCARDABLE | GMEM_NOTIFY | GMEM_MOVEABLE);
// Reload the data here.
}
lpMem = GlobalLock(hMem);
A typical notification routine in the DLL might resemble the
following:
BOOL FAR PASCAL NotifyProc(HANDLE hMemToDiscard)
{
BOOL bValid;
bValid = CheckForKnownMemory(hMemToDiscard);
return bValid;
}
The CheckForKnownMemory function compares the handle specified with
the function's list of known handles. If the function recognizes
the handle, the function saves the contents of the memory block to
disk and returns TRUE; otherwise, the function returns FALSE.
This function is initialized by adding the following line to the
application's WinMain function:
GlobalNotify(NotifyProc);
Calling the MakeProcInstance function to create a procedure
instance address is not necessary because the function is in a DLL.
The NotifyProc function must be in a fixed code DLL and must be
exported. The CheckForKnownMemory function should be in the same
code segment as NotifyProc for minimal movement of memory.
Additional reference words: 3.00