Announcement

Collapse
No announcement yet.

CALL DWORD

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

  • 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]

  • #2

    One problem is no parameter checks.

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


    James


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

    Comment


    • #3
      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]

      Comment


      • #4
        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]

        ------------------
        hutch at movsd dot com
        The MASM Forum

        www.masm32.com

        Comment


        • #5
          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]

          Comment


          • #6
            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]

            ------------------
            hutch at movsd dot com
            The MASM Forum

            www.masm32.com

            Comment

            Working...
            X