Hello,
Does anyone have an idea how to make invoke works on an external function that resides in a memory address?
Example:
.Data?
MyFunction dd ?
Mov EAX,MyMemAddress ;[MyMemAdress contains a pointer to an external function lets say GetTickCount]
MOV MyFunction,EAX
invoke [MyFunction]
Why not just use the CALL mnemonic ?
Exactly! There are a number of more or less acrobatic methods to do that, including the Declare (http://www.webalice.it/jj2006/MasmBasicQuickReference.htm#Mb1017) macro, but why bother? Just push the arguments in inverse order and call the function. If you are keen on complicated things: The jinvoke macro does exactly what you want, it's in \Masm32\MasmBasic\Res\JBasic.inc - only 325 lines and 6.8 kBytes.
Using Call must push all arguments in a reverse order and also makes code very unreadable.
Quote from: jj2007 on May 06, 2019, 07:15:56 PM
Exactly! There are a number of more or less acrobatic methods to do that, including the Declare (http://www.webalice.it/jj2006/MasmBasicQuickReference.htm#Mb1017) macro, but why bother? Just push the arguments in inverse order and call the function. If you are keen on complicated things: The jinvoke macro does exactly what you want, it's in \Masm32\MasmBasic\Res\JBasic.inc - only 325 lines and 6.8 kBytes.
Hi jj,
Thanks for the tip but i can not seem to find the 32bit version of this macro. Is this a 64bit only?
No, JBasic is a package that builds both 32- and 64-bit code from the same identical source. Simple example:
include \Masm32\MasmBasic\Res\JBasic.inc
Init ; OPT_64 0 ; put 0 for 32 bit, 1 for 64 bit assembly
PrintLine Chr$("This program was assembled with ", @AsmUsed$(1), " in ", jbit$, "-bit format.")
jinvoke MessageBox, 0, Chr$("There are LoadLibrary and GetProcAddress under the hood"), Chr$("Just a test:"), MB_OK
EndOfCode
Output: This program was assembled with ml64 in 64-bit format. (plus the MsgBox, of course)
The macro works fine but it is damn complicated (inter alia, it checks the parameter count and type), and it requires also a tiny static library that cares for the LoadLibrary & GetProcAddress part. I am no longer working on it because I am not interested in 64-bit coding.
Thanks for the info. I couldn't compile your example though
Error A2102: Symbol not defined : iaApi
Its indeed sounds a complicated task. Might just stick with the SPROTO.
If you want it to look more high level, just write a macro for it. Push reverse order then call the procedure address. It is a trivial macro to write.
Lua_setglobalProto TYPEDEF PROTO C luastate:DWORD, ptr_name:DWORD
Lua_setglobalPtr TYPEDEF PTR Lua_setglobalProto
.data
F_Lua_setglobal Lua_setglobalPtr 0 ; similar to defining F_Lua_setglobal as: F_Lua_setglobal DD 0
.code
...
; Assign the F_Lua_setglobal variable a function address value somewhere:
; mov eax, dwSomeAddress
; mov F_Lua_setglobal, eax
...
Invoke F_Lua_setglobal, g_lua, lpszFunctionName
...
Try like this for a function with 2 ptr arguments:
lea eax, funcToCall
FuncProto typedef PROTO :ptr, :ptr
assume eax : ptr FuncProto
invoke eax, dest, src
assume eax:nothing
Quote from: hutch-- on May 06, 2019, 08:22:55 PM
If you want it to look more high level, just write a macro for it. Push reverse order then call the procedure address. It is a trivial macro to write.
Very good solution! i have not thought of it. Do you know how to make the arguments variable in Macro? because not all API's have the same number of arguments.
Quote from: fearless on May 06, 2019, 08:42:08 PM
Lua_setglobalProto TYPEDEF PROTO C luastate:DWORD, ptr_name:DWORD
Lua_setglobalPtr TYPEDEF PTR Lua_setglobalProto
.data
F_Lua_setglobal Lua_setglobalPtr 0 ; similar to defining F_Lua_setglobal as: F_Lua_setglobal DD 0
.code
...
; Assign the F_Lua_setglobal variable a function address value somewhere:
; mov eax, dwSomeAddress
; mov F_Lua_setglobal, eax
...
Invoke F_Lua_setglobal, g_lua, lpszFunctionName
...
Thanks fearless for the example but this will also call the function from within the address space of the compiled exe. Exactly like SPROTO.
Quote from: AW on May 07, 2019, 12:37:01 AM
Try like this for a function with 2 ptr arguments:
lea eax, funcToCall
FuncProto typedef PROTO :ptr, :ptr
assume eax : ptr FuncProto
invoke eax, dest, src
assume eax:nothing
Nice work AW.
Example works, very good method.
I still don't know what you are after, "invoke" works with a normal address, the SPROTO macro works on addresses and you can manually use the standard PUSH/CALL Notation. What else are you after ?
Hi 2B||!2B,
You can use a macro simulating invoke to call functions through pointers :
include InvkReg.inc
.data
user32 db 'user32.dll',0
ApiFunc db 'MessageBoxA',0
.data?
hModule dd ?
mbox dd ?
.code
start:
invoke LoadLibrary,ADDR user32
mov hModule,eax
invoke GetProcAddress,eax,ADDR ApiFunc
mov mbox,eax
; mbox can be replaced with eax
_invoke mbox,0,"MessageBox test","Hello",MB_OK
invoke FreeLibrary,hModule
invoke ExitProcess,0
END start
Thanks AW for your macro. Combining your code, the prX macros from Windows.inc and some previous code :
_invoke MACRO p:REQ,args:VARARG
LOCAL counter,p2,tmp
counter=0
FOR param,<args>
counter=counter+1
ENDM
IF counter EQ 0
call p
ELSE
tmp TEXTEQU %(OPATTR(p))
IF tmp EQ 42
mov ecx,p
p2 TEXTEQU <ecx>
ELSE
p2 TEXTEQU <p>
ENDIF
FuncProto TYPEDEF @CatStr(<pr>,%counter)
ASSUME p2:PTR FuncProto
invoke p2,args
ASSUME p2:NOTHING
ENDIF
ENDM
include InvkReg.inc
.data
user32 db 'user32.dll',0
ApiFunc db 'MessageBoxA',0
.data?
hModule dd ?
mbox dd ?
.code
start:
invoke LoadLibrary,ADDR user32
mov hModule,eax
invoke GetProcAddress,eax,ADDR ApiFunc
mov mbox,eax
; mbox can be replaced with eax
_invoke mbox,0,CTXT("MessageBox test"),\
CTXT("Hello"),MB_OK
invoke FreeLibrary,hModule
invoke ExitProcess,0
END start
OK. No problem.
This is a more "modern" way of doing the same:
lea eax, myCalledFunction
FuncProto typedef PROTO :ptr, :ptr
invoke FuncProto ptr eax, dest, source