Add Zip Archiving Functions to your Alpha Five application

by Paul Verboom

Zipping and unzipping of files will be a feature of Alpha Five version 5, but Paul shows us that you don't have to wait for Alpha Software to implement features that you want. If you can find the utilities you need for sale as DLLs callable by C program, then you can call them through Xbasic. Paul can be reached at pverboom@ns.sympatico.ca

Introduction

This article shows how to add an archive feature to an ALPHA5 application using ZIP format files. This done through the use of a third party DLL (Dynamic Link Library). An additional topic covered is passing arrays to functions.

The uses of DLL’s within ALPHA5 is an advanced subject, but don’t let that scare you off. Although I have written some very elaborate software for ALPHA4 this is the first development work I have done for Windows. If a newbie can do it so can you.

If you’re interested in using DLL’s from within ALPHA5 I would recommend reading the following articles by Dr. Peter Wayne:

Although I will cover some of the things I learned along the way I won’t repeat the excellent information already in these articles.

Background

My application is used to summarize and report inspection results. Once these inspection results are reported they are seldom referenced again. Rather then having a database contain thousands of unused records we place the contents of the databases into an archive file and then clear the work databases. This is the approach used by the previous DOS version of this software and it has worked well.

For those that want to know, these inspections are done on Medical Gas systems used in hospitals. These systems provide Oxygen, Air and Vacuum to many of the patient rooms via plumbing and outlets mounted on the wall. As you may well imagine, piping 100% Oxygen through the walls and ceiling of a building could be dangerous. Many things that don’t burn in room air suddenly become torches when exposed to source of ignition and 100% O2. For these reasons many safety standards apply to these systems and that’s the purpose of these inspections: to ensure that the systems meet the safety standards thereby managing the risk.

The approach used by the DOS version of this package was to shell to DOS and run PKZIP to create the archive. I have also seen examples of launching a separate shell with ALPHA5. This approach, while workable, has several disadvantages:

  1. The PKZIP program, once launched, runs in a separate thread from your script. Your script must find some way to tell when the PKZIP has finished. You can test to see if the expected zip files appear, but if they don’t your script will, in effect, hang. You could use a timed pause but its length would depend on the system speed.
  2. You have no way to tell if the files you are going to compress even exist in the selected archive. The end user could select some shareware package to unzip and destroy your application in the process.
  3. Finally, it just doesn’t look professional to see a DOS box come up in a Windows application.

After reading the above listed articles by Dr. Peter Wayne I decided to use a DLL to provide the ZIP archive functions. I looked at three sources of DLL that provided ZIP functions. They are as follows:

  1. Info-ZIP DLL.

http://www.mirror.ac.uk/sites/ftp.freesoftware.com/pub/infozip/

Info-ZIP is a internet based group that provides a free ZIP libraries and source code. They also provide a DLL with ZIP archive functions. However, you get what you pay for. What little documentation that can be found for the ZIP DLL’s describes them as having rather convoluted calling structure and unlikely to work with non-mainstream programming environments. (I’m afraid ALPHA5 fits in this category.) You may need to search a bit to find information on Info-ZIP. Being a free product it tends to move from one server to an other. The link above worked when I authored this column.

http://www.innermedia.com/html/dynazip.htm

DynaZip is a commercial library used in many products. Unfortunately it carries a commercial price tag of least $249 US for the version that comes with DLL’s. I decided to keep looking for something more in my price range, and come to the following relatively new product.

http://www.bigspeedsoft.com/BSZipDll/BSZipDLL.html

BigSpeed ZIP DLL is the fastest and smallest ZIP library available. It is easy to interface to and has a reasonable price tag, $65. The only disadvantage of this product is it doesn’t support multi volume archives. That is, it won’t create a ZIP file across several floppies, at least as far as I could tell. If this is a concern for your application you may wish to contact the author of the product.

Using DLLs in ALPHA5

Using a function provided by a DLL in a script is much like calling a global function of your own making. The difference being this function is not within ALPHA5, therefore you must tell ALPHA5 everything about the function. Also ALPHA5 can’t shield you from yourself - if you get any of the details wrong ALPHA5 may crash. When ALPHA5 crashes you will need to reboot your system to release the user count consumed by the session that crashed.

The following paragraphs outline what information you must provide ALPHA5 to use a function within a DLL:

  1. Where is the function: what DLL file contains the function
  2. What parameter can be expected back from the function in the DLL.
  3. What parameters to pass to the function.

All 3 pieces of information are given in the DECLARE statement as shown in Table 1. The information shown in Table 1 is abbreviated to include only the information necessary for this project.

 

Table 1 ALPHA5 DECLARE Statement Documentation

Syntax:

DECLARE Library FunctionName Arguments

Description:

Declares an externally defined function (for example a windows API function).

The Library portion of the declaration indicates the name of the DLL in which the function is found.

Arguments is a list of types . The predefined types are all single character and are the following:

  • L = 32 bit long
  • I = 32 bit integer
  • W = 16 bit short
  • B = byte
  • N = IEEE 8 byte Double
  • F = IEEE 4 byte float
  • C = character (address of characters)

An external function can return a reference to data, but user defined data returned by reference by a function cannot be modified (it is treated as constant data).

The Library portion of the DECLARE statement can specify the complete path to the DLL. However this is not recommended, as the location of the files in your application can easily change between installations. Windows will look in the current directory and the \WINDOWS\SYSTEM directory for the DLL. It has been my experience that the current directory is not always the one with your application. Should the user have access to one of ALPHA5’s file selection dialogs the current directory can change to the directory selected. Therefore the only safe place I could find to place the DLL was the \WINDOWS\SYSTEM directory. This works fine and ALPHA5 can find the DLL every time.

It’s worth noting, if ALPHA5 can’t find a DLL referenced in a function, that function will fail to load. If the function won’t load any ALPHA5 script that calls the function reports a "Undefined Function Error". Although code for the function is there it won’t load, so as far as the calling script is concerned the function is not there. The moral of this story is:

If ALPHA5 can’t find the DLL you’re using the error reported may not clearly indicate the problem.

The Arguments passed to the function are a single string of characters from the list given in Table 1. What the help files fails to mention is the first character in the list is the data type returned by the function. For example, if the function returns an integer and requires a string the Arguments declared would be IC. Xbasic's calling structure here differs from the way user-defined functions are coded, in which the returned data type is clearly separated from the parameters passed to the function.

Also keep in mind that the data types used in the DECLARE (Table 1) command statement are different then the ones available internally in ALPHA5 (Table 2). For example ALPHA5 has a single numerical data type, "N", but the external function can expect one of several numerical data types. The data type used in the Argument list is determined by the DLL function. ALPHA5 will convert its data to the type specified in the DECLARE command when DLL function is called.

Table 2 Data Types in ALPHA5

Data Type

Character used in declarations

Numeric

N

Date

D

Character

C

Logical

L

Pointer

P

BLOB (Binary Large Object Block)

B

The documentation supplied with the DLL should indicate what data types are expected, but you may have to do some experimentation to get the data types correct. For example, the ZIP DLL documentation indicates a "bool" data type used in some of the functions. This data type -Boolean or bool for short - is also known as a logical type and indicates 0 or 1, for true or false. However the ALPHA5 documentation for the DECLARE statement does not list any Boolean or Logical data type. Because documentation that comes with ZIP DLL package is specific to the C programming language, I dug out my C programming textbook. I took a course once and that’s as far as I’ve delved into this language. Having said this I’m afraid there’s no escaping this C language stuff when you're programming a Windows based product.

As it turns out ANSI C doesn’t actually have a Boolean or Logical data type. The data passed is actually an integer value and the Boolean data type used in the function declarations is just some C trickery. The compiler actually sets up the functions to receive integer values the Boolean keyword is used to make the intent of parameter more clear. There is a lot of this trickery in the C language, it comes from the language being modified by so many sources and constantly being extended and expanding. The C language is just like the English language in that these exceptions and additions make it hard to learn.

The only additional bit of information I needed was, what Integer data type needed to be passed to the DLL. This was determined by trial and error, I would like to say I used more scientific methods but I didn’t. As it turned out, a 32 bit integer declared with ‘I’ worked fine.

I think that covers all the background information on using DLL’s. Next I will talk about the two functions written to create and extract from ZIP archives.

Writing functions to create and extract from ZIP archives.

In order to use the ZIP DLL functions I decided to write two general purpose ALPHA5 functions. These functions may be useful for other ALPHA5 applications as well. One function, ZipArchive, creates or replaces a ZIP Archive and the other, ZipRestore, restores files from ZIP Archive.

Both routines must be passed a list of files to extract or archive. This is best done with an array. Because ALPHA5 does not support passing arrays to functions, pointers must be used instead. The test program in Table 3 shows how this is done. The variable Array is of the type pointer. Then an Array is made off this pointer. Finally the pointer is passed to this function, not the Array itself. (Editor's note: for you language junkies, this is the same way arrays are passed in 'C' - by a pointer to the first element of the array.)

Because ALPHA5 is a multiuser database, the files that these functions are asked to access my be in use by other users or processes. For this reason these functions check that the required access is available to all files, before proceeding with any Archive operation.

Please note:

The ZIP DLL used in this project does not support multi-volume archives (a ZIP file that is split across multiple disks) therefore neither do these functions.

Table 3 Zip Restore Test Script

'Script to test ZipRestore Function
DIM Array AS P
DIM Array.File[5]
DIM Archieve AS C
DIM DestPath AS C
DIM Result AS N
Array.File[1] = "headdat.dbf"
Array.File[2] = "outdat.dbf"
Array.File[3] = "alarmdat.dbf"
Array.File[4] = "zonedat.dbf"
Array.File[5] = "sorcdat.dbf"
Archieve = "C:\medgasnw\abh93.mdg"
DestPath = "c:\temp2"+ CHR(92)
Result = ZipRestore (Archieve,DestPath,Array)
UI_MSG_BOX("ZipRestore Result",STR(Result))

 

ZipArchive Function

Creates ZIP file from predetermined list of files.

Parameters are as follows:

Archive - Archive file to create. If Null value is passed to the function, the user is presented with file select dialog. If file names given already exist user is warned that file will be replaced and given the chance to abort the routine. If path specified does not exist it will be created. Archives are always created in a temporary file and then renamed to the specified file once created. Existing Archives are deleted just prior to the temporary file being renamed.

SrcPath - Directory that contains the files to be put in the archive.

Array - Array of file names to be placed in the archive. Existence of these files and the ability to do an shared read open on these files is verified before the archive is created.

Return values:

0 - OK, everything worked
1 - User didn't enter a file name
2 - User chose not to replace existing archive
3 - Unable to get exclusive lock on existing archive
4 - source file does not exist
5 - unable to access source file.
6 - unable to get temporary file name to create archive in
7 - error creating archive file
8 - error adding file to archive contents list
9 - unable to create archive. We try to compress the file using all compression methods. If we get an error the MOST Likely cause is not enough free resources to compress the file(s). You don't have enough FREE Memory. This will usually happens if the files are VERY large or with a LARGE number of Very Large TEXT Files. So we try all four compression methods supported by the dll!
10 - Unable to rename final temporary file archive is created in. If the Archive file name to create already exists the function will create the newer archive under a temporary file name. Once the new Archive is successfully created the old archive is deleted and the new one is renamed to the file name given. This error indicates something has gone wrong with this process.

ZipRestore Function

Restores predetermined files from a ZIP archive using DLLs

Parameters are as follows:

Archive - Name of the ZIP archieve to extract files from. If null, user is presented with file selection dialog.

DestPath - Path to extract files too. If this path does not exist it will be created if possible.

Array - Pointer to array of files to be extracted from.

Archive. These files must be present in archive in order to proceed. If any of these file names exist in the Destination Path an exclusive open is attempted on them before file extraction begins. This is to ensure they can be replaced by the Unzipping operation.

Return values

0 - OK, everthing worked

1 - User didn't enter a file name

2 - Unable to open selected Archieve name

3 – Not a valid Zip file

4 - ZIP is missing one or more files

5 - Error unzipping file

6 - Unable to get exclusive access to an existing file that needs to be replaced

Demo program

fig1

Of course a picture is worth a thousand words, or in this case a Demo Program is worth a thousand words. Although I feel like I’ve written a million words, I’ve included a demo program. It’s not fancy, but it demonstrate the use of the ZipArchive and ZipRestore functions. Follow these steps to try out the DEMO:

The Version of the BigSpeed ZIP DLL included in this package is a DEMO version that pops up a notice to this effect each time it is run. The demo version is also limited to ZIP files less then 16 Meg in size. See the BigSpeed author’s WEB site for a full evaluation version including all documentation: http://www.bigspeedsoft.com/BSZipDll/BSZipDLL.html

If you incorporate this technique into any of your own programs you should obtained a licensed copy of the BigSpeed ZIP DLL and use your application's installer program to copy it to the \WINDOWS\SYSTEM directory.

7/8/00

Don't forget, we need your feedback to make this site better!

Return to home