Lasse,
The advantage as I saw it was that by passing the address of a structure,
you only have one DWORD size parameter being placed on the stack when you
call the function so stack handling is both normal and safe.
That will get the addresses of a variable number of parameters depending
on what you put in the structure before you pass its address. Now if you
get a problem with the parameter count as passed in the structure being
incorrect, you will actually get problems in the body of the code, not on
the stack.
If the structure you used has 8 members and the function you called needs
4 parameters, if you passed 6 parameters, it will still only read 4 if its
written to do that. Where the problem will occur is if you pass less than
the function requires, there will still be some undefined value in the
unused member of the structure so you will get unpredictable results.
Now with the technique that James used, as long as you get the correct
address of the function you want to call and you make sure you use the
same calling convention, it will work if you pass the correct number of
parameters.
If you are using it in your own programming, you just make sure you pass
the correct number and type of parameters but if you are writing something
that will be used by other people where there is a risk of the parameter
count being wrong, I would be inclined to put the calling technique within
a function that had the correct number and type of parameters so that you
get the normal parameter checking.
It has a slightly higher stack overhead but unless you are recursively
calling small assembler routines or similar very small functions, it will
not effect the performance of your code.
Regards,
[email protected]
------------------
Announcement
Collapse
No announcement yet.
CALL DWORD
Collapse
X
-
Guest repliedThank you guys for your comments.
Semen, COM is above my skills, OM
James and Steve, my concern at this point is the passing of parameters as you both discussed.
Assuming that variable types are not an issue, there are two main cases (from the point of view of a subroutine):
1. too few parameters
2. too many parameters
I guess this boils down to what gets pushed and popped into/from the stack in the case you make a procedure call w/optional parameters.
It seems that PB/DLL handles both cases. First case by allocating space in the stack for all parameters and making those not part of the actual call NULL. So a sub waiting for two parameters, gets two parameters (the second one being NULL) even if only one is actually supplied. I hope someone w/better understanding of inner workings of PB/DLL could comment on that.
In the case of too many parameters the subroutine happily ignores the extra ones. The caller then cleans the stack.
The type of parameters could cause problems but applying pointers as Steve discussed can take care of that, I suppose.
Lasse Rantanen
[email protected]
Leave a comment:
-
Lasse,
I have had no problems passing data in either arrays or structures, structures
are more flexible and have a fixed length so they are probably less problematic
in terms of stack length.
TYPE MyType DWORD
par1 as DWORD
par2 as DWORD
par3 as DWORD
par4 as DWORD
END TYPE
------------------------------------
LOCAL lpStruct as DWORD
LOCAL mt as MyType
lpStruct = VarPtr(mt) ' get the structure address
' ---------------------------------------
' fill the number of parameters you need
' ---------------------------------------
mt.par1 = 1
mt.par2 = 999 ' etc ....
' Call the function as you require and at the called
' function end, pull the parameters apart using pointers.
FUNCTION MyFunc(ByVal lpArray as DWORD) as DWORD
LOCAL par1 as DWORD PTR
LOCAL par2 as DWORD PTR
par1 = lpArray
par2 = lpArray + 4
' Then use the "pointer" operator on the 2 variables
FUNCTION = @var1 * @var2
END FUNCTION
Both James and myself posted some alternate architecture examples recently
that had different dispatching methods.
Regards and please post the results of the development you are doing.
[email protected]
------------------
Leave a comment:
-
Could be I'm wrong, but it looks like COM-relative thread.
I don't know C, but for me
STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;
sounds that this function should be called as STDCALL, not CDECL.
Am I right ?
------------------
E-MAIL: [email protected]
Leave a comment:
-
One problem is no parameter checks.
It's possible to call CodePtr(2) using just one parameter.
James
------------------
Leave a comment:
-
CALL DWORD
I have been playing with following usage of CALL DWORD.
Define a general template for e.g. subroutine calls with - say - 1 to 4 arguments:
Code:DECLARE SUB CDECL FuncTemplate(BYVAL X1 as ANY _ [,BYVAL X2 as ANY _ ,BYVAL X3 as ANY _ ,BYVAL X4 as ANY])
Code:SUB MySub1(BYVAL X AS INTEGER) ... END SUB SUB MySub2(BYVAL Y AS LONG, BYVAL Z AS BYTE) ... END SUB
Code:CodePtr(1) = CODEPTR(MySub1) CodePtr(2) = CODEPTR(MySub2) ...
Code:' Instead of X = 2 ' do for variables eventually used as arguments for ' a certain subroutine Arg1(1) = 2
Code:CALL DWORD CodePtr(i) USING FuncTemplate(Arg1(i), Arg2(i), Arg3(i), Arg4(i))
Code:SELECT CASE i CASE 1 MySub1 X CASE 2 MySub2 Y, Z ... END SELECT
My simple tests show that this works. What kind of problems do you see w/this approach? I'll be grateful for any comments.
TIA
Lasse Rantanen
[email protected]Tags: None
Leave a comment: