OpenFileRequester with ZIP integration
Posted: Thu Dec 09, 2004 2:27 pm
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 :
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