I defined a structured variable as follows in MASM32
Time STRUCT
Hour DW ?
Minute DW ?
Second Dw ?
End Time
I create multiple instances of time like:
Time1 Time <>
Time 2 Time <>
I want to call a procedure using the Time instances:
Something like:
Call TimeConvert,??Time1or Time2
I want to write a Procedure which will make conversions of Time instances
Something like:
TimeConverter PROC NEAR
? arg:STRUCT
How do you pass the Time instances to a procedure ?
This might do the job.
include \masm32\include\masm32rt.inc
TIME STRUCT
Hour DW ?
Minute DW ?
Second DW ?
TIME ENDS
Convert PROTO: TIME
.code
timeA TIME <10, 15, 30>
timeB TIME <15, 30, 00>
timeC TIME <21, 15, 30>
start:
invoke Convert, timeA
invoke Convert, timeB
invoke Convert, timeC
getkey
exit
Convert proc uses edi esi locTime:TIME
LOCAL buffer[80]:BYTE
lea edi, buffer
invoke lstrcpy, edi, chr$("Hours=")
invoke lstrcat, edi, str$(locTime.Hour)
invoke lstrcat, edi, chr$(", minutes=")
invoke lstrcat, edi, str$(locTime.Minute)
invoke lstrcat, edi, chr$(", seconds=")
invoke lstrcat, edi, str$(locTime.Second)
invoke lstrcat, edi, chr$(13, 10, 10)
print edi
ret
Convert endp
end start
By the way: posting in UPPERCASE is considered SHOUTING for help :wink
The method to use would depend in part on whether or not the procedure must be able to modify the structure members. If you pass a pointer to the structure then the procedure must access the structure members through the pointer, but using this method it can readily modify the structure members. If you pass the structure directly on the stack, then the procedure can access the structure members more easily, but any modifications will affect only the copies of the structure members on the stack. For this code I used DWORDs for the structure members so MASM would have no problems getting the stack operations right. There may be ways to use other member sizes, but in the time I had to spend on this I could not find any that would actually work. If my explanations regarding modifying the structure members are not clear, take a look at the disassembled code for the procedures.
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
include \masm32\include\masm32rt.inc
TIME struct
hour dd ?
minute dd ?
second dd ?
TIME ends
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
.data
time1 TIME <1,2,3>
time2 TIME <4,5,6>
.code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
PrintTimePointer proc ptime:DWORD
push ebx
mov ebx, ptime
;------------------------------------------------------
; For this method the access code is a little shorter,
; but the ASSUME statements are required.
;------------------------------------------------------
ASSUME ebx:ptr TIME
print str$([ebx].hour),":"
print str$([ebx].minute),":"
print str$([ebx].second),13,10
ASSUME ebx:NOTHING
;-----------------------------------------------------
; For this method the access code is a little longer,
; but no additional statements are required.
;-----------------------------------------------------
print str$([ebx].TIME.hour),":"
print str$([ebx].TIME.minute),":"
print str$([ebx].TIME.second),13,10
inc [ebx].TIME.second
pop ebx
ret
PrintTimePointer endp
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
PrintTimeDirect proc ts:TIME
print str$(ts.hour),":"
print str$(ts.minute),":"
print str$(ts.second),13,10
dec ts.second
ret
PrintTimeDirect endp
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
invoke PrintTimePointer, ADDR time1
invoke PrintTimePointer, ADDR time2
invoke PrintTimeDirect, time1
invoke PrintTimeDirect, time2
invoke PrintTimeDirect, time1
invoke PrintTimeDirect, time2
inkey "Press any key to exit..."
exit
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start
jj,
str$ expects a DWORD argument
The caps lock is strong in this one.
Quote from: MichaelW on February 06, 2009, 11:38:19 PM
jj,
str$ expects a DWORD argument
What you write is indeed correct. Interestingly enough, it works fine.
At least dwtoa should have complained... :dazzled:
str$ MACRO DDvalue
LOCAL rvstring
.data
rvstring db 20 dup (0)
align 4
.code
invoke dwtoa,DDvalue,ADDR rvstring
EXITM <ADDR rvstring>
ENDM
Probably, that has to do with recent progress re type-checking etc.; the old Masm 6.14 chokes indeed with an exception, but JWasm and ml 9.0 have become tolerant. They read my thoughts, and know that I mistook "dw" for "dword". It's called old age, but Microsoft and Japheth can deal with that :bg
Quote from: jj2007 on February 07, 2009, 01:29:54 AM
Probably, that has to do with recent progress re type-checking etc.; the old Masm 6.14 chokes indeed with an exception, but JWasm and ml 9.0 have become tolerant. They read my thoughts, and know that I mistook "dw" for "dword". It's called old age, but Microsoft and Japheth can deal with that :bg
But this would mean that MS has managed to fix the 18-year-old, well-known "invoke" bug in Masm v9.0 - almost impossible to believe; if true, it's a good reason for celebrations.
Quote from: japheth on February 07, 2009, 02:32:14 AM
But this would mean that MS has managed to fix the 18-year-old, well-known "invoke" bug in Masm v9.0 - almost impossible to believe; if true, it's a good reason for celebrations.
Yes indeed. And they don't even trash eax like JWasm does :bg
ML 6.14:
00401074 ³. 68 07204000 push offset TimeStruct.00402007
00401079 ³. 6A 00 push 0
0040107B ³. 66:FF75 08 push word ptr [arg.1]
ML 9.0:
00401074 ³. 68 07204000 push offset TimeStruct.00402007
00401079 ³. 66:6A 00 push word 0
0040107C ³? 66:FF75 08 push word ptr [ebp+8]
JWasm:
00401074 ³. 68 07204000 push offset TimeStruct.00402007
00401079 ³. 0FB745 08 movzx eax, word ptr [arg.1]
0040107D ³? 50 push eax
Anyway, all this problems could have been avoided with a slightly more intelligent version of str$:
str$ MACRO DDvalue
LOCAL rvstring
.data?
rvstring db 20 dup (?)
.code
if SIZEOF DDvalue lt 4
movzx eax, DDvalue
invoke dwtoa, eax, offset rvstring
else
invoke dwtoa, DDvalue, offset rvstring
endif
EXITM <offset rvstring>
ENDM
Compared to the old version, this str$
- knows about non-dword integers
- does not waste space in the initialised data section
- and allows the
mov esi, str$(eax) syntax
QuoteYes indeed. And they don't even trash eax like JWasm does
But they do trash the sign, silently. All three methods are replacing one quirk with another.
Quote from: MichaelW on February 07, 2009, 01:05:52 PM
QuoteYes indeed. And they don't even trash eax like JWasm does
But they do trash the sign, silently. All three methods are replacing one quirk with another.
Point taken :U
str$ MACRO DDvalue
LOCAL rvstring
.data?
rvstring db 20 dup (?)
.code
if SIZEOF DDvalue lt 4
ifdifi <eax>, <DDvalue> ; avoids a rather useless mov eax, eax
mov
sx eax, DDvalue ;
preserves the sign endif
invoke dwtoa, eax, offset rvstring
else
invoke dwtoa, DDvalue, offset rvstring
endif
EXITM <offset rvstring>
ENDM
Quote from: jj2007 on February 07, 2009, 02:37:52 PM
movsx eax, DDvalue ; preserves the sign
This preserves the sign if the value is "signed". If the value is unsigned and >= 8000h (or > 80h for bytes), it'll be wrong.
I agree that movsx would be wrong for unsigned values, but in this case dwtoa expectes signed values.
NUMBSKULL2,
One request, please do not post topics in upper case to attract atention, its is classed as bad manners, something like SHOUTING.
Quote from: MichaelW on February 07, 2009, 03:09:35 PM
I agree that movsx would be wrong for unsigned values, but in this case dwtoa expectes signed values.
It is a pity that
opattr does not tell us whether a variable is signed or unsigned. The only workaround I see is to have two macros instead of one:
str$ MACRO DDvalue
LOCAL rvstring
.data?
rvstring db 20 dup (?)
.code
if SIZEOF DDvalue lt 4
ifdifi <eax>, <DDvalue> ; avoids a rather useless mov eax, eax
movsx eax, DDvalue ; preserves the sign
endif
invoke dwtoa, eax, offset rvstring
else
invoke dwtoa, DDvalue, offset rvstring
endif
EXITM <offset rvstring>
ENDM
ustr$ MACRO DDvalue
LOCAL rvstring
.data?
rvstring db 20 dup (?)
.code
if SIZEOF DDvalue lt 4
ifdifi <eax>, <DDvalue> ; avoids a rather useless mov eax, eax
movzx eax, DDvalue ; keeps the value unsigned
endif
invoke udw2str, eax, offset rvstring
else
invoke udw2str, DDvalue, offset rvstring
endif
EXITM <offset rvstring>
ENDM
Thanks for the help
I apologize for shouting. I won't do i t anymore.
Pat
I was able to get the code you all wrote to run.
Both methods passed the members of the structure on the stack which requires code to copy any modified values on the stacks back to the structure members after the procedure is invoked.
I want to pass a pointer to the structure so that I can modify the members within the procedure and be done with it.
I have never worked with the Invoke method and I can't figure out how to pass the pointer.
I tried the following:
Time STRUCT
Hour DB ?
Minute DB ?
Second DB ?
HourTick DW ?
MinuteTick DW ?
SecondTick DW ?
Time ENDS
TickConvert PROTO :Time
.DATA
StartTime < >
EndTime <>
.CODE
Start: INVOKE TickConvert, ADDR StartTime
;*****************************************************************
TickConvert PROC NEAR Loctime:Time
mov al,Loctime.Second
mov bl, 64h
mul bl
mov Loctime.SecondTick,ax
ret
TickConvert ENDP
End Start
When the code above is assembled I get an error 2114: Invoke Argument type mismatch.
I think the Invoke statement is correct even though the error is on this statement.
I just can't figure out how to modify the PROTO statement or the PROC statement.
TickConvert PROTO :PTR Time
Quote from: Numbskull2 on February 09, 2009, 02:55:29 AM
I tried the following:
You didn't try hard enough.
include \masm32\include\masm32rt.inc
TickConvert PROTO :DWORD
Time STRUCT
Hour DB ?
Minute DB ?
Second DB ?
HourTick DW ?
MinuteTick DW ?
SecondTick DW ?
Time ENDS
.DATA
StartTime Time <12, 13, 14, 0, 0, 0 >
EndTime Time <12, 13, 14, 0, 0, 0>
.CODE
Start: INVOKE TickConvert, ADDR StartTime
movzx eax, word ptr StartTime.SecondTick
MsgBox 0, str$(eax), "Hi", MB_OK
exit
;*****************************************************************
TickConvert PROC NEAR Loctime:DWORD
mov edx, Loctime
mov al,[edx.Time.Second]
mov bl, 64h
mul bl
mov [edx.Time.SecondTick], ax
ret
TickConvert ENDP
End Start