IntroductionIntroductionThe Setup API is the recommended way to parse driver.INF and txtsetup.OEM files. Unfortunately, the Setup API is a collection of C style functions for which the .NET Framework has no equivalent interface. This article provides some simple .NET (C#) classes that wrap common functions from the Setup API used for parsing INF files. BackgroundI once had a need to parse hundreds of driver.INF, txtsetup.OEM, and other random .INF files written by dozens of third-party companies and individuals. I quickly found that the syntax of these files is more complex than I originally thought. At first they appear simple, for example: [Section 1]
Background
Using the Code
InfFile
InfLine
Error Checking and Reporting
Sample Code
History
key1 = field1,field2,fieldN
key2 = int,string,or,binary data
no,key,on,this,line[Section2]
key1 = field1,field2[Section 1]
keyN = field1,field2,fieldN
There can be many sections, each with many "key" lines. The keys are not necessarily unique, even within a section. Keys are not even required (a line can just be a list of values). Notice that [Section 1] appears twice. This is valid syntax that the Setup API handles transparently, as if the section wasn't physically split. There can be many fields on a given line. The fields can contain integers, strings, multi-strings, and binary data. There are all kinds of rules regarding comments, string fields with embedded blanks/commas/quotes, decimal vs. hex integer formats, line continuation, and localized string substitution. The text encoding for .INF files is not ASCII or even UTF-8. It's "Windows Western European", also known as Code Page 1252. This is a single-byte encoding very similar to, but not the same as, ASCII. Certain characters, such as the "registered" or "trademark" symbols (I don't remember which) have different encodings in Code Page 1252 compared to ASCII (or don't even exist in ASCII). Heed my warning, grasshopper: You do not want to parse such files manually. You want to use the Setup API since it can handle all the syntactic nuances you might stumble across.After using the Setup API directly for a while, I found myself repeating the same code patterns and error checking over and over. Many of the functions use a file handle or a C structure just begging to be encapsulated in a class, so I decided to write some C# wrapper classes. Using these classes made my code significantly cleaner and easier to write. Using the CodeThe download contains two classes you will use directly: InfFile and InfLine.InfFileThe InfFile constructor takes a file path. It merely captures the path, so no errors are possible.
InfFile.Open() opens the file. It returns 0 if it succeeds, a Win32 error code if it fails. More on error checking later.
InfFile.EnumSection() can be used to enumerate the sections within the file.
InfFile.FindFirstLine() returns an InfLine representing the first line within the specified section.
InfFile.FindFirstKey() returns an InfLine representing the first line within the specified section having the specified key.
When you're finished with the file, be sure to call InfFile.Close() or Dispose(). InfFile implements IDisposable.
InfLineThe InfLine class represents a line from within a section in the file. It has methods that do the following:Get the number of fields on the line.
Get the string, multi-string (array), int, or bytes in the Nth field
Get an InfLine for the next sequential line or the next line with a given key.
When calling InfLine.GetString(int fieldNum), pass 0 to get the line's key (value left of "="). Pass 1 to get the first comma-separated value to the right of the "=", and so on. As a rule, you have to have some idea of what sections and keys you're looking for, the type of data in each field, and so on. When parsing a true driver.inf file, many lines are references to other sections. For example, a string read from one line might the name of (or part of the name of) a section. Error Checking and ReportingBoth classes contain two error-related properties: LastError and LastMessage. LastError is the Win32 error code from the last method called. After calling any method in either class, you can check if LastError is 0. If it's not 0, an error occurs and LastMessage contains the error message corresponding to the error code in LastError. These properties are reset when any method is called. Also, most of the methods in both classes, such as InfLine.GetInteger(), have two overloads. In this case, both overloads accept an int specifying the field number that should contain an integer. An error occurs if the field doesn't contain an integer or there is no such field. The first overload (shown below) returns a Win32 error code (error codes are always uint). If no error occurs, it returns 0 and the int value read from the file is passed back as an out parameter. The second overload returns no error information. public uint GetInteger(int fieldNum, out int intVal);
public int GetInteger(int fieldNum);
In either case, you can check LastError after calling the method, but sometimes it's more convenient to check the error code returned directly by the method.
Read more: Codeproject