View and Extract CAB File Contents Programmatically
Cabinet (.CAB) files are used to store one or
more files in a compressed format. They are similar to ZIP (.ZIP)
files with a slight twist. ZIP files contain one or more individually compressed files. Thus,
a ZIP file is much smaller than the original file(s). A CAB file can compress files across
file boundaries and can often achive a better compression ratio.
That's great but how do you work with CAB files? To create a CAB file you must use
the MakeCab.exe program that comes with VB. This program is
documented in MSDN (see my Microsoft Links page) and not discussed here. This page talks
about viewing and extracting the contents of a CAB file which you can do programmatically
with the SetupIterateCabinet API.
Download Source Code
The core logic in this sample is contained in a class module that you can easily
incorporate into your project. The SetupIterateCabinet
function iterates through all the files in a cabinet and sends a notification to a
callback function in your code for each file found.
Since callback procedures must reside in a standard module, this
program includes a .BAS module you will need to add to your project as well.
The class itself provides several useful methods, properties and events as show.
Name
|
Type
|
Description
|
CabName
|
Property
|
Name of the cabinet to process.
|
FileCount
|
Property
|
Number of files in the cabinet.
|
Extract
|
Method
|
Extracts and decompresses the file(s) from the cabinet. You specify
a file to extract. All files are extracted by default. You can indicate
the folder to extract to. The default is the same folder as the cab file.
When extracting a single file, you can specify the extract file name. The
default is the original file name.
|
GetInfo
|
Method
|
Gets the name size and date of each file in the cabinet.
|
GetXML
|
Method
|
Returns a well-formed XML string containing the name, size and date of
each file in the cabinet.
|
AfterExtract
|
Event
|
Raised, by the Extract method, after a file is extracted and passes as a paramter
the extracted file's name.
|
BeforeExtract
|
Event
|
Raised, by the Extract method, before a file is extracted and passes as paramters
the name of the file to extract and a flag that can be used to cancel the extraction.
|
FileFound
|
Event
|
Raised as a file is found within the cabinet by the GetInfo method.
|
Since the class module raises events back to the caller, the variable used
to reference an instance of the class must be declared using the
WithEvents keyword. This allows the class'
event procedures to be displayed in the procedure dropdown when the variable
is selected in the object dropdown in the code edit window.
To call the SetupIterateCabinet function you need to
specify four values: the path to your CAB file, a zero for the second, reserved parameter,
your callback function's address, and a context indicator value. This value
is used to tell the callback function what to do. SetupIterateCabinet returns a non-zero
value upon success. If it fails you can use Err.LastDLLError
to see why.
Callback functions must reside in a .BAS module. However, to make this class more
self contained, the callback function in the .BAS module, CabinetCallback,
simply calls a similarly named method in the class passing along all the parameters
populated by SetupIterateCabinet. The address of the .BAS module's CabinetCallback procedure
is passed into the API using the AddressOf keyword. However,
for the real callback function to find the callback method, the class must call a
procedure in the .BAS module and pass in a reference to the class.
The context indicator value passed into the API can be any integer value you like.
It is simply returned by SetupIterateCabinet to your callback procedure as a
parameter. Thus, your callback procedure will know why SetupIterateCabinet was called
to begin with and how it should proceed. In this program the allowable context values
are defined in the SetupIterateCabinetActions enumeration.
Your callback function must be defined with four arguments. The first is a long that
returns your context indicator value. The second is the notification
message returned by SetupIterateCabinet. Parameter three is a long that will hold the
address of a structure describing the file being extracted or the file found in the
cabinet. The type of this structure varies depending on the notification message. It can
be either of type FILEPATHS or
FILEINCABINETINFO. The last parameter also varies based
on the notification.
Notification
|
Description
|
SPFILENOTIFY_FILEEXTRACTED
|
A file was extracted from the cabinet. Param3 is a FILEPATHS structure with
info on the extracted file. The callback function must return NO_ERROR if you
want to keep procesesing or non-zero to stop.
|
SPFILENOTIFY_FILEINCABINET
|
A file was found in the cabinet. Param3 is a FILE_IN_CABINET_INFO structure
describing the current file. Return FILEOP_SKIP to skip the file or FILEOP_DOIT
to extract it.
|
SPFILENOTIFY_NEEDNEWCABINET
|
The file being extracted is continued in the next cabinet. This is not handled
in this program. You would need to prompt for the next file or diskette,... (see
MSDN for SetupPromptForDisk) Param3 is a CABINETINFO structure. The callback
function must return NO_ERROR if you want to keep procesesing or non-zero to stop.
|
Things get confusing with parameter 3 of the callback function pointing to
different types of structures depending on the notification. To simplify this,
the parameter is defined as a FileInCabinetInfo structure and passed by
reference. This is the type of structure returned most often by the
SetupIterateCabinet API in this program. Doing this lets VB take the bytes at
that address and show them to you as a FileInCabinetInfo user defined type.
In the cases where the notification message returns a different type of
structure, the VB LSet function is used to copy the
bytes in the FileInCabinetInfo structure to the appropriate structure.
The last parameter of the callback function is a long which often contains the address
of a string, such as the file name being processed. This address must be converted to
a real string for VB to work with it. A call to the
CopyMemory API achieves this.
Each method and property in the class performs the same four basic steps. They insure the
cabinet file's name is set, call SetCabFile in the .BAS module to set a reference
to the class module so the fake callback function can call the real
callback method, call the SetupIterateCabinet API with the appropriate parameters, and
finally, check the return value from the API.
Run the program and click the Browse button to navigate to the .Cab file
to view. Once a cabinet file is selected, use the mouse and Shift or Control keys
to highlight one or more files. Then click the Extract button. On the subsequent
dialog box, navigate to the folder to extract the file(s) to and press Extract.
Also, once you have selected a .cab file, you can press the XML List button
to display an XML string representing the contents of the cab file.
|