Announcement

Collapse
No announcement yet.

Using API functions in PB/CC

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

  • Using API functions in PB/CC

    Dear PB Forum people

    Please can someone point me in the right direction for applying some API functions in PB/CC?

    I'm not by profession a programmer, but as a scientist I use programming as a tool for mathematical and statistical modelling (among other things). I find PB/CC really excellent for this purpose (in the past I used TurboBasic and then Turbo Pascal). I have no ambitions to be a Windows programmer, or at least that's not a mountain I wish to climb at present, but in some circumstances I like to make my life easier by using certain Windows functions. For example, by looking at examples posted in these forums, I have learned how to use OpenFileDialog and SaveFileDialog from ComDlg32.inc for easy access to files in different folders.

    However... there are a couple of things I'd like to do that I can't work out yet.

    Firstly, if I'm going to open a file for output and I find out that the file already exists, I have three options: overwrite, append or abort and choose a new file name. Of course it's very easy to do this in the console, but having got the file name using SaveFileDialog, I'd like a nice user-friendly message or dialog to pop up and offer the options on the click of a mouse. I've worked out how to get a message box with buttons for "yes", "no" and "cancel"...
    Code:
    x=MessageBox(0,"File already exists!","Warning:",%MB_YESNOCANCEL)
    ...and I can respond to the value of x returned, but how would I get a box with buttons labelled "Overwrite", "Append" and "Abort"? Or is this something best left to 'real' programmers...?

    Secondly, in the course of running a program I sometimes like to change my working directory. Again, easy to implement in the console, but not as convenient as clicking on a directory structure. SaveFileDialog and OpenFileDialog can be used to accomplish a folder change, but are obviously the wrong tools for the job. Is there a similar function which is the right tool?

    Finally, is there any handy documentation for Win32API.inc, ComDlg32.inc, etc. other than Win32.hlp? I'm looking for simple guidance on which function does what, with examples of how to use the syntax.

    Thanks in advance for any enlightenment!

  • #2
    Functions by Category:
    http://msdn.microsoft.com/en-us/libr...8VS.85%29.aspx

    Functions A-Z
    http://msdn.microsoft.com/en-us/libr...88(VS.85).aspx

    Home, sort of:
    http://msdn.microsoft.com/en-us/library/default.aspx

    The previous home page at http://msdn.microsoft.com/en-us/default.aspx has been re-done and now it stinks. The link above is what you get when you click on "Library"

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

    Comment


    • #3
      You usually set a flag/mask which let's the dialog notify the user the file exists.
      Not afterwards when the user presses ok.

      Does PB/CC has the new open file commandset?
      In PBWIN9 i believe there is an open/save file command set.
      hellobasic

      Comment


      • #4
        Code:
        #IF %DEF(%PB_CC32)
        
          #IF NOT %DEF(%WINAPI)
             DECLARE FUNCTION MessageBox LIB "USER32.DLL" ALIAS "MessageBoxA" (BYVAL hWnd AS DWORD, lpText AS ASCIIZ, lpCaption AS ASCIIZ, BYVAL dwType AS DWORD) AS LONG
             %MB_OK                        = &H00000000&
             %MB_TASKMODAL                 = &H00002000&
          #ENDIF
        
         FUNCTION MSGBOX (szText AS ASCIIZ, OPTIONAL BYVAL STYLE AS DWORD, OPTIONAL szCaption AS ASCIIZ) AS LONG
        
            LOCAL hWnd AS LONG, uType AS LONG, dwCap AS DWORD
        
            uType = IIF& (STYLE=%NULL,%MB_OK OR %MB_TASKMODAL, STYLE)
            dwCap =   VARPTR(szCaption)  ' if null, Windows uses "Error"
            FUNCTION = MessageBox (BYVAL %NULL, szText, BYVAL dwCap, BYVAL uType)
        
          END FUNCTION
        #ENDIF   ' if %DEF (%Pb_CC32)
        Useful styles and return values from Win32API.INC:
        Code:
        ' MessageBox() Flags
        %MB_OK                        = &H00000000&
        %MB_OKCANCEL                  = &H00000001&
        %MB_ABORTRETRYIGNORE          = &H00000002&
        %MB_YESNOCANCEL               = &H00000003&
        %MB_YESNO                     = &H00000004&
        %MB_RETRYCANCEL               = &H00000005&
        %MB_CANCELTRYCONTINUE         = &H00000006&
        
        %MB_ICONHAND                  = &H00000010&
        %MB_ICONQUESTION              = &H00000020&
        %MB_ICONEXCLAMATION           = &H00000030&
        %MB_ICONASTERISK              = &H00000040&
        
        %MB_USERICON                  = &H00000080&
        %MB_ICONWARNING               = %MB_ICONEXCLAMATION
        %MB_ICONERROR                 = %MB_ICONHAND
        
        %MB_ICONINFORMATION           = %MB_ICONASTERISK
        %MB_ICONSTOP                  = %MB_ICONHAND
        
        %MB_DEFBUTTON1                = &H00000000&
        %MB_DEFBUTTON2                = &H00000100&
        %MB_DEFBUTTON3                = &H00000200&
        %MB_DEFBUTTON4                = &H00000300&
        
        %IDOK       = 1
        %IDCANCEL   = 2
        %IDABORT    = 3
        %IDRETRY    = 4
        %IDIGNORE   = 5
        %IDYES      = 6
        %IDNO       = 7
        %IDCLOSE    = 8
        %IDHELP     = 9
        %IDTRYAGAIN = 10
        %IDCONTINUE = 11
        MCM
        Michael Mattias
        Tal Systems (retired)
        Port Washington WI USA
        [email protected]
        http://www.talsystems.com

        Comment


        • #5
          Thanks for the replies Edwin and Michael.

          Edwin: no PB/CC doesn't provide a dialog for opening and saving files, but it's easy enough to use ComDlg32.inc to display files and folders and return a file name to open. I just want to be able to display a message box or dialog which allows the user to select the appropriate action when a file to be saved already exists. If that's not possible by calling API functions from PB/CC then I'll either just display the messages in the console or just work with what is possible.

          Michael: good links - I'll trawl through to see what's useful for my purposes. Your MSGBOX function provides me with various combinations of buttons (actually, I could already do this with MessageBox straight from Win32API.inc, but your syntax is shorter...). I'd like to be able to have user-defined buttons, but I can certainly adapt to what is already within my reach...

          Comment


          • #6
            Another alternative.

            James
            Attached Files

            Comment


            • #7
              Thank you James. There's a lot there for me to learn from...

              Comment


              • #8
                > Edwin: no PB/CC doesn't provide a dialog for opening and saving files

                Native syntax, no; but the COMDLG32.INC file provided with PB/CC includes OpenFileDialog() and SaveFileDialog() functions.


                FWIW, the MSGBOX function above has as its purpose making the Pb/Win "MSGBOX" function available from PB/CC... so I can use the same #INCLUDE files regardless of which compiler I am using that day.

                Same goes for Simple STDOUT for PB/DLL and PB/Win 2-13-04 ... Makes STDOUT available if I'm working wth PB/Win that day.


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

                Comment


                • #9
                  I'd like to be able to have user-defined buttons,
                  You could use a hook function to modify the text on a standard messagebox buttons..
                  Code:
                  #COMPILE EXE
                  #REGISTER NONE
                  #DIM ALL
                  #INCLUDE "Win32Api.Inc"
                   
                  FUNCTION MsgBoxButtonText(BYVAL lMsg AS LONG, BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG
                           ' TT Pierre. [URL]http://www.powerbasic.com/support/pbforums/showpost.php?p=87690&postcount=4[/URL]
                   IF lMsg = %HCBT_ACTIVATE THEN
                     SetWindowText GetDlgItem(wParam, 6), "Overwrite"
                     SetWindowText GetDlgItem(wParam, 7), "Append" 
                     SetWindowText GetDlgItem(wParam, 2), "Abort" 
                   END IF
                    'in HCBT_ACTIVATE message, wParam holds the handle to the messagebox
                    'API sets ID's of the buttons on a message box.
                    'Values returned correspond to the IDs,
                    '%IDOK      = 1     '%IDCANCEL  = 2
                    '%IDABORT   = 3     '%IDRETRY   = 4
                    '%IDIGNORE  = 5     '%IDYES     = 6
                    '%IDNO      = 7     'etc
                    ' MessageBox with flag %MB_YESNOCANCEL creates buttons with IDs = 6, 7, 2
                  END FUNCTION
                  '------------------/
                   
                  FUNCTION PBMAIN()
                   Local hHook As Dword, RetVal As Long
                   
                    hHook = SetWindowsHookEx(%WH_CBT, CODEPTR(MsgBoxButtonText), GetModuleHandle(""), GetCurrentThreadId)
                    Retval = MessageBox(0, "Yes, No or Cancel ??", "Renamed Buttons!", %MB_ICONQUESTION OR  %MB_YESNOCANCEL OR %MB_TASKMODAL)
                    UnhookWindowsHookEx hHook
                   
                    MessageBox 0, "Selected:" + str$(RetVal) + $CR + $CR + _
                                  "6 = 'Overwrite'  (aka Yes)" + $CR + _
                                  "7 = 'Append'  (aka No)" + $CR + _
                                  "2 = 'Abort'  (aka Cancel)", "Returned value", %MB_ICONMASK
                   
                  END FUNCTION
                  '------------------/
                  Rgds, Dave

                  Comment


                  • #10
                    Cheers, thanks Dave! I don't know what a hook function is, but it does exactly what I want. I'll be using that one a lot.

                    Later...
                    OK, now I know what a hook function is (http://en.wikipedia.org/wiki/Hook_function). The details of your code are somewhat over my head, but I can certainly see how to use it and adapt it to other purposes.
                    Last edited by Michael Bell; 11 Nov 2009, 04:08 AM.

                    Comment


                    • #11
                      Does PB/CC has the new open file commandset?
                      Well, not included in the compiler.
                      In the include files that come with the compiler there are however many macro's
                      and special functions to make the use of certain Windows functions more easy.
                      You might search these files for this with any suitable search tool or, if you
                      don't have anything suitable, you could use the one that i posted for this purpose.
                      http://www.powerbasic.com/support/pb...ad.php?t=39500

                      Arie Verheul

                      Comment


                      • #12
                        >OK, now I know what a hook function is ...how to use it and adapt it to other purposes

                        I'm glad you looked that up, because there is a 'gotcha' in there.

                        That 'gotcha' is, the way the hook is created it ASSUMES the only window being activated in that thread context is the window created by the MessageBox function.

                        In your program(s), that may be a perfectly reasonable and safe assumption, but if you add, say, an "Open File" function and do so in that thread context you could have an interesting experience.

                        In this case you are probably good to go because this is done with this sequence...
                        Code:
                        hHook = SetWindowsHookEx ...
                        Retval = MessageBox....
                        UnhookWindowsHookEx ...
                        .. and the hook will be in effect only for the life of the MessageBox call. .. however, you might have created another window on this thread earlier in your program. If the user just stares at the MessageBox and then decides to activate (click on) that already-created window, your hook proc will receive an activate notification, but wParam will not refer to your message box.

                        I admit this is unlikely in the case of a console program... but it is not impossible.

                        You can disable that other window for this call sequence and now clicking on it won't do anything. See EnableWindow() function in your WinAPI reference)...

                        ...OR...

                        ... you can make that hWnd the owner window of this message box; that should disable the original window until the messagebox has been dismissed.

                        I'm not here to be the "doom and gloom" guy, but sometimes when you "adapt to other purposes" the original restrictions get lost in the shuffle.

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

                        Comment


                        • #13
                          Thanks Michael for the heads-up on that particular trap for the unwary. Yes, it's pretty unlikely that I'd blunder into it in the type of simple console applications that I write, but you never know, I might get above myself with winapi in future...

                          Arie: I copied SearchAPI today and am already finding it useful.

                          Comment


                          • #14
                            Secondly, in the course of running a program I sometimes like to change my working directory. Again, easy to implement
                            in the console, but not as convenient as clicking on a directory structure...
                            Is there a similar function which is the right tool?
                            Search the forums for the API function SHBrowseForFolder. Here is one example of it's use..
                            Code:
                            #COMPILE EXE
                            #INCLUDE "win32api.inc"
                             
                            FUNCTION BrowseForFolder(hWndOwner AS LONG, sPrompt AS STRING) AS STRING
                             LOCAL BI AS BrowseInfo                 ' Contains parameters for the the SHBrowseForFolder function and 
                                                                    ' receives information about the folder selected by the user
                             LOCAL pIDList AS LONG 
                             LOCAL szPath AS ASCIIZ * %MAX_PATH
                             
                              BI.hWndOwner = hWndOwner              ' 0 = DeskTop
                              BI.lpszTitle = STRPTR(sPrompt)
                              BI.ulFlags   = %BIF_RETURNONLYFSDIRS  ' try OR %BIF_DONTGOBELOWDOMAIN OR %BIF_USENEWUI OR %BIF_RETURNFSANCESTORS
                              pIDList = SHBrowseForFolder(BI)       ' Returns a pointer to an item identifier list (pIDL) - specifies 
                                                                    ' the location of the selected folder relative to the root of the namespace. 
                              ' The 'Shell namespace' organizes the file system and other objects managed by the Shell into a single 
                              ' tree-structured hierarchy. Conceptually, it is a larger and more inclusive version of the file system.                                        
                             
                              IF pIDList THEN                       ' If the user chooses the Cancel button, pIDList is NULL.
                                SHGetPathFromIDList (BYVAL pIDList, szPath)   ' Converts pIDL to a file system path.
                                FUNCTION = szPath
                              END IF
                              CoTaskMemFree pIDList             ' Calling application is responsible for freeing the returned Item Identifier List.
                            END FUNCTION
                            '------------------/
                             
                            FUNCTION PBMAIN() AS LONG
                             LOCAL sPath AS String
                             
                              sPath = BrowseForFolder(0, "Select folder...")
                             
                              MessageBox 0, "Folder = " + sPath, "Folder Selected", %MB_ICONMASK 
                            END FUNCTION
                            '------------------/
                            Finally, is there any handy documentation for Win32API.inc, ComDlg32.inc, etc. other than Win32.hlp?
                            I'm looking for simple guidance on which function does what, with examples of how to use the syntax.
                            In addition to the MSDN links provided by Michael you should check out POFFS offline search engine for PB Forums - download here: http://www.reonis.com/POFFS/index.htm
                            As you find yourself slidding deeper into the API you'll probably want to get a copy of the SDK Documentation on disk..
                            Microsoft Platform SDK CD (available at cost of shipping only) - order here: http://mssdk.orderport.net
                            (Windows XP SP2 edition is probably the best to start with)
                            Rgds, Dave

                            Comment


                            • #15
                              Another way to make using the hook 'safer' could be to declare hHook as Global and unhook imediately..
                              Code:
                               IF lMsg = %HCBT_ACTIVATE THEN
                                  UnhookWindowsHookEx hHook
                              ...
                              Rgds, Dave

                              Comment


                              • #16
                                Dave: excellent - thanks! A little research shows me how to specify different root directories for browsing, but is it possible to start browsing in a subfolder? Specifically, it would be good to start in the folder from which the application was launched, but have access to higher-level folders too.

                                Comment


                                • #17
                                  >but is it possible to start browsing [using ShBrowseForFolder] in a subfolder?

                                  Yes.

                                  Ok?

                                  Oh, you wanted code .

                                  Code:
                                  %GETFOLDER_START_ROOT     = 0&
                                  %GETFOLDER_START_LAST     = 1&
                                  %GETFOLDER_START_CURRENT  = 2&
                                  
                                  .....
                                        LOCAL bInf AS BROWSEINFO
                                  
                                        'Set some properties of the folder dialog
                                        bInf.hWndOwner    = hWndModal
                                        bInf.ulFlags      = %BIF_RETURNONLYFSDIRS OR %BIF_DONTGOBELOWDOMAIN
                                  [b]      bInf.lpfnCallback = CODEPTR (BrowseForFolderCallBack)   ' to start the search in another place[/b]
                                     ' No callback to make sure this is working with new compiler and Win32API.INC
                                     '   bInf.lpfnCallback = %NULL
                                        bInf.lparam       = StartFolder         ' passed to callback as lparam each call
                                  
                                  FUNCTION BrowseForFolderCallBack (BYVAL hwnd AS LONG,BYVAL uMsg AS DWORD,BYVAL lparam AS LONG, BYVAL pdata AS LONG) EXPORT AS LONG
                                     ' my lparam=function's pdata=%GetFolder_Start_Current, %GETFOLDER_START_LAST, or %GETFOLDER_START_ROOT
                                  
                                       STATIC szStartFolder AS ASCIIZ * %MAX_PATH
                                       LOCAL  szDummy       AS ASCIIZ * %MAX_PATH
                                  
                                       SELECT CASE uMSG
                                              CASE %BFFM_INITIALIZED
                                  
                                                  SELECT CASE pdata ' does lparam come BYVAL? Yes, in Pdata.
                                                    ' CASE %GETFOLDER_START_ROOT      ' do nothing...
                                                    '    EXIT FUNCTION
                                                     CASE %GETFOLDER_START_CURRENT
                                                        szDummy = CURDIR$
                                                        SendMessage hWnd, %BFFM_SETSELECTIONA, %TRUE, BYVAL VARPTR(szDummy)
                                                     CASE %GETFOLDER_START_LAST
                                                        SendMessage hWnd, %BFFM_SETSELECTIONA, %TRUE, BYVAL VARPTR(szStartFolder)
                                                  END SELECT
                                             ' We are getting BFFM_SELCHANGED TWICE BEFORE WE GET BFFM_INITIALIZED
                                             ' On these passes, szStartFolder is null, so we do not set szStartFolder
                                             CASE %BFFM_SELCHANGED
                                                    ' we only change the szStartDir if the current option (pdata) is start_last
                                                    ' I suppose we could do this under any cicumstances if we wanted...
                                                    STDOUT "Got BGGM_SELCHANGED"
                                                IF pdata = %GETFOLDER_START_LAST THEN
                                                    ' 6/07/02 It appears lparam, NOT PDATA is the pointer to the itemidlist!
                                                    ' THAT IS CORRECT!! ERROR IN MSDN DOCUMENTATION!!!
                                                     SHGetPathFromIDList  BYVAL lparam, szDummy
                                                     IF LEN(szDummy) THEN
                                                       szStartFolder = szDummy
                                                     END IF
                                                END IF
                                  
                                       END SELECT    ' of which %BFFM_xxx messsage
                                  
                                       FUNCTION = 0
                                  END FUNCTION
                                  I left a little work for you to do yourself.

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

                                  Comment


                                  • #18
                                    It just occurred to me...for a self-professed "newbie" to use of the Windows API, you are starting off with hook procedures, user-defined callbacks, dialog templates etc.....

                                    I think I might have started with some more basic things, like "creating a window and adding some controls."

                                    Wait a minute, that's exactly what I did!

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

                                    Comment


                                    • #19
                                      It just occurred to me...for a self-professed "newbie" to use of the Windows API, you are starting off with hook procedures, user-defined callbacks, dialog templates etc.....

                                      I think I might have started with some more basic things, like "creating a window and adding some controls."
                                      I take your point Michael. It's just that I'm comfortable working with console applications but have realised that there are things that can much more conveniently be done using API functions. I suppose that I'm working towards being motivated finally to take the plunge and use PB/Win (I do have a PB/Win 8 licence at home...). When I do, I will certainly start off along the lines you suggest. I think that the main mountain for me to climb is changing to an event-driven rather than linear approach. But, then again, I find that my console applications are tending towards things like waiting for mouse-events and mimicking Windows-like screens for collecting parameter values, etc.

                                      In the meantime, thanks for the SHBrowseForFolder code. I shall endeavour to understand and use.

                                      Comment


                                      • #20
                                        Here's a compilable example using the BrowseCallbackProc Function.
                                        That allows you to control the 'browse for folder' dialog somewhat (choose initial selection etc)..
                                        Code:
                                         
                                        #COMPILE EXE
                                        #INCLUDE "win32api.inc"
                                         
                                        FUNCTION BrowseForFolderProc(BYVAL hwnd AS DWORD, BYVAL uMsg AS LONG, BYVAL lparam AS LONG, BYVAL pData AS LONG)AS LONG
                                          DIM zBuffer AS ASCIIZ * %MAX_PATH
                                            IF uMsg = %BFFM_INITIALIZED Then                        ' Browse For Folder Messages
                                              SendMessage hwnd, %BFFM_SETSELECTION, %TRUE, pData    ' see BrowseCallbackProc Function in docs
                                            END IF 
                                        END FUNCTION
                                        '------------------/
                                         
                                        FUNCTION BrowseForFolder(hWndOwner AS LONG, sPrompt AS STRING, StartFolder AS String) AS STRING
                                         LOCAL BI AS BrowseInfo
                                         LOCAL pIDList AS LONG 
                                         LOCAL szPath AS ASCIIZ * %MAX_PATH
                                         
                                          BI.hWndOwner    = hWndOwner              ' 0 = DeskTop
                                          BI.lpszTitle    = STRPTR(sPrompt)
                                          BI.ulFlags      = %BIF_RETURNONLYFSDIRS OR %BIF_NEWDIALOGSTYLE OR %BIF_RETURNFSANCESTORS OR %BIF_DONTGOBELOWDOMAIN
                                          BI.lpfnCallback = CODEPTR(BrowseForFolderProc)  ' * callback function - so we can send messages to the browse dialog
                                          BI.lParam       = Strptr(StartFolder)           ' *
                                         
                                          pIDList = SHBrowseForFolder(BI)                                     
                                          IF pIDList THEN
                                            SHGetPathFromIDList (BYVAL pIDList, szPath)
                                            FUNCTION = szPath
                                            CoTaskMemFree pIDList
                                          END IF
                                        END FUNCTION
                                        '------------------/
                                         
                                        FUNCTION PBMAIN() AS LONG
                                         LOCAL sPath AS String
                                         
                                          sPath = BrowseForFolder(0, "Select folder...", CURDIR$) '"C:\Temp")' 'Replace CurDir$ with your StartFolder
                                         
                                          MessageBox 0, "sPath = " + sPath, "Folder Selected", %MB_ICONMASK 
                                        END FUNCTION
                                        '------------------/
                                        This is based on an example that Lance posted some time ago.. http://www.powerbasic.com/support/pb...39&postcount=7
                                        That code shows how to filter the selections too.
                                        Last edited by Dave Biggs; 12 Nov 2009, 09:01 AM. Reason: sp
                                        Rgds, Dave

                                        Comment

                                        Working...
                                        X