4.9.6 Displaying Memory

Selecting the Memory command from the View menu opens a Memory window. You can have two CVW Memory windows open at a time.

By default, memory is displayed as byte values in hexadecimal format, with 16 bytes per line. At the end of each line is a second display of the same memory in ASCII form. Values that correspond to printable ASCII characters (decimal values 32 through 127) are displayed in decimal format. Values outside that range are represented by periods (.).

Byte values are not always the most convenient way to view memory. If the area of memory you are examining contains character strings or floating-point values, you might prefer to view them in a directly readable form. The Memory Window command on the Options menu displays a dialog box with the display options in the following categories:

ASCII characters

Byte, word, or doubleword binary values

Signed or unsigned integer decimal values

Short (32-bit), long (64-bit), or 10-byte (80-bit) floating-point values

You can also cycle through these display formats directly by pressing SHIFT+F3.

If a section of memory cannot be displayed as a valid floating-point number, the value shown includes the characters NAN (not a number).

4.9.6.1 Displaying Local and Global Memory Objects

CVW is also useful for displaying global and local memory objects in their respective Windows heaps. You can use the wdg (Windows Display Global Heap) command to display the entire heap of global memory objects in the Command window, or you can use the wdl (Windows Display Local Heap) command to display the entire heap of local memory objects in the Command window.

For the wdg command, you can specify a global handle to display a partial list of the global heap. The Command window displays the first five memory objects in the global heap, starting at the handle rather than at the beginning of the heap. The following example illustrates the wdg output format:

 1      2        3          4       5      6
047E  (0A7D)  00000020b   MYAPP    PRIV MOVEABLE DISCARDABLE

                                                 7
0A6D          00000134b   MYAPP    DATA FIXED PGLOCKED=0001

                              8
0806  (0805)  00000600b   PDB (0465)

 9
FREE          000000A0b

The following table describes the indicated fields:

Field Description

1 The value of the handle of a global memory object. Global memory objects are displayed in the order in which Windows manages them, which is typically not in ascending handle order.
2 A memory selector. This value is not displayed if the selector value is the same as the global handle, as is the case for DATA objects.
3 The length, in bytes, of the global memory object.
4 The name of the application or library module that allocated the object.
5 The type of global memory object, which can be the following:
Field Description

Type Meaning

PRIV Application or DLL global data, or system object
CODE Code segment
DATA Data segment of application or DLL
FREE Free memory object in the global heap

6 One of the following memory allocation attributes: MOVEABLE MOVEABLE DISCARDABLE FIXED
7 One of the following dispositions if the object is movable:

Disposition Meaning

LOCKED=number Number of times the object has been locked with any of the Windows functions that lock data
PGLOCKED=number Number of times Windows has locked the object in its linear address space

8 The handle of the application or library module that allocated the process descriptor block (PDB).
9 A free memory object, followed by the size of the free object, in bytes.

The following example shows sample output of the wdl (Windows Display Local Heap) command:

 1     2      3      4
190A:  000A   BUSY   (16DA)

The following table describes the indicated fields:

Field Description

1 The offset of the local memory object in the local data segment
2 The length of the object, in bytes
3 One of the following dispositions:

Disposition Meaning

BUSY A currently allocated object
FREE A free object in the local heap

4 A local memory handle

4.9.6.2 Displaying Variables with a Live Expression

Section 4.9.4, “Using the Quick Watch Command,” explains how to display a specific array element by adding the appropriate expression to the Watch window. It is also possible to view a particular array element or structure element in the Memory window. This CVW display feature is called a live expression, because the displayed area of memory changes to reflect the value of a pointer or subscript. For example, if Buffer is an array and pBuf is a pointer to that array, then *pBuf points to the array element currently referenced. A live expression displays the section of memory beginning with this element.

CVW displays live expressions in a Memory window. To create a live expression:

1.From the Options menu, choose Memory Window.

2.Select the Live Expression check box, and type the name of the element you want to view.

For example, if pszMsg is a pointer to a null-terminated array of characters and you want to see what it currently points to, type the following:

*pszMsg

3.Choose the OK button, or press ENTER.

A new Memory window opens. The first memory location in the window is the first memory location of the live expression. The section of memory displayed changes to the section the pointer currently references.

You can use the Memory Window command on the Options menu to display the value of the live expression in a readable form. This is especially convenient when the live expression represents strings or floating-point values, which are difficult to interpret in hexadecimal form.

It is usually more convenient to view an item in the Watch window than as a live expression. However, you might find some items easier to view as live expressions. For example, you can examine what is currently at the top of the stack by specifying SS:SP as the live expression.

4.9.6.3 Dereferencing Memory Handles

In a Windows application, the LocalLock and GlobalLock functions are used to dereference memory handles into near or far pointers. In a debugging session, you may know the handle of the memory object, but might not know which near or far address it dereferences to, unless you are debugging in an area where the application has just completed a LocalLock or GlobalLock function call. To get the near and far pointer addresses for your local and global handles, use the (lh) and (gh) type casts. For example, you could use (lh) to dereference the array in the following code:

HANDLE hLocalMem;
PBYTE pbArray;

hLocalMem = LocalAlloc(LMEM_MOVEABLE, 100);
pbArray = (PBYTE)LocalLock(hLocalMem);

/* Use the array.     */

LocalUnlock(hLocalMem);

To properly display this array in CVW, you can use the following command:

dw (lh)hLocalMem

If you set a breakpoint immediately after the LocalLock function, you could find out where the local object was allocated in the application's data segment by looking at the value of the pbArray variable. To display the value of pbArray, use the following CVW command:

dw pbArray

Note that you cannot rely on the value of pbArray anywhere else in the application, because it may change or the memory object may move.

In the following example, the memory object lpszTest is a string:

HANDLE hGlobalMem;
LPSTR  lpszTest;

hGlobalMem = GlobalAlloc(GMEM_MOVEABLE, 10L)
lpszTest = GlobalLock(hGlobalMem);

lstrcpy(lpszTest, "ABCDEF");

GlobalUnlock(hGlobalMem);

To display the contents of the string, you could use double type casting, as follows:

? *(char far*) (gh)lpszTest,s

The (gh) type cast returns a pointer to the far address of the global memory object.