There's a temptation for developers of bespoke software to hard-code important stuff into their programs: stuff that they don't think will ever change, but which eventually does. Over the years there must have been thousands of useful little tools rendered useless because whoever wrote them hard-coded something important – the IP address of the database server it uses, for instance, or the name of an essential mail server.
The right way to write your bespoke programs is, of course, to store the stuff that you might need to change somewhere where it can be changed without having to recompile the program code. So where do you look?
If the tool you're developing is Windows-centric and isn't going to be run anywhere else, there's really only one sensible place to put your configuration information: the Windows Registry. Although Windows historically uses text-based .INI files to store changeable data, the registry was introduced with the advent of Windows 95 to provide a more structured, centralised repository for configuration data. The registry is hierarchical, and the various developer tools available make reading and writing registry data a breeze. In the following example we've stored some database connection information (database name, server IP address, TCP port number, user ID and password) in the HKEY_LOCAL_MACHINE\Software part of the registry in a sub-section called "MyCompany":
myKey = Registry.LocalMachine.OpenSubKey("Software\\MyCompany")
If myKey Is Nothing Then
MsgBox("Failed to open registry entry")
txtDBName.Text = CStr(myKey.GetValue("DBName", ""))
txtIP.Text = CStr(myKey.GetValue("IP", ""))
txtPort.Text = CStr(myKey.GetValue("Port", ""))
txtUserID.Text = CStr(myKey.GetValue("UserID", ""))
txtPassword.Text = CStr(myKey.GetValue("Password", ""))
If what you're writing is designed for use on multiple platforms, you can't rely on there being some generic equivalent of the Windows Registry – such a thing just doesn't exist. The answer is usually to store the information in one or more text files instead.
If you have a simple program that has a handful of basic parameters (e-mail server address, user ID, IP port number, that kind of stuff) then you don't need to go too mad – a simple text file will do, with one line per entry in a form that your program can easily parse. This is how many operating systems hold their own changeable data, in fact – look at any Unix and you'll see configuration files full of one-line-per-item values, and Windows .INI files work in much the same way. This snippet is from WIN.INI, and contains some entries that the WS_FTP Pro FTP client has plonked in there:
DIR=C:\Program Files\WS_FTP Pro
DEFDIR=C:\Program Files\WS_FTP Pro
There is, however, a feature of the Windows registry that it's often quite nice to be able to replicate in a file-based configuration schema: the hierarchical nature of the system. Imagine you have a particular system for which you've written a handful of useful little programs, all of which have some common parameters – the database server connection details, for instance. The last thing you want is to have to set these items in every single program you run, so you'd probably define some common parameters and use them in every program – the "set once, use many" approach. Of course, you may also want to use application-specific configuration data too (some data items might be relevant only to one program), and it's here that a hierarchical approach makes sense.
The obvious path to take is XML. It's modern, it's easy, and most programming systems include all the tools you need to load and parse XML files for easy insertion and extraction of data. So you might end up with an XML-based configuration file whose body looks something like this:
Which approach you take is entirely up to you. A good rule of thumb, though, is to go with an approach whose form you can rigidly enforce and verify.
Of the three approaches described here, XML is in fact the most robust, because you can enforce the data type and field size for each item simply by defining an associated schema and telling the parser to verify the data against that schema. This is a neat way to protect yourself against viruses and hackers – you'll never be the victim of a buffer over-run attack if the XML parser spots overly-long strings before they even reach the application.
The registry approach is second-best because it at least it has some hierarchy to it (and unlike XML, it's a centralised repository rather than just a random text file on a disk).
And if you insist on using text files, resign yourself to writing shedloads of code to parse everything and verify that the structure is in order before using the data.