Announcement

Collapse
No announcement yet.

Optional ByVal Parameter Change In Behavior

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

  • Optional ByVal Parameter Change In Behavior

    I've just come across one of my PBWin 8.04 programs that won't compile 'as is' with PBWin 9, and I'm not sure whether this is significant or not. Its a short program some of you might remember from last fall when I was working with using the C Runtime Library's printf for console output with PBWin. The program declares the printf function like so...

    Code:
    Declare Function printf CDecl Lib "msvcrt.dll" Alias "printf" _   'printf from stdio.h
    ( _
      szFmtStr As Asciiz _
      [, _
         Byval lpVar1 As Any, _
         Byval lpVar2 As Any, _
         Byval lpVar3 As Any, _
         Byval lpVar4 As Any _
      ] _
    ) As Long
    The PBWin error message states 'Byval parameter not allowed'. The documentation for optional parameters shows Byval examples with optional parameters, but it doesn't work for me. I don't know if the 'As Any' has anything to do with it. Getting the program to work isn't too much trouble though. All that needs done is to remove the four 'ByVal' keywords from the Declare, and put ByVal overrides in front of parameters passed to the printf function as in...

    printf("%d" + Chr$(9) + "My Name Is Fred And I Weigh %u Pounds!"+$Cr+$Lf, Byval i, Byval dwWeight)

    Here is the program again. If those changes are made it works. I will admit this is a rather unusual use of PowerBASIC, and pushes things pretty far.

    Code:
    'Program demonstrates how to restore standard output handle in C Runtime Library
    'which is zeroed out by initialization of GUI process.
    #Compile Exe
    #Include "Win32api.inc"           'Translation of Windows.h for PowerBASIC
    %IDC_BUTTON1 = 1250               'ctrl id of button
    %O_TEXT      = &H4000             'from Fcntl.h
    
    Type FILE      'From stdio.h      'When a GUI application is started the three standard OS handles
      pChar        As Asciiz Ptr      'STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, and STD_ERROR_HANDLE are all
      cnt          As Long            'zeroed out by the console initialization routines.  These three
      pBase        As Asciiz Ptr      'handles are replaced by valid values when a GUI application calls
      flag         As Long            'AllocConsole(). Therefore, once this is done, calling GetStdHandle()
      fil          As Long            'will always return valid handle values. The problem is that the
      charbuf      As Long            'CRT has already completed initialization before an application gets
      bufsize      As Long            'a chance to call AllocConsole(); the three low I/O handles 0, 1,
      TmpFileName  As Asciiz Ptr      'and 2 have already been set up to use the original zeroed out OS
    End Type                          'handles, so all CRT I/O is sent to invalid OS handles and CRT output
                                      'does not appear in the console.
    
    Declare Function GetConsoleWindow Lib "Kernel32.dll" Alias "GetConsoleWindow" () As Dword
    
    
    Declare Function printf CDecl Lib "msvcrt.dll" Alias "printf" _   'printf from stdio.h
    ( _
      szFmtStr As Asciiz _
      [, _
         Byval lpVar1 As Any, _
         Byval lpVar2 As Any, _
         Byval lpVar3 As Any, _
         Byval lpVar4 As Any _
      ] _
    ) As Long
    
    
    Declare Function Open_OSFileHandle CDecl Lib "msvcrt.dll" Alias "_open_osfhandle" _  'from IO.h
    ( _
      Byval hHandle As Long, _
      Byval iType   As Long _
    ) As Long
    
    
    Declare Function FDOpen CDecl Lib "msvcrt.dll" Alias "_fdopen" _   'from stdio.h
    ( _
      Byval hHandle As Long, _
      ByRef pszStr As Asciiz _
    ) As Dword
    
    
    Function WndProc(Byval hWnd As Long,Byval wMsg As Long,Byval wParam As Long,Byval lParam As Long) As Long
      Select Case wMsg
        Case %WM_CREATE
          Local hButton As Dword
          Local hIns As Dword
          hIns=GetModuleHandle(Byval 0)
          hButton=CreateWindow("button","Show Console!",%WS_CHILD Or %WS_VISIBLE,110,65,200,25,hWnd,%IDC_BUTTON1,hIns,Byval 0)
          WndProc=0
          Exit Function
        Case %WM_COMMAND
          If Lowrd(wParam)=%IDC_BUTTON1 And HiWrd(wParam)=%BN_CLICKED Then
             Local hStdOutput As Dword              'Standart Output Handle
             Local hf,ptrFile As FILE Ptr           'FILE *
             Local hDll,hCrt,dwWeight As Dword
             Local hSysMenu As Dword
             Register i As Long
             hDll=LoadLibrary("msvcrt.dll")         'Load/Increment Reference Count on msvcrt.dll
             If hDll Then                           'Get base address of exported symbol _iob from msvcrt.dll.  _iob is an
                ptrFile=GetProcAddress(hDll,"_iob") 'array of FILE structs that holds the stdin, stdout, and stderr handles.
                Call AllocConsole()                 'These handels are zeroed out at initialization of a GUI process, and
                hSysMenu=GetSystemMenu(GetConsoleWindow(),Byval 0)   'must be reset with valid operating system handles if
                Call DeleteMenu(hSysMenu,6,%MF_BYPOSITION)           'console output is desired in a GUI process.  With a
                hCrt=Open_OSFileHandle(GetStdHandle(%STD_OUTPUT_HANDLE),%O_TEXT)  'valid handel to stdout returned in hf, it
                hf=FDOpen(hCrt,"w")                 'is restored back in position 1 of the i/o buffer FILE array with
                @ptrFile[1][email protected]                     '@[email protected] printf output using CRT in PowerBASIC!
                dwWeight=210
                For i=1 To 200                     '
                  printf("%d" + Chr$(9) + "My Name Is Fred And I Weigh %u Pounds!"+$Cr+$Lf,i,dwWeight)
                Next i
                Call FreeLibrary(hDll)              'Free/decrement reference count on msvcrt.dll
             End If
          End If
          WndProc=0
          Exit Function
        Case %WM_DESTROY
          Call PostQuitMessage(0)
          WndProc=0
          Exit Function
      End Select
    
      WndProc=DefWindowProc(hWnd, wMsg, wParam, lParam)
    End Function
    
    Function WinMain(Byval hIns As Long, Byval hPrev As Long, Byval lpCL As Asciiz Ptr, Byval iShow As Long) As Long
      Local szBuffer As Asciiz * 64
      Local wc As WNDCLASSEX
      Local Msg As tagMsg
      Local hWnd As Dword
    
      szBuffer="Console_Output"                           : wc.lpszClAssName=Varptr(szBuffer)
      wc.lpfnWndProc=Codeptr(WndProc)                     : wc.cbSize=Sizeof(wc)
      wc.style=%CS_HREDRAW Or %CS_VREDRAW                 : wc.hInstance=hIns
      wc.cbClsExtra=0                                     : wc.cbWndExtra=0
      wc.hIcon=LoadIcon(%NULL, Byval %IDI_APPLICATION)    : wc.hCursor=LoadCursor(%NULL, Byval %IDC_ARROW)
      wc.hbrBackground=%COLOR_BTNFACE+1                   : wc.lpszMenuName=%NULL
      Call RegisterClAssEx(wc)
      szBuffer="GUI Console Output With C Runtime Library From PowerBASIC!"
      hWnd=CreateWindow("Console_Output",szBuffer,%WS_OVERLAPPEDWINDOW,500,550,440,200,0,0,hIns,Byval 0)
      Call ShowWindow(hWnd,iShow)
      Call UpdateWindow(hWnd)
      While GetMessage(Msg,%NULL,0,0)
        TranslateMessage Msg
        DispatchMessage Msg
      Wend
    
      Function=msg.wParam
    End Function
    Fred
    "fharris"+Chr$(64)+"evenlink"+Chr$(46)+"com"

  • #2
    Think about for minute Fred. What does BYVAL as ANY Mean????
    What if I pass a 128 byte asciiz string???

    I believe it was a unwanted feature from previous versions??

    James

    Comment


    • #3
      From win32api.inc:

      Code:
          Declare Function wsprintf CDecl Lib "USER32.DLL" Alias "wsprintfA" (lpOutput As Asciiz, lpFormat As Asciiz, x As Any, Optional x1 As Any, Optional x2 As Any, Optional x3 As Any, Optional x4 As Any, Optional x5 As Any, _
              Optional x6 As Any, Optional x7 As Any, Optional x8 As Any, Optional x9 As Any, Optional x10 As Any, Optional x11 As Any, Optional x12 As Any) As Long
      Note that all the parameters are BYREF (as the function expects). Since the function is CDECL, the caller will "clear up" the stack as it knows exactly how many pointers were passed, and the function will know what data to expect from the parameters used in the format string. PB has defined 13 (0-12) "data" variables for wsprintf(), but it can be as many as you are going to need -- right up to the maximum of 30 (2 strings + 30 data variables = 32).
      Last edited by Kev Peel; 26 Aug 2008, 02:27 PM.
      kgpsoftware.com | Slam DBMS | PrpT Control | Other Downloads | Contact Me

      Comment


      • #4
        It's 'BYVAL AS ANY' which makes no sense.

        'BYREF AS ANY' does make sense... the called routine is responsible to know what it expects in which parameter position.

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

        Comment


        • #5
          >Declare Function Open_OSFileHandle CDecl Lib "msvcrt.dll"....

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

          Comment


          • #6
            Well then why does one need to put a Byval override in front of every parameter one wishes to output with these printf family functions if one wishes to obtain the correct result? For example - and using Kev's wsprintf function, here is a Console Compiler program that gives the same incorrect result with either PBCC 4 or 5 using the declare in Win32Api.inc.

            Code:
            #Compile Exe
            #Dim All
            #Include "Win32Api.inc"
            
            Function PBMain () As Long
              Local szBuffer As Asciiz*64
              Local iLen, iNum As Long
            
              iNum = 25
              iLen=wsprintf(szBuffer,"iNum = %u",iNum)
              Print szBuffer
              Waitkey$
            
              PBMain=0
            End Function
            '
            'Output:
            '=======
            'iNum = 1244704
            If that declare was right, the correct answer for iNum should have been output. The correct answer is 25 - not 1244704. The latter is the virtual address where iNum is stored. If you want to get the correct answer, i.e., '25', then you need a Byval override in front of iNum in the last parameter position - like so...

            Code:
            #Compile Exe
            #Dim All
            #Include "Win32Api.inc"
            
            Function PBMain () As Long
              Local szBuffer As Asciiz*64
              Local iLen, iNum As Long
            
              iNum = 25
              iLen=wsprintf(szBuffer,"iNum = %u",Byval iNum)
              Print szBuffer
              Waitkey$
            
              PBMain=0
            End Function
            
            'Output:
            '=======
            'iNum = 25
            Or am I hopelessly screwed up in my thinking???
            Fred
            "fharris"+Chr$(64)+"evenlink"+Chr$(46)+"com"

            Comment


            • #7
              Fred,

              The wsprintf() function seems to use a "virtual byval" for numerics and the address passed is actually used as a data value. To prove my point, try the same code with "%s" and use a ASCIIZ string, or just pass "BYVAL 25" - both will work.

              This method is also used with the resource functions - you pass a resource ID using a BYVAL numeric (0-64k), or a BYREF string address. It all depends on the function being called, and in this case, using BYREF ANY is correct.
              kgpsoftware.com | Slam DBMS | PrpT Control | Other Downloads | Contact Me

              Comment


              • #8
                Hmm. I see what you mean Kev. I hadn't ever tried it with strings. What it seems to boil down to is that whichever way the function is declared, either numerics or strings will be awkward. For example, if the functions are declared as I did my original last fall, that is, optional byval, then if you are doing a string, i.e., %s, then you need a VarPtr(szString) passed. If the function is declared as PowerBASIC has it and as it apparently has to be declared with PB5 - PB9, then a byval override needs to be placed in front of every numeric parameter.
                Fred
                "fharris"+Chr$(64)+"evenlink"+Chr$(46)+"com"

                Comment


                • #9
                  Correct conversion is: USING$

                  Sheesh, two "functions to port " in one thread, where port is not necessary because PB includes intrinsic support for both.

                  Anyone still wonder why I say verb-for-verb, function-for-function conversions are stone losers?
                  Michael Mattias
                  Tal Systems (retired)
                  Port Washington WI USA
                  [email protected]
                  http://www.talsystems.com

                  Comment

                  Working...
                  X