Why does this work as argument of API?

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts
  • Gary Beene
    Member
    • May 2008
    • 20051

    Why does this work as argument of API?

    I was wanting to use TrackMenuPopu, declared in win32api.inc as

    Code:
    DECLARE FUNCTION TrackPopupMenu LIB "USER32.DLL" ALIAS "TrackPopupMenu" (BYVAL hMenu AS DWORD, BYVAL uFlags AS DWORD, BYVAL x AS LONG, BYVAL y AS LONG, BYVAL nReserved AS LONG, BYVAL hWnd AS DWORD, lprc AS RECT) AS LONG
    But in the few samples I found of its use, there was this type of statement:
    Code:
    TrackPopupMenu hPopup, %TPM_LEFTALIGN, x, y, 0, Cb.Hndl, ByVal 0
    Can someone explain where ByVal 0 works as a value for the last argument? I tried a plain 0 and it was rejected by the compiler. And neither are a type RECT.
    Last edited by Gary Beene; 18 Mar 2009, 11:29 PM.
  • José Roca
    Member
    • Mar 2004
    • 7918

    #2
    From the help file (CALL Statement topic):

    When you pass parameters from the calling code with an explicit BYVAL, you effectively switch off the compilers type-checking for that parameter. This can be useful in cases where the called code is expecting a BYREF parameter, and you wish to pass an address of another data type that would trigger a compile-time error without the BYVAL method.
    Forum: http://www.jose.it-berater.org/smfforum/index.php

    Comment

    • Gary Beene
      Member
      • May 2008
      • 20051

      #3
      Jose!

      Thanks for the response. I thought I was up alone tonight!

      But in general, I expected to have to pass a RECT type, or the API would object.

      In this case, ByVal lets me send a zero value without the PowerBASIC compiler objecting. But why doens't the API object?

      In this case, the MSDN topic says:
      prcRect
      Ignored.
      But in general, wouldn't I have expected the 0 (ByVal or not) to be rejected by the API since 0 isn't the right data type?

      Comment

      • José Roca
        Member
        • Mar 2004
        • 7918

        #4
        Many API functions expect that you pass a pointer to a variable or structure, or a null pointer. If you declare the parameter as BYREF, then the only way to pass a null pointer with PB is to use BYVAL 0.

        You could also declare the function as:

        Code:
        DECLARE FUNCTION TrackPopupMenu LIB "USER32.DLL" ALIAS "TrackPopupMenu" (BYVAL hMenu AS DWORD, BYVAL uFlags AS DWORD, BYVAL x AS LONG, BYVAL y AS LONG, BYVAL nReserved AS LONG, BYVAL hWnd AS DWORD, [B]BYVAL lprc AS RECT PTR[/B]) AS LONG
        in which case you will simply pass a 0.

        But if you declare it this way, then to pass a pointer to a RECT structure you will need to use VARPTR.

        Passing a variable by reference is the same that passing a pointer to that variable by value.
        Forum: http://www.jose.it-berater.org/smfforum/index.php

        Comment

        • José Roca
          Member
          • Mar 2004
          • 7918

          #5
          Please note that it is not the same to pass a null pointer than to pass a RECT structure with all the members filled with zero values.
          Forum: http://www.jose.it-berater.org/smfforum/index.php

          Comment

          • Michael Mattias
            Member
            • Aug 1998
            • 43467

            #6
            But in general, wouldn't I have expected the 0 (ByVal or not) to be rejected by the API since 0 isn't the right data type?
            External functions don't know what "data type" was passed in a particular parameter position.

            In this case, all TrackPopupMenu() knows is that parameter seven is 32 bits, which it ignores. This is a bad example, since it's rare that a parameter is "ignored", so let's pretend it is using parameter seven as a "lpRect" ..

            It still expects 32 bits, it does not care how those 32 bits get there, and when those 32-bits arrive it expects them to be the address of a RECT structure. As Jose points out, there are a good number of WinAPI functions which specify "address of something" as one or more parameters, generally a variable to be filled by that function. ... and "by convention" if that address is zero, it means the call-ER (you) is saying, "don't bother filling this parameter, I don't care what the results would be anyway."

            Point of call overrides (BYVAL, BYREF and BYCOPY) are only meaningful on the call-ING side...they enable you to override the compiler's type checking when it compares the passed parameter against the DECLARE statement used.

            In this case since the DECLARE says parameter seven is RECT by reference, passing simply "0" is a mismatch since there is no way to convert numeric zero into a RECT. (The compiler will convert numeric literals to the correct numeric data type when the DECLARE specifies a numeric data type in that position)

            "BYVAL 0&" or "BYVAL %NULL" tell the compiler, "never mind what the DECLARE says, pass a 32-bit value of zero in this position" ... what happens at runtime when zero is passed depends entirely on the called function.

            That is, the compiler provides type checking as a feature... but lets you disable it on a call-by-call basis. When you choose to actually USE the override capability, it becomes one hundred percent your responsibility to ensure the external function will accept that value.

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

            Comment

            Working...
            X