Click here to Skip to main content
15,881,757 members
Articles / Programming Languages / Visual Basic
Article

IniFile Class using VB.NET

Rate me:
Please Sign up or sign in to vote.
4.54/5 (36 votes)
21 Jan 20046 min read 333.6K   8.1K   61   38
A .NET control to assist in the creation and manipualtion of *.ini files

Introduction

The February 2004 edition of MSDN magazine included some example code on how to build a custom class to save your winform settings to an *.ini file. This was a great idea, but the code presented was extremely limited, and basically only offered some Getval/Setval functions and a custom function to Get/Set your form settings quickly. Further hampering this code was its reliance on the Kernel32.dll *.ini file functions (WritePrivateProfileString, GetPrivateProfileString). I searched on Google for a better solution, but found nothing.

Many programmers choose to store their custom program settings in the registry, but this defeats the XCopy deployment paradigm of .NET programs. You should be able to copy settings along with the executable and go. Microsoft would have you store this information in an XML file, but the fact is that many end users (and even many programmers) still prefer the simple to open/edit format of the venerable old *.ini file. But Microsoft left out any kind of native support for this storage solution in .NET.

I decided to write my own class to handle this function. I'm not sure why every reference to *.ini files begins and ends with accessing the Kernel32.dll. I suppose people think that this would make things faster, or perhaps more accurate or secure. But the fact is that *.ini files are ultimately text files, and there is no reason they can't be handled as such. Furthermore, I don't want to be limited by the Get/Set nature of the Kernel32.dll functions. Controls designed for .NET are feature rich in nature, and this one should be no different.

Aside from getting and setting key values, I want to able to add, remove and edit sections. I want to be able to comment/uncomment key values, or even entire sections with ease. I want to be able to move a key from section to section. I want to be able to sort my sections and keys for easy reading. I want an easy way to store my form settings. And just to top it off, let's add the ability to dump an *.ini file out to XML should I decide to take that route in the future. In short, it should be a fully featured, simple to use control. Oh, and it should be free.

Using the code

Download the attached source code, which contains both the class file, and demo project - an Ini File Editor (of course). The code for the class is heavily commented, and should be easy to understand. There is also a detailed help file included, produced by NDoc and the VB.DOC Visual Studio addin.

A simple example of the class file would look something like this:

VB.NET
Imports IniFile
Dim myIniFile As New IniFile("C:\Test.ini") 
    'Create an IniFile object and load the *.ini file
myIniFile.AddKey("MyKey","MyValue","MySection") 
    'Create a section, and add new key/value to it
myIniFile.Sort() 'Sort all the sections and keys
myIniFile.ToXML("C:\Test.xml") 'Save the file to XML
myIniFile.Save("C:\Test.ini") 'Save the file

Points of Interest

  • Add, Delete, Edit, Comment and UnComment Sections
  • Add, Delete, Edit, Comment, UnComment and Move Keys/Values
  • Save form settings easily
  • List all Sections
  • Dump to XML
  • Sort file

The IndexOf() and Sort() Conundrums

While speed is not of the essence in this class (I simply cannot imagine a scenario where an *.ini file is being referenced thousands of times a second, or put under any kind of heavy load situation), I did try to make things as simple and fast as possible.

My first draft of this class was scrapped completely. It was based on a single ArrayList - the contents of the file were read line-by-line into the ArrayList, and then had to meticulously examined and manipulated in order to perform the necessary functions. It worked, but the code was ugly, and every time I tried to add even the most simple feature, I found myself re-writing huge hunks of code, and introducing new bugs.

It was then that I remembered I was dealing with an object oriented based language, and I should re-think my approach. I tried to think like Microsoft. Ok, so we have an *.ini file, that's an object. That file is made up of sections, those are objects. And each section has keys/values. Those are objects too. Suddenly, this made a lot sense, and everything fell into place from there.

The main component, the IniFile, is an ArrayList. I chose this, because the ArrayList class has some powerful features that make life easy, such as Add(), RemoveAt(), and IndexOf(), as well as sorting and searching features. This made adding and manipulating sections easy. The Section object is also based on an ArrayList, since it too needs to deal with child objects, namely, the keys. And keys are simple classes, with simple name/value strings.

This posed an interesting problem for me. Consider the following example:

VB.NET
Dim myAL As New ArrayList()
myAL.Add("The")
myAL.Add("quick")
myAL.Add("brown")
Dim Quick_Index = myAL.IndexOf("quick")

In the above code, Quick_Index would contain a value of 1, which is the index of the string object called "quick". Simple enough.

But now consider this - the main ArrayList of

IniFile 
(called Sections in the source code) contains not strings, but other ArrayLists (Sections). How do I use IndexOf() when the object I'm attempting to locate isn't a string object? And can I still sort the ArrayList? This same problem continues in the Sections Object, as it also contains custom classes (keys), and not string objects.

The sorting problem was solved by creating a custom comparer. The custom comparer implements IComparer, and allows me to direct the code as to how to compare one section to another.

VB.NET
Public Class SectionComparer
 Implements IComparer
 Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer  
 Implements System.Collections.IComparer.Compare
   Dim s1 As String = LCase(x.Name)
   Dim s2 As String = LCase(y.Name)
   Return s1.CompareTo(s2)
   End Function
 End Class

As you can see above, the custom comparer takes the x and y objects (does x = y?) and tells the computer how to go about comparing them. Since my Section objects each have a name value, I instructed the Compare function to compare those names (in lower case, just to be safe) and returned the result of that comparison. Then in the Sort() Function, I specify which comparer to use:

VB.NET
Dim mySC As SectionComparer = New SectionComparer
Sections.Sort(mySC)

That leaves me with the IndexOf() problem.

IndexOf() 
doesn't take a comparer object. So now what? Well, it turns out that IndexOf() uses the Equals() method of the objects it is comparing to determine if we have a match. When you are comparing custom classes however, .NET simply uses the default Equals() method, which is to say, it compares the memory address of the object. Since two objects will never share the same memory address, they will never be equal. The fix is to override the Equals() method of the class, and tell the computer how to compare equal values of our custom class, much in the same way that we did with the custom comparer. An excellent example of this is here.

The problem is, this still isn't working. Take a look at the commented code in the GetKeyIndex() function to give this a try. If you find an answer, please email me so that I can update the code, and this article.

A final note

This is the first release of this code. It needs lots of testing, and has lots of room for improvement. If you find any bugs, or have any suggestions for improvements, they are welcomed. Thanks, and I hope you find this code to be of value to you.

History

  • Initial release of source code and documentation.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Systems Engineer Virtual RadioLogic
United States United States
Todd Davis has been working in web and application development for several years, using Silverlight, ASP.NET, VB.NET, C#, C++ and Javascript, as well as a great deal of work with SQL server and IIS.

He currently works for Virtual Radiologic in Eden Prairie, MN, however he is better known for his varied work in the open source community, especially the DotNetNuke project for which he provided several world-renowned training videos and modules. A huge advocate of open source and open knowledge sharing, everything on his website (www.SeaburyDesign.com) is always offered for free.

Whenever he is not actively coding at his laptop (a rarity to be sure), he can be found woodworking, walking with his wife and kids, or motoring along the back roads of MN on his Harley Davidson Fatboy.

Comments and Discussions

 
GeneralPoor coding style Pin
carlop()3-Aug-05 0:27
carlop()3-Aug-05 0:27 
General.net technologies Pin
Anonymous8-Jul-05 21:08
Anonymous8-Jul-05 21:08 
GeneralThis code... Pin
George Hendrickson27-May-05 2:42
professionalGeorge Hendrickson27-May-05 2:42 
GeneralRead the value of a key in a section Pin
Knautzberg11-Mar-05 10:01
Knautzberg11-Mar-05 10:01 
GeneralRe: Read the value of a key in a section Pin
darthatom16-Sep-05 10:06
darthatom16-Sep-05 10:06 
Generala simple DataBase Pin
kyta5-Mar-05 17:18
kyta5-Mar-05 17:18 
GeneralRe: a simple DataBase Pin
Todd Davis6-Mar-05 1:54
Todd Davis6-Mar-05 1:54 
GeneralKey value not set when saving form Pin
kuhnsmadhouse12-Oct-04 9:01
kuhnsmadhouse12-Oct-04 9:01 
I noticed that the key value is not being set when I save a form using SaveFormSettings, and the section already exists in the ini file.

In the AddKey method, the key value is being passed in, but it only gets set if the key does not exist. Here is a revised AddKey method that fixes the problem. Revised part is between the asterisks (*).

Thanks for an otherwise fine utility class! Made my life easier!


Public Function AddKey(ByVal KeyName As String, ByVal KeyValue as ......
...
...
...

If Not GetKey(KeyName, SectionName) Is Nothing Then

'**Added by kuhnsmadhouse *******************************
Dim MyKey As Key
MyKey = GetKey(KeyName, SectionName)
MyKey.Value = KeyValue
'********************************************************
Return False 'verify that the key does *not* exist
End If

Dim ThisKey As New Key(KeyName, KeyValue, IsCommented) ......
...
...
End Function



kuhnsmadhouse
GeneralRe: Key value not set when saving form Pin
Anonymous12-Oct-04 9:04
Anonymous12-Oct-04 9:04 
GeneralRe: Key value not set when saving form Pin
Tom Sander31-Jan-05 9:41
Tom Sander31-Jan-05 9:41 
GeneralThanks! Pin
Michael J. Collins28-Jan-04 4:08
professionalMichael J. Collins28-Jan-04 4:08 
GeneralNice work, some problems Pin
huuhaa23-Jan-04 1:47
huuhaa23-Jan-04 1:47 
GeneralRe: Nice work, some problems Pin
Todd Davis23-Jan-04 2:44
Todd Davis23-Jan-04 2:44 
GeneralRe: Nice work, some problems Pin
Icharus19-Jul-04 17:04
Icharus19-Jul-04 17:04 
GeneralRe: Nice work, some problems Pin
ToshRa25-Sep-07 8:31
ToshRa25-Sep-07 8:31 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.