Announcement

Collapse
No announcement yet.

How do you deal with arguments when using CODEPTR / CALL DWORD?

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

  • How do you deal with arguments when using CODEPTR / CALL DWORD?

    What am I missing here? Trying to learn CODEPTR / CALL DWORD
    How does USING fit into this??

    Code:
    FUNCTION PBMAIN () AS LONG
    
    LOCAL TEST_CODEPTR AS DWORD
    
    TEST_CODEPTR = CODEPTR(MY_TEST_CALLBACK_FUNCTION)
    
    TEST_FUNCTION(TEST_CODEPTR)
    
    END FUNCTION
    
    '------------------------------------------------------------------------------
    FUNCTION MY_TEST_CALLBACK_FUNCTION(CALLBACK_STRING AS STRING)AS LONG
    
    PRINT "THIS IS THE STRING YOU SENT THE CALLBACK - " + CALLBACK_STRING
    
    END FUNCTION
    '------------------------------------------------------------------------------
    FUNCTION TEST_FUNCTION(TEST_CODEPTR AS DWORD)AS LONG
    
    CALL DWORD TEST_CODEPTR("MOO")
    
    END FUNCTION

  • #2
    I got it!

    Code:
    FUNCTION PBMAIN () AS LONG
    
    LOCAL TEST_CODEPTR AS DWORD
    
    TEST_CODEPTR = CODEPTR(MY_TEST_CALLBACK_FUNCTION)
    
    TEST_FUNCTION(TEST_CODEPTR)
    
    END FUNCTION
    
    '------------------------------------------------------------------------------
    FUNCTION MY_TEST_CALLBACK_FUNCTION(CALLBACK_STRING AS STRING)AS LONG
    
    PRINT "THIS IS THE STRING YOU SENT THE CALLBACK - " + CALLBACK_STRING
    
    END FUNCTION
    '------------------------------------------------------------------------------
    FUNCTION TEST_FUNCTION(TEST_CODEPTR AS DWORD)AS LONG
    
    CALL DWORD TEST_CODEPTR USING MY_TEST_CALLBACK_FUNCTION("MOO")
    
    END FUNCTION

    Comment


    • #3
      Not exactly what I was thinking it would be...

      I have this function to recursively go through the disk:
      I was thinking I could pass the callback function name as an argument...

      See this below "'<-- Might be cool to have this passed in as an argument..."

      Code:
      FUNCTION GENERIC_GET_FILES_RECURSIVE(FILE_DRIVE_PATH AS STRING, FILE_EXTENTION AS STRING) AS LONG
      
      LOCAL CURRENT_PATH AS ASCIIZ * %MAX_PATH ' What to search for
      LOCAL SEARCH_HANDLE AS DWORD ' Search
      LOCAL STRUCT_FIND_DATA AS WIN32_FIND_DATA ' FindFirstFile structure
      LOCAL FILE_NAME AS STRING
      LOCAL FULL_FILE_NAME AS STRING
      
      
      CURRENT_PATH = FILE_DRIVE_PATH & "*." + FILE_EXTENTION
      SEARCH_HANDLE = FindFirstFile(CURRENT_PATH, STRUCT_FIND_DATA) 'GET A SEARCH_HANDLE FOR FindNextFile API CALLS
      
      
      
      IF SEARCH_HANDLE <> %INVALID_HANDLE_VALUE THEN
      DO
      
      'dwFileAttributes = STRUCT_FIND_DATA.dwFileAttributes
      
      FILE_NAME = STRUCT_FIND_DATA.cFileName
      IF FILE_NAME = "." OR FILE_NAME = ".." THEN ITERATE
      IF LEFT$(FILE_NAME,1) = "$" THEN ITERATE
      
      IF LEFT$(FILE_DRIVE_PATH,10) = "C:\Windows" THEN ITERATE
      IF LEFT$(FILE_DRIVE_PATH,34) = "C:\Program Files\Microsoft Office\" THEN ITERATE
      
      
      
      IF (STRUCT_FIND_DATA.dwFileAttributes AND %FILE_ATTRIBUTE_DIRECTORY) = %FILE_ATTRIBUTE_DIRECTORY THEN
      GENERIC_GET_FILES_RECURSIVE(FILE_DRIVE_PATH + FILE_NAME + "\", "*")
      ITERATE
      END IF
      
      
      FULL_FILE_NAME = FILE_DRIVE_PATH + FILE_NAME
      
      SEND_THIS_FILE_NAME_TO_THE_MAIN_PROCESS(FULL_FILE_NAME)  '<--  Might be cool to have this passed in as an argument...[
      
      LOOP WHILE FindNextFile(SEARCH_HANDLE, STRUCT_FIND_DATA)
      
      CALL FindClose(SEARCH_HANDLE)
      
      END IF
      
      END FUNCTION
      '------------------------------------------------------------------------------

      Comment


      • #4
        If you mean an actual window callback ((in real code)), you don't CALL it; you DIALOG SEND or DIALOG POST to it. Msg& would be %WM_USER + 500 + NumberYouAssign, pointer to file name string as wParam or lParam.

        Cheers,

        ((or CONTROL SEND / CONTROL POST))
        Dale

        Comment


        • #5
          Thanks Dale - I was thinking more interims of something I would do with PBCC. Perhaps callback is the wrong word...

          I was thinking I could pass the name of an function to a function as an argument - but it looks like I would have to use USING....

          Comment


          • #6
            PBCC does not use the CALLBACK FUNCTION / END FUNCTION statement. With (for example) TCP NOTIFY a Windows Proc is needed, and used like a CALLBACK in PBWin. PBCC Help refers to it as "callback". So use of the word was misleading, though otherwise okay.

            ref Post 2

            If
            FUNCTION MY_TEST_CALLBACK_FUNCTION(CALLBACK_STRING AS STRING)AS LONG
            PRINT "THIS IS THE STRING YOU SENT THE CALLBACK - " + CALLBACK_STRING
            END FUNCTION
            was (for example) in a DLL, then in the main program code you'd have just
            DECLARE FUNCTION MY_TEST_CALLBACK_FUNCTION(CALLBACK_STRING AS STRING)AS LONG
            so the compiler would know the parameters being passed and type being returned by CALL DWORD. The USING part tells which declare to use.

            Cheers,

            P.S. AFAIK procedure names don't exist in compiled code. (one exception is ALIAS so CODEPTR() can get pointer for use by CALL DWORD). So passing a function name can not work.
            Dale

            Comment


            • #7
              Originally posted by David Clarke View Post
              Thanks Dale - I was thinking more interims of something I would do with PBCC. Perhaps callback is the wrong word...

              I was thinking I could pass the name of an function to a function as an argument - but it looks like I would have to use USING....
              ISTM that "passing the name of a function to a function" has nothing to do with CALL DWORD (and USING) since both the location of the function and its required parameters are established at compile time using that construct.

              Since you have created the functions in your code already and know their names , the CallFunc function below becomes trivial.

              '
              Code:
              #COMPILE EXE
              #DIM ALL
              
              FUNCTION F1() AS LONG
                ? "One"
              END FUNCTION
              FUNCTION F2() AS LONG
                ? "Two"
              END FUNCTION
              FUNCTION F3() AS LONG
                ? "Three"
              END FUNCTION
              
              FUNCTION CallFunc(FuncName AS STRING) AS LONG
                  SELECT CASE FuncName
                      CASE "F1": F1
                      CASE "F2": F2
                      CASE "F3": F3
                  END SELECT
              END FUNCTION
              
              FUNCTION PBMAIN() AS LONG
                  CallFunc "F2"
                  CallFunc "F3"
                  CallFunc "F1"
              END FUNCTION
              '
              Of course, the string FuncName used in the SELECT CASE doesn't have to be the same as the function name, it could be any set of values.
              Last edited by Stuart McLachlan; 16 May 2022, 05:24 AM.

              Comment


              • #8
                I got it!


                You RTFM, hey?

                Thanks Dale - I was thinking more interims of something I would do with PBCC. Perhaps callback is the wrong word.
                You can send messages to windows using the WinAPI functions SendMessage() and PostMessage() .

                See:
                Directory List with Non-ASCII (Unicode) characters in file names 5-31-08 for PB/WIN or PB/CC"

                Code compiles 'as is' with EITHER PB/Win or PB/CC. (versions and include files as shown).

                One of the reasons I went with PowerBASIC as my main development product when I decided this 'Windows' thing offered me a better future than did mainframe COBOL was the 'open' access to the Windows API, as contrasted with the 'closed' design offered by "Brand M."

                MCM

                Michael Mattias
                Tal Systems (retired)
                Port Washington WI USA
                [email protected]
                http://www.talsystems.com

                Comment


                • #9
                  Dale

                  Comment


                  • #10
                    I was thinking I could pass the name of an function to a function as an argument - but it looks like I would have to use USING....
                    Stuart gave you the most likely correct answer to that... "No need to pass the function name, because the symbol - i.e., the user procedure name - is already in your program."

                    But there is no reason you could not pass the CODEPTR of a procedure as a numeric argument to that function and use CALL DWORD with that. You might do that if you obtain an address with LoadLibrary/GetProcAddress because a function you want to call using CALL DWORD within your recursing function is an external function.
                    Michael Mattias
                    Tal Systems (retired)
                    Port Washington WI USA
                    [email protected]
                    http://www.talsystems.com

                    Comment


                    • #11
                      He he, the world is full of dirty tricks. If you want something from within a WndProc, set one of the required message argument IN THE WNDPROC as a minus number then use CODEPTR() to that location to return a GLOBAL value. You normally never call a WndProc directly but it can be done IF you don't pass a valid MESSAGE ID number to it.

                      To answer Dave's question along with others in this topic, CODEPTR() gets that ADDRESS of a location in memory at runtime. A conventional main procedure that uses a WNDCLASSEX structure requires one argument to be the address of the WndProc and that is done with CODEPTR(). As with an ASMDATA block, you can use either LEA or CODEPTR() to get the start address.
                      hutch at movsd dot com
                      The MASM Forum - SLL Modules and PB Libraries

                      http://www.masm32.com/board/index.php?board=69.0

                      Comment


                      • #12
                        You normally never call a WndProc directly but it can be done IF you don't pass a valid MESSAGE ID number to it.
                        In your window procedure, message number is the primary selection object for coding.... selected by the programmer for processing or ignored to accept the default action. IOW, it's immaterial FOR PURPOSES OF CALLING THE PROCEDURE.

                        However, if you want to call the window procedure yourself - as you do when you subclass a control, you may (should?) use the CallWindowProc() function; or to use the default processing for a NON-DIALOG window, you use the DefWindowProc() function.
                        .
                        While you "can" call a window procedure directly, I sincerely recommend you don't. Use the provided facilities such as Send/Post Message and or one of the functions mentioned above. Those functions are provided for a reason, often performing "hidden" tasks related to system management, e.g., you may have threads waiting on a MessageWaitForMultipleObjects() function and "shortcutting" the provided methods may cause release of the waiting thread to be missed.

                        Michael Mattias
                        Tal Systems (retired)
                        Port Washington WI USA
                        [email protected]
                        http://www.talsystems.com

                        Comment


                        • #13
                          Thanks guys...

                          Here is an example of what I am talking about:

                          You make a DLL - You give it to someone... You have a function in your dll that does something asynchronously - when that thing happens you want to call a function in the users code. You don't know in advance what function name they will be using. You tell them in the HOW TO USE THE DLL that they can specify the name of the function that is called as the asynch event finishes.

                          This could be made much easier if you said YOU HAVE TO HAVE A FUNCTION NAMED THE_DLL_CALLBACK() so the DLL knows what to do with the asynch info.

                          There are lots of ways to accomplish this - many we already know... I was just fooling around with CODEPTR and thought this might be cool.
                          This example works but there is no clean way to pass arguments...
                          Well actually there are lots of ways just none like - CALL DWORD CALLBACK_FUNCTION(arg,arg)

                          PBCC EXAMPLE:


                          Code:
                          FUNCTION PBMAIN () AS LONG
                          
                          DO_SOMETHING(CODEPTR(MY_CALLBACK_FUNCTION))
                          
                          END FUNCTION
                          '------------------------------------------------------------------------------
                          FUNCTION DO_SOMETHING(CALLBACK_FUNCTION AS DWORD)AS LONG
                          
                          CALL DWORD CALLBACK_FUNCTION
                          
                          END FUNCTION
                          '------------------------------------------------------------------------------
                          FUNCTION MY_CALLBACK_FUNCTION()AS LONG
                          
                          PRINT "THIS IS THE FUNCTION I NAMED !"
                          
                          END FUNCTION

                          Comment


                          • #14
                            You make a DLL - You give it to someone... You have a function in your dll that does something asynchronously - when that thing happens you want to call a function in the users code. You don't know in advance what function name they will be using. You tell them in the HOW TO USE THE DLL that they can specify the name of the function that is called as the asynch event finishes.
                            You tell the user to pass the ADDRESS of their function, not the name. Just like any other callback (small letters, NOT the PowerBASIC proprietary) you use. e.g, when you CreateWindowEx() you specify the address of your window procedure.*

                            Practice needed with user-defined callbacks? Of course I have provided a demo in the Source Code Forum!

                            PB/WIN: Write your own ENUM functions to callback September 23, 2002


                            * I assume you have followed the (sage IMO) advice of some member here to learn how to manage windows using the WinAPI and therefore are familiar with the CreateWindowEx() function.
                            Michael Mattias
                            Tal Systems (retired)
                            Port Washington WI USA
                            [email protected]
                            http://www.talsystems.com

                            Comment


                            • #15
                              Hopefull clearing up a bit of the confusion above

                              To quote WIkipedia:
                              In computer programming, a callback or callback function is any reference to executable code that is passed as an argument to another piece of code; that code is expected to call back (execute) the callback function as part of its job. This execution may be immediate as in a synchronous callback, or it might happen at a later point in time as in an asynchronous callback. Programming languages support callbacks in different ways, often implementing them with subroutines, lambda expressions, blocks, or function pointers.
                              ...
                              Callbacks are used to program applications in windowing systems. In this case, the application supplies (a reference to) a specific custom callback function for the operating system to call, which then calls this application-specific function in response to events like mouse clicks or key presses


                              PB generally mplements callbacks using function pointers
                              (In certain cases, such as DDT and custom array sorts, the compiler creates the pointers to the callback function "behind the scenes" at compile time.)

                              Here's a simple demo of callbacks using CODPTR and CALL DWORD ... USING
                              '
                              Code:
                              #COMPILE EXE
                              #DIM ALL
                              
                              FUNCTION PBMAIN() AS LONG
                                  LOCAL cpr1,cpr2 AS DWORD
                                  cpr1 = CODEPTR(GetRand1To100) 'pointer to a callback
                                  cpr2 = CODEPTR(GetRand100To200) 'pointer to a different callback
                              
                                  'call the same function twice with different callbacks.
                                  ? GetTwoRands(cpr1) 'use the first callback function
                                  ? GetTwoRands(cpr2) 'use the second callback function
                              END FUNCTION
                              
                              FUNCTION getTwoRands(cp AS DWORD) AS STRING
                                 LOCAL v1,v2 AS LONG
                                 CALL DWORD cp USING rands TO v1   'call the "callback function"
                                 CALL DWORD cp USING rands TO v2   'call the "callback function"  as second time
                                FUNCTION =  STR$(v1) & " " & STR$(v2)
                              END FUNCTION
                              
                              'Callback functions
                              '--------------------------------------
                              DECLARE FUNCTION Rands() AS LONG ' template for the callback functions
                              FUNCTION GetRand1To100() AS LONG
                                   FUNCTION = RND(1,100)
                              END FUNCTION
                              
                              FUNCTION GetRand100To200() AS LONG
                                   FUNCTION = RND(100,200)
                              END FUNCTION
                              '
                              Note that ARRAY SORT arr() USING MyFunc() is another example of a callback function in PB (which is what prmpted me to re-visit this thread).

                              Comment

                              Working...
                              X