Guide Index Quick Links

Compressing and Distributing Files with MAKECAB and IExpress

Created on March 10, 2023 (Updated on March 10, 2023)

  1. Compression
    1. The Installation, or Lack Thereof
    2. Compressing One File
    3. Writing a DDF File
    4. A Caveat In Relation to Windows 9x Setup
  2. IExpress Simplifies Compression
  3. Corngratulation

While you should know how to create INFs to use for getting stuff installed by now, mashing a text file together with a bunch of other files scattered about is really not practical if you're going to distribute the whole thing. You could just zip them all up and call it a day; rolling everything up into one file and applying compression makes it all easy to pass around on the internet.

Even so, Microsoft came up with a number of different tools of their own in the past to help distributors reduce physical media costs, as well as improve convenience for both the developer and user in the installation of software.


The first important point of focus is being able to compress the files. Microsoft used a number of their own compression algorithms which helped to keep them from using too many floppy disks for one piece of software. Their operating systems most definitely made use of these. For the Windows 9x lineup, many files were rolled into a few sequential CAB files. For Windows NT (and MS-DOS 6 as well), every file was compressed individually and left as is, with a trailing underscore (_) to indicate it is compressed.

One of the compression algorithms from Microsoft is referred to as Quantum; this was used in Windows 95. Compression using this algorithm is extremely slow, even with a modern CPU on hand. To put things into perspective, on my Ryzen 9 5950X capable of boosting up to 4.9 GHz, a complete rebuild of Windows 95D Lite takes at least half an hour! But it's the only way to compress files as tightly as possible in a format Windows 95's 16-bit setup engine will recognize.

LZX is used by Windows 98 and ME. This algorithm is also very efficient on space, but it works much faster to compress files. This algorithm is used by a later compression program; one does not have both Quantum and LZX, but the decompression tools can work with both formats.

MSZIP is also present in all of the tools, but it is not as efficient as the other two, so it is better not to use it. Unless, maybe you want to tweak the official MS-DOS 6 setup program, assuming it uses that algorithm? I have not checked.

To use the Quantum algorithm, use the Diamond Disk Layout Tool. For everything else, I advise going with this suite of programs found in IEAK, also known as IExpress; this includes MAKECAB.EXE, which has the LZX algorithm on hand. I have used both programs in Windows 7 (64-bit) and Linux with WINE.

The Installation, or Lack Thereof

Whichever one you use, you'll want to put these in some directory where the executables can be easily accessed by the command prompt. You could drop them in C:\WINDOWS or C:\WINNT, but a better option would be to set up a new directory containing your own personal executables, and setting the PATH environment variable to it.

In Windows 95 and 98, this is defined in AUTOEXEC.BAT. In Windows NT, go to the System control panel and select the Environment tab. In the user variables section, set a new variable PATH, then point to a directory containing your programs. You can specify multiple paths separated by semicolons. Setting this variable will make it much easier to use these programs when you go to use the command prompt.

In addition to the two garbage text files we had been working with previously, I'm going to add in a large bitmap image to take up more space. It's not much, but being raw data, it should be highly compressible. I'll also throw in a file that's not as compressible, a Cinepak video. Keep that in mind for when we go to write a directive file.

Compressing One File

Compressing one file is as straightforward as can be. Depending on which program you'll use, you can type DIAMOND or MAKECAB followed by the name of the file to compress, then press <ENTER>. Watch it go to work, and you'll see it create a new file with the last character of the extension replaced with an underscore. You could probably compress many files this way with a for loop, or better yet, use GNU Parallel if you're using Linux to do this.

There are more ways to use these programs; run them without any arguments to get a list of all the possible options.

Individual file compression should work for rebuilding an entire Windows NT distribution (I haven't tried), but it's insufficient if you plan to make CAB files, or cabinets, as they are called. A directive file is required in order to accomplish this.

Writing a DDF File

A DDF file is nothing more than a plain text file containing directives for DIAMOND.EXE or MAKECAB.EXE to process. This is where the majority of the program's complexity in usage comes from. Let's start off simple... we just want to roll four files up into a cabinet set, nothing more.

; Set some very essential attributes for making the CABS
;.Set InfFileName=TESTLAYT.INF	; External INF listing all files used
.Set CompressionType=LZX	; Change to QUANTUM for use with Windows 95
.Set CompressionLevel=7
.Set CompressionMemory=21
.Set FailOnMissingSource=On
.Set MaxErrors=1
.Set UniqueFiles=ON
.Set MaxDiskSize=1474560	; Size of floppy disk
.Set DiskDirectoryTemplate=OUT	; We don't want many directories
.Set CabinetNameTemplate=TEST_*.CAB

; Change this to where your source files are.
.Set SourceDir="C:\TEST"

; Compress files AND create cabinets.
.Set Compress=ON
.Set Cabinet=ON

; All of the files

In my case, I did manage to get everything crammed into a single volume, so now 6MB worth of files can fit into a single floppy disk. To make your life easier, when you're dealing with hundreds, if not thousands of files, run dir /b (or ls -1) on the directory your source files are located, and redirect the output to a file. In my case, I'd enter this command:

dir /b TEST > list.txt

Then copy and paste the contents into the DDF file at the appropriate position.

To execute compression, run the following command:


...replacing TEST.DDF with the name of your DDF file, and MAKECAB with DIAMOND if you're using the Quantum algorithm. I'm not joking when I say DIAMOND.EXE is slow with building cabinets, though. Even for just 6MB worth of stuff, the whole process was being dragged to an absolute crawl on a 333MHz workstation running Windows NT 4.0.

It makes me wonder, how did Microsoft even manage to use this program for building the Windows 95 cabinets back then? Maybe... did they use some other method... gonna have to look at another route for using this program later on, I'm just going by what I know right now. Either way, please always use MAKECAB wherever possible.

Remember, the DDF file is processed one line at a time, so you can call something like .Set SourceDir multiple times to use multiple source directories.

So, great, we've got a compressed cabinet, but how does the user unload stuff from it? If the version of Windows Explorer supports it (most will), they can extract the contents directly, or use EXTRACT.EXE to do the job. Accessing CABs has never been intuitive, though; maybe it would be better to use our INF we've been writing to take care of things.

You may have noticed that MAKECAB generated a file called SETUP.INF; with some adjustments, this could be used to supplement our own INF and offload a number of lines. In the DDF file, right before the list of files, write this magic formula to tweak the layout file output to conform to a format Windows 9x would use:

; In practice, setup engines tend to expect a layout format rather
; off from the default one used. We should adjust some headers.

; If you're going to rebuild the Windows NT cabinets, you may need
; a different format.

.Set InfDiskHeader="[Version]"
.Set InfDiskLineFormat=""	; Empty!
.InfBegin Disk
.InfWriteDisk signature="$CHICAGO$"	; assuming Windows 9x
; The class may differ if you're loading a more specific component.
.InfWriteDisk "SetupClass=BASE"

.Set InfCabinetHeader="[SourceDisksNames]"
.Set InfCabinetHeader1="; Cabinet file names and associated disks"
.Set InfCabinetHeader2="; <cab#> = <disk#>,<cabinet filename>, ID (Unused, must be 0)"
; Using labels with disk numbers just in case you actually
; go through the trouble.
.Set InfCabinetLineFormat="*cab#*,""Idiottron 5000 Disk *disk#*"",""*cabfile*"",0"

.Set InfFileHeader="[SourceDisksFiles]"
.Set InfFileHeader1=";<file> = <cabinet number>,<subdir>,<filename>,<size>,<checksum>"
.Set InfFileHeader2=";Note: File is not in a cabinet if cab# is 0"
.Set InfFileHeader3=""
.Set InfFileLineFormat="*file*=*cab#*,,*size*"

It may seem like a lot, but this is exactly what I use to create layout files for Windows 9x, taken straight out of my THEMES.DDF file used for the theme cabinets in Windows 95D Lite. It really works!

You'll probably want to use Windows 98 or ME to see if the procedure works, given their 16-bit setup engines can use the LZX algorithm.

Taking the new files we introduced into account, you should update the CopyFiles and DelFiles sections as needed. Following this, you can add more entries to SourceDisksNames and SourceDisksFiles as needed. In that regard, you may want to set MaxDiskSize to a much higher amount. However, we did adjust the layout file output to conform to what Windows 9x likes... as such, you can delete these sections entirely, and add a new line to the Version section instead:


Then, you can bundle the layout file with the installation INF and your cabinets in the same directory. Run an installation with this (don't run Install on the layout file), and you should get the results much like what we had been typing up earlier.

If you won't be using a layout file, you don't have to create cabinets. You'll have to compress files individually using the command line as described earlier, as single file compression is oddly not supported in directive files. When you do, though, you can supply the compressed files (trailed by underscores) and the setup engine will automatically recognize them; you don't have to change any CopyFiles listings to account for the different names. You WILL have to go the route of adding lines to SourceDisksFiles, though.

A Caveat In Relation to Windows 9x Setup

If you're going to extract the entire contents of the Windows 9x setup cabinets and repackage them with the appropriate modifications, one thing I should note is that when you do so, you MUST rebuild the PRECOPY cabinets separately. Otherwise, you WILL get a memory error that forces Setup to quit! To clarify, the entire line of cabinets must be rebuilt, including the PRECOPY cabinets before anything else, then the PRECOPY cabinets must be rebuilt again.

It's really strange how it works, but it's more of a product of a time when floppy disks were still a prime means of distributing an entire operating system. The PRECOPY cabinets cannot link forward to the rest of the cabinets, but those cabinets must be able to link back to the PRECOPY cabinets.

IExpress Simplifies Compression

Have you ever, say, grabbed a Visual C++ 6.0 redistributable package to install onto Windows 95 or the like, so some programs will run? It comes in a very particular self-extracting format; this format is generated by a program called IExpress. It's basically a GUI wizard that walks you through the process of building such a package, and calls upon MAKECAB.EXE to do the actual compression.

Welcome to IExpress 2.0

In the supplied IEAK package, run IEXPRESS.EXE. Here, we'll create a new Self Extraction Directive, or SED file.

Package purpose

We can create a package that either extracts files only, or one that also executes an installer afterwards. Either option will be very useful for distributing compressed archives that Windows 95 users can load easily without a separate extractor. There's also "Create compressed files only", though you're not likely to use that option much when you're using this wizard.

Package title: Evil Software Idiottron 5000

Give the package a title. This will be seen in various dialog boxes such as the confirmation prompt and the extraction progress bar.

Confirmation prompt

You can prompt the user with a message if you need them to confirm if they want to install your package. This should definitely be used if the installation is to be executed by an INF and the package is intended to be installed interactively. If your package runs another program that loads its own user prompt or you're designing it for an unattended installation, you can leave the default setting of having no prompt.

License agreement

If you want, you can import a plain text file to use as a license agreement which will be displayed to the user. You may also use this section to load a detailed description of the package instead.

Packaged files

This is the part where you'd load your files in. If an INF is to be used for the installation command, it needs to be loaded in here and have a DefaultInstall section present.

Install Program to Launch

Now, you may select the installation program or INF file to execute which you've added previously. Normally, you should not need to run a post install command.

Show window

Generally, it's best practice to use the default setting for displaying the installation program's window. This holds true even if this installer is to be executed in unattended mode; displaying installation progress for any such component could be helpful. This is NOT to be confused with the extraction progress dialog which appears before the actual installer is loaded.

Finished message

When the installation is finished, you can optionally display another dialog box. Often, this shouldn't be used; an executable installer will likely supply its own "installation complete" message, and specifying a dialog here could get annoying if the package is to prompt the user to reboot the system.

Package Name and Options

The destination file should have an EXE extension, as this program will generate a self-extracting program. Here, you can define some extra options; you can hide the extraction progress dialog box from the user, and if your package contains long filenames (exceeding the 8.3 format), you can set the option to store them in their full length here.

Configure restart

Ususally, you'll want to have the package determine if a reboot is necessary. However, if you're going to have a different entity determine if the computer needs to be restarted (one way to do this is by checking for the existence of WININIT.INI), or this package is explicitly designed for integration into a longer string of automated package installations (such as during the RunOnce portion of Windows 95 Setup), set this to No restart.

If the installation of your program absolutely requires a restart and the package is not deciding that one is required, set the option to Always restart.

Save Self Extraction Directive

You should save the SED file somewhere in case you need to rebuild the package or make adjustments to it; chances are you may end up doing that on your first few tries.

Create package

That's it! Now, click Next, and the program will call MAKECAB.EXE to compress the files, then it will assemble the cabinets into a self-extracting executable package.

MAKECAB running in the command prompt

The package is created

Once that's done, you can now close the program. Test the package on your target system to make sure everything's working.

The package is being installed

What a mess...


If you've managed to go through this entire INF writing tutorial, by now you should have a deeper understanding of how Microsoft-fashioned installations tended to work. In the event that you plan to remaster Windows 9x, set up a customized installation routine, or create self-extracting packages with easy-to-create installers, this baseline knowledge should really help you along the way.

The complete INF file used to supplement these instructions can be grabbed here.


flatrute - March 17, 2023 at 10:29 AM

There are a few specification documents on the compression algorithm which in theory would let me be able to build a replacement that scales better on modern systems but I am so busy in college at the time I am typing this...

1 comment on this page

Sort: Ascending | Descending

Leave a Comment

Name: (required)

Website: (optional)

Maximum comment length is 1000 characters.
First time? Read the guidelines

Enter the text shown in the image: