Pascal Newsletter #5
INDEX
1. A FEW WORDS FROM THE EDITOR
2. FREE PASCAL
3. DELPHI ZIP
a) Where to get it?
b) Installation
c) Trying the demo
d) How does it work?
1) Creating a new archive
2) Adding files to an archive
3) Adding files to an archive in multiple volumes
4) Deleting files from an archive
5) Extracting files from an archive
6) Testing an archive
7) Intercepting the messages
8) Listing the files stored in the archive
________________________________________________________________________
1. A FEW WORDS FROM THE EDITOR
Our new web site is now working... or at least it should be! ;)
http://www.latiumsoftware.com/en/
It's the same stuff, nothing new so far, but this month probably we will
start adding material more or less continuously if we can. We'll keep you
posted.
In the last issue we printed wwww instead of www in the address of our
site, so if you couldn't enter the site, now you know why! ;) Oops!
Thanks to Alejandro who pointed this out.
Regards,
Ernesto De Spirito
eds2008 @ latiumsoftware.com
________________________________________________________________________
JfControls Library. Multi-language. Multi-appearance. Skins. Privileges.
More than 40 integrated and customizable components. Impressive GUI.
Centralized resources administration. Multiple programming problems
solved. For Delphi 3-2006 & C++ Builder 3-6. http://www.jfactivesoft.com
________________________________________________________________________
2. FREE PASCAL
Version 1.00 of this pascal compiler was officially released last July,
and it is expected that little by little it will start being included in
many Linux distributions. It is available as RPM, .deb and .tar.gz
packages. But Free Pascal is not only for Linux, since it is also
available for DOS (requires the GO32 extender), 32-bit Windows, OS/2
(requires the EMX extender) and Amiga (Version 0.99.5).
If you wish to download it, go to http://www.freepascal.org/sdown.html
We suggest you choose a mirror, because the main site is usually very
slow.
________________________________________________________________________
3. DELPHI ZIP
This is a set of freeware Delphi components and a demo application (with
full source code included) that access ZIP files using the ZIPDLL and
UNZDLL DLLs of the Info-Zip Project. They work on all 32-bit versions of
Delphi (from 2 to 5).
a) Where to get it?
===================
It is available at:
BCB and Delphi Freeware Zip Components
http://www.geocities.com/SiliconValley/Orchard/8607/
http://members.tripod.lycos.nl/Vleghert/
I downloaded the following files:
* Delphi Zip 1.6L beta release (360K)
http://www.geocities.com/SiliconValley/Orchard/8607/beta/dz-del160.zip
http://members.tripod.lycos.nl/Vleghert/beta/dz-del160.zip
* TZipMaster 1.6L help file (81K)
http://www.geocities.com/SiliconValley/Orchard/8607/beta/zipmst16.zip
http://members.tripod.lycos.nl/Vleghert/beta/zipmst16.zip
The first archive has it all, except the help file of the TZipMaster
component, and the source code of the DLLs:
* ZipDll and UnZDll source files for BCB 3 or BCB 4 (241K)
http://www.geocities.com/SiliconValley/Orchard/8607/dz-dllsrc15.zip
I didn't download them because they are for C++ Builder. The DLLs are
included in the main archive (dz-del160.zip) and there are also
optimized versions available, like:
* Pentium DLLs. Compiled with BCB 4 optimized for Pentium (129K)
http://www.geocities.com/SiliconValley/Orchard/8607/pendll15.zip
b) Installation
===============
1) Unzip dz-del160.zip in a temporal directory and run dz-del160.exe to
install. It will prompt you for an installation directory. I chose
"C:\Delphi\Zip", but you con extract it anywhere you like it (just
substitute "C:\Delphi\Zip" with your path).
2) Copy or move these files to your Windows\System directory:
C:\Delphi\Zip\DLL\*.DLL and C:\Delphi\Zip\SFX\*.BIN
3) Now you should either copy or move "C:\Delphi\Zip\VCL\*.*" files to
a directory in the VCL path, or include "C:\Delphi\Zip\VCL" in your
VCL path (in Delphi 5 select Environment Options from the Tools
menu and add this directory to the Library Path and Browsing Path).
4) Install the VCL components. How? This is ABC! You should know how! :)
Ok, start Delphi 5. Select Close All from the File menu and select
Install Component from the Component menu. Click Browse to select
the unit files and select all *.pas files in the "C:\Delphi\Zip\VCL"
directory (or where you placed these files) and click Open and then
OK to compile. Finally close the package and save it when prompted.
If you have a previous version of Delphi, follow the instructions
provided in "C:\Delphi\Zip\Install.txt".
5) Install the help files. How? This is ABC! You should know how! :)
Ok, unzip zipmst16.zip and move the two files to your Delphi Help
directory (for example "C:\Program files\Borland\Delphi5\Help").
Edit delphi5.cnt and add these two lines with the others:
:Index ZipMaster Component Help=ZipMstr.hlp
:Include ZipMstr.cnt
Delete the files delphi5.GID, delphi5.FTS and delphi5.FTG.
This also works with Delphi 3 and 4 (just substitute the "5" above
with your version number). If you have Delphi 2 and want to integrate
the help file, you can build a .kwf file. The sources are available
for download:
* Help source files (98K)
http://www.geocities.com/SiliconValley/Orchard/8607/dz-hlpsrc15.zip
http://members.tripod.lycos.nl/Vleghert/
c) Trying the demo
==================
Open the project "C:\Delphi\Zip\Demo1\ZipDemo1.dpr" and try to compile
it. When I did it, I got the following error:
[Fatal Error] mainunit.pas(632): Internal error: C3517
This is a compiler error and I'm reporting it to Borland. I isolated the
problem and it apparently occurs when optimizations are on (the default)
and you explicitly cast an Int64 object property (not a constant or
variable) to Int64. It might not occur in your version/build of Delphi,
but if it does, there would be two solutions.
1) Turn off optimizations around the ZipMaster1Progress procedure:
{$OPTIMIZATION OFF}
procedure TMainform.ZipMaster1Progress(Sender: TObject...
...
end;
{$OPTIMIZATION ON}
2) Or (better) remove the unnecessary Int64 castings:
// Step := Integer(Int64(TotalProgress1) * Int64(10000)
// div Int64(TotalSize1));
Step := Integer(TotalProgress1 * 10000 div TotalSize1);
// Step := Integer(Int64(TotalProgress2) * Int64(10000)
// div Int64(TotalSize2));
Step := Integer(TotalProgress2 * 10000 div TotalSize2);
Now run the program and click the "Open Zip" button. Select a ZIP file
and click "Open". Now what? If you get an EConvertError exception, don't
worry: it's not a bug, it's a feature! ;) This time it's true, because
TSortGrid uses exceptions to determine the column data type to perform
the sort. So, just click OK and let the app keep running (press F9).
You'll have to do it three times. If you don't want to see these errors
in the future, go to Tools / Debugger Options / Language Exceptions and
unmark the checkbox "Stop on Delphi Exceptions" (in previous versions of
Delphi it was named "Break on Exceptions" or something like it, and it
was located somewhere else...).
d) How does it work?
====================
All the work is done by the DLLs, and the TZipMaster component provides
a nice programming interface to work with these DLLs, so we don't have
to call the APIs directly, relieving us from a lot of the details.
The demo application is quite complete and shows all the basic
functionality of the TZipMaster component. You can take a look at the
code and use the integrated help file to learn more about the use of
this component. To help you understand it better we decided to build an
alternative demo application, which will be very simple, thinking of
providing you a quick start on how to add minimal Zip management
capabilities to your application (for back-up purposes, for example),
rather than building a compression utility (like WinZip or Power
Archiver).
To begin, we select New Application from the File menu. Then we edit the
program file and we add a resource directive ($) to load the messages
(they are available in many languages):
program Project1;
uses
Forms,
Unit1 in 'Unit1.pas' {Form1};
{$R *.RES}
{$R ZipMsgUS.RES} // Load the English messages
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
Notice that this will only affect messages generated by the component,
not by the DLLs (which will be in English).
Now we add a TZipMaster component onto the form and we name it Zip to
give it a shorter name. Before we start the real work, we'll load the
DLLs in memory when the form is created, and we'll unload them when
the form is closed. It isn't necessary to do this because TZipMaster
handles this automatically, loading and unloading the libraries as
needed, but this can mean a performance penalty (it takes time), so
we decided to do it on our own:
procedure TForm1.FormCreate(Sender: TObject);
begin
Zip.Load_Zip_Dll;
Zip.Load_Unz_Dll;
end;
procedure TForm1.FormClose(Sender: TObject;
var Action: TCloseAction);
begin
Zip.Unload_Zip_Dll;
Zip.Unload_Unz_Dll;
end;
The libraries take some memory when they are loaded, so this is not
necessarily the best approach either, but it's better than loading and
downloading them every now and then. The problem now is that loading the
form would take more time, so perhaps the best approach could be loading
the DLLs the first time they are used and unloading them when you stop
using them (for example when the form closes), but we leave this up to
you. :-)
1) Creating a new archive
-------------------------
To show how to create a new Zip file we place a button on the form and
we name it CreateZip, and in its Click event we write:
procedure TForm1.CreateZipClick(Sender: TObject);
const
ZipArch: string = 'C:\Temp\Test.zip';
begin
if FileExists(ZipArch) then
if MessageDlg('"' + ZipArch + '" already exists. Overwrite?',
mtConfirmation, [mbYes, mbNo], 0) = mrYes then
DeleteFile(ZipArch)
else
exit;
Zip.ZipFilename := ZipArch;
if Zip.ZipFilename = '' then begin
ShowMessage('Could not create "' + ZipArch + '"!');
exit;
end;
Zip.AddOptions := [];
Zip.FSpecArgs.Add('Project*.*');
try
Zip.Add;
ShowMessage('Zip archive successfully created!');
except
ShowMessage('Add failed!');
end;
end;
First we asked if the archive already exists, and if so we ask for
confirmation to overwrite it. In the affirmative case we delete the
existing archive, so when we later add files to the archive, it will be
automatically created. The Add method is the one that does all the job,
but before we can invoke it we have to do some preparations:
a) Set the Zip file name in the ZipFilename property
b) Set the options to add the files (for example we can recurse
subdirectories, encrypt the files and other stuff).
c) Set the files that will be added in the FSpecArgs property (a
TStringList object).
2) Adding files to an archive
-----------------------------
We have just seen how to add files, but here goes another example.
First we place a new button on the form and we name it AddToZip, and in
its Click event we write:
procedure TForm1.AddToZipClick(Sender: TObject);
const
ZipArch: string = 'C:\Temp\Test.zip';
begin
Zip.ZipFilename := ZipArch;
if Zip.ZipFilename = '' then begin
ShowMessage('Could not open "' + ZipArch + '"!');
exit;
end;
Zip.AddOptions := [AddUpdate];
Zip.FSpecArgs.Add('*.d*');
Zip.FSpecArgs.Add('Unit1.pas');
try
Zip.Add;
ShowMessage('Files added!');
except
ShowMessage('Add failed!');
end;
end;
This example is similar to the previous one, except that we used the
AddUpdate option that tells the Add method that if the files we are
adding already exist in the archive, they shouldn't be replaced unless
they are newer, but files that don't exist in the archive will be added.
AddFreshen is like AddUpdate, but doesn't add new files to the archive.
The 'standard' Add (if no option is set) will add or replace files
unconditionally. AddMove is like the standard Add, but deletes the disk
files afterwards.
3) Adding files to an archive in multiple volumes
-------------------------------------------------
To span the archive (divide it in multiple parts named volumes), simply
include AddDiskSpan in the AddOptions property. To try the following
example, add a button named Span to the form and generate its Click
event:
procedure TForm1.SpanClick(Sender: TObject);
const
ZipArch: string = 'C:\Temp\SpanTest.zip';
begin
Zip.ZipFilename := ZipArch;
if Zip.ZipFilename = '' then begin
ShowMessage('Could not open "' + ZipArch + '"!');
exit;
end;
Zip.AddOptions := [AddDiskSpan];
Zip.KeepFreeOnDisk1 := 10000;
Zip.MaxVolumeSize := 100000;
Zip.FSpecArgs.Add('*.*');
try
Zip.Add;
ShowMessage('Files added!');
except
ShowMessage('Add failed!');
end;
end;
When spanning the archive in multiple disks, set MaxVolumeSize to 0 and
the size of the diskette will be detected automatically. Setting this
property to another value will force the parts of the archive (volumes)
to be no larger than the value you specify (in bytes). This is useful
when spanning the archive in the hard disk. Use KeepFreeOnDisk1 to set
the number of bytes to be left free in the first volume. In the above
example, the volume size is 100,000 bytes and we requested 10,000 bytes
free in the first volume, so the size of the first volume will not
exceed the 90,000 bytes.
4) Deleting files from an archive
---------------------------------
To delete a file or set of files from an archive we can use the Delete
method. To see an example, add a button named DeleteFromZip to the form
and generate its Click event:
procedure TForm1.DeleteFromZipClick(Sender: TObject);
const
ZipArch: string = 'C:\Temp\Test.zip';
begin
Zip.ZipFilename := ZipArch;
if Zip.ZipFilename = '' then begin
ShowMessage('Could not open "' + ZipArch + '"!');
exit;
end;
Zip.FSpecArgs.Add('*.c*');
Zip.FSpecArgsExcl.Add('*.cfg');
try
Zip.Delete;
ShowMessage('Files deleted!');
except
ShowMessage('Delete failed!');
end;
end;
In this example we introduced the FSpecArgsExcl property, a StringList
that contains the names of the files to exclude from the operation (in
this case Delete). In the above example, all files matching the pattern
*.c* but not *.cfg will be deleted from the archive.
5) Extracting files from an archive
-----------------------------------
This operation is performed by the Extract method. To see an example,
add a button named ExtractFromZip to the form and generate its Click
event:
procedure TForm1.ExtractFromZipClick(Sender: TObject);
const
ZipArch: string = 'C:\Temp\Test.zip';
var
CurrentDir: string;
begin
Zip.ZipFilename := ZipArch;
if Zip.ZipFilename = '' then begin
ShowMessage('Could not open "' + ZipArch + '"!');
exit;
end;
CurrentDir := GetCurrentDir;
ChDir(ExtractFilePath(ZipArch));
Zip.ExtrOptions := [ExtrOverWrite, ExtrUpdate];
try
Zip.Extract;
ShowMessage('Files extracted!');
except
ShowMessage('Extract failed!');
end;
ChDir(CurrentDir);
end;
The destination folder is the current working directory, so we should
change it (with the ChDir procedure) if we want it to be another one.
Previously we save the current directory so we can restore it later.
In the example, we used the folder where the Zip archive is located
('C:\Temp'). Since we didn't specify the files to process in FSpecArgs,
all files in the archive will be extracted.
You can specify some extracting options in the ExtrOptions property. The
default extract method will only extract files if they don't exist in
the disk. If you want to overwrite existing files, use the ExtrOverWrite
option (equivalent to the standard Add). You can combine it with
ExtrUpdate (equivalent to AddUpdate) or ExtrFreshen (equivalent to
AddFreshen). You can use the option ExtrDirNames to recreate the
relative pathnames stored in the archive (paths are stored using the
AddDirNames option with the Add method).
6) Testing an archive
---------------------
To test the integrity of a Zip archive we use the Extract method with
the ExtrTest option and then we check the value of the ErrCode property.
To see it working, add a button named TestZip to your form and generate
its Click event:
procedure TForm1.TestZipClick(Sender: TObject);
const
ZipArch: string = 'C:\Temp\Test.zip';
begin
Zip.ZipFilename := ZipArch;
if Zip.ZipFilename = '' then begin
ShowMessage('Could not open "' + ZipArch + '"!');
exit;
end;
Zip.ExtrOptions := [ExtrTest];
try
Zip.Extract;
if Zip.ErrCode = 0 then
ShowMessage('Test successful!')
else
ShowMessage('Error(s) found in Zip file');
except
ShowMessage('Test failed!');
end;
end;
7) Intercepting the messages
----------------------------
Add a Memo control to your form and generate the Message event of the
Zip component:
procedure TForm1.ZipMessage(Sender: TObject; ErrCode: Integer;
Message: String);
begin
if ErrCode = 0 then
Memo1.Lines.Add(Message)
else
Memo1.Lines.Add('Error #' + IntToStr(ErrCode) + ': ' + Message);
end;
The Memo will now show the messages sent by the DLL. Try the operations
we introduced above to see them.
8) Listing the files stored in the archive
------------------------------------------
The ZipContents property is a TList that holds pointers to ZipDirEntry
records that contain detailed information about the files stored in the
zip archive. To see an example, add a button named ListFiles to the form
and generate its Click event:
procedure TForm1.ListFilesClick(Sender: TObject);
const
ZipArch: string = 'C:\Temp\Test.zip';
var
i: integer;
f: ^ZipDirEntry;
begin
Zip.ZipFilename := ZipArch;
if Zip.ZipFilename = '' then begin
ShowMessage('Could not open "' + ZipArch + '"!');
exit;
end;
for i := 0 to Zip.Count - 1 do begin
f := Zip.ZipContents[i];
Memo1.Lines.Add(Format('%s %.1fK (%.0f%%)', [f.FileName,
f.UncompressedSize / 1024,
f.CompressedSize / f.UncompressedSize * 100]));
end;
end;
Well, this is as far as we go. The demo application that comes with
Delphi Zip is more complete and will show you many features of the
TZipMaster component (like encryption and Self-Extracting executables),
and you can learn more from the help file.
You can download the full source code of the examples presented in this
newslettter:
http://www.latiumsoftware.com/en/file.php?id=p05
In the next issue we'll use this component in our Find File application
to extend the search to zipped files. See you then.
________________________________________________________________________
YOU CAN HELP US
We need your help to keep this newsletter going and growing. You can
help by referring the newsletter to your colleagues:
http://www.latiumsoftware.com/en/pascal/delphi-newsletter.php
Or you can help by voting for us in some or all of these rankings to
give more visibility to our web site and thus increase the number of
subscriptions to this newsletter:
http://www.programmingpages.com/?r=latiumsoftwarecomenpascal
http://top100borland.com/in.php?who=20
It's just a few seconds for you that REALLY mean a lot to us.
________________________________________________________________________
If you haven't received the full source code examples for this issue,
you can get them from http://www.latiumsoftware.com/en/file.php?id=p05
________________________________________________________________________
This newsletter is provided "AS IS" without warranty of any kind. Its
use implies the acceptance of our licensing terms and disclaimer of
warranty you can read at http://www.latiumsoftware.com/en/legal.php
where you will also find a note about legal trademarks. Articles are
copyright of their respective authors and they are reproduced here with
their permission. You can redistribute this newsletter as long as you do
it in full (including copyright notices), without changes, and gratis.
________________________________________________________________________
Main page: http://www.latiumsoftware.com/en/pascal/delphi-newsletter.php
Group home page: http://groups.yahoo.com/group/pascal-newsletter/
Subscribe/join: pascal-newsletter-subscribe@yahoogroups.com
Unsubscribe/leave: pascal-newsletter-unsubscribe@yahoogroups.com
Problems with your subscription? eds2008 @ latiumsoftware.com
________________________________________________________________________
Latium Software http://www.latiumsoftware.com/en/index.php
Copyright (c) 2000 by Ernesto De Spirito. All rights reserved.
________________________________________________________________________
|