MORE INFORMATION
A DLL may not load for several reasons:
- The module is not found.
- A dependent module is not found.
- The DLL returns a failure from its DLLMain() function.
For applications that use the
LoadLibrary() function to load the DLL, on failure the application can call the
GetLastError() to get the error code and then to determine the reason for the
failure.
This article discusses how Windows CE loads a DLL so that
you can understand why a DLL may not load because of a lack of address space on
the part of the calling application. When an application lacks address space,
LoadLibrary returns a NULL value.
GetLastError returns error code 14,
ERROR_OUTOFMEMORY.
Windows CE loads a DLL differently than Microsoft
Windows 98, Microsoft Windows Millennium Edition, Microsoft Windows 2000, or
Microsoft Windows XP do. Because of these differences, a DLL may not load
although there appears to be enough memory or address space for the
DLL.
The following two examples describe how Windows CE loads DLLs.
- The ROM of the Windows CE device includes a ROM-based DLL.
The ROM of the Windows CE device includes a ROM-based DLL. The ROM-based DLL is
designated to map and to run from ROM. A module that maps and runs from ROM is
also known as execute in place (XIP).
- A RAM-based DLL is one that maps into RAM when the DLL
loads. The RAM-based DLL may be a custom DLL that you install on the device. A
RAM-based DLL may also come with the Windows CE operating system. The RAM-based
DLL is designated to be copied from ROM into RAM when the operating system
starts, before the application loads the DLL.
The process address space for an active Windows CE process
begins at 0x00000000 and then ends at 0x02000000, for a total of 32 MB. You
must share that address space with ROM-based DLLs, RAM-based DLLs, the EXE
module for the process, stacks, heaps, and with any other allocations that you
create for the process.
The size of the DLL file does not indicate
the actual space that the DLL requires to load. You can determine the initial
address space that you require to load a DLL when you run Dumpbin.exe for your
DLL.
dumpbin is a command-line tool that is included with eMbedded Visual
Tools.
dumpbin outputs information to the command window. The summary
information includes the size of each section. To load the DLL, you must have
address space equal to the sum of the section sizes plus 4 KB. For more
information, search the eMbedded Visual Tools help on the keyword,
dumpbin. To download eMbedded Visual Tools 3.0, visit the following
Microsoft Developer Network Web site:
To determine where in a process address space to load a DLL, Windows CE finds
the highest address and then seeks down until it finds enough free virtual
address space to fit the DLL module. For example, on the Pocket PC 2002 device
of one OEM, this address is 0x00AB0000. The address varies between different
device makes and models. The device maker build tools of the Windows CE image
automatically calculates the value.
Windows CE does not map a
RAM-based DLL from anywhere between 0x02000000 and the address where the lowest
ROM module is mapped.
- That area of address space is reserved for ROM modules
during the build of the operating system image.
- When the operating system is built, the modules that are
designated as XIP load only in that area of memory.
- If a process loads a DLL that is in ROM and is designated
as XIP, the Windows CE loader maps it at its predetermined address.
The Windows CE loader ignores the image base address
for the RAM-based DLL. When a DLL is compiled and linked, the linker writes an
address that is labeled the "image base" in the portable executable (PE)
header. The image base address tells the module loader the preferred address to
load the DLL. Although the image base is present in the DLL file, the Windows
CE loader does not use it.
When a DLL is loaded in one process,
Windows CE reserves that address space in every process address space. Multiple
processes that use the same DLL share it at the same relative address in every
process. If your application does not use the same DLL, it cannot use the
memory that is reserved for that DLL. In other words, Windows CE does not map a
RAM-based DLL at an address where another process maps another DLL. For
example, if Process A loads DLL
X at address 0x00970000, Windows CE does not map DLL
Y in the Process B address space at 0x00970000. Instead, Windows CE
seeks the next lower address that is available, depending on the size of DLL
Y. So if DLL
Y is in the size range of 128 KB, Windows CE selects 0x00950000 if
that address is available for Process B. Because of the way that Windows CE
allows processes to share a common DLL, Windows CE does not permit two
different processes to load two different DLLs at the same relative address of
each process.
Before a DLL is mapped in memory the Windows CE loader
resolves the implicit links to other DLLs, known as dependent DLLs. If any of
those modules is not yet loaded, then Windows CE stops the load of the current
DLL and starts the process to load the dependent DLLs. To do this, Windows CE
uses the same algorithm recursively. This is one point where Windows CE is
similar to desktop versions of Windows. It is mentioned here because a DLL may
not load because of factors of the dependent DLLs, not the DLL
itself.
If you determine that your application cannot load a DLL
because of a lack of address space for the DLL, consider the following
workarounds:
- If your application is implemented in Microsoft C or
Microsoft C ++, or if your eMbedded Visual Basic application uses custom DLLs,
determine whether you use the VirtualAlloc function with the MEM_TOP_DOWN flag. When you use this flag, you
allocate memory as high as possible, and you can cause DLLs to not load. VirtualAlloc must not use this flag.
- If your application uses a lot of small custom DLLs,
consolidate the code in one or two DLLs. The minimum address space that a DLL
consumes is 64 KB. Therefore, for example, if you design your application so
that thirty DLLs all fall between 8 and 10 KB, you waste 1,620 KB of address
space.
- Break the application down into more than one process. Use
one process to load one set of DLLs and then use another to load a different
set of DLLs. (Based on the application design, this may not be practical. If
both processes must run simultaneously, then it does not help to use two
separate processes.)
- Load all your essential DLLs when you first load the
application. If possible, keep the DLLs loaded. After you make this change in
your application, watch to see if memory allocations or other processes do not
work as a result. If they do, you must redesign your application to minimize
DLL or memory.
- Redesign the application to use less memory overall. Use
only essential DLLs and then unload them if you do not require them. Minimize
heap usage, as this impacts how many DLLs can load. Note that references to
ActiveX objects do not unload when you set the object variable to Nothing.