I thought someone may like this one. I am trying to simplify a template for a dialog code design as it makes the code generator easier to write when you don't have to make multiple entries for the same value. The example is for setting a global scope handle to the return value of an API call but the general idea for global handles looks like it will be useful for writing simpler cleaner code.
;; -------------------------------------------------------
;; Use this macro as follows.
;; UniqueHandle = SetGlobalHandle(ParentHandle,Control_ID)
;; EXAMPLE : hButton1 = SetGlobalHandle(hWin,250)
;;
;; NOTE that the unique handle is created in the .DATA? section
;; by the MACRO, do NOT create a LOCAL or GLOBAL value for
;; this handle or you will get s "symbol redefinition" error.
;; -------------------------------------------------------
SetGlobalHandle MACRO hParent, ctlID
LOCAL hndl
.data?
hndl dd ?
.code
invoke GetDlgItem,hParent,ctlID
mov hndl, eax
EXITM < hndl>
ENDM
;; -------------------------------------------------------
This one looks even more useful.
gh MACRO args:VARARG
LOCAL hndl
.data?
hndl dd ?
.code
invoke args
mov hndl, eax
EXITM < hndl>
ENDM
It makes general purpose global handles available to any API/function that returns a value that you want in the .DATA? section.
hInstance = gh(GetModuleHandle, NULL)
Hutch,
Interesting stuff. I am still trying to figure out what exactly it does: in the disassembly below, the middle assignment does not appear, i.e. the hInstance = 12345678 gets treated like any other assembly time constant definition. But the other two do assign runtime values... ::)
include \masm32\include\masm32rt.inc
gh MACRO args:VARARG
LOCAL hndl
.data?
hndl dd ?
.code
invoke args
mov hndl, eax
EXITM < hndl>
ENDM
.code
AppName db "Masm32:", 0
start:
; int 3
hInstance = gh(GetModuleHandle, NULL)
nop
hInstance = 12345678
nop
hInstance = gh(GetTickCount)
MsgBox 0, str$(hInstance), str$(rv(GetTickCount)), MB_OK
exit
end start
CPU Disasm
Address Hex dump Command Comments
00401009 ³. 6A 00 push 0 ; ÚModuleName = NULL
0040100B ³. E8 BC000000 call <jmp.&kernel32.GetModuleHandleA> ; ÀKERNEL32.GetModuleHandleA
00401010 ³. A3 F0204000 mov dword ptr [NewWin32.4020F0], eax
00401015 ³. 90 nop ; ÚType => MB_OK|MB_DEFBUTTON1|MB_APPLMODAL
00401016 ³? 90 nop ; ³
00401017 ³. E8 B6000000 call <jmp.&kernel32.GetTickCount> ; ³Caption = ""FF,"%",88," @"
0040101C ³. A3 F4204000 mov dword ptr [NewWin32.4020F4], eax ; ³Text => ""
At compiletime 'hndl' gets replaced by something like ??0012 - this is then assigned to the assembly constant: hInstance=??0012
Having played with this idea for a while I have reverted back to the form that uses the MASM "EQU" notation because it provides an error message when a duplicate ID is use. You can redefine a value set with the " = " notation where an "EQU" cannot. This is the macro form that I will propbably use.
;; -------------------------------------------------------
IFNDEF cgv
cgv MACRO args:VARARG ;; create GLOBAL value
LOCAL hndl
.data?
hndl dd ?
.code
invoke args
mov hndl, eax
EXITM < equ <hndl>>
ENDM
ENDIF
;; -------------------------------------------------------
The IFNDEF is purely so I can add the macro to macros.asm later without duplicates.
In terms of usage the difference is very slight, you use no " = " in this form.
hInstance cgv(GetModuleHandle, NULL)
The way it works is reasonably simple, The .DATA? section items are known at assembly time and effectively what the macro is doing is runnig the function/API/procedure call in the normal manner, writing the return value to the .DATA? section entry then setting an equate for the .DATA? section entry to a name.