Page 1 of 1

OpenFileRequester with ZIP integration

Posted: Thu Dec 09, 2004 2:27 pm
by Leo
Inspired by the OpenFileRequester_with_Preview from the CodeArchiv, I wrote a customized OpenFileRequester (and SaveFileRequester) with ZIP compression support. For the handling of the zipfiles I use the ZLIBWAPI.dll that can be downloaded from the www.zlib.org website. The following customizations are implemented :
OpenFileRequester :
- A TextGadget and a ListviewGadget are added to the Dialog
- Internally the pattern is extended with zipfiles. Thus if the
Pattern is *.txt then txt and zip files are shown.
- Selecting a txt file means the normal procedure
- Selecting a zip file causes the ListViewGadget to be filled with txt files
if there are any present in the zip file.
- Pressing Open or doubleclicking a txt file in the ListViewGadget results
in a return of the selected zipfile + "#"+the selected txt file in the
ListViewGadget
SaveFileRequester :
- A TextGadget, a ListviewGadget and a StringGadget are added to the
Dialog
- Internally the pattern is extended with zipfiles. Thus if the
Pattern is *.txt then txt and zip files are shown.
- Selecting a txt file means the normal procedure
- Selecting a zip file causes the ListViewGadget to be filled with txt files
if there are any present in the zip file.
- Clicking a txt file in the ListViewGadget result in copying the entry
into the StringGadget
- The StringGadget may be modified manually
- Pressing Save or doubleclicking a txt file in the ListViewGadget results
in a return of the selected zipfile + "#"+the contents of the
StringGadget
To avoid OS version problems, depending on the OS OPENFILENAME or OPENFILENAMEEX structure is used. In principle compiling on Win98 and running on XP is possible.

The PureBasic code :

Code: Select all

;################################## 
;OpenFileRequester with Zip 
; uses ZLIBWAPI.dll  
;################################## 
;Leo * December 2004 
;##################################
  
;##################################
; ZLIPWAPI.dll Declarations
;##################################

#UNZ_OK                           = 0
#UNZ_END_OF_LIST_OF_FILE          = -100
#UNZ_EOF                          = 0
#UNZ_PARAMERROR                   = -102
#UNZ_BADZIPFILE                   = -103
#UNZ_INTERNALERROR                = -104
#UNZ_CRCERROR                     = -105

#Z_DEFLATED                       = 8

#Z_NO_COMPRESSION                 = 0
#Z_BEST_SPEED                     = 1
#Z_BEST_COMPRESSION               = 9
#Z_DEFAULT_COMPRESSION            = -1

#APPEND_STATUS_CREATE             = 0
#APPEND_STATUS_CREATEAFTER        = 1
#APPEND_STATUS_ADDINZIP           = 2
;/* tm_unz contain date/time info */

Structure tm_date
  tm_sec.l;            /* seconds after the minute - [0,59] */
  tm_min.l;            /* minutes after the hour - [0,59] */
  tm_hour.l;           /* hours since midnight - [0,23] */
  tm_mday.l;           /* day of the month - [1,31] */
  tm_mon.l;            /* months since January - [0,11] */
  tm_year.l;           /* years - [1980..2044] */
EndStructure

;/* unz_global_info structure contain global data about the ZIPfile
;   These data comes from the end of central dir */
Structure unz_global_info
  number_entry.l      ;         /* total number of entries in
  size_comment.l      ;         /* size of the global comment of the zipfile */
EndStructure

Structure unz_file_info
    version.l;              /* version made by                 2 bytes */
    version_needed.l;       /* version needed to extract       2 bytes */
    flag.l;                 /* general purpose bit flag        2 bytes */
    compression_method.l;   /* compression method              2 bytes */
    dosDate.l;              /* last mod file date in Dos fmt   4 bytes */
    crc.l;                  /* crc-32                          4 bytes */
    compressed_size.l;      /* compressed size                 4 bytes */
    uncompressed_size.l;    /* uncompressed size               4 bytes */
    size_filename.l;        /* filename length                 2 bytes */
    size_file_extra.l;      /* extra field length              2 bytes */
    size_file_comment.l;    /* file comment length             2 bytes */
    disk_num_start.l;       /* disk number start               2 bytes */
    internal_fa.l;          /* internal file attributes        2 bytes */
    external_fa.l;          /* external file attributes        4 bytes */
    tmu_date.tm_date ;
EndStructure

Structure zip_file_info
  tm_zip.tm_date
  dosDate.l
  internal_fa.l
  external_fa.l
EndStructure

Global GlobalInfo.unz_global_info
Global FileInfo.unz_file_info

;##################################
; OpenFile Hook Declarations
;##################################

Global *FileBuffer.l
*FileBuffer = AllocateMemory(2*#MAX_PATH)

#OpenFileButtonGadget = 1 
#QuitButtonGadget = 2 
#OpenFileButtonGadget2 = 3
#SaveFileButtonGadget = 4

#ZipFileStringGadget = 30
#ZipFileListViewGadget = 31
#ZipFileStringGadget2 = 32

#ZLIBWAPI_LIB = 11 

#CDN_FIRST              = (-601)
#CDN_LAST               = (-699)
#CDN_INITDONE           = #CDN_FIRST
#CDN_SELCHANGE          = (#CDN_FIRST-1)
#CDN_FOLDERCHANGE       = (#CDN_FIRST-2)
#CDN_SHAREVIOLATION     = (#CDN_FIRST-3)
#CDN_HELP               = (#CDN_FIRST-4)
#CDN_FILEOK             = (#CDN_FIRST-5)
#CDN_TYPECHANGE         = (#CDN_FIRST-6)

Structure OSVERSIONINFOEX Extends OSVERSIONINFO
  wServicePackMajor.w
  wServicePackMinor.w
  wSuiteMask.w
  wProductType.b
  wReserved.b
EndStructure

Structure OPENFILENAMEXP Extends OPENFILENAME
  pvReserved.l
  dwReserved.l
  FlagsEx.l
EndStructure 

Structure OFNOTIFY  
  hdr.NMHDR 
  lpOFN.OPENFILENAME 
  pszFile.l 
EndStructure 

Global OldCallback, hOK 


Procedure ListViewCallbackOpen(hwnd, msg, wparam, lparam) 
  result = CallWindowProc_(OldCallback, hwnd, msg, wparam, lparam) 
  Select msg 
    Case #WM_LBUTTONDBLCLK
      SendMessage_(hOK,#BM_CLICK,0,0)
  EndSelect 
  ProcedureReturn result 
EndProcedure 

Procedure ListViewCallbackSave(hwnd, msg, wparam, lparam) 
  result = CallWindowProc_(OldCallback, hwnd, msg, wparam, lparam) 
  Select msg 
    Case #WM_LBUTTONDBLCLK
      SendMessage_(hOK,#BM_CLICK,0,0)
    Case #WM_LBUTTONDOWN
      SetGadgetText(#ZipFileStringGadget2, GetGadgetText(#ZipFileListViewGadget))
  EndSelect 
  ProcedureReturn result 
EndProcedure 

Procedure OFHookProc(hdlg,uiMsg,wParam,lParam) 
  Shared hLV, lCustData
  ZipFile$ = Space(#MAX_PATH) 
  Result = #FALSE
  Select uiMsg
    Case #WM_NOTIFY 
      *of.OFNOTIFY = lParam
      Select *of\hdr\code
        Case  #CDN_FILEOK
          SendMessage_(GetParent_(hdlg),#CDM_GETFILEPATH,#MAX_PATH,ZipFile$)
          If lCustData = 0
            InternalFile$=Trim(GetGadgetText(#ZipFileListViewGadget))
          Else
            InternalFile$=Trim(GetGadgetText(#ZipFileStringGadget2))
          EndIf    
          If InternalFile$="" And UCase(Right(ZipFile$,4))=".ZIP"
            If lCustData=0
              MessageRequester("!! Attention !!","Please select file to be extracted.",0)
            Else  
              MessageRequester("!! Attention !!","No filename specified.",0)
            EndIf  
            SetWindowLong_(hdlg,#DWL_MSGRESULT,1)
            ZipSelect=1
          Else
            *OFN.OPENFILENAME=*of\lpOFN
            If InternalFile$
              PokeS(*FileBuffer,ZipFile$+"#"+InternalFile$)  
            Else
              PokeS(*FileBuffer,ZipFile$)  
            EndIf  
          EndIf  
        Case  #CDN_FOLDERCHANGE
        Case  #CDN_HELP
        Case  #CDN_INITDONE
        Case  #CDN_SELCHANGE
          ClearGadgetItemList(#ZipFileListViewGadget)
          SetGadgetText(#ZipFileStringGadget,"No ZIP File selected")
          GlobalInfo.unz_global_info
          FileInfo.unz_file_info
          SendMessage_(GetParent_(hdlg),#CDM_GETFILEPATH,#MAX_PATH,ZipFile$)
          If UCase(Right(ZipFile$,4))=".ZIP" 
            If ReadFile(1, ZipFile$)
              CloseFile(1)
              *OFN.OPENFILENAME=PeekL(*of\lpOFN)
              FilterIndex=*OFN\nFilterIndex
              FilterAddress=*OFN\lpstrFilter
              For i=1 To 2*FilterIndex-1
                FilterAddress+Len(PeekS(FilterAddress))+1
              Next
              ZipCaption.s=ReplaceString(PeekS(FilterAddress),";*.zip","")
              If ZipCaption="*.*" Or ZipCaption=""
                SetGadgetText(#ZipFileStringGadget, "All Files")
              Else  
                SetGadgetText(#ZipFileStringGadget, "Only "+ZipCaption+" Files")
              EndIf  
              If OpenLibrary(#ZLIBWAPI_LIB,"zlibwapi.dll")
                FileName=AllocateMemory(500)
                Comment=AllocateMemory(500)
                ExtraField=AllocateMemory(500)
                Handle.l=CallFunction(#ZLIBWAPI_LIB,"unzOpen",ZipFile$)
                Result.l=CallFunction(#ZLIBWAPI_LIB,"unzGetGlobalInfo",Handle,@GlobalInfo)
                NrOfCompressed.l=GlobalInfo\number_entry
                Result.l=CallFunction(#ZLIBWAPI_LIB,"unzGoToFirstFile",Handle)
                MaxLen=0
                MaxStr.s=""
                For i=1 To NrOfCompressed
                  Result.l=CallFunction(#ZLIBWAPI_LIB,"unzGetCurrentFileInfo",Handle,@FileInfo,FileName,100,ExtraField,100,Comment,100)
                  Extension.s=UCase(Right(PeekS(FileName),4))
                  Pos.l=FindString(Extension,".",1)
                  If Pos=0
                    Extension="No Filter"
                  ElseIf Pos>1
                    Extension=Mid(Extension,Pos,4)
                  EndIf
                  If (FindString(ZipCaption,"*.*",1) Or FindString(UCase(ZipCaption),Extension,1) Or FilterIndex=0) And Right(PeekS(FileName),1)<>"/"   
                    If Len(PeekS(FileName))>MaxLen
                      MaxLen=Len(PeekS(FileName))
                      MaxStr=PeekS(FileName)
                      hDC.l=GetDC_(GadgetID(#ZipFileListViewGadget))
                    EndIf  
                    hDC.l=GetDC_(GadgetID(#ZipFileListViewGadget))
                    GetTextExtentPoint32_(hDC,MaxStr,MaxLen,@Size)
                    SendMessage_(GadgetID(#ZipFileListViewGadget),#LB_SETHORIZONTALEXTENT,Size,0)
                    AddGadgetItem(#ZipFileListViewGadget, -1, PeekS(FileName))
                  EndIf  
                  Result.l=CallFunction(#ZLIBWAPI_LIB,"unzGoToNextFile",Handle)
                Next
                CloseLibrary(#ZLIBWAPI_LIB)
              EndIf    
            EndIf  
          EndIf
        Case  #CDN_SHAREVIOLATION
        Case  #CDN_TYPECHANGE
        Default
          ClearGadgetItemList(#ZipFileListViewGadget)
      EndSelect 
      Result = #TRUE 
    Case #WM_INITDIALOG
      *OFN.OPENFILENAME = lParam
      lCustData = *OFN\lCustData
      GetWindowRect_(GetParent_(hdlg),wr.RECT) 
      GetWindowRect_(GetDesktopWindow_(),wr1.RECT) 
      MoveWindow_(GetParent_(hdlg),wr1\right/2-(wr\right+210)/2,wr1\bottom/2-(wr\bottom)/2,wr\right+210,wr\bottom,#TRUE) 
      CreateGadgetList(GetParent_(hdlg)) 
      TextGadget(#ZipFileStringGadget,wr\right-5,6,200,20,"No ZIP File selected",#PB_Text_Border) 
      If lCustData = 0
        hLV=ListViewGadget(#ZipFileListViewGadget, wr\right-5,33,200,wr\bottom-63 )
        OldCallback = SetWindowLong_(GadgetID(#ZipFileListViewGadget), #GWL_WNDPROC, @ListViewCallbackOpen()) 
      Else   
        hLV=ListViewGadget(#ZipFileListViewGadget, wr\right-5,33,200,wr\bottom-93 ) 
        StringGadget(#ZipFileStringGadget2,wr\right-5,wr\bottom-50,200,20,"") 
        OldCallback = SetWindowLong_(GadgetID(#ZipFileListViewGadget), #GWL_WNDPROC, @ListViewCallbackSave()) 
      EndIf
      Styles.l = GetWindowLong_(GadgetID(#ZipFileListViewGadget), #GWL_STYLE)
      Styles = Styles | #WS_HSCROLL | #WS_VSCROLL | #WS_CHILD
      SetWindowLong_(GadgetID(#ZipFileListViewGadget), #GWL_STYLE, Styles)
      hOK=GetDlgItem_(GetParent_(hdlg),#IDOK)
      Result = #TRUE 
    Default
  EndSelect 
  ProcedureReturn Result 
EndProcedure 

Procedure.s ZipFileRequester(Title$, DefaultFile$, Pattern$, PatternPosition, OpenYesNo ) 
  PokeS(*FileBuffer,DefaultFile$)
  i=1
  PatField$=StringField(Pattern$,i,"|")
  NewPattern$=""
  While PatField$
    If i % 2 = 1
      NewPattern$+PatField$+"|"
    Else  
      NewPattern$+PatField$+";*.zip|"
    EndIf  
    i+1
    PatField$=StringField(Pattern$,i,"|")
  Wend
  NewPattern$=ReplaceString(NewPattern$,"*.*;*.zip","*.*")
  NewPattern$+"|"
  AddrPattern=AllocateMemory(Len(NewPattern$))
  PokeS(AddrPattern,NewPattern$)
  For i=0 To Len(NewPattern$)-1
    If PeekB(AddrPattern+i)='|'
      PokeB(AddrPattern+i,0)
    EndIf
  Next
  NewPattern$=ReplaceString(NewPattern$,"|",Chr(0))
  Result.s = "" 
  of.OPENFILENAMEXP
  of\lpstrTitle = @Title$
  of\lStructSize = SizeOf(OPENFILENAME)
  OS.OSVERSIONINFOEX
  OS\dwOSVersionInfoSize=SizeOf(OSVERSIONINFOEX)
  If GetVersionEx_(@OS)
    If OS\dwMajorVersion>4
      of\lStructSize = SizeOf(OPENFILENAMEXP)
    EndIf
  EndIf  
;  If OSVersion()>49
;    of\lStructSize = SizeOf(OPENFILENAMEXP)
;  Else
;    of\lStructSize = SizeOf(OPENFILENAME)
;  EndIf   
  of\flags = #OFN_EXPLORER|#OFN_ENABLEHOOK 
  of\lpstrFilter = AddrPattern
  of\nFilterIndex = PatternPosition 
  of\nMaxFile = 2*#MAX_PATH 
  of\lpstrFile = *FileBuffer
  of\lpfnHook = @OFHookProc()
  of\lCustData = OpenYesNo
  If OpenYesNo=0 
    If GetOpenFileName_(of) 
      Result = PeekS(*FileBuffer) 
    EndIf
  Else    
    If GetSaveFileName_(of) 
      Result = PeekS(*FileBuffer) 
    EndIf
  EndIf    
  ProcedureReturn Result 
EndProcedure
 
Procedure.s OpenZipFileRequester(Title$, DefaultFile$, Pattern$, PatternPosition ) 
  ProcedureReturn ZipFileRequester(Title$, DefaultFile$, Pattern$, PatternPosition, 0 )
EndProcedure

Procedure.s SaveZipFileRequester(Title$, DefaultFile$, Pattern$, PatternPosition ) 
  ProcedureReturn ZipFileRequester(Title$, DefaultFile$, Pattern$, PatternPosition, 1 )
EndProcedure


If OpenWindow(0,0,0,270,220,#PB_Window_SystemMenu|#PB_Window_ScreenCentered,"OpenFileDialog with Zip") And CreateGadgetList(WindowID(0)) 
  ButtonGadget(#OpenFileButtonGadget, 10, 10,120,20,"OpenFile with Pattern") 
  ButtonGadget(#OpenFileButtonGadget2, 10, 40,140,20,"OpenFile without Pattern") 
  ButtonGadget(#SaveFileButtonGadget, 10, 70,140,20,"SaveFile with Pattern") 
  ButtonGadget(#QuitButtonGadget, 10, 100,80,20,"Quit") 
  Repeat 
    EventID.l = WaitWindowEvent() 
    If EventID = #PB_EventGadget 
      Select EventGadgetID()
        Case #OpenFileButtonGadget
          pathname.s = Space(#MAX_PATH) 
          GetCurrentDirectory_(#MAX_PATH, @pathname)
          If Right(pathname,1)="\"
            pathname=Left(pathname,Len(pathname)-1)
          EndIf  
          StandardFile$ = pathname+"\leo.txt"
          Pattern$ = "Text (*.txt or *.bat)|*.txt;*.bat|PureBasic (*.pb)|*.pb|All files (*.*)|*.*" 
          Pattern = 0 
          opf.s = OpenZipFileRequester("OpenZipFileRequester",StandardFile$,Pattern$,Pattern)
          MessageRequester("File :",opf,0)
          ZipFile$=StringField(opf,1,"#")
          InternalFile$=StringField(opf,2,"#")
          If InternalFile$ 
            If OpenLibrary(#ZLIBWAPI_LIB,"zlibwapi.dll")
              FileName=AllocateMemory(500)
              Comment=AllocateMemory(500)
              ExtraField=AllocateMemory(500)
              Handle.l=CallFunction(#ZLIBWAPI_LIB,"unzOpen",ZipFile$)
              Result.l=CallFunction(#ZLIBWAPI_LIB,"unzLocateFile",Handle,InternalFile$)
              Result.l=CallFunction(#ZLIBWAPI_LIB,"unzGetCurrentFileInfo",Handle,@FileInfo,FileName,100,ExtraField,100,Comment,100)
              Debug FileInfo\external_fa
              Result.l=CallFunction(#ZLIBWAPI_LIB,"unzOpenCurrentFile",Handle)
              Text.s=Space(FileInfo\uncompressed_size)
              Result.l=CallFunction(#ZLIBWAPI_LIB,"unzReadCurrentFile",Handle,@Text,FileInfo\uncompressed_size)
              Text=Left(Text,FileInfo\uncompressed_size)
              MessageRequester(Str(Len(Text)),Text,0)
              CloseLibrary(#ZLIBWAPI_LIB)
            EndIf
          Else
            If ReadFile(3, ZipFile$)
              FLen=Lof()
              AddrFile=AllocateMemory(FLen+1)
              ReadData(AddrFile,Flen)
              MessageRequester(Str(FLen),Left(PeekS(AddrFile),FLen),0)
              CloseFile(3)
            EndIf      
          EndIf 
        Case #OpenFileButtonGadget2
;          opf.s = PB_OpenFile()
          pathname.s = Space(#MAX_PATH) 
          GetCurrentDirectory_(#MAX_PATH, @pathname)
          If Right(pathname,1)="\"
            pathname=Left(pathname,Len(pathname)-1)
          EndIf  
          StandardFile$ = pathname+"\leo.txt"
          Pattern$=""
          Pattern = 0 
          
          opf.s = OpenZipFileRequester("OpenZipFileRequester",StandardFile$,Pattern$,Pattern)
          MessageRequester("File :",opf,0)
          ZipFile$=StringField(opf,1,"#")
          InternalFile$=StringField(opf,2,"#")
          If InternalFile$ 
            If OpenLibrary(#ZLIBWAPI_LIB,"zlibwapi.dll")
              FileName=AllocateMemory(500)
              Comment=AllocateMemory(500)
              ExtraField=AllocateMemory(500)
              Handle.l=CallFunction(#ZLIBWAPI_LIB,"unzOpen",ZipFile$)
              Result.l=CallFunction(#ZLIBWAPI_LIB,"unzLocateFile",Handle,InternalFile$)
              Result.l=CallFunction(#ZLIBWAPI_LIB,"unzGetCurrentFileInfo",Handle,@FileInfo,FileName,100,ExtraField,100,Comment,100)
              Result.l=CallFunction(#ZLIBWAPI_LIB,"unzOpenCurrentFile",Handle)
              Text.s=Space(FileInfo\uncompressed_size)
              Result.l=CallFunction(#ZLIBWAPI_LIB,"unzReadCurrentFile",Handle,@Text,FileInfo\uncompressed_size)
              Text=Left(Text,FileInfo\uncompressed_size)
              MessageRequester(Str(Len(Text)),Text,0)
              CloseLibrary(#ZLIBWAPI_LIB)
            EndIf
          Else
            If ReadFile(3, ZipFile$)
              FLen=Lof()
              AddrFile=AllocateMemory(FLen+1)
              ReadData(AddrFile,Flen)
              MessageRequester(Str(FLen),Left(PeekS(AddrFile),FLen),0)
              CloseFile(3)
            EndIf      
          EndIf 
        Case #SaveFileButtonGadget
          pathname.s = Space(#MAX_PATH) 
          GetCurrentDirectory_(#MAX_PATH, @pathname)
          If Right(pathname,1)="\"
            pathname=Left(pathname,Len(pathname)-1)
          EndIf  
          StandardFile$ = pathname+"\leo.txt"
          Pattern$ = "Text (*.txt or *.bat)|*.txt;*.bat|PureBasic (*.pb)|*.pb|All files (*.*)|*.*" 
          Pattern = 0 
          opf.s = SaveZipFileRequester("SaveZipFileRequester",StandardFile$,Pattern$,Pattern)
          MessageRequester("File :",opf,0)
          ZipFile$=StringField(opf,1,"#")
          InternalFile$=StringField(opf,2,"#")
          If InternalFile$ 
            If OpenLibrary(#ZLIBWAPI_LIB,"zlibwapi.dll")
              Handle.l=CallFunction(#ZLIBWAPI_LIB,"zipOpen",ZipFile$,#APPEND_STATUS_ADDINZIP)
              zfi.zip_file_info
              zfi\tm_zip\tm_sec=11
              zfi\tm_zip\tm_min=6
              zfi\tm_zip\tm_hour=18
              zfi\tm_zip\tm_mday=9
              zfi\tm_zip\tm_mon=0
              zfi\tm_zip\tm_year=2003
              zfi\dosDate=0
              zfi\internal_fa=0
              zfi\external_fa=0
              Result=CallFunction(#ZLIBWAPI_LIB,"zipOpenNewFileInZip",Handle,@InternalFile$,@zfi,#NULL,0,#NULL,0,#NULL,#Z_DEFLATED,5) 
              Content.s="Leo Mijnders"+Chr(13)
              For i=1 To 5
                Content+Content
              Next
              Result=CallFunction(#ZLIBWAPI_LIB,"zipWriteInFileInZip",Handle,@Content,Len(Content))
              Result=CallFunction(#ZLIBWAPI_LIB,"zipCloseFileInZip",Handle)
              Result=CallFunction(#ZLIBWAPI_LIB,"zipClose",Handle,0)
              CloseLibrary(#ZLIBWAPI_LIB)
            EndIf
          Else
            If OpenFile(3, ZipFile$)
              WriteStringN("This is a testfile used in the SAVEZIPFILEREQUESTER !!")
              CloseFile(3)
            EndIf      
          EndIf 
        Case #QuitButtonGadget 
          SendMessage_(WindowID(),#WM_CLOSE,0,0) 
      EndSelect  
    EndIf    
  Until EventID = #PB_Event_CloseWindow 
EndIf 

Posted: Thu Dec 09, 2004 3:29 pm
by PolyVector
very cool leo 8)

Posted: Thu Dec 09, 2004 7:48 pm
by Num3
Nice work!

I can't seem to pick zip files on the desktop folder, only on the folder the program runs!