INF Files for Bears of Little Brain
May 1, 2003
Brian Catlin

Copyright © 2003 by Brian Catlin. All rights reserved

Just the other day, while walking through the hundred acre wood, I was accosted by the local fauna.

"Excuse me", asked a small pink pig. "B-B-B-But do you know anything about Windows Device Drivers? Because, if you do, our friend here needs some help", he said, pointing to a rather rolly polly teddy bear.

"What kind of help?", I asked the little bear.

"Well", replied the little bear, "I am a Bear of Little Brain. I just wrote a Windows Device Driver, but I dont know how to install it".

"What you need to do, is write an .INF file, which describes your driver and the device it controls, to the Windows operating system", I said. "Uh, by the way, what device does your driver control?".

"It is a hunny filter.  It removes dirt, bees, and other impurities in hunny. It is my own invention.", he said rather proudly.

"Hmm", I thought to myself, "not bad for a Bear of Little Brain".

"Do you think, that is to say, do you know how to write one of these 'Dot Eye Eneff' files?", the bear asked.

"Sure, why dont we all sit down right here, and Ill tell you all about .INF files – Hey, wheres everyone going?  Come back! Theyre not that bad!"

The small group of animals slowly reappeared, one by one, with more than a little trepidation in their eyes.

"Dont worry, .INF files arent nearly as bad as you think", I said, trying to sooth their fears.

"W-W-Well, thats n-n-not what m-m-most p-p-people say", said the little pink pig, clearly frightened.

"Calm yourself my little friend, nervous eaters dont grow up to be big tasty – er, healthy pigs", I said.

The little pig calmed down noticeably, but still regarded me with suspicion.

Purpose of .INF Files

Ask just about any device driver writer, "What is the worst part of writing Windows device drivers?" and most will reply, "Writing .INF files!" The reason for this is that the documentation on .INF files in the DDK has not provided a procedural approach to describing .INF files, such as, "If you want to accomplish X, then do Y followed by Z".

This article will describe the basics of .INF files and how they are used in the installation of a device driver.

An .INF file can do many things; however, 97% of all .INF files really only perform three tasks:

Identify the driver for a particular device. This is done using one or more Hardware IDs or Compatible IDs. The system device installer will take the Hardware IDs and Compatible IDs that were reported for a device (by its bus driver), and try and find an exact character for character match in an .INF file. When a match is found, then the system device installer knows that the .INF file describes the driver(s) for the device.

Copy files from the installation medium to the system. In addition to the driver binary (the .SYS file), driver packages may also include DLLs, co-installers, applications, or any other type of file.

Add entries to the registry. This describes the device and its relationship to other devices, provides for device or driver specific configuration information, and describes the driver "service" to the service control manager.

Thats it. Sounds simple, doesnt it? Actually, it is pretty simple (no, Im not kidding!).

"Youre right", replied the little bear, "even a Bear of Little Brain understands that"

The two most confusing aspects of .INF files are usually:

The .INF file is not 'run from the beginning to the end; individual sections in the .INF file are 'run based upon the phase of the installation process.

Most of the sections in the .INF file are actually part of a well-defined hierarchy. This fact is obscured by the squashing of the hierarchy into a flat text file. 


An .INF file consists of tables called 'sections, and comments. Each section has a name, which is enclosed in square brackets, e.g.


All section names are case insensitive, and may in theory be up to 255 non-whitespace ANSI or Unicode characters in length (although Win9x requires names to be less than 19 ANSI characters). Spaces, tabs, other control characters, and [%];"\ are not allowed (well, in some cases some of those characters are allowed, but to simplify things, lets just not use them). To separate words in a section name, do not use periods ("."), which are reserved to Microsoft; instead, use the underscore ("_") or dash ("-"), e.g.


Each section contains zero or more 'directives (yes, that means that sections may be empty). The directives tell the system device installer what to do, e.g. copy a file, or add an entry to the registry. The comment character is the semi-colon (";"), which can appear anywhere on a line.

There are no conditional statements in the .INF language, which means there are no "IF-THEN-ELSE" or other similar constructs; however, section names can be 'decorated with a platform-dependent suffix which the system device installer will preferentially select when installing on the specified platform, e.g.


This is a section that will only be 'run on Windows 2000 or later.

As I mentioned earlier, the sections are not 'run in the order in which they appear in the file, sections are 'run based upon the installation phase; therefore, sections may appear in any order in the file. Although, by convention, the [Version] section is always first, and the [Strings] section is always last.

There are several strings in an .INF file that will be displayed to the user. There is a string substitution capability within .INF files that works very similarly to the #define macro in C. String substitution macros are defined in a section called [Strings]. The directives in the section define the string macros, e.g.

my_company = "California Death Beams and Stuff"
my_device = "Basselope 2003 Stealth Weapons System"

The system device installer will perform the macro substitution where ever it finds a macro invocation of the form %macro-name%, e.g.

%my_company% = install_my_stuff

Most people in the world who use computers generally have an 'English to their language dictionary next to their computer, but frankly, non-English speaking people would much rather have everything on their computer output in their own language. You can declare all the printable strings in your .INF file using these macros, and the system device installer will chose the correct strings based upon what language the user has installed on the system.

You do this by providing multiple [Strings] sections. Each string section may be decorated (decorated names were discussed earlier) with a Language ID. The Language ID follows the same form used in the SDK, and consists of a four digit hexadecimal number with the low ten bits indicating the primary language, and the upper six bits indicating the sublanguage. For example, U.S. English is 0409. The definitions of the language and sublanguage IDs are in the SDK. For example:

[Strings]               ; Default, US English
one = "One"
two = "Two"

[Strings.040c] French (Standard)
one = "Un"
two = "Deux"

[Strings.080a]          ; Spanish (Mexico)
one = "Uno"
two = "Dos"

With the above strings sections, whereever the system device installer encounters %one% or %two% in the .INF file, it will substitute it with the string from one of the strings sections. If the user has installed some other language that isnt specified in a strings section, the system will choose the default strings section (without the decoration) for the macro definitions. An .INF file that supports multiple languages is often referred to as having been 'localized.

Commonly-used Sections

If you look at the DDK documentation on .INF files, you will find that there are 39 (as of this writing, new sections are added occasionally) section types understood by the system device installer. Each class installer, e.g. Network, Video, etc., can add its own section types, or directives to existing sections.

Thirty-nine section types may seem a bit daunting, but 97% of all .INF files can generally get away with about a dozen or so section types, which well briefly cover. Of course, the DDK is the definitive source for information on .INF files.

As I mentioned earlier, most of the sections in the .INF file are ordered in a hierarchy, as seen in figure 1:

The sections on the left are not part of the hierarchy, and are essentially 'global throughout the .INF file (G for global, G for green; I know, it sounds like "Sesame Street," but it works). The root of the hierarchy is the [Manufacturer] section.

Some of the section names are required, because the section is called by the system device installer (e.g. Manufacturer, Strings, Version, .Service, .HW, etc.), other section names can be called whatever you like, because they are only referenced from within the .INF file by you.

Following are the most commonly used sections and their most commonly used directives. For a definitive list of sections and their directives, look in the DDK documentation.

"Wait a minute", said the little bear, theres something missing".

"What? Lets see, Manufacturer, Models, Install Component, AddReg, CopyFiles, .Services, .HW, Version, Control Flags, SourceDisksNames, SourceDisksFiles, DestinationDirs, and Strings. Yep, thats all of them. Whats missing?", I said.


"Hunny?", I asked.

"Yes", the little bear replied, "you forgot Hunny".

"Um… Microsoft doesnt have a Hunny section in .INF files", I said.

"Why not?", asked a puzzled little bear.

"Well, .INF files are used for installing device drivers, and you dont install Hunny in a computer system".

"Everythings better with Hunny", he said rather smugly.

"Yes, Im … sure it is, but Hunny is rather sticky, and -"

"The stickiness is the best part", he interrupted.

"OK, but I dont think it will do the circuits much good, and for the record, I would prefer that you not install Hunny in any of my systems!", I said rather strongly.

"OK", he grudgingly agreed.

"Allright, can I get on with the lesson?", I asked.

"Yes, please", he replied.


This is the standard header for all .INF files, and it specifies which operating system and class installer can parse this .INF file.

; Identify this .INF file
Signature = "$Chicago$"       ; or $Windows NT$ for 2000/XP
Class = Fishbowl My class name
ClassGUID = {30320101-C613-11d2-9647-0020AFEB03E0}; My GUID
Provider = %my_company%             ; My company
CatalogFile =          ; WHQL checksum file
DriverVer = 04/01/2003,    ; Driver date & version

Signature specifies which operating systems can parse this .INF file. $Chicago$ (why Chicago? Who knows? I do know that 'Chicago was the code name for Windows 95, but what that has to do with this I can't say) indicates that all versions of Windows can parse it, while $Windows NT$ indicates Windows 2000 and later operating systems.

Class specifies the name of the class the device is a member of. See DevGUID.H for a list of predefined classes and their GUIDs. In this case, I created my own class, the 'Fishbowl class. If you create your own class name, then you must also have a ClassInstall32 section.

ClassGUID specifies the device class GUID for this .INF file. The Class and ClassGUID directives better match, or the device install will fail. If you create your own class, create a new GUID using the GUIDGEN tool in the DDK or SDK. If you are using a known class, e.g. Mouse, then look up the GUID in DevGUID.H.

Provider identifies who wrote the .INF file. Generally, this will be the company that produced the device, but it is often "Microsoft", since they write a lot of .INF files for vendors.

CatalogFile specifies the file containing the digital signature of the driver and the .INF file. This file is received from WHQL after a device/driver combination has successfully passed the Hardware Compatibility Tests and received a logo. During development, you wont have a catalog file, so either omit this directive or point it to an empty file.

DriverVer identifies the date the driver was built and its version number. The system device installer uses this information to select which .INF file to use, when it finds more than one.


This section specifies which devices need special processing during the installation process.

; This section prevents the user from being able to load
; the driver unless the hardware is present

ExcludeFromSelect = *

ExcludeFromSelect is the most common directive used in a ControlFlags section. It contains a list of which devices that are installed by this .INF file reside on enumerable buses (buses that can uniquely identify each device on its bus, e.g. PCI, but not ISA). This directive informs the Add Device Wizard not to allow the user to select any of the specified devices for manual installation. Instead, the driver will be loaded when the device is detected by the PnP manager. If all devices installed by the .INF file are on enumerable buses, then you may specify an asterisk; otherwise, specify the hardware ID or compatible ID of each device, separated by a comma.


This section identifies the installation disks that contain the files to be copied to the system during the installation process.

; Identify the installation media
1 = "Fishbowl Installation Disk #1"
2 = "Fishbowl Installation Disk #2"

The directives for the SourceDisksNames section are different from the directives we have discussed up to this point. The format of the directive is:

disk-id = disk-description[,[tag-file],[unused,path][,flags]]

disk-id is simply an ordinal number for a disk. Generally, disks are numbered starting at one, and increase by one after.

disk-description is some string that identifies the disk. This string will be displayed to the user when the system device installer requires the disk to be inserted into the system.

tag-file is the name of a file known to be only on that disk. I usually use Notepad to create a zero-length file on each disk, e.g. Disk1, Disk2, etc.

unused is not used in Windows 2000 and later.

path allows a subdirectory on the disk to be specified.

flags allow the tag-file to specify the name of a cabinet (.cab) file that the files are in. On WinXP and later, if the cabinet file is used, then the tag-file name follows the flags field.


This section identifies all the files that will be copied to the system during the installation process.

; Identify the files on the installation media
Fish.hex = 1            ; on disk #1
Fishbowl.sys = 2  ; on disk #2

Like the SourceDisksNames section, the directives here are different from most other section types. In this case, for each file that shall be copied to the system, the disk on which the file resides is identified. This section works in conjunction with the SourceDisksFiles section. The format of the directive is:

filename = disk-id[,[sub-directory][,size]]

filename is the name of a file on one of the installation disks.

disk-id is the disk the contains the file, and is listed in the SourceDisksNames section.

sub-directory identifies a sub-directory on the disk in which the file is located.

size is the uncompressed size of the file in bytes. Generally not used.


This section specifies which directories on the system the files will be copied to, by providing a list of section names that contain a list of files and a directory number.

; Identify where the files will be copied to
Fb-W98-Driver-Files = 10,System32\Drivers
Fb-W2K-Driver-Files = 12

The format for directive in this section is:

section-name = directory-id[,sub-directory]

section-name is the name of a section created by the .INF file writer. This section contains a list of file names (that are also listed in the SourceDisksFiles section), that will be copied to a specific directory. Alternatively, the reserved word "DefaultDestDir" may be used, which specifies the destination directory for all files that do not have their destination directory specified explicitly.

directory-id is a pre-defined identifier for a system directory. The most commonly used directory-ids for driver writes are: 11 = %WinDir%\System32, and 12 = %WinDir%\System32\Drivers, where %WinDir% is a pre-defined environment variable that points to your system directory, not a macro in the strings section.

sub-directory identifies a sub-directory of the directory identified by directory-id.


This section provides macro definitions for strings used within the .INF file.

; String substitution definitions
ClassName = "Fishbowl"
MfgName = "Sannas Consulting, LLC."
Fishbowl = "Fishbowl USB Demonstration Device"
ServiceDesc = "Fishbowl driver"

The format of this section is:

macro-name = "some string"

macro-name is the name of the macro defined for the string, and is de-referenced elsewhere in the .INF file by surrounding it with percent ("%") signs, e.g. %macro-name%.

"some string" is the definition of the macro, and will replace the invocation of the macro where ever it appears in the .INF file.


This section is very similar to a directory; it lists all the manufacturers whose devices are supported by this .INF file. For 3rd parties, it is very rare for there to be more than one manufacturer listed; however, .INF files written by Microsoft may have a dozen or more manufacturers supported by a single .INF file. The manufacturer section is the root of the hierarchy for the rest of the sections (see figure 1).

; The root of the hierarchy for this file
%MfgName% = Sannas

The syntax for this section is also different from any other section in the .INF file. If you look at the directive, it appears that a quoted string (via the macro substitution) is being given the value of some identifier. Well, that is not the case. The equal sign ("=") is not used as an assignment operator, but as a separator (a rather poor choice for a separator, but it is a separator none the less). This section is used during the early phase of the installation process when the system device installer is searching the .INF files for a matching Hardware ID or Compatible ID. The format of this section is:

manufacturer-name = models-section-name

manufacturer-name is some string that identifies the manufacturer.

models-section-name is the name of a section (created by the .INF file writer) that contains a list of the device models for this manufacturer supported by this .INF file.


This section identifies the various device models for a particular manufacturer that are supported by this .INF file. The name of this section is determined by the .INF file writer, and is referenced in the Manufacturer section.

; Supported devices
%device1-name% = product-install, hardware_ID, hardware_ID
%device2-name% = product-install, compatible_ID

The directives in this section are similar to those found in the Manufacturer section. The format of this section is:

device-description = install-section-name, PNP-id[,PNP-id]…

device-description is a string (usually via a macro) that describes the device.

install-section-name is the name of a section created by the .INF file writer, which contains the directives for installing the driver for the device.

PNP-id is either a hardware ID or compatible ID.

In the following example, the system device installer would start at the beginning of the Manufacturer section when searching for an .INF file for a particular device. It would then search the .INF file for the models section [California_Death_Beams], which contains a list of the devices from that manufacturer that are supported by this .INF file. If none of the hardware IDs or compatible IDs in the [California_Death_Beams] models section match what the installer is looking for, it will then look at the next entry in the Manufacturer section. It would then search the .INF file for the [Texas_Techo_Gizmo] models section, and examine the hardware IDs and compatible IDs listed. If it finds a match, then it has determined that this .INF file supports the device, and the specified install-section-name will install the driver for the device.

%cdbs% = California_Death_Beams
%ttg% = Texas_Techno_Gizmo
%phaser% = install-phaser, pci\ven_9876&dev_1234
%blaster% = install-blaster, pci\ven_9876%dev_5678
%bass% = install-bass, dog\type_basselope&model_2003
cdbs = "California Death Beams and Stuff, Inc."
ttg = "Texas Techo Gizmo, LLC."
phaser = "Hand-held phaser, model 1234"
blaster = "Hand-held blaster, model 5678"
bass = "Basselope 2003 Stealth Weapons Platform"


This section (also called DDInstallSection in the DDK documentation), performs the actions required to install the driver for the device. The name of this section is determined by the .INF file writer, and is referenced in the Models section.

; Install the component
CopyFiles = Fb-W98-Driver-Files
AddReg = AddReg-Win98, AddReg-All
; Identify the driver

; Add entries to the registry - Win98

; Add entries to the registry - Win98 and WinNT

This section supports many different directives; the most common are CopyFiles and AddReg.

The CopyFiles directive specifies the name of one or more sections created by the .INF file writer that contain a list of file names (previously specified in the SourceDisksFiles section) to be copied.

The AddReg directive specifies the name of one or more sections created by the .INF file writer that contain a list of entries to add to the registry.


After the InstallComponent section has been run, the system device installer will search the .INF file for a section name that is identical to the InstallComponent section, with the suffix ".Services". The .Services section is used to add entries to the "services" key in the registry, describing the driver to the service control manager.

; Add our service - WinNT
AddService = Fishbowl, 0x00000002, Add-Service
; Describe the service

DisplayName    = %ServiceDesc%
ServiceType    = 1                  ; SERVICE_KERNEL_DRIVER
StartType      = 3                  ; SERVICE_DEMAND
ErrorControl   = 1             ; SERVICE_ERROR_NORMAL
ServiceBinary  = %11%\Drivers\Fishbowl.sys

This section supports several different directives, but the most common is AddService.

The AddService directive specifies the name of a section created by the .INF file writer that contains a series of directives that describes the driver.


This section is primarily used for installing PnP filter drivers. After the .Services section has been run, the system device installer will search the .INF file for a section name that is identical to the InstallComponent section, with the suffix ".HW". The .HW section is used to add entries to the "hardware" key (HKLM\System\CCS\Enum\<enumerator>\<device-id>\<instance-id>).

; Add the filter information to the registry
AddReg = AddReg-HW

; Putting this in the registry causes the filter to be
; loaded

This section supports several different directives, but the most common is AddReg, which specifies a section (created by the .INF file writer) containing an entry to be added to the registry. Specify the key "UpperFilters" to load your driver as an upper filter (on top of the FDO), or "LowerFilters" to load your driver as a lower filter (below the FDO).

"OK", I asked my budding .INF file writers, "any questions?"

They said that they all understood.

"OK, now you get to apply a little of the knowledge you just gained. Following are a few questions that you should all be able to answer", I said.


After reading this tutorial, you should be able to answer the following questions:

  1. What section in an .INF file is used to install a hardware-specific function filter?
  2. What is the Manufacturer section used for?
  3. What types devices must have their PnP Ids listed in the [ControlFlags] ExcludeFromSelect directive? Why?
  4. What is the Strings section used for?

 What do you know! The furry little guys got all the answers correct, and they all ambled off into the wood to continue on their various projects. As the little pig walked away, he still regarded me with suspicion, as he watched his back.

"Say hello to Oscar Mayer for me!", I called back to him.

About the author:

Brian Catlin is a Windows driver consultant based on the West Coast. His company, Azius Developer Training, offers training seminars in a variety of subject areas, including driver programming.