Announcement

Collapse
No announcement yet.

Parameter as Reply

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

  • Cliff Nichols
    replied
    Mike,
    what is ve? (I assume you meant ve = value)
    although most the time I agree with you, if negative an error, if 0 no error, if positive then success, but to the strictest sense of True vs False (or success vs error), Windows describes it as True = Non-zero, and False as Zero

    Although I am hard pressed to think of a good example that "True" had a negative number at the moment (***NOTE*** I said "Hard Pressed" not that I have not seen it before)

    But I do know of Compilers that True = -1 and False = 0 so if preparing for another language (or even using a dll compiled in another language) True could be anything non-positive

    Leave a comment:


  • Mike Trader
    replied
    Just a minor point, Cliff, successful API routines normally return zero to indicate no errors.
    I asked a while ago what is the convention for Function return values and as I recall the consensus was that -ve = error, 0=Not an error, +ve=Success.

    I have used this convention for a while now and with very few exceptions it is compatile with Win API returns etc.

    Leave a comment:


  • Cliff Nichols
    replied
    Don't get to enthusiastic about eliminating globals. You'll find that in many instances globals are necessary, especially in callback functions since your code should not/cannot invoke a callback function directly.
    Well maybe not TOTALLY eliminate globals, but minimize the number of globals I am currently using.
    In my larger apps, from time to time I get odd results, or the compiler saying a duplicate Variable or Equates exists, and does not tell me where I may have declared it the second place (could be in a includes file I wrote years ago, and just now happened to use the same Variable name not realizing it), so I have to have windows do a search in every one of my files for that term and then go through each file till I find it.
    (1 point against globals)

    (1 point for globals) -
    judicious use of globals can speed up applications because every time you invoke a procedure with an argument list the values or pointers must be pushed onto the stack before the procedure executes and must be poped off the stack when the procedure completes.
    it all boils down to "What is best?" and the answer is "It depends"
    or more to the point the answer is "What is the point of diminishing returns?"

    Anyways thanx for all the input I am currently working on a block of code I wrote a while back and used many globals (and confusing to follow now that I have not touched it in months) just to see if I can cut down from 7 files, to 3 files (if my guess is right), and see if I have any speed decrease I can see, or if this way may be faster and easier to follow when done?

    Leave a comment:


  • Walt Decker
    replied
    Walt your statement about checking out the %DEF statement just gave me another idea how to simplify my code
    It isn't %DEF, it's DEF[variable type]. For example:

    DEFLNG A - Z automatically produces long integers for all variable names beginning with "A" to "Z".

    DEFBYTE A, C, D automatically produces byte variables beginning with "A", "C", and "D".

    Don't get confused with passing UDTs BYVAL vs. BYREF. Remember, you can pass an element of a UDT BYVAL and BYREF just as you can pass an element of a normal array by the same methods. Also, you cannot pass an entire "normal" array BYVAL. And, if you think about it, a UDT is just an array in which the various fields are specially defined.

    Don't get to enthusiastic about eliminating globals. You'll find that in many instances globals are necessary, especially in callback functions since your code should not/cannot invoke a callback function directly.

    Also, judicious use of globals can speed up applications because every time you invoke a procedure with an argument list the values or pointers must be pushed onto the stack before the procedure executes and must be poped off the stack when the procedure completes. These extra steps take extra time. That's one reason game programmers 1) use globals and 2) use as few procedures as possible (i.e. the "unroll" code).
    Last edited by Walt Decker; 13 Dec 2007, 02:43 PM.

    Leave a comment:


  • Cliff Nichols
    replied
    I was working on things a step farther, to see what it would take for arrays being passed.

    @Walt Decker
    You should also know the difference between BYVAL (by value) and BYREF (by reference). The following are examples of both:

    SUB A(BYVAL B AS LONG, BYREF C AS INTEGER, D AS SINGLE)

    Parameter "B" is passed like a literal, it can be changed in the procedure, but it is not changed on return from the procedure. However, if it is the "address" of a variable that variable can be changed in the procedure.

    Parameter "C" is actually a "pointer" to its address and on return is changed.

    Parameter "D" is an implyed BYREF pass and the same as "C".
    Programming 101...How in the world could I have not thought of that?
    but then again I am what MCM would call a VB Refugee, where they don't TEACH why ByVal or ByRef, but rather just tell you to use one or the other. But still I should have thought of that.

    It would also explain why in the back of my head I thought I would have to pass pointers to arrays as parameters to work, but my sample below somehow worked. (Because in reality I was passing BYREF and not thinking about it)

    @David Roberts
    successful API routines normally return zero to indicate no errors.
    Good point. Maybe not all API routines do, but on that thought it gave me an idea to "Beef Up" my functions to return the error code, and not just a "Ooops, some error occurred, but not saying why" type of return.
    So thank you for pointing that out.

    @Walt Decker
    SUB A(BYVAL B AS LONG, BYREF C AS INTEGER, D AS SINGLE)

    Parameter "B" is passed like a literal, it can be changed in the procedure, but it is not changed on return from the procedure.
    Just for clarification I included a lil test in Sample1 below to test that.

    Sample1 - Longs
    Code:
    #COMPILE EXE
    #DIM ALL
    #INCLUDE "Win32Api.inc"
    
    DECLARE FUNCTION A(BYVAL B AS LONG, C AS LONG, D AS LONG) AS LONG
    
    FUNCTION PBMAIN () AS LONG
         LOCAL MyTest AS LONG          'Declare variable
         LOCAL B AS LONG               'Declare variable
         LOCAL C AS LONG               'Declare variable
         LOCAL D AS LONG               'Declare variable
         LOCAL TempB AS LONG
         B = 1                         'Fill Variable with a value
         TempB = B
         C = 2                         'Fill Variable with a value
         D = 3                         'Fill Variable with a value
    '     MyTest = A(1, 2, 3)           '<--- Values can not be passed as literals if wanting variable values on return
         MyTest = A(B, C, D)           '<--- Pass Parameters (on return variables have a new value)
         MSGBOX "Function = " + FUNCNAME$ + $CR _
                   + "Function Passed = " + STR$(MyTest) + $CR _
                   + "B was " + STR$(TempB) + " now it is " + STR$(B) + $CR _
                   + "C was 2 now it is " + STR$(C) + $CR _
                   + "D was 3 now it is " + STR$(D)
    END FUNCTION
    
    FUNCTION A( BYVAL B AS LONG, C AS LONG, D AS LONG) AS LONG
         ON ERROR GOTO ErrHandler
         LOCAL TempB AS LONG
         TempB = B
         B = B + 1                     'Change variable value        '<--- If Byval then B only changes in this function, not on return
    MSGBOX "Function = " + FUNCNAME$ + $CR + "B was " + STR$(TempB) + $CR + "B is now " + STR$(B)
         C = C + 2                     'Change variable value
         D = D + 3                     'Change variable value
         FUNCTION = %False             'Return %False if no errors   '<--- Not really needed but kept for readability
         EXIT FUNCTION                 'Exit function so correct value returned
    ErrHandler:                        'If error then jump to here
         FUNCTION = ERR                'If error then return ErrorNumber
    END FUNCTION
    Now in that sample, if you take out the BYVAL then you see B is 2 on return, but with the BYVAL that B is only 2 while in FunctionA


    Sample 2 started out as just simple arrays, but I had quickly jumped to including User Defined Types
    Sample2 - Arrays with UDT's
    Code:
    #COMPILE EXE
    #DIM ALL
    #INCLUDE "Win32Api.inc"
    
    TYPE Apples
         AppleSize AS LONG
         AppleName AS ASCIIZ * %MAX_PATH
    END TYPE
    
    DECLARE FUNCTION TestReplies(MyStringIn() AS Apples, MyStringRemain() AS Apples)AS LONG
    
    
    FUNCTION PBMAIN () AS LONG
         LOCAL MyReply AS LONG
         DIM MyStringIn() AS Apples
         DIM MyStringRemain() AS Apples
         LOCAL i AS LONG
         
         REDIM MyStringIn(0 TO 1)
         MyStringIn(0).AppleSize = 1
         MyStringIn(0).AppleName = "MacIntosh"
         MyStringIn(1).AppleSize = 3
         MyStringIn(1).AppleName = "Summer"
         MyReply = TestReplies(MyStringIn(), MyStringRemain())      'Passing variables gets correct reply
         REDIM PRESERVE MyStringRemain(UBOUND(MyStringRemain))
         FOR i = LBOUND(MyStringIn) TO UBOUND(MyStringIn)
              MSGBOX FUNCNAME$ + $CR _
                        + "Function Passed = " + STR$(MyReply) + $CR _
                        + "MyStringIn" + STR$(i) + ".AppleSize = " + STR$(MyStringIn(i).AppleSize) + $CR _
                        + "MyStringIn" + STR$(i) + ".AppleName = " + MyStringIn(i).AppleName + $CR _
                        + "MyStringRemain" + STR$(i) + ".AppleSize = " + STR$(MyStringRemain(i).AppleSize) + $CR _
                        + "MyStringRemain" + STR$(i) + ".AppleName = " + MyStringRemain(i).AppleName
         NEXT i
    END FUNCTION
    
    FUNCTION TestReplies(MyStringIn() AS Apples, MyStringRemain() AS Apples)AS LONG
         ON ERROR GOTO ErrHandler
         LOCAL i AS LONG
         FOR i = LBOUND(MyStringIn) TO UBOUND(MyStringIn)
              REDIM PRESERVE MyStringRemain(i)
              MyStringIn(i).AppleSize = MyStringIn(i).AppleSize + 1               'Change variable value
              MyStringIn(i).AppleName = STRREVERSE$(MyStringIn(i).AppleName)                'Change variable value
              MyStringRemain(i).AppleSize = MyStringIn(i).AppleSize + 5               'Change variable value
              MyStringRemain(i).AppleName = STRREVERSE$(MyStringIn(i).AppleName)                'Change variable value
         NEXT i
         FUNCTION = %False             'Return %False if no errors   '<--- Not really needed but kept for readability
         EXIT FUNCTION                 'Exit function so correct value returned
    ErrHandler:                        'If error then jump to here
         FUNCTION = ERR                'If error then return ErrorNumber
    END FUNCTION
    Now in that sample, if you even TRY to pass an array of UDT's BYVAL the compiler will not let you. Which makes sense because I know I read in the manual that you have to pass pointers to the UDT's and not the UDT itself (For lack of a better word)


    Thanx again guys, Simple clarifications on stuff I read lonnnnng ago and did not think about when trying to cement an idea in my head.

    Anyways, I am sure if there is a VB Refugee reading all this, your help and comments will go a LONNNNNnnnnng way for them to easily understand, as well as reminding me of concepts that I was not thinking of (or did not fully understand when I read it in the manual)

    also Walt your statement about checking out the %DEF statement just gave me another idea how to simplify my code that in the past I had multiple INC files, and Multiple "Header" files (*.h files that held all my declares so if 1 INC file relied on a Variable declared in another INC file, I could move the variable to a header file, and just load all my declares before loading my INC files)

    Now I can almost get rid of all Globals and interdependencies between my INC files.

    Thanx guys, you ROCK!!!!

    Leave a comment:


  • Walt Decker
    replied
    You're welcome, Cliff.

    You should also know the difference between BYVAL (by value) and BYREF (by reference). The following are examples of both:

    SUB A(BYVAL B AS LONG, BYREF C AS INTEGER, D AS SINGLE)

    Parameter "B" is passed like a literal, it can be changed in the procedure, but it is not changed on return from the procedure. However, if it is the "address" of a variable that variable can be changed in the procedure.

    Parameter "C" is actually a "pointer" to its address and on return is changed.

    Parameter "D" is an implyed BYREF pass and the same as "C".

    Another thing you might want to investigate is the DEF statement. Personally I normally use that to define integer class variables and hand define all other type variables.

    Leave a comment:


  • David Roberts
    replied
    Just a minor point, Cliff, successful API routines normally return zero to indicate no errors.

    For consistencies sake your TestReplies routine, if you like, will be

    Code:
    FUNCTION TestReplies(MyStringIn AS STRING, MyStringRemain AS STRING)AS LONG
      ON ERROR GOTO ErrHandler
      MyStringRemain = MID$(MyStringIn, 3, 2) 'Change variable value
      MyStringIn = MID$(MyStringIn, 4, 1)     'Change variable value
      EXIT FUNCTION                           'Exit function so correct value returned
    ErrHandler:                               'If error then jump to here
      FUNCTION = %True                        'If error then return %True to indicate the function failed
    END FUNCTION
    A FUNCTION is a variable and if undefined defaults to zero, in this case, so there's no need for %False.

    Leave a comment:


  • Cliff Nichols
    replied
    Thanx guys

    I modified the 2 examples and over-commented them in case someone else out there is wondering the same thing.

    Longs
    Code:
    #COMPILE EXE
    #DIM ALL
    #INCLUDE "Win32Api.inc"
    
    DECLARE FUNCTION A(B AS LONG, C AS LONG, D AS LONG) AS LONG
    
    FUNCTION PBMAIN () AS LONG
         LOCAL MyTest AS LONG          'Declare variable
         LOCAL B AS LONG               'Declare variable
         LOCAL C AS LONG               'Declare variable
         LOCAL D AS LONG               'Declare variable
         B = 1                         'Fill Variable with a value
         C = 2                         'Fill Variable with a value
         D = 3                         'Fill Variable with a value
    '     MyTest = A(1, 2, 3)           '<--- Values can not be passed as literals if wanting variable values on return
         MyTest = A(B, C, D)           '<--- Pass Parameters (on return variables have a new value)
         MSGBOX FUNCNAME$ + $CR _
                   + "Function Passed = " + STR$(MyTest) + $CR _
                   + "B was 1 now it is " + STR$(B) + $CR _
                   + "C was 2 now it is " + STR$(C) + $CR _
                   + "D was 3 now it is " + STR$(D)
    END FUNCTION
    
    FUNCTION A( B AS LONG, C AS LONG, D AS LONG) AS LONG
         ON ERROR GOTO ErrHandler
         B = B + 1                     'Change variable value
         C = C + 2                     'Change variable value
         D = D + 3                     'Change variable value
         FUNCTION = %True              'Return %True if function passed
         EXIT FUNCTION                 'Exit function so correct value returned
    ErrHandler:                        'If error then jump to here
         FUNCTION = %False             'If error then return %False to indicate the function failed
    END FUNCTION
    Strings
    Code:
    #COMPILE EXE
    #DIM ALL
    #INCLUDE "Win32Api.inc"
    
    DECLARE FUNCTION TestReplies(MyStringIn AS STRING, MyStringRemain AS STRING)AS LONG
    
    FUNCTION PBMAIN () AS LONG
         LOCAL MyReply AS LONG
         LOCAL MyStringIn AS STRING
         LOCAL MyStringRemain AS STRING
         MyStringIn = "HELLO"
    '     MyReply = TestReplies("HELLO", MyStringRemain)         'Passing literal then only MyStringRemain has a value on return
         MyReply = TestReplies(MyStringIn, MyStringRemain)      'Passing variables gets correct reply
         MSGBOX FUNCNAME$ + $CR _
                   + "Function Passed = " + STR$(MyReply) + $CR _
                   + "MyStringIn was HELLO now it is " + MyStringIn + $CR _
                   + "MyStringRemain was empty string now it is " + MyStringRemain
    END FUNCTION
    
    FUNCTION TestReplies(MyStringIn AS STRING, MyStringRemain AS STRING)AS LONG
         ON ERROR GOTO ErrHandler
         MyStringRemain = MID$(MyStringIn, 3, 2)                'Change variable value
         MyStringIn = MID$(MyStringIn, 4, 1)                    'Change variable value
         FUNCTION = %True                                       'Return %True if function passed
         EXIT FUNCTION                                          'Exit function so correct value returned
    ErrHandler:                                                 'If error then jump to here
         FUNCTION = %False                                      'If error then return %False to indicate the function failed
    END FUNCTION
    Understanding these principles will go a long way towards my way of thinking when I code, and eliminating the use of GLOBALS
    (Yes I know I am just inviting a comment about Globals vs Locals with that one, but in this case its worth it )

    Thanks again guys

    Leave a comment:


  • Knuth Konrad
    replied
    Win APIs are often constructed the way that the return value of a function indicates failure or success of the function's operation, whereas one or more of the parameters receive the result(s) of the function's work.

    Leave a comment:


  • Robert DeBolt
    replied
    Code:
     
    #COMPILE EXE
    #DIM ALL
    DECLARE FUNCTION TestReplies(MyStringIn AS STRING, MyStringRemain AS STRING)AS STRING
    FUNCTION PBMAIN () AS LONG
       LOCAL MyReply AS STRING
       LOCAL MyRemain AS STRING
       MyReply = TestReplies("HELLO", MyRemain)
    '   MyRemain = MyStringRemain
       MSGBOX MyReply
       MSGBOX MyRemain
    END FUNCTION
    FUNCTION TestReplies(MyStringIn AS STRING, MyStringRemain AS STRING)AS STRING
         MyStringRemain = MID$(MyStringIn, 3, 2)
         FUNCTION = MID$(MyStringIn, 4, 1)
    END FUNCTION

    Leave a comment:


  • Walt Decker
    replied
    Of course it doesn't work, Cliff. In the first place you're passing literals instead of variables. You can't change the value of a literal in a call argument.

    In the second place, you have #DIM ALL on and you haven't declared all your variables. Jose' pointed that out with his example.

    Personally, if I wanted more than one result from a routine I'd use a SUB. But there are a number of different ways to get multiple results from a routine: structures and pointers come to mind. You can even use a pointer to a structure of pointers or pointers to pointers to pointers.

    Leave a comment:


  • José Roca
    replied
    Code:
    #COMPILE EXE
    #DIM ALL
    
    DECLARE FUNCTION A(B AS LONG, C AS LONG, D AS LONG) AS LONG
    
    FUNCTION PBMAIN () AS LONG
      DIM MyTest AS LONG
      DIM B AS LONG
      DIM C AS LONG
      DIM D AS LONG
      B = 1
      C = 2
      D = 3
      MyTest = A(B, C, D)               '<--- Pass Parameters and expect they change on return (obviously wrong thought)
      MSGBOX STR$(MyTest)               '<--- Valid in this function because it is the reply from Function A
      MSGBOX STR$(B)                   '<--- InValid in this function (as a reply to the parameter I passed into it)
      MSGBOX STR$(C)                   '<--- InValid in this function (as a reply to the parameter I passed into it)
      MSGBOX STR$(D)                   '<--- InValid in this function (as a reply to the parameter I passed into it)
      
    END FUNCTION
    FUNCTION A( B AS LONG, C AS LONG, D AS LONG) AS LONG
    
    B = B + 1                           '<--- Valid in this function because it is a parameter passed
    C = C + 2                           '<--- Valid in this function because it is a parameter passed
    D = D + 3                           '<--- Valid in this function because it is a parameter passed
    
    FUNCTION = D                        '<--- Valid in this function because it is passed back to the function that called it
    END FUNCTION

    Leave a comment:


  • Cliff Nichols
    replied
    Either I misunderstand or you do, so using your example I modified to
    Code:
    #COMPILE EXE
    #DIM ALL
    
    DECLARE FUNCTION A(B AS LONG, C AS LONG, D AS LONG) AS LONG
    '*** Tried this just in case it worked for some reason
    'global B AS LONG, C AS LONG, D AS LONG
    
    FUNCTION PBMAIN () AS LONG
      DIM MyTest AS LONG
      MyTest = A(1, 2, 3)               '<--- Pass Parameters and expect they change on return (obviously wrong thought)
      MSGBOX STR$(MyTest)               '<--- Valid in this function because it is the reply from Function A
    '  MSGBOX STR$(B)                   '<--- InValid in this function (as a reply to the parameter I passed into it)
    '  MSGBOX STR$(C)                   '<--- InValid in this function (as a reply to the parameter I passed into it)
    '  MSGBOX STR$(D)                   '<--- InValid in this function (as a reply to the parameter I passed into it)
      
        
    
    END FUNCTION
    FUNCTION A( B AS LONG, C AS LONG, D AS LONG) AS LONG
    
    B = B + 1                           '<--- Valid in this function because it is a parameter passed
    C = C + 2                           '<--- Valid in this function because it is a parameter passed
    D = D + 3                           '<--- Valid in this function because it is a parameter passed
    
    FUNCTION = D                        '<--- Valid in this function because it is passed back to the function that called it
    END FUNCTION
    As you uncomment lines you will see it will not compile, Much less even work.
    However if it were an API call that allowed it, I could find the value of C as Well as D if those were the answers I was after.

    Sure I could go about things differently and check the value separately, but was curious how an API call I could check directly
    (best guess is something to do with pointers)

    Leave a comment:


  • Walt Decker
    replied
    Getting the results of more than one argument in a function is just like a sub, unless, of course, the argument is passed BYVAL.

    For example:

    Function A( B, C, D) as long

    B = B + 1
    C = C + 2
    D = D + 3

    function = D
    End Function

    The results for B and C are contained in the function argument.

    Leave a comment:


  • Cliff Nichols
    started a topic Parameter as Reply

    Parameter as Reply

    Often I see API functions that one or more of the parameters passed into the function, is a reply that you need back (besides the actual reply) but I am unsure how I would do the same in PB (if its even possible).

    Since this statement sounds counter-intuitive, below is a sample of what I am trying to figure out.
    Code:
    #COMPILE EXE
    #DIM ALL
    DECLARE FUNCTION TestReplies(MyStringIn AS STRING, MyStringRemain AS STRING)AS STRING
    FUNCTION PBMAIN () AS LONG
       LOCAL MyReply AS STRING
       LOCAL MyRemain AS STRING
       
       MyReply = TestReplies("HELLO", "")
       MyRemain = MyStringRemain
       MSGBOX MyReply
       MSGBOX MyRemain
    END FUNCTION
    
    FUNCTION TestReplies(MyStringIn AS STRING, MyStringRemain AS STRING)AS STRING
         MyStringRemain = MID$(MyStringIn, 3, 2)
         FUNCTION = MID$(MyStringIn, 4, 1)
    END FUNCTION
    In this example what I need is
    1. The Reply from the function (obvious answer of course)
    2. What is left of the string in "MyStringRemain" (Could be the length of whats left, or something else, but for simplicity, I just wanted whats left etc..)

    I know its all pseudo-code, since the idea I had does not work (obviously). So I wondered how would I make it work?
Working...
X