Hi!
I was trying to figure out how SystemTime and LocalTime work, so I wrote this.
But as you already now, I'm sort of a sloppy coder, so as I couldn?t figure out how to make a procedure work, I wrote a whole series of repeating macros.

So what I propose you is: give solutions of how you would solve it, and I will post my solution in 24-hours time.

Fun, isn't it?


.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\kernel32.lib
include \masm32\include\user32.inc
includelib \masm32\lib\user32.lib

TimeProcedure PROTO

.data

Caption DB "Localtime and Systemtime",0
Text DB " LOCAL SYSTEM",0Dh,0Ah
DB "Year: "
localyear DB 126,32,32,32,32
DB 11 DUP(32)
systemyear DB 126,32,32,32,32
DB 0Dh,0Ah,"Mon"
localmonth DB "t","h",":",32,32
DB 15 DUP (32)
systemmonth DB 32,32,32,32,32
DB 0Ah, 0Dh,"Day of w"
localdow DB "e","e","k",":",32
DB 9 DUP (32)
systemdow DB 32,32,32,32,32
DB 0Dh,0Ah,"Day:"
localday DB 32,32,126,32,32
DB 16 DUP (32)
systemday DB 32,32,126,32,32
DB 0D,0Ah,"Hour:"
localhour DB 32,32,32,32,32
DB 17 DUP (32)
systemhour DB 32,32,32,32,32
DB 0Dh,0Ah,"Minute:"
localmin DB 32,32,32,32,32
DB 15 DUP (32)
systemmin DB 32,32,32,32,32
DB 0Dh,0Ah,"Second:"
localsec DB 32,32,32,32,32
DB 15 DUP (32)
systemsec DB 32,32,32,32,32
DB 0Dh,0Ah,"Milliseconds:"
localm DB 32,32,32,32,32
DB 7 DUP (32)
systemm DB 32,32,32,32,32
DW NULL

m2m MACRO M1, M2
push M2
pop M1
ENDM


change MACRO TextParam, StrctParam
LOCAL convert

xor eax,eax
mov ax,StrctParam
lea edi, [TextParam]
add edi,5
mov cx,10
convert:
xor edx,edx
div cx ;Remainder in DL
add dl,30h ;To ASCII
mov [edi],dl
dec edi
cmp ax,0
jne convert
ENDM


S STRUCT WORD
SYear DW ?
SMonth DW ?
SDayOfWeek DW ?
SDay DW ?
SHour DW ?
SMinute DW ?
SSecond DW ?
SMilliseconds DW ?
S ENDS

.code
start:

invoke TimeProcedure
invoke MessageBox, NULL, addr Text, addr Caption, MB_OK
invoke ExitProcess, NULL

TimeProcedure PROC
LOCAL Loc :S
LOCAL Syst :S
invoke GetLocalTime, addr Loc
invoke GetSystemTime, addr Syst

pushfd
push edi

change localyear, Loc.SYear
change systemyear, Syst.SYear
change localmonth,Loc.SMonth
change systemmonth,Syst.SMonth
change localdow,Loc.SDayOfWeek
change systemdow,Syst.SDayOfWeek
change localday, Loc.SDay
change systemday,Syst.SDay
change localhour,Loc.SHour
change systemhour,Syst.SHour
change localmin,Loc.SMinute
change systemmin,Syst.SMinute
change localsec,Loc.SSecond
change systemsec, Syst.SSecond
change localm, Loc.SMilliseconds
change systemm, Syst.SMilliseconds

;We should use a procedure instead of all these macros, but it
; sometimes gives problems with run-time structs like Loc and Syst

pop edi
popfd
ret
TimeProcedure ENDP
end start
Posted on 2002-07-29 10:58:33 by slop
So what I propose you is: give solutions of how you would solve it, and I will post my solution in 24-hours time.


Solve what? I don't understand. :confused:
Posted on 2002-07-29 11:26:24 by iblis
Man , don?t you have sense of homour?

You can:
1) play;
2) don?t play;
3) get a handkerchief and clean that slime from your face.

It?s THAT easy ;)
Posted on 2002-07-29 11:40:04 by slop
Here's my solution

--uses proc instead of macro
--STRUC definition is removed cause I can't see a use for it
--DATA section is cleaned up quite a bit
--values are right align under the columns (of course the message box font messes this up so it don't look so aligned)
--removed preservation of flags and edi since IntToStrBk preserves registers. I'm not sure why you're preserving flags, but you can put it back in if you like




.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\kernel32.lib
include \masm32\include\user32.inc
includelib \masm32\lib\user32.lib

TimeProcedure PROTO
IntToStrBk PROTO :DWORD,:DWORD

.data

Caption DB "Localtime and Systemtime",0

;each string is 32 bytes, not including the CF-LF
;The last "L" in local is 18 bytes in, the "M" in system is
;32 bytes in. Hence the invoke IntToStrBk,addr [YearText+17],
;etc. That way if you force a fixed with font, everything
;will be aligned to the right underneath their respective
;labels

Text DB " LOCAL SYSTEM",0Dh,0Ah
YearText DB "Year: ",0Dh,0Ah
MonthText DB "Month: ",0Dh,0Ah
DoWText DB "Day of Week: ",0Dh,0Ah
DayText DB "Day: ",0Dh,0Ah
HourText DB "Hour: ",0Dh,0Ah
MinuteText DB "Minute: ",0Dh,0Ah
SecondText DB "Second: ",0Dh,0Ah
MillisecondText DB "Millisecond: ",0Dh,0Ah,0

.code
start:

invoke TimeProcedure
invoke MessageBox, NULL, addr Text, addr Caption, MB_OK
invoke ExitProcess, NULL

TimeProcedure PROC
LOCAL Loc :SYSTEMTIME
LOCAL Syst :SYSTEMTIME

invoke GetLocalTime, addr Loc
invoke GetSystemTime, addr Syst
invoke IntToStrBk,addr [YearText+17],Loc.wYear
invoke IntToStrBk,addr [YearText+31],Syst.wYear
invoke IntToStrBk,addr [MonthText+17],Loc.wMonth
invoke IntToStrBk,addr [MonthText+31],Syst.wMonth
invoke IntToStrBk,addr [DoWText+17],Loc.wDayOfWeek
invoke IntToStrBk,addr [DoWText+31],Syst.wDayOfWeek
invoke IntToStrBk,addr [DayText+17],Loc.wDay
invoke IntToStrBk,addr [DayText+31],Syst.wDay
invoke IntToStrBk,addr [HourText+17],Loc.wHour
invoke IntToStrBk,addr [HourText+31],Syst.wHour
invoke IntToStrBk,addr [MinuteText+17],Loc.wMinute
invoke IntToStrBk,addr [MinuteText+31],Loc.wMinute
invoke IntToStrBk,addr [SecondText+17],Loc.wSecond
invoke IntToStrBk,addr [SecondText+31],Loc.wSecond
invoke IntToStrBk,addr [MillisecondText+17],Loc.wMilliseconds
invoke IntToStrBk,addr [MillisecondText+31],Loc.wMilliseconds
ret
TimeProcedure ENDP

;convert a dword to a string
;starting at lpDest and working backwards (i.e., right align the
;string to the lpDest variable)

IntToStrBk PROC uses ebx ecx edx lpDest,Value:DWORD
mov eax,Value
mov ebx,lpDest
mov ecx,10
@@: xor edx,edx
div ecx
add dl,30h
mov BYTE PTR [ebx],dl
dec ebx
test eax,eax
jnz @B
ret
IntToStrBk ENDP

end start




--Chorus
Posted on 2002-07-29 13:35:00 by chorus
Thank you chorus, you are the only one to answer, so you have won it ;)

It has take me more than 24 hours, coz I couldn?t get it done... and it?s not finished yet. But im giving up I think.
My solution is the less obvious.

I called this thread "a riddle" because it's sort of it, and the answer is probably one you wouldn't think of: I've changed assembler.
Yes, I've retyped the whole thing using fasm and a great help from Michael Pruitt, and this is the solution.
But I don?t seem to make it work properly, I think it could be solved by using some 'virtual at' in the macro, but maybe probably only Privalov, bAZiK or bitRAKE can help me solve this out ;)


;
; Sorry, I can?t make it work: 'symbol already defined' while using macros
;

format PE GUI 4.0
entry start

include 'include\kernel.inc'
include 'include\user.inc'

include 'include\macro\stdcall.inc'
include 'include\macro\import.inc'

macro convert place,offset,number
{ local number
local offset
local place
mov edi,place + offset
cmp [number],2
jz @f ;Anonymous labels are a new feature of v. 1.39 beta2
sub edi,36 ;This macro is dependent on this particular data structure
@@: call .convert
}


section '.code' code readable executable
start:
invoke GetLocalTime, Time
invoke Format_Time, Time,1

invoke GetSystemTime,Time
invoke Format_Time, Time,2

invoke MessageBox,0,Text,Caption,MB_OK
invoke ExitProcess,0

proc Format_Time, AnyTime,AnyNumber
enter

mov ax, [AnyTime.wYear] ;16-bit data
convert Text.Date,9+36,AnyNumber ;Does conversion to printable format

mov ax,[AnyTime.wDay]
convert Text.Date,4+36,AnyNumber

mov ax,[AnyTime.wMonth]
convert Text.Date,1+36,AnyNumber

mov edi,Text.Day-36
mov esi,ListDays
repeat 2 ;How will FASM translate this? Like a macro? Or will it make a counter 2 loop?
add edi, 36
xor eax,eax
mov ax, [AnyTime.wDayOfWeek]
add esi, eax
add esi, eax
add esi, eax ;Clever way to move in ListDays
mov ecx, 3
cld
rep movsb
end repeat

mov ax, [AnyTime.wHour]
convert Text.Time,1+36,AnyNumber

mov ax,[AnyTime.wMinute]
convert Text.Time,4+36,AnyNumber

mov ax,[Anytime.wSecond]
convert Text.Time,7+36,AnyNumber

return

.convert: ;by Michael Pruitt, this gave me the idea to translate the first version
std
cmp ax,10
jl .one

and ah,ah
jz .two

mov bh,10
div bh
or ah,30h
mov [edi],ah
dec edi
.two:
aam
or al,30h
stosb
mov al,ah
cmp ah,9
jg .two
.one:
or al,30h
stosb

cld
ret

section '.data' data readable writeable

Caption db "Tempus fugit...",0
Text: db "LOCALTIME: "
.Day db "WkD"
.Date db " 0/00/0000"
.Time db " 0:00:00", Cr, Lf
.More db "SYSTEMTIME: WkD 0/00/0000 0:00:00",0

ListDays db "SunMonTueWedThuFriSat"

Cr = 0Dh
Lf = 0Ah
Time SYSTEMTIME

section '.idata' import data readable writeable

library kernel, 'kernel32.dll',\
user, 'user32.dll'

kernel:
import GetLocalTime, 'GetLocalTime',\
GetSystemTime, 'GetSystemTime',\
ExitProcess, 'ExitProcess'

user:
import MessageBox, 'MessageBoxA'



Chorus, of course, after following your answers, see that it was easier than I did it, the best of all is that it works!.
I don?t know, maybe I?m sloppy because I don?t seem to make thinks work with modularity and good programming principles... so I switch to sloppines to get the job done.
I wish you could tell me how do you get it done, and at the same time looks clear, intelligent, and readable.


Thanx, chorus. (I?ll have to think what the prize for you is, any idea?)
sloopy.
Posted on 2002-07-30 13:19:39 by slop
I gave it a quick look and did a small corrections to make it work (quick and dirty):


format PE GUI 4.0
entry start

include 'include\kernel.inc'
include 'include\user.inc'

include 'include\macro\stdcall.inc'
include 'include\macro\import.inc'

macro convert place,offset,number
{
mov edi,place + offset
cmp [number],2
jz @f
sub edi,36
@@: call .convert
}

section '.code' code readable executable
start:
invoke GetLocalTime, Time
stdcall Format_Time, Time,1

invoke GetSystemTime,Time
stdcall Format_Time, Time,2

invoke MessageBox,0,Text,Caption,MB_OK
invoke ExitProcess,0

proc Format_Time, AnyTime,AnyNumber
enter
mov ebx,[AnyTime]
virtual at ebx
ATime SYSTEMTIME
end virtual

mov ax, [ATime.wYear] ;16-bit data
convert Text.Date,9+36,AnyNumber ;Does conversion to printable format

mov ax,[ATime.wDay]
convert Text.Date,4+36,AnyNumber

mov ax,[ATime.wMonth]
convert Text.Date,1+36,AnyNumber

mov edi,Text.Day-36
mov esi,ListDays
repeat 2
add edi, 36
xor eax,eax
mov ax, [ATime.wDayOfWeek]
add esi, eax
add esi, eax
add esi, eax
mov ecx, 3
cld
rep movsb
end repeat

mov ax, [ATime.wHour]
convert Text.Time,1+36,AnyNumber

mov ax,[ATime.wMinute]
convert Text.Time,4+36,AnyNumber

mov ax,[ATime.wSecond]
convert Text.Time,7+36,AnyNumber

return

.convert: ;by Michael Pruitt, this gave me the idea to translate the first version
std
cmp ax,10
jl .one

and ah,ah
jz .two

mov dh,10
div dh
or ah,30h
mov [edi],ah
dec edi
.two:
aam
or al,30h
stosb
mov al,ah
cmp ah,9
jg .two
.one:
or al,30h
stosb

cld
ret

section '.data' data readable writeable

Caption db "Tempus fugit...",0
Text: db "LOCALTIME: "
.Day db "WkD"
.Date db " 0/00/0000"
.Time db " 0:00:00", Cr, Lf
.More db "SYSTEMTIME: WkD 0/00/0000 0:00:00",0

ListDays db "SunMonTueWedThuFriSat"

Cr = 0Dh
Lf = 0Ah
Time SYSTEMTIME

section '.idata' import data readable writeable

library kernel, 'kernel32.dll',\
user, 'user32.dll'

kernel:
import GetLocalTime, 'GetLocalTime',\
GetSystemTime, 'GetSystemTime',\
ExitProcess, 'ExitProcess'

user:
import MessageBox, 'MessageBoxA'


EDIT: To assemble it with fasm version older than 1.40 beta 2, replace the convert macro with following (doesn't need anonymous labels):


macro convert place,offset,number
{
local .cnv
mov edi,place + offset
cmp [number],2
jz .cnv
sub edi,36
.cnv: call .convert
}
Posted on 2002-07-30 13:48:47 by Tomasz Grysztar


.386
.model flat,stdcall
option casemap:none

include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc


includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib

TimeProcedure PROTO
IntToStr PROTO :DWORD,:DWORD
StringCopy PROTO :DWORD,:DWORD

CR EQU 13
LF EQU 10

DOW STRUC
NameOfDay db 16 dup (0)
DOW ENDS

.data

Caption DB "Localtime and Systemtime",0


LocalText DB "Local Time: ",0
SystemText DB "System Time: ",0
Buffer DB 128 dup (0)
WeekdayNames DOW <"Sunday ">
DOW <"Monday ">
DOW <"Tuesday ">
DOW <"Wednesday ">
DOW <"Thursday ">
DOW <"Friday ">
DOW <"Saturday ">


.code
start:
invoke TimeProcedure
invoke MessageBox, NULL, addr Buffer, addr Caption, MB_OK
invoke ExitProcess, NULL

TimeProcedure PROC
LOCAL Loc :SYSTEMTIME
LOCAL Syst :SYSTEMTIME

invoke GetLocalTime, addr Loc
invoke GetSystemTime, addr Syst
invoke StringCopy,addr Buffer,addr LocalText
movzx edx,Loc.wDayOfWeek
shl edx,4
add edx,offset WeekdayNames
invoke StringCopy,eax,edx

invoke IntToStr,eax,Loc.wDay
mov BYTE PTR [eax],'/'
invoke IntToStr,addr [eax+1],Loc.wMonth
mov BYTE PTR [eax],'/'
invoke IntToStr,addr [eax+1],Loc.wYear
mov DWORD PTR [eax],' '
invoke IntToStr,addr [eax+4],Loc.wHour
mov DWORD PTR [eax],':'
invoke IntToStr,addr [eax+1],Loc.wMinute
mov DWORD PTR [eax],':'
invoke IntToStr,addr [eax+1],Loc.wSecond
mov DWORD PTR [eax],':'
invoke IntToStr,addr [eax+1],Loc.wMilliseconds
mov BYTE PTR [eax],CR
mov BYTE PTR [eax+1],LF
invoke StringCopy,addr [eax+2],addr SystemText
movzx edx,Loc.wDayOfWeek
shl edx,4
add edx,offset WeekdayNames
invoke StringCopy,eax,edx
invoke IntToStr,eax,Syst.wDay
mov BYTE PTR [eax],'/'
invoke IntToStr,addr [eax+1],Syst.wMonth
mov BYTE PTR [eax],'/'
invoke IntToStr,addr [eax+1],Syst.wYear
mov DWORD PTR [eax],' '
invoke IntToStr,addr [eax+4],Syst.wHour
mov DWORD PTR [eax],':'
invoke IntToStr,addr [eax+1],Syst.wMinute
mov DWORD PTR [eax],':'
invoke IntToStr,addr [eax+1],Syst.wSecond
mov DWORD PTR [eax],':'
invoke IntToStr,addr [eax+1],Syst.wMilliseconds
ret
TimeProcedure ENDP

IntToStr PROC uses ebx ecx edx esi edi lpDest,value:DWORD
LOCAL textbuffer[10]:BYTE
mov eax,value
xor edi,edi
lea esi,textbuffer
mov ecx,10
@@: xor edx,edx
div ecx
add dl,30h
mov BYTE PTR [esi+edi],dl
inc edi
test eax,eax
jnz @B
mov ebx,lpDest
lea eax,[ebx+edi]
dec edi
@@: mov dl, BYTE PTR [esi]
mov BYTE PTR [ebx+edi],dl
inc esi
sub edi,1
jns @B
ret
IntToStr ENDP

StringCopy PROC uses edi esi edx lpDest,lpSource:DWORD
mov edi,lpDest
mov esi,lpSource
or eax,-1
xor edx,edx
@@: inc eax
mov dl,BYTE PTR [esi+eax]
mov BYTE PTR [edi+eax],dl
test dl,dl
jnz @B
add eax,edi
ret
StringCopy ENDP

end start
Posted on 2002-07-30 17:24:26 by chorus
Sloppy, haven't tried FASM yet, but I hear it's "All the Rage" ;)

Since you asked, here's a few notes about my code:

1st version
--pass on the macros if you can. In some instances they are useful but I find they often "bloat" the code. Some people on the board use em, but you have to be careful. Macros have several drawbacks. The two foremost I would say is increasing code size (when you could use a procedure and "reuse" the same bytes) and also you can't get as much control as you may want.

Ex. m2m, uses push/pop's which can be slower than a mov eax,/mov ,eax. Plus, you can't schedule the instructions in a macro.

--Cleaned up the data section so not only is it readable, it makes for easy coding.

2nd version
--introduce two new procs StringCopy and IntToStr. StringCopy is a stripped down version of the string copy proc I usually use, but it has the one important property that I like in my own StringCopy: it returns the ptr to the end of the dest so it's easy to make multiple calls.

Ex.
invoke StringCopy,addr Buffer,addr FirstName
invoke StringCopy,eax,addr LastName
invoke StringCopy,eax,addr Address
etc.

This is also true of IntToStr; it returns a ptr to the byte past the ASCII number. Note that StringCopy is zero terminated whereas IntToStr isn't

--Add formating bytes. Take advantage of the return value of IntToStr to move in backslashes and colons, etc to format the string. This way, we needn't worry about extra string in our data section. We also don't need to worry about the length of the integer.

--Use the DOW STRUC. This struc automatically zeroterminates strings for me and keeps strings blocked into 16 bytes. When you store it in an array you can easily extract the name of the Day of the week from the SYSTEMTIME.wDayOfWeek value.

--Couple of equates for CR and LF. Just to make the code more readable

There's a couple things I think you can take from these examples:

--If you're gonna write your own procs, return something useful. Thus your program is more data driven and more flexible
--Proper use of strucs can make your source clearer
--calling a proc 10 times is smaller code than using 10 macros that do what the proc does and it isn't any worse for readability
--Clearer code is faster to debug and to type

--Chorus
Posted on 2002-07-30 17:38:00 by chorus
These two thanks arrive one week later, but, you can guess. don?t make me say it... I think only of sayng it I?ll have another.
Thanks a lot Privalov; thanks a lot chorus. I already owed Tomasz a beer, so I see now it?s two ;)
I hope some day I?ll be as sharp as you, and won?t have that many krashes (you see,scientica, even more than you) (I?ll change my nick then ;) )
Posted on 2002-08-06 10:44:42 by slop