Perhaps you already noticed, but I still want to point out that the $INVOKE macro does not work correctly when nesting it. Example:


mov Result,$invoke(Proc1,$invoke(Proc2,1),$invoke(Proc3,2))

Assembles this:


push 2
call Proc3
push 1
call Proc2
push eax
push eax
call Proc1
mov Result,eax

Wich is surely not what we intended. :(
Since "$INVOKE" is actually a wrapper for the built-in "INVOKE" macro in MASM, I imagine that INVOKE actually tries to evaluate all parameters to check that it matches the prototype definition, and only then it assembles the pushes and call. So another $INVOKE call would be evaluated before having pushed the previous parameters. The result in our example is the same as:


invoke Proc3,2
invoke Proc2,1
invoke Proc,eax,eax
mov Result,eax

Maybe we could ask the macro champion here (I mean BitRAKE, of course ;) ) to code a new version of this macro, that would produce the correct results... The parameter pushing and the calls can be done in a FOR loop, but the really hard part would be to check the function prototypes (I don't know how, or if, macros can access this information).
Posted on 2003-10-03 14:33:04 by QvasiModo
Your still writing for MASM not a HLL. Invoke was never written to "nest" deeply as your showing. The point was to simplify some of the simpler routines, like:

mov hDC, $invoke( GetDC, hWin )

When you write this, you *should* still be thinking what is happening. If you dont your might as well be using a HLL.


To address this point with our OOP lib, we made a series of identical method calling macros, $EBX() $ESI() $EDI() etc. This allows you to do what your asking for. So if you make $Invoke_EAX() $Invoke_EBX() $Invoke_ESI() $Invoke_EDI():

mov  Result,$invoke_EAX(Proc1, $invoke_ESI(Proc2,1), $invoke_EDI(Proc3,2) ) 


You would get your listing:


push 2
call Proc3
[b]mov EDI, EAX[/b]
push 1
call Proc2
[b]mov ESI, EAX[/b]
push [b]EDI[/b]
push [b]ESI[/b]
call Proc1
mov Result,[b]EAX[/b]


Regards,
:NaN:
Posted on 2003-10-05 10:33:55 by NaN
Thanks for the help, Nan :)

I know that macros should be used with care, it's just that this is not an obvious issue when looking at the macro source. The only way to realize that this code does not work as intended is to test it, since MASM will obviously not report any errors. The point of this thread was mostly to spare a headache to other people that uses the $invoke macro, and tried to nest it like that.

I'll be taking a look at your invoke macros, they could prove very useful. ;)
Posted on 2003-10-06 12:51:51 by QvasiModo
Its not a problem...

I urge you to learn up on them. They are a true asset to assembly programming....

Feel free to ask questions. ;)
:alright:
NaN
Posted on 2003-10-06 21:11:57 by NaN
My silly $invoke alternative... it still has many flaws, but it may be improved. Please tell me what you think of it :)
; This is similar to $invoke... it calls a function, and returns <eax>.

; Advantages:
; - It can be nested better than $invoke (calls are interleaved correctly)
; - It does not require a prototype to be defined to call a function
; - You can pass it any pointer, including registers
; Drawbacks:
; - It does not check that the correct number of parameters is being passed
; - Does not support the use of ADDR
; - You can only span it across lines using a backslash
; - It only supports the STDCALL convention
$call MACRO Fun:REQ, A:VARARG
IFB <A>
call &Fun&
ELSE
FOR Arg, @ArgI(A)
push Arg
ENDM
call &Fun&
ENDIF
EXITM <eax>
ENDM
Posted on 2003-10-14 17:57:21 by QvasiModo
Looks like your getting the hang of them ;)

Not 100% on the ArgI() macro, but i believe you can get the same effect from the FOR loop with:

FOR Args, <A>

However, i didnt test it ;)
:alright:
NaN
Posted on 2003-10-14 23:03:00 by NaN