Announcement

Collapse
No announcement yet.

Calling a FUNCTION with a TYPE in the agrgument

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

  • Calling a FUNCTION with a TYPE in the agrgument

    I want to call my Unzip function with 2 arguments,
    NumFiles = ExtractFiles( ArchivePathAndName, Files() )

    ArchivePathAndName AS STRING * 260 ' no problem

    The Array: Files() is used to return 3 things for
    each file unzipped from the .ZIP archive

    1 - the FilePathAndName AS STRING * 260 of the unzipped file
    2 - The Length of the file AS LONG of the unzipped file
    3 - the unzipped File AS STRING

    So I cant use a TYPE cos the File could be any length
    (typically about 1MB) but that is what I need to hold the
    different data types.

    Can yuo pass a TYPE to a function anyway?

    How would you experts handle this?


    ------------------
    Kind Regards
    Mike

  • #2
    Don't pass "unzipped file" as a STRING -- pass a pointer to the data.
    Then you can use a type something like this:
    Code:
    TYPE foo
      FileSpec AS STRING * %MAX_PATH
      FileSize AS LONG
      FileData AS BYTE PTR
    END TYPE
    ------------------
    Tom Hanlin
    PowerBASIC Staff

    Comment


    • #3
      Thx Tom,

      But isnt a STRING passed BYREF as default?
      Thats a pointer anyway isnt it?


      And what If the Unzip function generates 4 unzipped files?
      I would have to have 4 STRINGs in that function each holding
      an unzipped file that the pointer points to right?

      I guess i could do this with a STRING array,
      but once the function ENDs the array would be destroyed, so
      the array would have to be GLOBAL in which case why even bother
      with a pointer?

      ------------------
      Kind Regards
      Mike

      [This message has been edited by Mike Trader (edited August 13, 2001).]

      Comment


      • #4
        You can pass an ARRAY of types, and REDIM the array to fit as needed

        Here is some crude code:

        Code:
        TYPE ZipFileType
         szFileName AS ASCIIZ * %MAX_PATH
         Filesize   AS LONG
        END TYPE
        
        FUNCTION WinMain yadda yadda
          LOCAL szZipFileName AS ASCIIZ * %MAX_PATH
          REDIM ZF(0) AS ZipFileType
          CALL UnZipMe (szZipFileName, ZF())
        
          FOR I = 1 to UBOUND(ZF,1)
            ProcessUnzippedFile ZF(I)
          NEXT
        
        END FUNCTION
        
        FUNCTION UnzipMe (szFile AS ASCIIZ * %MAX_PATH,ZF() AS ZipFileType) AS LONG
        
           NumZippedFiles = Somefunction(szFile)
           REDIM zf (NumZippedFiles)
           FOR I = 1 TO NumZIppedFiles
             ZF(i).szFileName = somefunction
             ZF(I).Filesize = someotherfunction
           NEXT
        END FUNCTION
        If you can't get the number of zipped files in the archive without extracting, take a look at REDIM PRESERVE to resize the array.

        MCM


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

        Comment


        • #5
          oooook if we giong to get into code then here is
          what I got working so far using a 2 dimensional array:

          Code:
          '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ 
          FUNCTION UnpackZip( PathAndFile AS STRING, SaveFlag AS LONG, FileAndData() AS STRING ) AS LONG
           
          LOCAL StrLen   AS LONG,   RetVal AS LONG, ZippedFile AS LONG, UzFileLen AS LONG
          LOCAL hFile    AS DWORD
          LOCAL aStr     AS STRING, UzFileStr AS STRING, TempStr AS STRING
          LOCAL zZipFile AS ASCIIZ * 260, zFileName AS ASCIIZ * 260 'or %MAX_PATH if you #INCLUDE "WIN32API.INC" 
          LOCAL global_info AS unz_global_info_s, zipfi AS zip_fileinfo_s
           
              REDIM FileAndData(4, 3) ' dimension fo 4 files to start with
              FUNCTION = 0
              zZipFile = PathAndFile
              hFile    = unzOpen(zZipFile)
              IF ISFALSE hFile THEN MSGBOX zZipFile,,"Bad Zip File" : EXIT FUNCTION
           
              RetVal   = unzGetGlobalInfo(hFile, global_info)
              IF RetVal THEN MSGBOX "Zip Archive bad, Fail #" + FORMAT$(RetVal) : EXIT FUNCTION
           
              Count    = 0
              RetVal   = unzGoToFirstFile(hFile)' get first file handle
              DIALOG SEND hDlgProgBar, %PROGBARID, 0, 0 ' Reset Progress bar
              ProgBarClr 255,153,000,  005,005,005 ' Zip-Icon-Orange On Black
              FOR ZippedFile = 1 TO global_info.number_entry 
                  IF RetVal THEN RetVal = unzGoToNextFile(hFile) : MSGBOX "Can't get a Handle",,zZipFile : ITERATE ' Try next file
                  UzFileLen = UnZipFile(hFile, zFileName, UzFileStr )
                  IF UzFileLen THEN ' Success, file was unzipped
                      INCR Count
                      IF Count > UBOUND(FileAndData(1)) THEN REDIM PRESERVE FileAndData(Count+4, 3)
                      FileAndData(Count, 1) = zFileName           ' Name of Archived file
                      FileAndData(Count, 2) = FORMAT$(UzFileLen)  ' Length of UnZipped File
                      FileAndData(Count, 3) = UzFileStr           ' The complete UnZipped file
                      IF SaveFlag THEN CALL SaveFile( zFileName, UzFileStr )
                  END IF
                  RetVal = unzGoToNextFile(hFile) ' get next file handle
                  DIALOG SEND hDlgProgBar, %PROGBARID, ROUND(ZippedFile/global_info.number_entry *100 ,0), 0 ' update progress bar
              NEXT ZippedFile
              CALL unzClose(hFile)
              REDIM PRESERVE FileAndData(Count, 3) ' Make the array size the right size
              FUNCTION = Count ' number of files succesfully unzipped
           
          END FUNCTION
           
          '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ 
          
          FUNCTION PBMAIN()
          '
          '
          '
              DO WHILE FileNum < UBOUND(DropFiles) AND Done = 0
                  INCR FileNum
                  Seperate DropFiles(FileNum), DropFo, DropFi ' Extract Path and Name
                 '================================  
           
           
                  IF PARSE$(UCASE$(DropFi), ".", 2) = "ZIP" THEN ' TnS files
                      NumTnSZip = UnpackZip( DropFo+DropFi, 0, TnSFiles() ) ' unzip the archive, find number of files
                  ELSE
                      ' read the file into VbTFiles(1, 3)
                  END IF 
                 '================================  
           
           
                  FOR i = 1 TO NumTnSZip ' Process the file(s)
                      NumCtr  = ProcessVbT( VAL(VbTFiles(i, 2)),  VbTFiles(i, 3) ) ' Send: file length and the File to a function
                      NumCtr  = ProcessTnS( VAL(TnSFiles(i, 2)),  TnSFiles(i, 3) ) ' Send: file length and the File to a function
                  NEXT 
                 '================================ 
           
              WEND ' Run thru all the dropped files 
          '
          '
          '
          END FUNCTION

          So If I just get a pointer back from the unzipping function then
          wont the actual data be destroyed when the function ends?


          ------------------
          Kind Regards
          Mike

          Comment


          • #6
            IF Count > UBOUND(FileAndData(1)) THEN REDIM PRESERVE FileAndData(Count+4, 3)
            This should not have worked for you. The PRESERVE option of REDIM only allows you to change the last subscript of a multi-dimension array..

            As far as data being destroyed (although, 'abandoned' might be the more accurate term), if data are local, they are gone when the procedure terminates and pointers to it are no longer valid. STATIC and GLOBAL data live.

            MCM


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

            Comment


            • #7
              Mike, the idea for the UDT is, you can use an array of type "foo",
              where each element contains (or points to) all of the information
              for a single extracted file. The reason for using BYTE PTR instead
              of STRING for FileData is so that you can have a UDT: UDTs must be
              of a fixed length.

              The data won't be destroyed if you pass it back from your FUNCTION
              or SUB. This is a more flexible technique than using GLOBAL values,
              but you're the one who best knows your requirements. If GLOBAL suits,
              use it.

              ------------------
              Tom Hanlin
              PowerBASIC Staff

              Comment


              • #8
                Michael,
                the last dimension only. I did not know that! I have only been
                testing with archives containing 4 files so far!

                Can you make a STATIC STRING array? I dont think so.

                Tom,
                I understand what you are saying.
                The part I am confused about is:
                > The data won't be destroyed if you pass it back from your FUNCTION
                (i dont know how to make the two quote lines you guys do)

                If my UDT passes a BYTE PTR back and then the function Ends (destroying
                or "abandoning" the File data that the PTR points to, what use is
                the pointer?

                Dont I have to pass the data itself back to the calling function?

                ------------------
                Kind Regards
                Mike

                Comment


                • #9
                  Docs for UBB codes can be found here: http://www.powerbasic.com/support/forums/ubbcode.html
                  (or click on the "faq" link in the upper right when reading forum messages).

                  There is no problem with allocating data so that it remains valid outside the function. You
                  just need to make sure it's allocated as global memory... say, using a Windows API call like
                  GlobalAlloc or HeapAlloc. The data will stick around until you explicitly free it or the
                  program ends.

                  ------------------
                  Tom Hanlin
                  PowerBASIC Staff

                  Comment


                  • #10
                    Tom,

                    If im going to declare the memory as global, why dont I just
                    make a GLOBAL array of the UDT?

                    TYPE foo ' Where did foo come from???
                    FileSpec AS STRING * %MAX_PATH
                    FileSize AS LONG
                    FileData AS BYTE PTR
                    END TYPE

                    GLOBAL UzData() as foo

                    I thought the point was to get away from globals by somehow using
                    a BYTE PTR. I think I misunderstood. It doesnt seem like
                    I can use PTR here.
                    (As you can tell Im a little shaky on Pointers)

                    ------------------
                    Kind Regards
                    Mike

                    Comment


                    • #11
                      The key to using pointers is that there has to be a target and the target has to be "valid" for the pointer to use usable.

                      Returning a pointer to LOCAL data (from a sub/function) is not going to work since the LOCAL data memory will be deallocated when the sub/function ends.

                      However, you can certainly return a pointer to GLOBAL and STATIC data, and also if the calling code "owns" the data. ie, allocate a memory block (or string, or,...) in the calling code and pass it that to a sub/function by reference. When the target sub/function ends, the calling code still owns the data, and the data is still in "in scope".

                      In summary, declaring a GLOBAL UDT is fine (and using a pointer to it in the code), as the data will still be "in-scope" in both the calling code and any sub/functions that are called.

                      However, since the data is GLOBAL, using a pointer may be of little benefit anyway, since you can reference the GLOBAL UDT directly anyway.


                      ------------------
                      Lance
                      PowerBASIC Support
                      mailto:[email protected][email protected]</A>
                      Lance
                      mailto:[email protected]

                      Comment


                      • #12
                        If im going to declare the memory as global, why dont I just
                        make a GLOBAL array of the UDT?
                        I hope there's no confusion of "global data" with GLOBAL arrays, here.
                        It's useful to avoid using GLOBAL variables in your program for several
                        reasons. Avoiding GLOBALs means your code is more modular, which makes
                        it easier to maintain and to reuse for other purposes. It also helps
                        avoid confusion in cases where you might have a LOCAL variable by the
                        same name as a GLOBAL variable. Plus, you don't have to wonder about
                        where a variable comes from: it's either LOCAL or passed to you as a
                        parameter to your SUB or FUNCTION. Plus, you're much less likely to
                        run into problems with multi-threaded or callback operations.

                        When you allocate global data and assign it to a pointer in a LOCAL
                        array, you get the usual benefits of LOCAL values, but are assured
                        that the data will persist until you're ready to deallocate it or, at
                        least, until the LOCAL value goes out of scope: you do need to free
                        up the memory before the LOCAL array is automatically freed by the
                        compiler.

                        However, it all depends on what you have in mind. This may well be
                        overly complicated or otherwise inappropriate for your purposes.

                        TYPE foo ' Where did foo come from???
                        "Foo" (from "foobar") is one of a list of common names used by
                        programmers as generic names. In this case, I might've been better off
                        choosing a more meaningful name, such as MYFILEINFO.


                        ------------------
                        Tom Hanlin
                        PowerBASIC Staff

                        Comment

                        Working...
                        X