This article was written back when Visual Studio 6 was new. As such, I cannot guarantee that the content of this article still applies in modern Windows environments.
The Windows registry is an excellent place to store program information. From recent file lists to program settings, the registry provides programmers with a central location to store information for future use. Registry access can be quite simple, provided that you accept a few limitations. First, you must be willing to store your registry values on a per-user basis (rather than for all users). Second, you may only read and write values to your own application's registry branch. Poking around in arbitrary places in the Windows registry is somewhat more complicated than the method provided in this article. If you are interested in the advanced method of access, feel free to read the article I've written on the subject.
Do not assume that the constraints mentioned above render this method of registry access useless. I personally use this registry access method for all of my applications, using the advanced access method only when necessary. The simple method described below will do everything you need it to do for simple storage of application specific information.
Enabling Registry Access
The method we will use to access the registry comes through the legacy CWinApp
Initialization File (*.ini) functionality. This means of access gives us read and write permissions to the following registry key tree branch:
HKEY_CURRENT_USER\Software\<Your_Company_Name>\<Your_Program_Name>\
We first need to add the following line of code to the InitInstance()
function of our program. If you are writing an SDI or MDI based application, this function call should have already been inserted by the AppWizard (when you first created the project). For dialog based programs, you must manually insert the function call. Here's the code:
SetRegistryKey(_T("Your Company Name or Identity"));
You should obviously replace the "Your Company Name or Identity" string with an appropriate value. This string identifies the registry branch in which your application settings will be stored. By making this call to SetRegistryKey
, we set the value of the m_pszRegistryKey
variable, which tells our CWinApp
object to write all preference to the registry; not to an INI file.
Setting the Application Title
Now we need to either add or modify the following entry in the string table resource:
AFX_IDS_APP_TITLE
This string's value should be set to what you want your program to be called in the registry. As you probably can deduce, this will take the place of the <Your_Program_Name>
entry in the registry branch mentioned at the beginning of this article. I usually use the program name itself (for example, I use the string "Paper Plus" for my wallpaper changing program).
Reading and Writing Keys
You will find an instance variable of your application called theApp
in your CWinApp
derived class file (usually named <projectname>.cpp). This instance is a global object and we will use it to read and write values from the registry. Select this variable declaration and copy it to the clipboard (make sure you copy rather than cut). Then decide which class you will be doing your registry reading and writing in. For a dialog based application, I usually place my registry reading and writing code in the CDialog
derived class. Specifically, the InitDialog()
method is where I read my stored values and the OnDestroy()
method is where I do the writing.
Open up the .cpp file for the class that you have selected. At the top of this file (outside of any class definitions), paste the declaration of the CWinApp
object we just copied, and make it an extern variable, just like this (obviously, CYourApplication
will be whatever type your application variable is):
extern CYourApplication theApp;
Once you've declared this variable to be an extern
, you can begin reading and writing values. Before we discuss how, let's first take a look at how keys are stored. We already know what registry branch we have access to, but what structure gets used within that branch? It's actually quite simple:
\<Section Name>\<Entry Name>
Think of the section as being a folder, and think of the entry name as being a file in that folder. Using this analogy, envisioning the structure of the registry is easy. Sections are merely a way to organize your entries, and they don't have to be used (read on to find out how and why). But they make things nice and neat, so it's good practice to use them. To write or read some values, use code similar to the following:
// Code to write some values
// Usually occurs right before the application exits
theApp.WriteProfileInt("", "Keep On Top", m_KeepOnTop);
theApp.WriteProfileString("Files", "Last Saved", m_LSFile);
// Code to read some values
// Usually occurs right after the application starts
m_KeepOnTop = theApp.GetProfileInt("", "Keep On Top", 0);
m_LSFile = theApp.GetProfileString("Files", "Last Saved", "");
Understanding the Code
These lines of code deserve an explanation. Each of these functions take 3 parameters:
- Points to a null-terminated string that contains the section name.
- Points to a null-terminated string that contains the entry name.
- The default value of the entry (if reading), or the value to store for the entry (if writing).
So, as you can see from my example code, the section name can be empty ("") or it can point to a name you specify ("Files"). If you decide to use an empty section value, the registry entries you write to will appear in the branch specified by:
HKEY_CURRENT_USER\Software\<Your_Company_Name>\<Your_Program_Name>\
The entry name can be whatever you want it to be, but it is strongly recommended that you make it readable, so that users of your program can edit the registry values manually should they so desire.
The context of the third parameter in the functions mentioned above changes between reading and writing values. If you are writing a value, this third parameter is the variable name that contains the value to be written. Conversely, if you are reading a value, the third parameter specifies the default value to use should the key not already exist. This is an incredibly handy way to initialize program settings after a user installs your application for the first time. Also note that, when reading values, the return value of the GetProfileXXXXX()
calls is the value of the entry that was read.
As you can see, Windows registry access on an application level isn't a difficult task. Accessing other areas of the registry is a little more involved, however, and I cover that very topic in my advanced registry article.