News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

How to invoke a pointer to a function.

Started by tilman, September 20, 2011, 02:09:05 PM

Previous topic - Next topic

tilman

So I'm trying to invoke a pointer to a function, but I'm failing. Could somebody please help?

I'm storing the function pointer like so:

mov pFunction,offset Function

I can actually get the call to work by doing this:

call pFunction

But when I try this:

invoke pFunction

I get "error A2190: INVOKE requires prototype for procedure".

And if I try this:

invoke Function pFunction

I get "error A2206: missing operator in expression".

Any ideas?

dedndave

FuncName EQU <pr0 PTR pFunction>


        INVOKE  FuncName


if it has parameters, chage the "pr0" to "pr1", "pr2", and so on

Erol gives a nice example where he actually creates a jump table entry for it
http://www.masm32.com/board/index.php?topic=11772.msg89003#msg89003

although, the jump should not be required

tilman

Hi dedndave,

Thanks for the speedy reply. Although this assembles it doesn't do what I want it to, i.e. it doesn't call Function, it calls 'offset pFunction'. Or am I misunderstanding something?

Here is the whole listing:

.386
.model flat,stdcall
   option       casemap: none
   include      d:\masm32\include\windows.inc
   include      d:\masm32\include\kernel32.inc
   includelib    d:\masm32\lib\kernel32.lib
   
   Function proto
.const
   FuncName EQU <pr0 PTR pFunction>
.data?
   pFunction   dd      ?
.code
start:
   mov pFunction,offset Function
   INVOKE  FuncName
   
   push   0
   call   ExitProcess
   
Function proc
   ret
Function endp
end start

dedndave

no - my mistake
it looks like the jump is required, although Erol's example may be dereferenced

let me play with it for a minute....

dedndave

well - i know there is a better way to do it - lol
but, for now, use Erol's method
i will play with it later today - or someone else will show us before then   :P

tilman

Thanks a lot for your help, I just found the answer here

http://webster.cs.ucr.edu/Page_TechDocs/MASMDoc/ProgrammersGuide/Chap_07.htm

although it seems a bit crackpot to me...

This is what you have to do:

.386
.model flat,stdcall
option casemap: none
include d:\masm32\include\windows.inc
include d:\masm32\include\kernel32.inc
includelib d:\masm32\lib\kernel32.lib

FUNCPROTO       TYPEDEF PROTO
FUNCPTR         TYPEDEF PTR FUNCPROTO
.data?
pFunction FUNCPTR ?
.code
start:
mov pFunction,offset Function
mov eax,offset pFunction
invoke FUNCPTR ptr [eax]

push 0
call ExitProcess

Function proc
ret
Function endp
end start

dedndave

well - that is less than ideal - you don't want to do all that every time - lol

the problem i was having is, there is no near absolute direct JMP instruction
but, with minimal effort, we can make a relative JMP work for us
we just have to add a SUB instruction to make the address relative

        .DATA

FuncBranch db 0E9h
pFunc      dd ?

FuncName    EQU <pr0 PTR FuncBranch>

        .CODE

;EAX = FunctionAddress

        sub     eax,offset pFunc+4
        mov     pFunc,eax

;then, to INVOKE the function...

        INVOKE  FuncName


you may be able to eliminate the SUB like this...

        mov     pFunc,offset Function-offset pFunc-4

dedndave

        .DATA

FuncBranch db 0E9h
pFunc      dd ?

FuncName    EQU <pr0 PTR FuncBranch>

        .CODE

;initialization

        mov     pFunc,offset Function-offset pFunc-4

;then, to INVOKE the function...

        INVOKE  FuncName

dedndave

because you can grab "offset Function", this should work - with no init code...
        .DATA

FuncBranch db 0E9h
pFunc      dd offset Function-offset pFunc-4

FuncName    EQU <pr0 PTR FuncBranch>

        .CODE

;then, to INVOKE the function...

        INVOKE  FuncName

dedndave

i am not sure why you are doing all this   :lol
unless you want to be able to change the function address in code
if that's the case, use the previous 2 posts

Function PROTO

        .CODE

        INVOKE  Function
;
;
;
Function PROC
        ret
Function ENDP

tilman

What I actually want to do is pass a callback to a function. (Isn't that a common task?) The example here is just simplification which demonstrated my problem.

I actually discovered another simplification of the official solution:

Instead of

mov pFunction,offset Function
mov eax,offset pFunction
invoke FUNCPTR ptr [eax]


i can just do

mov pFunction,offset Function
invoke FUNCPTR ptr pFunction


Now my main complaint is that I may have to define function prototypes twice. Oh vell...

Some questions about your solution:

a) Where does the magic 0e9h come from?
b) Does your code still do type checking on parameters?

Cheers!

dedndave

well - type checking is a matter of the "prN" definitions in windows.inc (or wherever they are defined)
for most 32-bit applications, they are always DWORD's of some sort

i am assuming that you have more than 0 parameters for this function
otherwise, a simple CALL would be easier

so - you want to pass the address of a callback and store it in a global variable ?

tilman

Quotewell - type checking is a matter of the "prN" definitions in windows.inc (or wherever they are defined)
for most 32-bit applications, they are always DWORD's of some sort

I actually switched to WinInc, because MASM32 was missing some COM structures. They use all sorts of types... ;)

Quoteso - you want to pass the address of a callback and store it in a global variable ?

That is correct. I've got the caller in a seperate file and I want to keep it general, so it doesn't know what to call at assemble time.

Vortex

Hi tilman,

You can also use a macro simulating invoke :


include     FuncPointer.inc

.data

capt        db 'Hello',0
message     db 'Function invoked through pointer',0


.data?

pFunction   dd ?


.code

start:

    mov     pFunction,OFFSET Function

    _invoke pFunction,ADDR message

    invoke  ExitProcess,0


Function PROC msg:DWORD

    invoke  MessageBox,0,msg,ADDR capt,MB_OK
    ret

Function ENDP


END start


_invoke mimics Masm's internal macro invoke

tilman

Hey Vortex,

Thanks for that. I'm not that hot on macros (yet), but does the macro check that the correct number and type of parameters were passed? Because, as I understand it, that's the whole point of using invoke over call (and yes, I tried to get by with just call and I failed and invoke saved my bacon  :bg)