I am writing a program to display the current time and date for 10 seconds. I am directed that i may ONLY use smallwin.inc for this. I wrote a program that works using Irvine32.inc, but when i switch to ONLY smallwin, i needed to write some procedures for outputting numbers. When i added these, a VERY STRANGE behavior began to happen! I use the call "dec repTime" and it will decrease by 2 instead of 1! I have tried "sub repTime, 1" and it still does the same! I have even moved repTime to eax, then subtracted 1, then moved eax back to repTime, it still subtracts 2!
The program i wrote is supposed to run for 10 seconds. Because of the subtract 2 issue, it runs for 4 seconds instead! What is wrong?!?
Here is my code:
; this code demonstrates the usage of Windows API functions to display
; current date and time. It provides a running digital clock that updates
; itself for 10 seconds. The output is displayed starting with cursor position
; (5,5) and uses yellow foreground and blue background.
INCLUDE smallwin.inc
.data
buffer DB 256 DUP(?)
prompt BYTE "Today is: " ; strings used to format the output
slash BYTE '/'
colon BYTE ':'
space BYTE " Time: "
newLine WORD 0D0Ah
repTime DWORD 10 ; display time for 10 seconds
cursPos COORD <5,5> ; cursor coordinates
.data?
outHandle DWORD ? ; storage for console output handle
sysTimeNow SYSTEMTIME <> ; storage for system time structure
sysTimeFuture SYSTEMTIME <>
.code
WriteChar PROC
pushfd
pushad
mov buffer,al
INVOKE WriteConsole, outHandle, OFFSET buffer, 1, 0, 0
popad
popfd
ret
WriteChar ENDP
outInt PROC USES eax ebx ecx edx,
number: SDWORD ; method parameter
mov ebx, 10 ; divisor for the radix system
xor ecx, ecx ; digits counter
cmp number, 0 ; is number >= 0?
jge go ; yes - proceed
neg number ; negate the number
mov al, '-'
INVOKE WriteChar
go:
mov eax, number
puDigit:
xor edx, edx
div ebx ; get one digit
push edx ; save it for further processing
inc ecx ; update the digits counter
cmp eax, 0 ; end of processing
jne puDigit
printIT:
pop eax ; get a digit from stack
or al, 30h ; ASCII conversion
INVOKE WriteChar ; print it
loop printIT
ret
outInt ENDP
format2 PROC
LOCAL zero:BYTE
mov zero, '0'
cmp ax, 10 ; number < 10 ?
jge L
push eax ; YES - output preceeding 0
INVOKE WriteConsole, outHandle, ADDR zero, 1, 0, 0
pop eax
L: INVOKE outInt, eax ; output the number itself
ret
format2 ENDP
main PROC
INVOKE GetStdHandle, STD_OUTPUT_HANDLE
mov outHandle, eax ; get console handle for output
INVOKE SetConsoleTextAttribute, outHandle, 30 ; setup colors
INVOKE GetLocalTime, ADDR sysTimeFuture
;set Future Time to Dec 25, 2013
mov sysTimeFuture.wDay, 25
mov sysTimeFuture.wMonth, 12
mov sysTimeFuture.wYear, 2013
mov sysTimeFuture.wHour, 0
mov sysTimeFuture.wMinute, 0
mov sysTimeFuture.wSecond, 0
startLabel:
INVOKE SetConsoleCursorPosition, outHandle, cursPos
INVOKE GetLocalTime, ADDR sysTimeNow ; retrieve current date/time
INVOKE WriteConsole, outHandle, ADDR prompt,
SIZEOF prompt, 0, 0 ; output prompt
mov eax, 0
mov ax, sysTimeNow.wDay ; day of the month
call format2
INVOKE WriteConsole, outHandle, ADDR slash, 1, 0, 0 ; output '/'
mov ax, sysTimeNow.wMonth ; month number
call format2
INVOKE WriteConsole, outHandle, ADDR slash, 1, 0, 0 ; output '/'
mov ax, sysTimeNow.wYear ; print out the year
INVOKE outInt, ax
INVOKE WriteConsole, outHandle, ADDR space, SIZEOF space, 0, 0
mov ax, sysTimeNow.wHour ; output hours
call format2
INVOKE WriteConsole, outHandle, ADDR colon, 1, 0, 0 ; output ':'
mov ax, sysTimeNow.wMinute ; output minutes
call format2
INVOKE WriteConsole, outHandle, ADDR colon, 1, 0, 0 ; output ':'
mov ax, sysTimeNow.wSecond ; output seconds
call format2
INVOKE Sleep, 1000 ; wait for 1 second
dec repTime ; update the stop watch counter
jnz startLabel
INVOKE SetConsoleTextAttribute, outHandle, 15 ; reset the colors
INVOKE WriteConsole, outHandle, ADDR newLine, 2, 0, 0 ; start new line
INVOKE ExitProcess, 0
main ENDP
END main
Look at the prototype for outint
:
outInt PROTO number:SDWORD
The parameter expected is a S igned DWORD - SDWORD
or it could be DWORD
, does not matter, look what you are passing as a parameter:
mov ax, sysTimeNow.wYear ; print out the year
INVOKE outInt, ax
You are passing a WORD
sized register as a parameter, and your using eax
in the procedure.
Change the above two lines to:
movzx eax, sysTimeNow.wYear ; print out the year
INVOKE outInt, eax
or:
xor eax, eax
mov ax, sysTimeNow.wYear ; print out the year
INVOKE outInt, eax
Which will "zero out" the upper half of eax
and make it work. Or, what you could do, is make the procedure expect a WORD
sized parameter since that is what you are passing, and use ax
instead of eax
in the proc.