Can anyone help me in understanding how this code is able to access the correct elements of the arrays?
;;
;; MAIN WINDOW MESSAGES
;;
CONST
ALIGN 4
MainMsg DD WM_COMMAND,\
WM_WINDOWPOSCHANGED,\
WM_PAINT,\
WM_CREATE, WM_CLOSE, WM_DESTROY
MainM DD MainWM_COMMAND,\ {THIS UP HERE}
MainWM_WINDOWPOSCHANGED,\
MainWM_PAINT,\
MainWM_CREATE, MainWM_CLOSE, MainWM_DESTROY
CODE
ALIGN 4
MainWND:
FRAME hWnd, uMsg, wParam, lParam
USES ebx,esi,edi
;IF message is not found
mov eax,[uMsg]
mov edi,ADDR MainMsg
mov ecx,SIZEOF(MainMsg)/4
repne scasd
je >.Process
;THEN let DefWindowProc handle this message
.Default
push [lParam] ;lParam
push [wParam] ;wParam
push [uMsg] ;Msg
push [hWnd] ;hWnd
call [DefWindowProc] ;User32
jmp >.Return
;ELSE process this message possibly setting carry flag for default processing
ALIGN 4
.Process
call D[edi+SIZEOF(MainMsg)-4] ; {HOW DOES THIS ACCESS}
jc <.Default
.Return
ret
ENDF
Hi bigrichlegend, welcome to the forum!
Assuming the code you have posted actually does work, it looks as though prior to the repne scasd instruction the address of the MainMsg table is given to edi. This table contains the message constants which must be somewhere else in the file or in an include file. Repne scasd will return zero (zero flag set) if it found the correct message, not zero if it didn't.
If it found the correct message, the code jumps down to .Process where the call is made to the function to process the message (the function will be elsewhere in the code).
At the time of the call, edi holds the address in the MainMsg where the message was found by repne scasd, plus 4 bytes. The extra 4 bytes is because the scasd instruction moves four bytes at a time even if it is about to return zero. So the 4 bytes are removed in the call instruction using "-4". And to get to the second table (holding the addresses of the functions) it's necessary to move edi over the first table. This is done by adding the size of the first table using "+SIZEOF(MainMsg)".
The second table holds the addresses of the functions to process the correct message in exactly the same sequence as the first table.
Personally I find it easier to make the tables if you have only one table (not split into two) as in the GoAsm HelloWorld examples.
Thanks for the assist. It makes more sense now!. However, I was of the opinion that to access an element in an array one would use this approach
Element_Address = [Base_Address + index * Element_Size]
= [edi + value returned by scasd - 4]
Base_Address would be [ADDR MainMsg] in edi.
That looks familiar :bg with a sensible description above :U... the label MainM is required for SIZEOF to do its thing (in this case with two tables) but is not used elsewhere in the code as may have been expected.
The opinion is still good and could be used if you set up your own loop to scan through the table(s) (as in the GoAsm HelloWorld examples). It just doesn't apply to the way repne scasd processes by advancing from the base address with increases (in this case) to edi, using ecx as a count rather than an index.