Microsoft KB Archive/264320

{|
 * width="100%"|

PRB: Windows NT Virtual DOS Machine Does Not Free 16-bit Environment Blocks

 * }

Q264320

-

The information in this article applies to:


 * Microsoft Windows NT Server version 4.0
 * Microsoft Windows NT Workstation version 4.0
 * Microsoft Windows 2000 Advanced Server
 * Microsoft Windows 2000 Server
 * Microsoft Windows 2000 Professional

-

SYMPTOMS
The Windows NT Virtual DOS Machine (NTVDM) can run 16-bit tasks on Windows NT and Windows 2000. However, if you run more than one instance of the same 16-bit executable file, the NTVDM will not free the DOS environment block for each instance until all instances exit. These lingering allocations can cause fragmentation of the NTVDM memory, which can cause &quot;out of memory&quot; errors when you attempt to start new 16-bit tasks.

CAUSE
In Windows 3.x, the DOS environment block belonged to the task itself. When the task exited, the environment block was freed.

Under NTVDM, the DOS environment block belongs to the executable module rather than the task. This module loads when you start the task. As long as at least one instance of the task is running, the module remains in memory. Therefore, the environment blocks that are owned by the module also remain in memory. When the last instance of the task exits, the module unloads and NTVDM frees all of the environment blocks that are associated with it.

RESOLUTION
To reduce this memory fragmentation in NTVDM, you can modify the 16-bit task to free its own DOS environment block as it exits. To avoid corrupting the memory on other versions of Windows, you should programmatically check to see if the module owns the environment block before freeing it. See the sample code in the &quot;More Information&quot; section to follow on how to do this.

MORE INFORMATION
The following sample code demonstrates how to locate and free the DOS environment block for the current 16-bit task when you run it under NTVDM. You should add this code to the end of the 16-bit executable so that the code runs as the task exits.

// This code requires the following header files: //   windows.h //    toolhelp.h //    dos.h

// You should link the executable with toolhelp.lib.

GLOBALENTRY ge; TASKENTRY  te; DWORD      dwEnvBaseAddr; LPSTR      szEnv;

// The global heap manager's handle to the segment that contains the // DOS environment block will be the linear address of the selector // retrieved from GetDOSEnvironment. szEnv = GetDOSEnvironment; dwEnvBaseAddr = GetSelectorBase(_FP_SEG(szEnv));

// You can use TaskFindHandle to obtain the module handle for the 16-bit // executable (te.hModule). te.dwSize = sizeof(TASKENTRY); TaskFindHandle(&te, GetCurrentTask);

// You can now enumerate through the global heap until you find the DOS // environment block. ge.dwSize = sizeof(GLOBALENTRY); GlobalFirst(&ge, GLOBAL_ALL);

do {

// The deletion should only occur when the block is owned by the // module rather than the task. The following combination of tests will // always produce false on Windows 3.x and Windows 9x. That's fine // because these systems do not leave behind environment blocks. if (ge.hOwner == te.hModule && ge.dwAddress == dwEnvBaseAddr) {

// Found it! Now delete it. GlobalFree(ge.hBlock); break; }

} while (GlobalNext(&ge, GLOBAL_ALL)); Additional query words:

Keywords : kbKernBase kbMemory kbOSWinNT400 kbOSWin2000 _IK kbGrpDSKernBase

Issue type : kbprb

Technology : kbWinNTsearch kbWinNTWsearch kbWinNTW400 kbWinNTW400search kbWinNT400xsearch kbwin2000AdvServ kbwin2000AdvServSearch kbwin2000Serv kbWinNTSsearch kbWinNTS400xsearch kbWinNTS400 kbwin2000ServSearch kbwin2000Search kbwin2000ProSearch kbwin2000Pro kbWinAdvServSearch