Is there a way to determine the number of arguments a procedure needs before it is called from invoke?
Say you don't know how many arguments are needed for a given procedure... Is it possible to determine this (with macro or otherwise) before calling the function?
Sliver
Say you don't know how many arguments are needed for a given procedure... Is it possible to determine this (with macro or otherwise) before calling the function?
Sliver
If you know it to be a stdcall function, here is what i would do: push an excessive number of arguments onto the stack, then call the function. When (or if) the function returns, examine the stack to see how many of the original 10 parameters are still there, that way you will know how many parameters the function used. Obviously this has some limitations: the function may crash or GPF due to incorrect parameter values, the function may not clean up the stack properly, the function you called may call another function etc which means you may be a couple of levels deep if (when) you crash.....
AFAIK, there is no official way to tell, you either have to reverse engineer the function (which is not illegal), or use pure guesswork. If you use this on some of the low-level undocumented windows APIs, be prepared for a possible mess if you get it wrong :)
AFAIK, there is no official way to tell, you either have to reverse engineer the function (which is not illegal), or use pure guesswork. If you use this on some of the low-level undocumented windows APIs, be prepared for a possible mess if you get it wrong :)
Obviously invoke checks that the amount of param's is correct -- Is there a way to exploit tht fact and use the same technique?
Sliver
Sliver
Yeah, invoke does check that you have the correct number of parameters, but it can only do that because you have declared the functions you are calling somewhere. But if you have already declared them somewhere, then you usually know what parameters are needed :)
Remember, invoke is actually a macro, and it forces the compiler to do a typecheck on the parameters as well as check the number, in the actual code you just get a bunch of pushes then a call.
Remember, invoke is actually a macro, and it forces the compiler to do a typecheck on the parameters as well as check the number, in the actual code you just get a bunch of pushes then a call.
If you don't know how many parameters a procedure requires, it's probably not the best programming practise to use it. Though I can't think of a situation (save some fantasic self programing ai implementation) where you'd ever have to call code that you don't have documented, though sluggy's aproach sounds pretty good.
try checking the mcall macro, it has a variable called mcallNumArgs...Maybe you could get some info from it. I don't know, just a guess. Since I'm not a macro expert.
I forgot, credit goes to bizarre creations for this awesome macro. :)
Check_mcallArgs MACRO a1,a2,a3,a4,a5,a6,a7,a8,a9,a10
LOCAL x,len
IFNB <a1>
mcallNumArgs=mcallNumArgs+1
Check_mcallArgs <a2>,<a3>,<a4>,<a5>,<a6>,<a7>,<a8>,<a9>,<a10>
len SIZESTR <a1>
IF (len GE 5)
x SUBSTR <a1>,1,5
IFIDNI x,<ADDR >
mcallDanger=mcallDanger+1
ENDIF
ENDIF
ENDIF
ENDM
mcall MACRO ObjPtr:REQ,MethodName:REQ,Args:VARARG
CurrMethodProto CATSTR <MethodName>,<Proto>
IFNB <Args>
mcallDanger=0
mcallNumArgs=0
IFIDNI <ObjPtr>,<[eax]>
Check_mcallArgs Args
ENDIF
IF mcallDanger
echo Warning: Dangerous mcall!
push [eax] ; save ObjPtr
invoke CurrMethodProto ptr [eax],Args
ORG $-2
mov eax,[esp+mcallNumArgs*4]
push eax ; this
mov eax,[eax] ; vtable*
call dword ptr [eax+MethodName]
add esp,4 ; clean up stack
ELSE
invoke CurrMethodProto ptr [eax],Args
ORG $-2
mov edx,edx ; filler!
mov eax,ObjPtr
push eax ; this
mov eax,[eax] ; vtable*
call dword ptr [eax+MethodName]
ENDIF
ELSE ;----- No args
mov eax,ObjPtr
push eax ; this
mov eax,[eax] ; vtable*
invoke CurrMethodProto ptr [eax+MethodName]
ENDIF
ENDM
I forgot, credit goes to bizarre creations for this awesome macro. :)
I want bitRake's opinion on that macro, it lost me :)
Well, I do know how many params a specific procedure takes...
What I'm trying to do is add the functionality to Object.inc to define my own constructor and still have a default constructor...
In otherwords
In C++
Now both of these are defined with PROTO's
When you create a new class using Object.inc
It calls the NEWOBJECT macro:
This macro is used to create a new instance of a class definition. The instances are taken from the local heap. As well this macro will call the constructor of the class to do any needed initializations.
As you can see it invokes the initilization function for the class (ie. the default construtor) or an overloaded constructor, but it doesn't have the option of both
What I want to do is, depending on the amount of params passed, to pick the correct constructor...
So I can do:
What I'm trying to do is add the functionality to Object.inc to define my own constructor and still have a default constructor...
In otherwords
In C++
Box() <--default constructor
Box(param1, param2, param3) <-- my own overloaded constructor
Now both of these are defined with PROTO's
When you create a new class using Object.inc
It calls the NEWOBJECT macro:
NEWOBJECT MACRO ObjType:REQ, args:VARARG
invoke GetProcessHeap
invoke HeapAlloc, eax, NULL, SIZEOF ObjType
push eax
IFNB <args>
invoke ObjType&_Init, eax, &args
ELSE
invoke ObjType&_Init, eax
ENDIF
pop eax
ENDM
This macro is used to create a new instance of a class definition. The instances are taken from the local heap. As well this macro will call the constructor of the class to do any needed initializations.
As you can see it invokes the initilization function for the class (ie. the default construtor) or an overloaded constructor, but it doesn't have the option of both
What I want to do is, depending on the amount of params passed, to pick the correct constructor...
So I can do:
NEWOBJECT Box, 10, 20, 30 ;length, width, height
mov hBox, eax
NEWOBJECT Box ;the length width height == 0 or some predefined value
mov hBox2, eax
I'm not sure this will be usefull, but here's how I handled arbitrary numbers of parameters in a single object constructor prototype when I wrote CoLib for COM objects:
What I did was pass an extra parameter, a simple dword. Then the constructor procedure (method? procedure?) was at liberty tro interpet this value in any way you choose.
One typical use is to pass a reference to a structure, and the constructor would then know how to interpet this struct. This allowed me the option to initialize objects as they are created, without having to create any special object creator super objects.
Should you wish to use default values, pass in a NULL, and have the constructor interpet this as 'use default.'
Also, the struct could be a list of variable pointers, so every parameter could be either 'turned on' (valid pointer in its position) or 'turned off' (with a NULL pointer).
Sorry, I'm not very familiar with Nan and Thomas's work to know how usefull this suggestion is.
It certainly lacks some elegance.
What I did was pass an extra parameter, a simple dword. Then the constructor procedure (method? procedure?) was at liberty tro interpet this value in any way you choose.
One typical use is to pass a reference to a structure, and the constructor would then know how to interpet this struct. This allowed me the option to initialize objects as they are created, without having to create any special object creator super objects.
Should you wish to use default values, pass in a NULL, and have the constructor interpet this as 'use default.'
Also, the struct could be a list of variable pointers, so every parameter could be either 'turned on' (valid pointer in its position) or 'turned off' (with a NULL pointer).
Sorry, I'm not very familiar with Nan and Thomas's work to know how usefull this suggestion is.
It certainly lacks some elegance.
If your C++ compiler can compile to asm code, which I think most can, try overloading the constructor in C++ with some simple function. Then take a look at the asm code to see how the compiler manages the situation.
I read Ernie's reply, then i came up with almost the same thought as Canite. Is there a description anywhere (or better still, a logic diagram), of what the C compiler produces for overloaded functions (not just constructors)?
A C++ compiler can just choose the right function at compile-time, the problem is not at code level.
You could create several protos for the same function using a number suffix:
Then get the number of arguments passed to the newobject macro, concatenate this number to {ClassName}_Init (example: Box_Init4). With IFDEF, check if this symbol exists. If it does, use that symbol in your invoke. If it doesn't, use the default constructor instead.
Thomas
You could create several protos for the same function using a number suffix:
Box_Init PROTO STDCALL :DWORD ;default
Box_Init4 PROTO STDCALL :DWORD, :DWORD, :DWORD, :DWORD
Then get the number of arguments passed to the newobject macro, concatenate this number to {ClassName}_Init (example: Box_Init4). With IFDEF, check if this symbol exists. If it does, use that symbol in your invoke. If it doesn't, use the default constructor instead.
Thomas
This was exactly how I planned on doing it (just didn't know how to find the # of args.) Although I'm working on the functionality of my program before i deal with this...
Sliver
Sliver