Announcement

Collapse
No announcement yet.

CALL DWORD

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Steve Hutchesson
    replied
    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]

    ------------------

    Leave a comment:


  • LRantanen
    Guest replied
    Thank 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:


  • Steve Hutchesson
    replied
    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:


  • Semen Matusovski
    replied
    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:


  • jcfuller
    replied

    One problem is no parameter checks.

    It's possible to call CodePtr(2) using just one parameter.


    James


    ------------------

    Leave a comment:


  • LRantanen
    Guest started a topic CALL DWORD

    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])
    All subroutines are then programmed using appropriate names.

    Code:
    	SUB MySub1(BYVAL X AS INTEGER)
    	...
    	END SUB
    
    	SUB MySub2(BYVAL Y AS LONG, BYVAL Z AS BYTE)
    	...
    	END SUB
    Then for every sub I want to call, I store the procedure address into a variable, e.g. in an array.
    Code:
    	CodePtr(1) = CODEPTR(MySub1)
    	CodePtr(2) = CODEPTR(MySub2)
    	...
    Also arguments could be stored in an array.

    Code:
    	' Instead of
    	X = 2
    	' do for variables eventually used as arguments for
    	' a certain subroutine
    	Arg1(1) = 2
    Now I can call any of these subs with a call

    Code:
    	CALL DWORD CodePtr(i) USING FuncTemplate(Arg1(i), Arg2(i), Arg3(i), Arg4(i))
    instead of using e.g.

    Code:
    	SELECT CASE i
    		CASE 1
    			MySub1 X
    		CASE 2
    			MySub2 Y, Z
    		...
    	END SELECT
    and supply only those arguments which are appropriate.

    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]
Working...
X