Transcript Chapter 11

Chapter 11
Win32 windows programming
The chapter introduces a subset
of the Win 32 API functions
• You can find out more by visiting Help in
VC++
• Or MSDN website
• There are predefined constants
• Two sets of chars available: old 8-bit
ASCII or 16 bit Unicode via writeConsoleA
or writeConsoleW functions.
High/low level access available
• High level access read or write to screen
buffer
• Low level functions can access mouse and
kbd events
smallWin.inc
• A file created by Irvine includes many
constant definitions, text equates and
function prototypes for win32 API
programming
• Included automatically in 32 bit asm
Some things in smallwin
• The structures COORD and SYSTIME we
looked at in chapter 10
• Definition for HANDLE (file handle) as a
DWORD
• Console handles are predefined
• GetSTDHandle returns a handle to an
input, output or error output
Win32 console functions
• Text pg 424-425
• Functions like readConsoleInput,
GetConsoleMode, GetSTDHandle, etc
readconsole
• Example pg 431-432
• A convenient way to read text input and
store in a buffer
ReadConsole : run
Assembling: ReadConsole.asm
Volume in drive C has no label.
Volume Serial Number is 07D2-0208
Directory of C:\masm615\examples\CH11
01/20/2002 01:23 PM
614 ReadConsole.asm
11/26/2006 01:19 PM
4,177 ReadConsole.obj
11/26/2006 01:19 PM
16,364 ReadConsole.lst
11/26/2006 01:19 PM
33,352 ReadConsole.ilk
11/26/2006 01:19 PM
28,729 ReadConsole.exe
11/26/2006 01:19 PM
91,136 ReadConsole.pdb
11/26/2006 01:19 PM
6,948 ReadConsole.map
7 File(s)
181,320 bytes
0 Dir(s) 4,048,109,568 bytes free
Press any key to continue . . .
C:\MASM615\EXAMPLES\CH11>readconsole
123abc
Dump of offset 00404000
------------------------------31 32 33 61 62 63 0D 0A 00 00 00 00 00 00 00 00
ReadConsole : code
INCLUDE Irvine32.inc
BufSize = 80
.data
buffer BYTE BufSize DUP(?),0,0
stdInHandle DWORD ?
bytesRead DWORD ?
.code
main PROC
; Get handle to standard input
INVOKE GetStdHandle, STD_INPUT_HANDLE
mov stdInHandle,eax
; Wait for user input
INVOKE ReadConsole, stdInHandle, ADDR buffer,
BufSize - 2, ADDR bytesRead, 0
; Display the buffer
mov esi,OFFSET buffer
mov ecx,16
; 16 bytes
mov ebx,TYPE buffer
call DumpMem
exit
main ENDP
END main
Running readconsole
Running Application with parameters:
W:\assembly\irvinecd\content\Examples\ch11
ReadConsole.exe
xyz
Dump of offset 00404000
------------------------------78 79 7A 0D 0A 00 00 00 00 00 00 00 00 00 00 00
Press any key to continue . . .
Console1 pg 436
• Writing a string to console
Console1: run
Assembling: console1.asm
Volume in drive C has no label.
Volume Serial Number is 07D2-0208
Directory of C:\masm615\examples\CH11
01/20/2002 01:40 PM
1,170 Console1.asm
11/26/2006 01:26 PM
4,255 console1.obj
11/26/2006 01:26 PM
17,927 console1.lst
11/26/2006 01:26 PM
14,536 console1.ilk
11/26/2006 01:26 PM
28,726 console1.exe
11/26/2006 01:26 PM
66,560 console1.pdb
11/26/2006 01:26 PM
1,610 console1.map
7 File(s)
134,784 bytes
0 Dir(s) 4,043,505,664 bytes free
Press any key to continue . . .
C:\MASM615\EXAMPLES\CH11>console1
-------------------- Console1.asm ----------------------This program is a simple demonstration of console
mode output, using the GetStdHandle and WriteConsole
functions.
--------------------------------------------------------C:\MASM615\EXAMPLES\CH11>
Console1: code
INCLUDE Irvine32.inc
.data
endl EQU <0dh,0ah>
; end of line sequence
message \
BYTE "-------------------- Console1.asm -----------------------"
BYTE endl,endl
BYTE "This program is a simple demonstration of console ",endl
BYTE "mode output, using the GetStdHandle and WriteConsole ",endl
BYTE "functions.",endl
BYTE "---------------------------------------------------------"
BYTE endl,endl,endl
messageSize = ($-message)
consoleHandle DWORD 0 ; handle to standard output device
bytesWritten DWORD ? ; number of bytes written
.code
main PROC
; Get the console output handle:
INVOKE GetStdHandle, STD_OUTPUT_HANDLE
mov consoleHandle,eax
; Write a string to the console:
INVOKE WriteConsole,
consoleHandle,
; console output handle
ADDR message,
; string pointer
messageSize,
; string length
ADDR bytesWritten,
; returns num bytes written
0
; not used
INVOKE ExitProcess,0
main ENDP
END main
Run of console1.asm
Console2.asm positions cursor
TITLE Console Demo #2
(Console2.asm)
; Demonstration of SetConsoleCursorPosition,
; GetConsoleCursorInfo, SetConsoleCursorInfo,
; SetConsoleScreenBufferSize, SetConsoleCursorPosition,
; SetConsoleTitle, and GetConsoleScreenBufferInfo.
; Last update: 9/28/01
INCLUDE SmallWin.inc
.data
outHandle DWORD ?
scrSize COORD <120,50>
xyPos COORD <20,5>
consoleInfo CONSOLE_SCREEN_BUFFER_INFO <>
cursorInfo CONSOLE_CURSOR_INFO <>
titleStr BYTE "Console2 Demo Program",0
Console2 continued
.code
main PROC
; Get Console output handle.
INVOKE GetStdHandle,STD_OUTPUT_HANDLE
mov outHandle,eax
; Get console cursor information.
INVOKE GetConsoleCursorInfo, outHandle,
ADDR cursorInfo
; Set console cursor size to 75%
mov cursorInfo.dwSize,75
INVOKE SetConsoleCursorInfo, outHandle,
ADDR cursorInfo
; Set the screen buffer size.
INVOKE SetConsoleScreenBufferSize,
outHandle,scrSize
And a bit more
; Set the cursor position to (20,5).
INVOKE SetConsoleCursorPosition, outHandle, xyPos
; Set the console window's title.
INVOKE SetConsoleTitle, ADDR titleStr
; Get screen buffer & window size information.
INVOKE GetConsoleScreenBufferInfo, outHandle,
ADDR consoleInfo
INVOKE ExitProcess,0
main ENDP
END main
Wrapping api functions
• Irvine32.Inc file contains wrappers for file
i/o (also covered in chpt 5)
• On pg 442 text provides source code for
these wrapper functions:
– createOutputFile
– OpenFile
– WriteToFile
– ReadFromFile
– CloseFile
ReadFile
• Code on pg 445
• Just opens file created by writefile
example and displays contents
Readfile: run…displays contents
of file from writefile.asm
Readfile: code
INCLUDE Irvine32.inc
.data
buffer BYTE 500 DUP(?)
bufSize = ($-buffer)
errMsg BYTE "Cannot open file",0dh,0ah,0
filename BYTE "output.txt",0
fileHandle DWORD ? ; handle to output file
byteCount DWORD ?
; number of bytes written
.code
main PROC
INVOKE CreateFile,
ADDR filename, GENERIC_READ, DO_NOT_SHARE, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0
mov fileHandle,eax
.IF eax == INVALID_HANDLE_VALUE
mov edx,OFFSET errMsg
call WriteString
jmp QuitNow
.ENDIF
; save file handle
; Display error message
Readfile: code
INVOKE ReadFile,
; write text to file
fileHandle,
; file handle
ADDR buffer,
; buffer pointer
bufSize,
; number of bytes to write
ADDR byteCount,
; number of bytes written
0
; overlapped execution flag
INVOKE CloseHandle, fileHandle
mov esi,byteCount
mov buffer[esi],0
mov edx,OFFSET buffer
call WriteString
QuitNow:
exit
main ENDP
END main
; insert null terminator
; into buffer
; display the buffer
Writefile: run (no output) & file
contents
C:\MASM615\EXAMPLES\CH11>writefile
C:\MASM615\EXAMPLES\CH11>type
output.txt
This text is written to an output file.
• Each run will create file and put text in the
file.
Writefile: code
INCLUDE Irvine32.inc
.data
buffer BYTE "This text is written to an output file.",0dh,0ah;;;;here is text to write
bufSize = ($-buffer)
errMsg BYTE "Cannot create file",0dh,0ah,0
filename BYTE "output.txt",0 ;;;;name of output file
fileHandle DWORD ?
; handle to output file
bytesWritten DWORD ? ; number of bytes written
.code
main PROC
INVOKE CreateFile,
ADDR filename, GENERIC_WRITE, DO_NOT_SHARE, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0
mov fileHandle,eax
; save file handle
.IF eax == INVALID_HANDLE_VALUE
mov edx,OFFSET errMsg
; Display error message
call WriteString
jmp QuitNow
.ENDIF
INVOKE WriteFile,
; write text to file
fileHandle,
; file handle
ADDR buffer,
; buffer pointer
bufSize,
; number of bytes to write
ADDR bytesWritten,
; number of bytes written
0
; overlapped execution flag
INVOKE CloseHandle, fileHandle
QuitNow:
exit
main ENDP
END main
Appendfile.asm is similar, but
appends text to an existing file
TITLE Appending to a File
(AppendFile.asm)
; This program appends text to an existing file.
; Last update: 1/30/02
INCLUDE Irvine32.inc
.data
buffer BYTE "This text is appended to an output file.",0dh,0ah
bufSize = ($-buffer)
errMsg BYTE "Cannot open file",0dh,0ah,0
filename BYTE "output.txt",0
fileHandle DWORD ?
; handle to output file
bytesWritten DWORD ? ; number of bytes written
Appendfile.asm code
.code
main PROC
INVOKE CreateFile,
ADDR filename, GENERIC_WRITE, DO_NOT_SHARE, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0
mov fileHandle,eax
; save file handle
.IF eax == INVALID_HANDLE_VALUE
mov edx,OFFSET errMsg
; Display error message
call WriteString
jmp QuitNow
.ENDIF
; Move the file pointer to the end of the file
INVOKE SetFilePointer,
fileHandle,0,0,FILE_END
; Append text to the file
INVOKE WriteFile,
fileHandle, ADDR buffer, bufSize,
ADDR bytesWritten, 0
INVOKE CloseHandle, fileHandle
QuitNow:
exit
main ENDP
END main
Scroll: writes 50 lines (and console
window scrolls)
C:\MASM615\EXAMPLES\CH11>scroll
0: This line of text was written to the screen buffer
1: This line of text was written to the screen buffer
2: This line of text was written to the screen buffer
3: This line of text was written to the screen buffer
4: This line of text was written to the screen buffer
5: This line of text was written to the screen buffer
6: This line of text was written to the screen buffer
7: This line of text was written to the screen buffer
8: This line of text was written to the screen buffer
9: This line of text was written to the screen buffer
10: This line of text was written to the screen buffer
11: This line of text was written to the screen buffer
12: This line of text was written to the screen buffer
13: This line of text was written to the screen buffer
14: This line of text was written to the screen buffer
15: This line of text was written to the screen buffer
16: This line of text was written to the screen buffer
17: This line of text was written to the screen buffer
18: This line of text was written to the screen buffer
19: This line of text was written to the screen buffer
20: This line of text was written to the screen buffer
21: This line of text was written to the screen buffer
22: This line of text was written to the screen buffer
23: This line of text was written to the screen buffer
24: This line of text was written to the screen buffer
25: This line of text was written to the screen buffer
26: This line of text was written to the screen buffer
27: This line of text was written to the screen buffer
28: This line of text was written to the screen buffer
29: This line of text was written to the screen buffer
Scroll: example from text pg 449: write
50 lines of text to screen buffer
INCLUDE Irvine32.inc
.data
message BYTE ": This line of text was written "
BYTE "to the screen buffer",0dh,0ah
messageSize = ($-message)
outHandle DWORD 0
; standard output handle
bytesWritten DWORD ?
; number of bytes written
lineNum DWORD 0
windowRect SMALL_RECT <0,0,60,11>
; left,top,right,bottom
.code
main PROC
INVOKE GetStdHandle, STD_OUTPUT_HANDLE
mov outHandle,eax
.REPEAT
mov eax,lineNum
call WriteDec
; display each line number
INVOKE WriteConsole,
outHandle,
; console output handle
ADDR message,
; string pointer
messageSize,
; string length
ADDR bytesWritten,
; returns num bytes written
0
; not used
inc lineNum
; next line number
.UNTIL lineNum > 50
scroll
; Resize and reposition the console window relative to the
; screen buffer.
INVOKE SetConsoleWindowInfo,
outHandle,
TRUE,
ADDR windowRect
call Readchar
; wait for a key
call Clrscr ; clear the screen buffer
call Readchar
; wait for a second key
INVOKE ExitProcess,0
main ENDP
END main
Write colors
• Text pg 452
• Create an array of chars and an array of
attributes (one for each char)
• It calls writeconsoleattribute to put
attributes on screenbuffer
• It calls writeconsolecharacter to copy the
characters to the same screen buffer cells
Writecolors
INCLUDE Irvine32.inc
.data
outHandle DWORD ?
cellsWritten DWORD ?
xyPos COORD <10,2>
; Array of character codes:
buffer BYTE 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
BYTE 16,17,18,19.20
BufSize = ($ - buffer)
; Array of attributes:
attributes WORD 0Fh,0Eh,0Dh,0Ch,0Bh,0Ah,9,8,7,6
WORD 5,4,3,2,1,0F0h,0E0h,0D0h,0C0h,0B0h
.code
main PROC
; Get the Console standard output handle:
INVOKE GetStdHandle,STD_OUTPUT_HANDLE
mov outHandle,eax
; Set the colors from (10,2) to (30,2):
INVOKE WriteConsoleOutputAttribute,
outHandle, ADDR attributes,
BufSize, xyPos,
ADDR cellsWritten
; Write character codes 1 to 20:
INVOKE WriteConsoleOutputCharacter,
outHandle, ADDR buffer, BufSize,
xyPos, ADDR cellsWritten
call ReadChar
exit
main ENDP
END main
writecolors
TimingLoop just prints dots (slowly)
INCLUDE Irvine32.inc
TIME_LIMIT = 5000
.data
startTime DWORD ?
dot BYTE ".",0
.code
main PROC
INVOKE GetTickCount
mov startTime,eax
L1:
mov edx,OFFSET dot
; display a dot
call WriteString
INVOKE Sleep,100
; sleep for 100ms
INVOKE GetTickCount
sub eax,startTime ; check the elapsed time
cmp eax,TIME_LIMIT
jb L1
L2: exit
main ENDP
END main
Timingloop counts elapsed time
before keypress
C:\MASM615\EXAMPLES\CH11>timer
5000 milliseconds have elapsed
Timer.asm
• Text pg 454-455
• A stopwatch program gets elapsed time
between two calls to tickcount
timer
INCLUDE Irvine32.inc
TimerStart PROTO,
pSavedTime: PTR DWORD
TimerStop PROTO,
pSavedTime: PTR DWORD
.data
msg BYTE " milliseconds have elapsed",0dh,0ah,0
timer1 DWORD ?
.code
main PROC
INVOKE TimerStart,
; start the timer
ADDR timer1
INVOKE Sleep, 5000
; sleep for a while
INVOKE TimerStop,
; EAX = elapsed milliseconds
ADDR timer1
call WriteDec
; display elapsed time
mov edx,OFFSET msg
call WriteString
exit
main ENDP
timer
;-------------------------------------------------TimerStart PROC uses eax esi,
pSavedTime: PTR DWORD
; Starts a stopwatch timer.
; Receives: pointer to a variable that will hold
; the current time.
; Returns: nothing
;-------------------------------------------------INVOKE GetTickCount
mov esi,pSavedTime
mov [esi],eax
ret
TimerStart ENDP
;-------------------------------------------------TimerStop PROC uses esi,
pSavedTime: PTR DWORD
;
; Stops the current stopwatch timer.
; Receives: pointer to a variable holding the
;
saved time
; Returns: EAX = number of elapsed milliseconds
; Remarks: Accurate to about 10ms
;-------------------------------------------------INVOKE GetTickCount
mov esi,pSavedTime
sub eax,[esi]
ret
TimerStop ENDP
END main
Running timer
winApp.asm text pg 461
• Display text in a pop up messagebox
• About winMain
• Every windows app needs a startup proc
typically named WinMain which
– Gets handle to current program
– Loads program icon and mouse cursor
– Creates main window
– Show/update window
– Loops to receive and dspatch messages
A windows app
A windows app
A windows app
Winapp data area
INCLUDE Irvine32.inc
INCLUDE GraphWin.inc
;==================== DATA =======================
.data
AppLoadMsgTitle BYTE "Application Loaded",0
AppLoadMsgText BYTE "This window displays when the WM_CREATE "
BYTE "message is received",0
PopupTitle BYTE "Popup Window",0
PopupText BYTE "This window was activated by a "
BYTE "WM_LBUTTONDOWN message",0
GreetTitle BYTE "Main Window Active",0
GreetText BYTE "This window is shown immediately after "
BYTE "CreateWindow and UpdateWindow are called.",0
CloseMsg BYTE "WM_CLOSE message received",0
ErrorTitle BYTE "Error",0
WindowName BYTE "ASM Windows App",0
className BYTE "ASMWin",0
; Define the Application's Window class structure.
MainWin WNDCLASS <NULL,WinProc,NULL,NULL,NULL,NULL,NULL, \
COLOR_WINDOW,NULL,className>
msg
MSGStruct <>
winRect RECT <>
hMainWnd DWORD ?
hInstance DWORD ?
Winapp code-4 slides
;=================== CODE =========================
.code
WinMain PROC
; Get a handle to the current process.
INVOKE GetModuleHandle, NULL
mov hInstance, eax
mov MainWin.hInstance, eax
; Load the program's icon and cursor.
INVOKE LoadIcon, NULL, IDI_APPLICATION
mov MainWin.hIcon, eax
INVOKE LoadCursor, NULL, IDC_ARROW
mov MainWin.hCursor, eax
; Register the window class.
INVOKE RegisterClass, ADDR MainWin
.IF eax == 0
call ErrorHandler
jmp Exit_Program
.ENDIF
Winapp code
; Create the application's main window.
; Returns a handle to the main window in EAX.
INVOKE CreateWindowEx, 0, ADDR className,
ADDR WindowName,MAIN_WINDOW_STYLE,
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
CW_USEDEFAULT,NULL,NULL,hInstance,NULL
mov hMainWnd,eax
; If CreateWindowEx failed, display a message & exit.
.IF eax == 0
call ErrorHandler
jmp Exit_Program
.ENDIF
; Show and draw the window.
INVOKE ShowWindow, hMainWnd, SW_SHOW
INVOKE UpdateWindow, hMainWnd
; Display a greeting message.
INVOKE MessageBox, hMainWnd, ADDR GreetText,
ADDR GreetTitle, MB_OK
; Begin the program's message-handling loop.
Message_Loop:
; Get next message from the queue.
INVOKE GetMessage, ADDR msg, NULL,NULL,NULL
; Quit if no more messages.
.IF eax == 0
jmp Exit_Program
.ENDIF
; Relay the message to the program's WinProc.
INVOKE DispatchMessage, ADDR msg
jmp Message_Loop
Exit_Program:
INVOKE ExitProcess,0
WinMain ENDP
Winapp code
;----------------------------------------------------WinProc PROC,
hWnd:DWORD, localMsg:DWORD, wParam:DWORD, lParam:DWORD
; The application's message handler, which handles
; application-specific messages. All other messages
; are forwarded to the default Windows message
; handler.
;----------------------------------------------------mov eax, localMsg
.IF eax == WM_LBUTTONDOWN
; mouse button?
INVOKE MessageBox, hWnd, ADDR PopupText,
ADDR PopupTitle, MB_OK
jmp WinProcExit
.ELSEIF eax == WM_CREATE
; create window?
INVOKE MessageBox, hWnd, ADDR AppLoadMsgText,
ADDR AppLoadMsgTitle, MB_OK
jmp WinProcExit
.ELSEIF eax == WM_CLOSE
; close window?
INVOKE MessageBox, hWnd, ADDR CloseMsg,
ADDR WindowName, MB_OK
INVOKE PostQuitMessage,0
jmp WinProcExit
.ELSE
; other message?
INVOKE DefWindowProc, hWnd, localMsg, wParam, lParam
jmp WinProcExit
.ENDIF
WinProcExit:
ret
WinProc ENDP
Winapp code
;--------------------------------------------------ErrorHandler PROC
; Display the appropriate system error message.
;--------------------------------------------------.data
pErrorMsg DWORD ?
; ptr to error message
messageID DWORD ?
.code
INVOKE GetLastError
; Returns message ID in EAX
mov messageID,eax
; Get the corresponding message string.
INVOKE FormatMessage, FORMAT_MESSAGE_ALLOCATE_BUFFER + \
FORMAT_MESSAGE_FROM_SYSTEM,NULL,messageID,NULL,
ADDR pErrorMsg,NULL,NULL
; Display the error message.
INVOKE MessageBox,NULL, pErrorMsg, ADDR ErrorTitle,
MB_ICONERROR+MB_OK
; Free the error message string.
INVOKE LocalFree, pErrorMsg
ret
ErrorHandler ENDP
END WinMain
ReadFile
• Code on pg 445
• Just opens file created by writefile
example and displays contents
Readfile: run…displays contents
of file from writefile.asm
Readfile: code
INCLUDE Irvine32.inc
.data
buffer BYTE 500 DUP(?)
bufSize = ($-buffer)
errMsg BYTE "Cannot open file",0dh,0ah,0
filename BYTE "output.txt",0
fileHandle DWORD ? ; handle to output file
byteCount DWORD ?
; number of bytes written
.code
main PROC
INVOKE CreateFile,
ADDR filename, GENERIC_READ, DO_NOT_SHARE, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0
mov fileHandle,eax
.IF eax == INVALID_HANDLE_VALUE
mov edx,OFFSET errMsg
call WriteString
jmp QuitNow
.ENDIF
; save file handle
; Display error message
Readfile: code
INVOKE ReadFile,
; write text to file
fileHandle,
; file handle
ADDR buffer,
; buffer pointer
bufSize,
; number of bytes to write
ADDR byteCount,
; number of bytes written
0
; overlapped execution flag
INVOKE CloseHandle, fileHandle
mov esi,byteCount
mov buffer[esi],0
mov edx,OFFSET buffer
call WriteString
QuitNow:
exit
main ENDP
END main
; insert null terminator
; into buffer
; display the buffer
The Heap
• Objects are created off the heap (dynamic
mem allocation) not the stack
• Functions:
– You can get the process heap – default heap
owned by current program
– Heap destroy
– Heap alloc
Heaptest1
• Creates and fills a 1000-byte array
Heap test… allocating heap
space
Title Heap Test #1
(Heaptest1.asm)
INCLUDE Irvine32.inc
; This program uses dynamic memory allocation to allocate and
; fill an array of bytes.
.data
ARRAY_SIZE = 1000
FILL_VAL EQU 0FFh
hHeap DWORD ?
pArray DWORD ?
newHeap DWORD ?
str1 BYTE "Heap size is: ",0
; handle to the process heap
; pointer to block of memory
; handle to new heap
Heap test… allocating heap
space
.code
main PROC
INVOKE GetProcessHeap
.IF eax == NULL
;call
WriteWindowsMsg
jmp
quit
.ELSE
mov
hHeap,eax
.ENDIF
call
jnc
;call
call
jmp
allocate_array
arrayOk
WriteWindowsMsg
Crlf
quit
arrayOk:
; get handle to prog's heap
; failed?
; success
; failed (CF = 1)?
; ok to fill the array
call
call
call
fill_array
display_array
Crlf
; free the array
INVOKE HeapFree, hHeap, 0, pArray
And more
;-------------------------------------------------------display_array PROC USES eax ebx ecx esi
;
; Displays the array
; Receives: nothing
; Returns: nothing
;-------------------------------------------------------mov
ecx,ARRAY_SIZE
; loop counter
mov
esi,pArray ; point to the array
L1:
mov
mov
call
inc
loop
ret
display_array ENDP
END main
al,[esi]
ebx,TYPE BYTE
WriteHexB
esi
L1
; get a byte
; display it
; next location
Had to Comment off call to
writewindowmsg
Heaptest 2 code not show…request blocks until no more
available