Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

Cabinet File (*.CAB) Compression and Extraction

4.93/5 (217 votes)
23 Mar 2012CPOL38 min read 67   26.6K  
How to implement creation and extraction of Microsoft CAB files

Introduction

With this project, C++ and .NET programmers get a very versatile library for compression and extraction of Microsoft CAB files.

.NET 1.1 does not offer compression functionality. .NET 2.0 offers the System.IO.Compression.GZipStream class. But this is awkward to use and very primitive; it can only compress a stream but it is not possible to compress folders containing files and subfolders.

If you search the internet for more comfortable compression libraries, you find, for example, ICSharpCode.SharpZipLib.dll which offers ZIP compression. But this library is awkward to use and buggy, and so is unusable. Although the bugs have been known for years, the author has not fixed them.

I asked myself why should I search for another open source library (which will again have other bugs) while Windows itself supports CAB archives since the first days? Microsoft's Cabinet.dll (in the System32 directory) is not buggy. Many Microsoft installers (like the installer for Internet Explorer or Windows patches) use it. Additionally, CAB reaches a much better compression ratio than ZIP.

Features

  • This library is VERY easy to use.
  • This library is lightweight and VERY fast. (pure C++ code)
  • This library can be extended very easily.
  • One project is for C++ developers.
  • Another project is for .NET developers.
  • Both projects compile on Visual Studio 2005 and 2010
  • The .NET project runs on all platforms where the required .NET framework is installed
  • Both projects support multithreading
  • Optional Encryption / Decryption of CAB files.
  • CAB files can contain trees of subfolders and files.
  • File dates (in either UTC or local time) and file attributes are preserved when compressing / extracting
  • Extraction of CAB files which are embedded in the resources of your Win32 project or .NET project.
  • In .NET you can additionally extract CAB files from a stream.
  • The compression can split large CAB files into multiple pieces. (Pack1.cab, Pack2.cab, Pack3.cab etc)
  • An event handler allows to display the compression / extraction progress in the GUI of your application.
  • A lot of event handlers are called during compression and extraction which allows to interact with the progress (for example filtering specific files)
  • Both projects come with a demo application which shows how to compress and extract files and embedded CAB resources. Encryption and Decryption is also included in the demo.
  • This project makes use of Microsoft's Cabinet.dll in your System(32) directory, which is part of the operating system since Windows NT/98.
  • Cabinet.dll will be loaded only when it is needed and unloaded afterwards. You can also link statically and the external DLL is not required.
  • In the download you find Release versions of CabLib.dll for VS 2003,2005,2008 x32 and x64.
  • The C++ and the .NET project support Unicode in paths and filenames (e.g. Japanese) independent if compiled as MBCS or UNICODE.
  • The .NET library is strong named, it can be installed into the GAC with gacutil.exe.

Version History

  • Since version Jan 2007 Msvcp70/71/80.DLL is not required anymore.
  • Since version Apr 2008
    • you can extract CAB files directly from a server, (URL extraction from HTTP(S) / FTP)
    • you can even extract only specific files out of a CAB on a server without downloading the entire CAB file, (partial download)
    • you can also abuse this library to only download a file (MP3, AVI,..) from the internet to disk without CAB extraction.
  • Since version May 2008 the .NET library also extracts files with the extensions .URL or .LNK.
  • Since version Jun 2008 the encryption/decryption of CAB files uses the Blowfish algorithm. (see below)
  • Since version Aug 2008 the creation of CAB archives without compression is supported.
  • Since version Sep 2008 you can extract directly to memory. Additionally UTF7 was replaced with UTF8.
  • Since version Oct 2008 both projects can be compiled as 32 Bit or 64 Bit version.
  • Since version Jan 2009 you can turn off UTF8 encoding. (See below!)
  • Since version Feb 2009 you can link Cabinet.dll statically. (See Defines.h)
  • Since version Mar 2009 CabLib.dll is strong named.
  • Since version Aug 2009 both projects support multithreading.
  • Since version Dec 2009
    • a new callback shows the progress when extracting huge files,
    • splitted CAB files may be embedded as resources,
    • a bugfix allows to skip files when extracting splitted CAB's,
    • another bugfix corrects the default compression Temp directory,
    • Solution and Release DLL for Visual Studio 2008 added
  • Since version Feb 2010 a bug has been fixed concerning the extraction of some splitted CAB files, LZX compression added.
  • Since version March 2010 several error messages have been added when the library is used in a wrong way. Support for extraction of non-standard-conform CAB files.

  • Since version Mrz 2012 a bug has been fixed concerning URL extraction from a HTTPS server.
  • Since version Jan 2016 the project compiles on Visual Studio 14 and higher. (Microsoft has removed the option /clr:oldsyntax)

You can download my Universal Installer (incl sourcecode) which uses the CabLib Library for software setups and updates.
This application demonstrates all the available CabLib features like URL extraction, extraction to memory, how to display the progress in a progressbar, etc..

Dependencies

Cabinet / CabLib Project Dependencies Framework C++ Redistributable
Cabinet C++ Project - 32 Bit
VS 6, 2002, 2003, 2005, 2010
none none none
Cabinet C++ Project - 64 Bit
VS 2005, 2010
none none none
CabLib .NET Project - 32 Bit
VS 2005
MsVcr80.DLL, MsVcm80.DLL (x32) 2.0 2005 x86 Download
CabLib .NET Project - 64 Bit
VS 2005
MsVcr80.DLL, MsVcm80.DLL (Amd64) 2.0 2005 x64 Download
CabLib .NET Project - 32 Bit
VS 2010
MsVcr100.DLL (x32) 4.X 2010 x86 Download
CabLib .NET Project - 64 Bit
VS 2010
MsVcr100.DLL (Amd64) 4.X 2010 x64 Download

Microsoft removed a VS 2003 feature which is no longer available since VS 2005:
The compiler switch /MT does not work anymore for Managed C++ projects. (Error D8016)
On VS 2003 this switch links the C++ funcions (fopen, fread, flose etc.) statically into CabLib.dll.
On VS 2005/2008 this is no longer possible, so the external DLLs MSVCR80/90.DLL and MSVCM80/90.DLL are additionally required.

ATTENTION:
If these DLL's are not installed on the target machine the user will NOT get an intelligent error message telling him what is wrong. Instead Microsoft .NET throws the most stupid exceptions like: "CabLib.dll or one of its dependencies could not be loaded" or "System.IO.FileLoadException:....This application has failed to start because the application configuration is incorrect. Reinstalling the application may fix this problem". The users of your application will never suspect that the cause is a missing MsVcr80/90.dll!

Since VS 2005 a manifest file (XML) is automatically generated and compiled into CabLib.dll (RT_MANIFEST) telling on which DLL's it depends. You can see this manifest when you open CabLib.DLL with ResourceHacker.

There are 2 ways to assure that the MsVcr/MsVcm DLLs exist on the target computer:

  1. The users of your application must download and install the correct version of the Visual C++ Redistributable Package (see download links in table above). The files will be installed "side by side" as shared assemblies into C:\Windows\WinSxS\Cryptic Folder.
  2. Or you install the following files directly into the application folder as private assemblies: Microsoft.VC80.CRT.manifest, msvcr80.dll, msvcm80.dll. You find these files in your Visual Studio folder under VC\Redist. The versions of these DLLs must be EXACTLY the same as those in the manifest compiled into CabLib.dll. You can read the following articles in the MSDN: Private Assemblies and Assembly Searching Sequence but probably you will get quite confused. You find a better article on tydbits.

Limitations

  • The maximum size for files that Cabinet.dll can compress is 2 GB.
  • The maximum size of one CAB file is also 2 GB. But you can create splitted CAB files of unlimited size. (Part1.cab, Part2.cab, see below)
  • This project cannot compress or extract InstallShield CAB files. (see below)
  • You cannot add files to or delete files from an existing CAB archive.
  • For Windows 95/98/ME Microsoft's "Layer for Unicode" must be installed.

Source Code

You will find a very clean source code with a tidy error handling and plenty comments written by a very experienced programmer.

You get a high quality library and you will save several weeks of coding time. The code is reusable, you can reuse for example the Internet class for downloads from FTP / HTTP(S) or the Blowfish class.

You can study LibExtract.h to see how managed callbacks can be passed to unmanaged C++ code (which is not easy and requires gcroot or GCHandle)
All code is written in Plain C++ / Manged C++ and does not use MFC to avoid problems with missing DLLs on the computers where your application will run.

Different CAB File Formats

There are two completely different types of CAB files: The ones which this project supports are the "Microsoft CAB" files (also called "MS-CAB"). The internal pack format may be Microsoft's MSZIP or LZX. Some years later, InstallShield created the "InstallShield CAB" files. But these are absolutely incompatible with the MS-CAB files although they use the same file extension!

If you open a MS-CAB file with a hex editor, you will notice that the first four bytes are "MSCF" (MicroSoft Cab File), while the first three bytes of an InstallShield-CAB file are "ISc". (InstallShield Cab). You cannot open or create InstallShield CAB files with this project. There exist only very few tools which are capable of managing InstallShield CAB files; for example, the tool WinPack which you can download from my homepage.

Compression Ratio

MS-CAB files have a very good compression ratio, especially if you use the LZX compression algorithm. To test this I packed a bunch of about hundred text files. This is the result of my test:

Pack Format Packed File Size
CAB (LZX) 125 kB
CAB (MSZIP) 139 kB
TAR + GZ 142 kB
ARJ 174 kB
TAR + LZH 189 kB
RAR 197 kB
TAR + JAR 242 kB
ZIP 242 kB

MSZIP versus LZX

You can choose between two compression algorithms:

Feature MSZIP LZX
Speed faster slower
Compression ratio lower higher
Compresses files separately yes no
Partial URL Extraction possible yes no

MSZIP compresses each file one by one and then stores the compressed data into the CAB file.
LZX works completely different: It first creates a Huffman Tree from all files and then stores the entire tree into the CAB file.
The consequence is notable when you compress the same file multiple times:
Compressing 3 identical (or nearly identical) files with MSZIP results in 300% of the CAB size compared to compressing one file.
Compressing 3 identical (or nearly identical) files with LZX results in approx 110% of the CAB size.

Intelligent Installers

Microsoft's intention of CAB files was to use them for installations:

  • They are used in the Internet Explorer 6 Setup.
  • You see plenty CAB files on the Windows 95/98/ME setup CD.
  • All files ending with an underscore like "Kernel32.dl_" on your Windows 2000/XP setup CD are CAB files with the wrong file extension.

Many installers are stupid. If you start an unintelligent installer (like the one of Nero 6) you will see that it first extracts ALL files from the packed EXE installer into a temp directory.

  1. This is slow and the user has to wait until the first dialog will open.
  2. It is wasting diskspace and if the user's drive space on C: is low he will get an error of "no disk space".
  3. It carries the risk that temporary files remain on the disk when aborting the installation.

In contrary with this Cabinet library you can build an Intelligent Installer:

Scenario 1. You Deliver only Two Files to your Clients: A Tiny EXE File and a Huge CAB File

Put a huge CAB file on a local server or CD or DVD and let the user only start a tiny EXE setup file. The installer will start immediately and extract only the files from the CAB file which are really needed. This cabinet library obviously can extract the whole CAB file. But it is also possible to extract only specific files directly from the CAB file on server/CD/DVD to harddisk. The data transfer is compressed and — if you like — encrypted.

Scenario 2. You Deliver only one Huge EXE File to Your Clients

You can also embed the CAB file into the Setup.exe and directly extract specific files from the embedded resource without creating temporary files. Because Windows accesses the embedded resources via Filemapping directly from disk rather than loading them into memory there is no problem with memory usage even for huge embedded CAB files.

Scenario 3. You Deliver only a tiny EXE and an URL to your Clients

If you chose URL extraction you deliver only a tiny EXE file which downloads the CAB file from the internet. (FTP or HTTP(S))

If you use this for updates you can even configure the Cabinet library to download only the files from the CAB archive which require an update. Example: Your company sells an ASP server which consists of 500 files. You put a CAB file of 100 Megabyte on your Update server which contains all files. Let's say the client wants to update to the latest version and needs to replace only 15 files of 500 files. The Cabinet library downloads only 2 Megabyte instead of 100 Megabyte from your server! The data transfer is compressed and optionally encrypted.

If you need an installer/updater, download my project "An Intelligent .NET Multilanguage Installer

The C++ Project

To add CAB support to your C++ project download the project Cabinet at the top of this page (a demo application is included) and copy the entire subfolder "Cabinet" to your project.
Additionally you must add Static.cpp manually to the Solution Explorer, then right click it and under Settings -> Precompiled Headers you must select "Not using precompiled headers" otherwise you get C1010: unexpected end of file while looking for precompiled header directive

Image 1

The .NET Project

The second project is for .NET developers. I wrote a wrapper in Managed C++ around this C++ project. The result compiles into a .NET DLL. You simply add the .NET assembly CabLib.dll to the references of your .NET project (C# or Visual Basic .NET or Managed C++) and you get CAB support. In the second download at the top of this page you will find CabLib.DLL already compiled and ready to use. (A demo application is included)

Image 2

Cabinet.dll

Microsoft's tiny Cabinet.dll which is located in your System(32) directory since Windows NT/98 offers the following Compression API:

FciCreate FciAddFile FciFlushCabinet FciFlushFolder FciDestroy

 

 

And the Extraction API:

FdiCreate FdiIsCabinet FdiCopy FdiDestroy

 

 

You get a detailed description of these functions in the file Microsoft Cabinet.dll Doku.doc which you find in both projects and the files FCI.H and FDI.H contain plenty comments.

You can eliminate the external dependency to Cabinet.dll by setting in the file Defines.h:

#define STATIC_LINK_CABINET_DLL TRUE

The API in Cabinet.Dll uses a bunch of Callbacks which are called while a CAB file is created or extracted. The C++ project wraps these callbacks and you can override each of the callback functions to modify the behaviour.

The .NET project offers events which you can use to handle these callbacks in your .NET application.

You can use these callbacks / events to filter specific files or you can read compression data from a stream or from memory instead of a file on disk. This makes the library extremely versatile. (examples see below)

Compression

File Compression

The following sample compresses into a file C:\Temp\Packed.cab.
The file C:\Windows\Explorer.exe will be packed into a subfolder FileManager in the CAB file.
The file C:\Windows\Notepad.exe will be packed into a subfolder TextManager in the CAB file.

  Image 3

C++

C++
Cabinet::CCompress i_Compress;
if (!i_Compress.CreateFCIContextW(L"C:\\Temp\\Packed.cab"))
    { Error handling... }
 
if (!i_Compress.AddFileW(L"C:\\Windows\\Explorer.exe", L"FileManager\\Explorer.exe", E_ComprMSZIP, 0))
    { Error handling... }
 
 
if (!i_Compress.AddFileW(L"C:\\Windows\\Notepad.exe",  L"TextManager\\Notepad.exe", E_ComprMSZIP, 0))
    { Error handling... }
 
if (!i_Compress.DestroyFCIContext())
    { Error handling... }

With AddFile("...", "...", E_ComprNONE, 0) you can turn off compression. The specified file will be stored uncompressed into the cabinet. This may be required for installations on Pocket PC.

C#

C#
ArrayList i_Files = new ArrayList();
i_Files.Add(new string[] { @"C:\Windows\Explorer.exe", @"FileManager\Explorer.exe" });
i_Files.Add(new string[] { @"C:\Windows\Notepad.exe",  @"TextManager\Notepad.exe"  });
 
CabLib.Compress i_Compress = new CabLib.Compress();
i_Compress.CompressFileList(i_Files, @"C:\Temp\Packed.cab", true, true, 0);

VisualBasic .NET

VB
Dim i_Files As ArrayList = New ArrayList
i_Files.Add(New String() { "C:\Windows\Explorer.exe", "FileManager\Explorer.exe" })
i_Files.Add(New String() { "C:\Windows\Notepad.exe",  "TextManager\Notepad.exe"  })
 
Dim i_Compress As CabLib.Compress = New CabLib.Compress
i_Compress.CompressFileList(i_Files, "C:\Temp\Packed.cab", True, True, 0)

Folder Compression

You can also easily compress all HTM files in the folder "C:\Web" and all its subfolders into a CAB file which will reflect the folder structure as it is on harddisk:

C#

C#
CabLib.Compress i_Compress = new CabLib.Compress();
i_Compress.SwitchCompression(eCompress.LZX);
i_Compress.CompressFolder(@"C:\Web", @"C:\Temp\Packed.cab", "*.htm", true, true, 0);

C++

C++
Cabinet::CCompress i_Compress;
if (!i_Compress.CreateFCIContextW(L"C:\\Temp\\Packed.cab"))
    { Error handling... }
 
if (!i_Compress.AddFolderW(L"C:\\Web", L"*.htm", E_ComprLZX))
    { Error handling... }
 
if (!i_Compress.DestroyFCIContext())
    { Error handling... }

Compression Splitting

If you want to deliver your data on a medium with limited size or for download on a webpage you can split the CAB file into pieces which the extraction functions will automatically put together afterwards.

The following sample will create CAB files of 200 KB.
In this case the file name !MUST! contain a %d at the end!
The minimum allowed split size is 20 KB. The maximum is 2 GB.

Image 4

C++

C++
Cabinet::CCompress i_Compress;
if (!i_Compress.CreateFCIContextW(L"C:\\Temp\\Packed_%d.cab", TRUE, TRUE, 200000))
    { Error handling... }
 
etc..

C#

C#
i_Compress.CompressFileList(i_Files, @"C:\Temp\Packed_%d.cab", true, true, 200000);
or
i_Compress.CompressFolder(@"C:\Web", @"C:\Temp\Packed_%d.cab", "*.htm", true, true, 200000);

Setting the Compression TEMP Directory

During compression Cabinet.DLL will create some temporary files which will be automatically deleted afterwards.

By default it uses the TEMP directory which Windows specifies. If you want to compress huge files and the space on drive C: is low you should specify a TEMP directory on another drive. It is possible to use the same directory as output folder for the CAB file and as TEMP directory.

C++ and C#

i_Compress.SetTempDirectory("E:\\Temp");

Encryption

You can encrypt the CAB file with a key. The C++ code encrypts/decrypts the CAB data "on the fly" in blocks of 8 Bytes using the Blowfish algorithm. Blowfish is a very fast, symmetrical, license-free algorithm.

As encryption key you can use any binary data up to 72 Byte length. If the key is longer than 72 Bytes the remaining bytes will be ignored. If the key is shorter than 72 Bytes, some bytes are reused.

It is possible but not recommended to use a plain text password directly for the Blowfish encryption. (see: KDF) Instead you should derive a binary hash from the plain text password.

The .NET code does this with a SHA 512 hash which always has a length of 64 Bytes.

In the .NET project you can set a plain text password (string) of any length, of which first a 64 Byte SHA hash is derived and then this hash is used as key for the Blowfish encryption of the CAB data.

You can also directly set your own binary data as key for Blowfish.

C#

C#
i_Compress.SetEncryptionKey(String);   // SHA 512 + Blowfish

or

C#
i_Compress.SetEncryptionKey(Byte[72]); // only Blowfish

C++

C++
i_Compress.SetEncryptionKey(void* p_Key, DWORD u32_KeyLength); // only Blowfish

More Compression Functions

Normally you will not need the following C++ functions:

With i_Compress.SwitchCompression(eCompress) you can turn off compression, then all following files will be stored uncompressed into the cabinet. This may be required for installations on Pocket PC. Or you can chose between the LZX and MSZIP algorithm.

With i_Compress.AbortOperation() you can abort a lengthy compression. Obviously this must be called from another thread.

With i_Compress.FlushFolder() you can force that the current folder is finished.

With i_Compress.FlushCabinet() you force that the current CAB file is closed and any further files to be added will be written to the next CAB file in the split sequence.

For further details see the file Microsoft Cabinet.dll Doku.doc and the numerous comments in the file FCI.H

With CabLib.Compress.EnumFiles() (C# only) you can create an ArrayList of the files of interest. You can call this function once for each file extension you want to compress and then pass the ArrayList to CompressFileList().

With CabLib.Compress.Sprintf() (C# only) you can format a .NET string using the good old swprintf functionality which is not yet available in C#. The command allows a format string like "File_%02d.cab" and a variable unlimited amount of parameters of any type.

Compression Callbacks / Events

CCompress.OnFilePlaced() (C++ Callback)
CabLib.Compress.evFilePlaced (.NET event)
This is called whenever the compression has successfully placed a file into the cabinet.

CCompress.OnUpdateStatus() (C++ Callback)
CabLib.Compress.evUpdateStatus (.NET event)

This can be used to update your GUI to display the progress during a lengthy compression.

ATTENTION

It is recommended to start compression from another thread to avoid a dead GUI and to be able to call AbortOperation() and show the progress.

In C# you must call Control.BeginInvoke() in the event handler routine to asynchronously access GUI elements otherwise you will run into trouble!

For details see the file Microsoft Cabinet.dll Doku.doc and the plenty comments in the file FCI.H

Extensions / Modifications

If you want a different behaviour for compression, do NOT modify the existing compression class CCompress. Instead derive a new class from CCompress and override the functions you want to change.

Unicode

Unicode filenames are compressed in the CAB archive using UTF8 encoding.

When extracting the CAB file the original Unicode filename is restored. This has the advantage over MBCS (MultiByte) that the encoding is independent of any codepage which avoids a lot of problems.

If your application is run on Windows 95/98/ME Microsoft's Layer for Unicode must be installed.

To use the Unicode functionality it is NOT required to compile the C++ project with the UNICODE compiler switch (#ifdef UNICODE). Although compiled as MBCS it will work correctly because the code uses explicitly the Wide versions of the functions like CreateFileW().

UTF8 is the standard encoding for CAB filenames. You can open a CAB file with Unicode filenames for example in Windows Explorer:

Image 5

If CAB files don't open in Windows Explorer, execute the file "Open_CAB_with_Explorer.reg" which you find in the ZIP file!

ATTENTION:
Not all Programs show the UTF8 Filenames in CAB files correctly. In Windows Explorer and in WinZip they appear correctly. But Unicode filenames appear crippled in: WinRar 3.80 and WinAce 2.69 and TotalCommander 7.0. These programs don't have UTF8 support. Write to their support and ask them to add this!

Disabling UTF8 Encoding

Disabling UTF8 encoding is a workaround if you know that your users will use an unpacker which does not support UTF8 filenames (e.g. WinRar). In this case it becomes possible to use characters like áéíóúñöäüß in filenames which are normally UTF8 encoded but appear crippled in WinRar, WinAce, etc.

No matter if you disable UTF8 encoding or not: The filenames will ALWAYS be restored correctly when extracting the CAB file because an invisible flag is set in the CAB file which denotes whether the filename is UTF8 encoded or not.

CABCompressExtract/UnicodeTable.gif

UTF8 encoding can be disabled during compression:

 

C++
i_Compress.CompressFileList(i_Files, s_CabFile, true, false);

If you want to compress the file Test.exe with a Russian/Greek/Chinese filename into the CAB file you will ALWAYS need UTF8 encoding.

The following will throw an exception if you have disabled UTF8 encoding:

 

C++
i_Files.Add(new string[] { "C:\\Test\\Test.exe",
                           "\u0416\u0435\u043B\u0435\u0437\u043D\u043E.exe" });

On the other hand even with UTF8 encoding disabled you will still be able to compress Unicode files on disk into a CAB file if you store them under an ANSI name:

C++
i_Files.Add(new string[] { "C:\\Test\\\u0416\u0435\u043B\u0435\u0437\u043D\u043E.exe",
                           "Test.exe" });

You should ONLY disable UTF8 encoding if all the following conditions apply:

  1. You know that your users will use an unpacker which does not support UTF8 filenames (e.g. WinRar)
  2. You have written an email to the support of the unpacker software begging to add UTF8 support, so in the future you can remove this workaround.
  3. You are absolutely sure that all filenames you want to store in the CAB file don't use characters above ASCII Code 0xFF.

UTC Time

With the parameter b_UtcTime in CreateFCIContext() you can decide if during compression the CAB archive will store file times as UTC time or local time. On extraction the library uses automatically the correct time because an invisible flag is set in the CAB file which denotes whether the time is UTC or not.

The Windows file system stores all file times always as UTC time! The file times you see in Explorer depend on your timezone and daylight saving. (Open a folder in Explorer, remember the file times, change your timezone in Control Panel and you will see that all files on your disk show another time now!!)

b_UtcTime = false:

  • Compression: Read the UTC file times from harddisk, convert them to local time and store these in the CAB file.
  • Extraction: Read local times from the CAB file, convert them to UTC time and store these on harddisk.

b_UtcTime = true:

  • Compression: Read the UTC file times from harddisk and store these unchanged in the CAB file.
  • Extraction: Read UTC times from the CAB file and store these unchanged on harddisk.

It is recommended to compress using UTC time so after changing the PC's timezone or after daylight saving has changed the files in the CAB archive and on disk will still have the same time.

On the other hand if you compress/extract using local time a CAB file extracted in winter has a time shift of one hour compared with a CAB file extracted in summer.

Multithreading

Both, the C++ and the .NET project support multithreading for compression and extraction.
The Microsoft Cabinet.dll documentation says:
"FCI and FDI support multiple simultaneous contexts, so it is possible to create or extract multiple cabinets simultaneously within the same application. If the application is multi-threaded, it is also possible to run a different context in each thread; however, it is not permitted for the application to use the same context simultaneously in multiple threads (e.g. one cannot call FCIAddFile from two different threads, using the same FCI context)."

So you must never access one class instance from two threads. (except AbortOperation())
This means if you want to compress or extract multiple CAB files from multiple threads at the same time every thread must use it's own instance of CExtract/CCompress.

In C++ there is an additional caveat:
Before using a new instance of CExtract/Resource/Url in the same thread previous instances must either execute their destructor or you must call CleanUp() manually.

C++

Cabinet::CExtract i_Extract;
  ...work with i_Extract
  i_Extract.CleanUp();
  
  Cabinet::CExtractResource i_ExtractRes;
  ...work with i_ExtractRes
  i_ExtractRes.CleanUp();

File Extraction

During extraction there will be NO temporary files created.

The following sample extracts a file C:\Temp\Packed.cab into the folder E:\ExtractFolder. The required subfolders will be created automatically if the CAB file contains subfolders.

C++

C++
Cabinet::CExtract i_Extract;
if (!i_Extract.CreateFDIContext()) 
    { Error Handling ... }
if (!i_Extract.ExtractFileW(L"C:\\Temp\\Packed.cab", L"E:\\ExtractFolder"))
    { Error Handling ... }

C#

C#
CabLib.Extract i_Extract = new CabLib.Extract();
i_Extract.ExtractFile(@"C:\Temp\Packed.cab", @"E:\ExtractFolder");

The .NET library automatically detects files with the extension .LNK and resolves the shortcut (to the CAB file) inside and files with the extension .URL are redirected to URL extraction.

Win32 Resource Extraction

The following sample extracts a Cabinet file which is stored in the Win32 resources of a DLL or EXE file. You can extract files DIRECTLY from a CAB file in memory!

There are some rules to respect when you add a CAB file to the resources of your project:

In the file Cabinet.rc of the C++ project and in CabLib.rc of the .NET project you find this line:

C++
ID_CAB_TEST             CABFILE                 "Res\\Test.cab"

and in the file Resource.h you find this line:

C++
#define ID_CAB_TEST                     101

IMPORTANT:
If you define ID_CAB_TEST in Resource.h, the resource will be stored under:
ResourceName = 101         (integer)
ResourceType = "CABFILE" (string)

If you do NOT define ID_CAB_TEST in Resource.h, the resource will be stored under:
ResourceName = "ID_CAB_TEST" (string)
ResourceType = "CABFILE"         (string)

  Image 7

If you replace "CABFILE" in CabLib.rc with one of the predefined values
like for example "RCDATA" the following applies:

If you define ID_CAB_TEST in Resource.h, the resource will be stored under:
ResourceName = 101   (integer)
ResourceType =   10   (integer value of RT_RCDATA, see WinUser.h)

If you do NOT define ID_CAB_TEST in Resource.h, the resource will be stored under:
ResourceName = "ID_CAB_TEST" (string)
ResourceType =  10                 (integer value of RT_RCDATA, see WinUser.h)

  Image 8

To extract the embedded resource Test.cab (which I added to both projects) write:

C++

C++
Cabinet::CExtractResource i_Extract;
if (!i_Extract.CreateFDIContext()) 
    { Error Handling ... }

if (!i_Extract.ExtractResourceW(L"Cabinet.exe", ID_CAB_TEST, L"CABFILE",
                                L"C:\\ExtractFolder"))
    { Error Handling ... }

C#

C#
CabLib.Extract i_Extract = new CabLib.Extract();
i_Extract.ExtractResource("CabLib.dll", 101, "CABFILE", @"C:\ExtractFolder");

The first parameter specifies the filename (without path) from which to extract the Win32 CAB resource. You can set this = 0 (null) if the resource is inside the EXE which has created the process.

It is possible to embed splitted CAB files.
They may be compiled as resources with string names like "Part_01.cab", "Part_02.cab", "Part_03.cab" or with consecutive ID's like 101, 102, 103.
ATTENTION: If you use strings, the resource names MUST be identical to the filenames that you have compressed!

You can use this functionality to extract a CAB file from ANY DLL currently loaded into the process or from the application EXE itself.
To explore the resources of files which are already compiled download the tool ResourceHacker.

Most of the Windows Update patches contain a CAB file inside.

.NET Resource Extraction / Stream Extraction

.NET stores resources in a completely different way so you cannot see them in the tool ResourceHacker.
Under the resource's properties you must set the Build Action = "Embedded Resource".

To extract a file Test.cab which is located in a project named MyProject in a subfolder named Resources write:

Image 9

C#

C#
System.Reflection.Assembly i_Ass  = System.Reflection.Assembly.GetExecutingAssembly();
System.IO.Stream i_Strm = i_Ass.GetManifestResourceStream("MyProject.Resources.Test.cab");
 
CabLib.Extract i_Extract = new CabLib.Extract();
i_Extract.ExtractStream(i_Strm, @"E:\ExtractFolder");

URL Extraction

Let's say you want to build an updater which updates your software package to the latest version on the client's computers. If your software package consists of 500 files, of which only 15 files have changed in the latest version you could deliver an update patch which contains these 15 files.

A more intelligent solution is to build an updater which extracts only the files which require an update from a huge CAB archive on your update server. This CAB archive contains the latest version of your entire software package and no matter which version is currently installed on your client's computer, the updater will only download the files which are out of date:

Image 10

The data transfered will be compressed data and optionally encrypted data. (see CAB encryption)

Obviously you will have to pack a filelist with the MD5's of all files into the CAB archive so that the updater knows in advance which files he has to download and which files are up to date.

A complete installer project using this type of URL extraction (and more) can be found here: "An Intelligent .NET Multilanguage Installer"

Approximately the first 1% of the archive is an index which contains the filenames and pointers into the compressed data.

The Cabinet library reads this index and for each file it calls the callback function OnBeforeCopyFile. (see below)

If you return FALSE in this callback the file will neither be downloaded nor extracted.

To be able to download a file only partially from the server you have two options:

  1. A FTP server which permits resuming broken downloads (the server must support the FTP command "REST" (Restart))
    URL: ftp://user:password@ftp.server.com:Port/Updates/Setup_1.35.cab
  2. A HTTP(S) server which permits resuming broken downloads (the server must support the HTTP header "Range:")
    URL: http(s)://www.server.com:Port/Updates/Setup_1.35.cab
    The HTTP URL may also contain a username and password if required.

All the actual servers (IIS, Apache,...) support these commands.

IMPORTANT:
Partial URL extraction requires MSZIP compressed CAB files. Due to the way LZX stores the data, it cannot be used for partial URL extraction!

Microsoft's Cabinet.dll requests block sizes between 8 Bytes and 32000 Bytes in the callback FDIRead. It would be nonsense to request such tiny blocks from the server. Additionally Cabinet.Dll accesses the CAB data not completely sequentially. For that the Cabinet library uses the class CCache between Cabinet.dll and the internet to assure that no data block must be read twice and to improve the performance.

An important factor is the size of the blocks which the cache reads from the server.

A too small blocksize results in a bad performance because for each block a new data connection is opened to the server. A too big blocksize will download more data than is really needed when extracting only specific files from a huge archive.

I recommend to enable tracing in the file Trace.hpp and play around with the blocksize. In the Trace you will see the download speed in KB/s.

If you do not want to use the functionality of extracting only parts of a CAB file it is strongly recommended to download the entire CAB archive to a temporary file on disk and then extract it. The cabinet library will do that for you automatically and also delete the temporary file after extracting it. This results in the maximum download speed because there is a continuous data stream coming from the server.

You enable the download of the entire CAB file to disk by setting the blocksize = 0.

 

Blocksize
URL
Note
Blocksize = 50 kB Slow download speed, but no downloading of unnecessary data.
Use for partial updates, not recommended for complete setups.
HTTP(S) server must
support header "Range:"

FTP server must
support command "REST"
Blocksize = 1 MB Higher download speed, but downloading more unnecessary data.
Use for partial updates, not recommended for complete setups.
Blocksize = 0 Highest download speed, download entire CAB, then extract it.
Use for complete setups, not recommended for partial updates.
No special
server requirements

 

 

You should not use blocksizes greater than 2 MB as you don't gain any advantage by doing that. See my comments in the file ExtractUrl.hpp !
If the Blocksize is zero, the download uses only a little buffer in memory to copy the data to disk.

If you do not specify username and password inside the URL, FTP will use anonymous login.

The class CExtractUrl uses the internet functionality in Wininet.dll to download data from the server. Internet Explorer 5.0 or higher is required.

C++

C++
Cabinet::CExtractUrl i_Extract;
if (!i_Extract.CreateFDIContext()) 
    { Error Handling ... }
 
if (!i_Extract.ExtractUrlW(URL, Blocksize, DownloadFile, ExtractFolder))
    { Error Handling ... }
 
i_Extract.CleanUp(); // see below

C#

C#
CabLib.Extract i_Extract = new CabLib.Extract();
i_Extract.ExtractUrl(URL, Blocksize, DownloadFile, ExtractFolder);
i_Extract.CleanUp(); // see below

There are several options using this function:

Download the entire CAB file to "C:\Installer.cab", then extract it:
Blocksize == 0 DownloadFile = "C:\Installer.cab" ExtractFolder = "C:\Extracted"
Download the entire CAB file to a temporary file, extract it, then delete it:
Blocksize == 0 DownloadFile = "" ExtractFolder = "C:\Extracted"
Download ANY file from FTP / HTTP(S) to disk without CAB extraction:
Blocksize == 0 DownloadFile = "C:\Metallica.mp3" ExtractFolder = ""
Download blocks of CAB file to memory and extract them:
Blocksize > 0 DownloadFile = "" ExtractFolder = "C:\Extracted"

You can extract from the same CAB file on the server multiple times, so the content of the internet cache can be reutilized. A downloaded temporary file can also be reutilized in this way:

i_Extract.SetSingleFile(FileName1);
i_Extract.ExtractUrl(Url, Blocksize, DownloadFile, ExtractFolder);
i_Extract.SetSingleFile(FileName2);
i_Extract.ExtractMoreUrl(ExtractFolder);
i_Extract.CleanUp(); // see below

More Internet Functions

With i_Extract.CleanUp() you free the memory of the internet cache and close downloaded files. Call this when you are ready with the CAB file.

IMPORTANT:
CleanUp() is not called automatically to allow reusing partial downloads to memory or full downloads to a temp file for later extractions from the same CAB file. So you MUST call CleanUp() manually after the last URL extraction as the library can not know when you are done.

With i_Extract.SetProxy() you can specify a CERN, TIS or SOCKS proxy for HTTP, HTTPS, FTP.

The string must be in the format "http=http://Proxy1.com:8000 https=https://Proxy2.com:443". If you pass an empty string or never call this function the default settings of Internet Explorer will be used. (stored in the Registry)

With i_Extract.SetPassiveFtpMode() you can turn to active or passive FTP mode. If you never call this function passive mode will be used.

With i_Extract.SetHttpHeaders() you can specify additional HTTP headers which are sent to the server.

The headers consist of "Name: Value". Multiple headers can be separated by the pipe character. Example: "Referer: http://www.test.com|Accept-Language:en" There must be no space before or after the pipe character!

With i_Extract.InternetGetProgress() you can display the download progress in a progress bar. (This is not a callback!) The extraction must be started from another thread and in the GUI thread you must set a timer (e.g. 500 ms) to poll the progress from this function. A progressbar does not make much sense for partial updates.

(If you specified a blocksize > 0 the progressbar will restart at zero for each downloaded block anew.)

Attention: Not all HTTP Servers return "CONTENT-LENGTH" (e.g. AOL servers), in this case the progressbar will not work.

Codepages

When extracting CAB files that have been compressed with this library, you don't have to care about the Codepage nightmare. The compression encodes filenames as UTF-8 and sets the flag _A_NAME_IS_UTF which is stored in the CAB file. This flag indicates to the extraction that the filename is UTF-8 encoded. (See chapter Unicode above.)

But what if you want to extract old CAB files that have been compressed on Windows 98 using the Greek Codepage or even the OEM (=DOS) Codepage with a compressor that did not UTF-encode the filenames?

In this case (!!and ONLY in this case!!), you can define the codepage:

C++
i_Extract.SetCodepage(850); <span style="color: rgb(0, 102, 0)">// OEM Codepage</span>

NOTE 

  1. The default conversion for non-UTF filenames is the ANSI codepage (1252).
  2. Your codepage setting will be ignored if the flag _A_NAME_IS_UTF is set in the CAB file!

Special Features

More Extraction Functions

With i_Extract.AbortOperation() you can abort a lengthy extraction. Obviously this must be called from another thread.

With i_Extract.IsCabinet() you can check if the specified CAB file is valid or corrupt. Additionally this function returns a structure with information about the CAB file. This information is read from the CAB file header. You get, for example, the total count of files in the CAB file and if this CAB is part of a splitted archive, and more.

With i_Extract.SetSingleFile() you can extract only the specified file from the cabinet. The file must be in the root folder of the CAB. (see below)

With CabLib.Extract.ResolveShortcut() you can obtain the content of a *.LNK or *.URL file.

Decryption

Similar to the encryption you can decrypt an archive. (see above Encryption)

How to Extract only One File from the CAB File/Resource/Stream

C#

C#
CabLib.Extract i_Extract = new CabLib.Extract();
i_Extract.SetSingleFile("FileList.xml");
i_Extract.ExtractFile(@"C:\Temp\Packed.cab", @"E:\ExtractFolder");

This will create a file E:\ExtractFolder\FileList.xml.

The file to be extracted MUST be located in the root folder of the CAB archive.

If the file does not exist in the archive, nothing will happen. (no error)

If a single file is extracted the event evBeforeCopyFile will not be fired. (see below)

C++

CExtract::kCallbacks k_Callbacks;
k_Callbacks.f_OnBeforeCopyFile = &CMain::OnBeforeCopySingleFile;
i_Extract.SetCallbacks(&k_Callbacks);
 
CStrW s_SingleFile = L"FileList.xml";
i_Extract.ExtractFileW(L"C:\\Temp\\Packed.cab", "E:\\ExtractFolder", (void*)&s_SingleFile);
 
BOOL CMain::OnBeforeCopySingleFile(CExtract::kCabinetFileInfo *pk_Info, void* p_Param)
{
    CStrW* ps_SingleFile = (CStrW*)p_Param;
    return (*ps_SingleFile == pk_Info->u16_File);
}

Extraction Callbacks / Events

CExtract.OnBeforeCopyFile() (C++ Callback)
CabLib.Extract.evBeforeCopyFile (.NET event)

This is called before Cabinet.dll copies an extracted file to disk. You get detailed information about the file to be extracted. If you don't want this file to be copied to disk you can return FALSE here and the file will be skipped. (Examples see below)
This callback can be used to display progress information in your GUI if you extract small files (< 20 MB).

CExtract.OnAfterCopyFile() (C++ Callback)
CabLib.Extract.evAfterCopyFile (.NET event)

This is called after Cabinet.dll has placed a new file onto disk.
This callback can be used to display progress information in your GUI if you extract small files (< 20 MB).
If you have enabled Extraction to Memory, no file is written to disk, instead this callback receives the entire content of the file in a buffer / Byte Array.

CExtract.OnProgessInfo()   (C++ Callback)
CabLib.Extract.evProgressInfo (.NET event)This must be used if you extract huge files (> 50 MB) and want to show the progress in the GUI.
This callback is called every 200 ms while huge files are written to disk. Example:

  1. OnBeforeCopyFile()
  2. OnProgressInfo() --> 27,5 %
  3. OnProgressInfo() --> 52,9 %
  4. OnProgressInfo() --> 81,3 %
  5. OnAfterCopyFile()

CExtract.OnCabinetInfo() (C++ Callback)
CabLib.Extract.evCabinetInfo (.NET event)

This function will be called exactly once for each cabinet when it is opened. It passes information about the CAB file.

CExtract.OnNextCabinet() (C++ Callback)
CabLib.Extract.evNextCabinet (.NET event)

This function will be called when the next cabinet file in the sequence of splitted cabinets needs to be opened.
Here you can display a message like "Please insert disk 2!"

ATTENTION:

It is recommended to start extraction from another thread to avoid a dead GUI and to be able to call AbortOperation() and show the progress.

In C# you must call Control.BeginInvoke() in the event handler routine to asynchronously access GUI elements otherwise you will run into trouble!

For details see the file Microsoft Cabinet.dll Doku.doc and the plenty comments in the file FDI.H

Manipulating the Extraction Process

With the callback OnBeforeCopyFile() you can control exactly what you want to extract from the CAB file. The callback/event passes a structure kCabinetFileInfo which tells you details of the file to be extracted: file name, subfolder, full path, file size, file date/time and file attributes.

With this information you can decide if you want the file to be extracted and return false if not.

In C# you must attach an event handler first:

C#

C#
CabLib.Extract.delBeforeCopyFile i_Delegate = 
    new CabLib.Extract.delBeforeCopyFile(OnBeforeCopyFile);

i_Extract.evBeforeCopyFile += i_Delegate;
 
i_Extract.ExtractResource("CabLib.dll", 101, "CABFILE", @"E:\ExtractFoder");
 
i_Extract.evBeforeCopyFile -= i_Delegate;

C++

C++
CExtract::kCallbacks k_Callbacks;
k_Callbacks.f_OnBeforeCopyFile = &CMain::OnBeforeCopyFile;
 
i_Extract.SetCallbacks(&k_Callbacks);

How to Extract only Files with a Specific File Extension

If you want to only extract the files from the CAB which have the extension ".DLL" (including all subfolders) you can write:

C++

C++
BOOL OnBeforeCopyFile(kCabinetFileInfo &k_Info, void* p_Param)
{ 
    int Len = wcslen(k_Info.u16_File);   // length of filename
    return (wcsicmp(k_Info.u16_File +Len -4, L".DLL") == 0);
}

C#

C#
private bool OnBeforeCopyFile(CabLib.Extract.kCabinetFileInfo k_Info)
{
    return k_Info.s_File.ToUpper().EndsWith(".DLL");
}

How to Extract only Files within a Specific Subfolder in the CAB

If you want to extract only one folder from a CAB with the name "Setup\" and all its subfolders, write:

C++

C++
BOOL OnBeforeCopyFile(kCabinetFileInfo &k_Info, void* p_Param)
{ 
    return (wcsnicmp(k_Info.u16_SubFolder, L"Setup\\", 6) == 0);
}

C#

C#
private bool OnBeforeCopyFile(CabLib.Extract.kCabinetFileInfo k_Info)
{
    return k_Info.s_SubFolder.ToUpper().StartsWith(@"SETUP\");
}

How to Extract only Newer Files

If you want to make an update of existing files and you want only those files on disk to be replaced which have an older date than the files in the CAB, you can write:

C++

C++
BOOL OnBeforeCopyFile(kCabinetFileInfo &k_Info, void* p_Param)
{
    // try to open the file on disk
    HANDLE h_File = CreateFileW(k_Info.u16_FullPath, GENERIC_READ,
                                FILE_SHARE_READ, 0, OPEN_EXISTING, 
                                FILE_ATTRIBUTE_NORMAL, 0);
    
    // The file does not yet exist --> copy it!
 
    if (h_File == INVALID_HANDLE_VALUE)
        return TRUE;
    
    FILETIME k_FileTime, k_LocalTime;
    BOOL b_OK = GetFileTime(h_File, 0, 0, &k_FileTime);
    
    CloseHandle(h_File);
    
    if (!b_OK)
        return TRUE;
    
    // Last write time UTC --> Local time
    FileTimeToLocalFileTime(&k_FileTime,    &k_LocalTime);
    return (CompareFileTime(&k_Info.k_Time, &k_LocalTime) > 0);
}

C#

C#
private bool OnBeforeCopyFile(CabLib.Extract.kCabinetFileInfo k_Info)
{
    if (!System.IO.File.Exists(k_Info.s_FullPath)) 
        return true;
    
    // retrieve local file time
    System.DateTime k_FileTime = System.IO.File.GetLastWriteTime(k_Info.s_FullPath);
    return (k_Info.k_Time.CompareTo(k_FileTime) > 0);
}

How to Extract a File Directly to Memory

If you have, for example, an XML filelist packed into the CAB file and want to load this filelist into a XML reader, it does not make much sense to first extract the filelist to a temporary file on disk, then read it into the XML reader and then delete the temp file.

Instead you can directly extract this file to memory by setting the target directory = "MEMORY".

If you extract a Stream or a Resource to memory, you do an extraction FROM memory TO memory.

With Memory Extraction you can extract encrypted data without ever writing the plain decrypted data to disk.

IMPORTANT:
Obviously you can also extract multiple files to memory by omitting SetSingleFile(..) in the example below. But if you don't know in advance that the files you extract to memory are small files you must check their size in the callback OnBeforeCopyFile().

This callback tells you the size of the file BEFORE allocating memory for the extraction. If a file is bigger than 10 Megabyte you should not extract it to memory and return false in OnBeforeCopyFile() to skip this file. If you extract huge files to memory computers with little physical RAM will become very slow!

C#

C#
CabLib.Extract i_Extract = new CabLib.Extract();
i_Extract.SetSingleFile("FileList.xml"); // see above
i_Extract.evAfterCopyFile += new CabLib.Extract.delAfterCopyFile(OnAfterCopyFile);
 
i_Extract.ExtractFile(@"C:\Temp\Packed.cab", "MEMORY");
 
private void OnAfterCopyFile(string s_File, Byte[] u8_ExtractMem)
{
    string s_Content = Encoding.UNICODE.GetString(u8_ExtractMem);
    
    // Cut the first character which identifies the Unicode encoding
    if (s_Content.Length > 1 && s_Content[0] == 0xFEFF)
        s_Content = s_Content.Substring(1);
                
    XmlDocument i_Doc = new XmlDocument();
    i_Doc.LoadXml(s_Content);
    .....
}

C++

C++
Cabinet::CExtract i_Extract;
Cabinet::CExtract::kCallbacks k_Callbacks;
k_Callbacks.f_OnAfterCopyFile = &CMain::OnAfterCopyFile;
i_Extract.SetCallbacks(&k_Callbacks);
 
if (!i_Extract.CreateFDIContext())
   { Error Handling ... }
if (!i_Extract.ExtractFileW(L"C:\\Temp\\Packed.cab", L"MEMORY"))
   { Error Handling ... }
......
 
void CMain::OnAfterCopyFile(WCHAR* u16_File, Cabinet::CMemory* pi_ExtractMem,
     void* p_Param)
{
     if (wcsicmp(u16_File, L"MEMORY\\FileList.xml") == 0)
     {
          int  s32_Length;
          BYTE* u8_Data = pi_ExtractMem->GetData(&s32_Length);
          ParseXmlFileList(u8_Data); 
     }
}

How to Get the Count of Files in a CAB

This information is stored in the CAB header. You get a lot of information about a CAB file by calling IsCabinet() which fills the given structure.

C++

C++
FDICABINETINFO k_Info;
BOOL b_ValidFile  = i_Extract.IsCabinetW(u16_File, &k_Info);
int s32_FileCount = k_Info.cFiles;

C#

C#
CabLib.Extract.k_HeaderInfo k_Info;
bool b_ValidFile  = i_Extract.IsFileCabinet(s_File, out k_Info);
int s32_FileCount = k_Info.u16_Files;

How to get a list of all files in a CAB

Start a normal Extraction process and return false in OnBeforeCopyFile(). So you get all files but nothing will be written to disk.
If you need more information like size, date, attributes, store the entire k_Info instead into the ArrayList.

C#

C#
ArrayList mi_FileList = new ArrayList();
  
  private bool OnBeforeCopyFile(CabLib.Extract.kCabinetFileInfo k_Info)
  {
    mi_FileList.Add(k_Info.s_RelPath);
    return false;
    }

The Extraction Class Hierarchy

This diagram demonstrates the C++ classes which are used in both projects:

Image 11

If you want a different behaviour, do NOT modify the existing classes. Instead derive a new class from the existing classes and override the functions you want to change.

CExtract contains the functions to extract a "real" CAB file from disk.

CExtract contains the following callbacks which are called from Cabinet.dll:

  • Open() to open a file
  • Read() to read from a file
  • Write() to write to a file
  • Seek() to set the file pointer or ask its position
  • Close() to close a file

IMPORTANT: These callbacks are called from Cabinet.dll to read the CAB file AND to write all the extracted files to disk.

CExtractMemory is a class which overrides the file access functions and replaces them with functions which read the CAB data from memory instead of disk. CExtractMemory itself cannot be instantiated. Other classes must be derived from it. It provides these additional callbacks:

  • OpenMem() to open the memory which represents the CAB file
  • ReadMem() to read from the memory of the CAB file
  • SeekMem() to set the memory pointer or ask its position
  • CloseMem() to release the memory which holds the CAB file

IMPORTANT: These callbacks are ONLY called when Cabinet.dll wants to read the CAB file.

CExtractResource is derived from CExtractMemory to read data from a Win32 resource. CExtractStream is derived from CExtractMemory to read data from a .NET stream. CExtractUrl is derived from CExtractMemory to read data from the internet.

You can easily derive your own classes for example to read data from a pipe or whatever you like. The data stream must be capable of seeking (random access).

Debugging

If you want to debug the whole compression/extraction process with a tool like DebugView from SysInternals you can modify the file Trace.hpp:

C#
#define _TraceCompress (_DEBUG && TRUE) // CAB compression
and / or
#define _TraceExtract  (_DEBUG && TRUE) // CAB extraction
and / or
#define _TraceInternet (_DEBUG && TRUE) // communication with the server
and / or
#define _TraceCache    (_DEBUG && TRUE) // storage of downloaded blocks in cache

IMPORTANT:
To see anything in DebugView you must compile CabLib in DEBUG mode and start the compiled application in Visual Studio with CTRL + F5

An Installer / Updater based on CabLib

Check out my project "An Intelligent .NET Multilanguage Installer" which installs or updates a software package from a local CAB file, a CAB file on a fileserver or a CAB file on a FTP / HTTP(S) server.

If you have any problems to get CabLib running, study the source code of the Installer project, which demonstrates all features.

P.S.
From my homepage you can download free C++ books in compiled HTML format.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)