With the subject of the Registry frequently coming up in the forum I thought I would take time to write a FAQ about how to save you applicationÆs settings without using the Registry.
Why? The reasoning behind this is simply that IÆve never really been a fan of the Registry or the principal of one, as it is all too easy to corrupt. By storing your applicationÆs configuration information in its own file you remove the reliance on the registry being operational for your own application to work. Indeed, your own application may even be a registry editor!
The code that follows is a Visual Basic class file that provides wrappers around the low-level Windows API file handling routines. Constructed to use events the code is easily extensible to suit virtually all of your configuration needs.
1.) To include the code in your project, simply cut and paste the code into notepad or another similar editor, and save the file as config.cls.
If you use notepad be sure to include the ôö around the filename (ôconfig.clsö) to force notepad into not appending an additional .txt extension to the fileÆs name.
2.) Once you have the source on disk, to include the code in your project open the Project Explorer (Ctrl+R), select your project then right click. From the menu that appears select Add, then from its sub menu select Class module.
3.) From the dialog presented, select the Existing tab. If you saved the class file in your projectÆs directory it should appear in the list. If not, then navigate to the location where it is stored. Highlight the file the click open or double click on the class name. The class will now be included in your project.
Depending on your intentions implementing the Config class is really a matter of personal choice. The class provided has been built for demonstration purposes so will require some additional modifications to support your own project.
A zip file of 3,924 bytes, (4K) containing a VB Project and test form that demonstrates the class is available for download here.
Public Event CfgIOError(m_Error As String) Public Event cfgWrite() Public Event cfgRead()
Private Type ConfigInfo m_Item1 As Integer m_Item2 As Long m_Item3 As Boolean m_Item4 As String * 33 ' Max string length is 32 chars. End Type
Dim cfgInfo As ConfigInfo ' Structure to hold configuration information Dim m_hFile As Long ' File Handle Dim m_szFilePath As String ' Fully qualified path to config file.
' Win32 API Declaration for File I/O, etc. Private Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, ByVal lpSecurityAttributes As Long, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long Private Declare Function WriteFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToWrite As Long, lpNumberOfBytesWritten As Long, ByVal lpOverlapped As Long) As Long Private Declare Function ReadFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, ByVal lpOverlapped As Long) As Long Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
' Configuration File Name Private Const CFG_FILE = "myconfig.cfg" ' Change this to suit you
Public Property Let SetInt(ByVal vData As Integer) cfgInfo.m_Item1 = vData End Property
Public Property Get GetInt() As Integer GetInt = cfgInfo.m_Item1 End Property
Public Property Let SetLong(ByVal vData As Long) cfgInfo.m_Item2 = vData End Property
Public Property Get GetLong() As Long GetLong = cfgInfo.m_Item2 End Property
Public Property Let SetBool(ByVal vData As Boolean) cfgInfo.m_Item3 = vData End Property
Public Property Get GetBool() As Boolean GetBool = cfgInfo.m_Item3 End Property
Public Property Let SetStr(ByVal vData As String) cfgInfo.m_Item4 = vData End Property
Public Property Get GetStr() As String GetStr = cfgInfo.m_Item4 End Property
Public Function Initialise() As Boolean Dim bOk As Boolean ' Initialised to False by default m_szFilePath = "c:\Projects\Config\" & CFG_FILE m_hFile = CreateFile(m_szFilePath, 0, 0, ByVal CLng(0), OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0) If (m_hFile = INVALID_HANDLE_VALUE) Then ' The config file is missing so set sensible defaults. RaiseEvent CfgIOError("Configuration file is Missing! These are defaults.") ' These values indicate the ListIndex value of the value's control in the properties form. cfgInfo.m_Item1 = 1 ' Radio Button cfgInfo.m_Item2 = 64 ' Combo Box cfgInfo.m_Item3 = True ' Check Box cfgInfo.m_Item4 = "George, Bungle & Zippy" ' Text Control (70s cartoon) Else ' Close the file as we only checked to see if it existed If (CloseFile()) Then ' Now read the configuration data proper bOk = ReadConfig() ' Set bOk to the return value of ReadConfig() End If End If ' Return the Results to the Caller. Initialise = bOk End Function
Public Function ReadConfig() As Boolean Dim dwRead As Long, bOk As Boolean m_hFile = CreateFile(m_szFilePath, GENERIC_READ, 0, ByVal CLng(0), OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0) If (m_hFile = INVALID_HANDLE_VALUE) Then RaiseEvent CfgIOError("Error opening Configuration file for Reading") Else If (ReadFile(m_hFile, cfgInfo, Len(cfgInfo), dwRead, ByVal CLng(0))) Then RaiseEvent cfgRead ' File read successfully so raise event. Else RaiseEvent CfgIOError("Error reading configuration file!") ' Ooops! End If bOk = CloseFile() ' Close File End If ReadConfig = bOk End Function
Public Function WriteConfig() As Boolean Dim dwWrite As Long, bOk As Boolean ' Truncate (dump) the File everytime it's written. m_hFile = CreateFile(m_szFilePath, GENERIC_WRITE, 0, ByVal CLng(0), CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0) If (m_hFile = INVALID_HANDLE_VALUE) Then RaiseEvent CfgIOError("Error opening Configuration file for Writing!") Else If (WriteFile(m_hFile, cfgInfo, Len(cfgInfo), dwWrite, ByVal CLng(0))) Then RaiseEvent cfgWrite ' File written successfully so raise event. Else RaiseEvent CfgIOError("Error writing configuration file!") End If bOk = CloseFile() End If WriteConfig = bOk End Function
Private Function CloseFile() As Boolean CloseFile = CloseHandle(m_hFile) End Function
After the class is included in your project use the Dim and set statements to create an instance.
Dim m_Config as Config Set m_Config as New Config
This will then allow you access to the classes Functions. Is should be pointed out that the first step in operation once the class is instantiated is to call the Initialise method.
Of course if you want to make use of this code yourself all you need to do is modify the ConfigInfo type to suit your needs. Then create the accessors required to get and set these values.
For example if you add a member to the ConfigInfo structure called m_Username, you need to create the Get and Let accessors for it. Since Username would be a string you would add the following code:
Public Property Let Username(ByVal vData As String) cfgInfo.m_Username = vData End Property
Public Property Get Username() As String Username = cfgInfo.m_Username End Property
Also, for every member variable you remove from the ConfigInfo type you also need to remove the Get & Let accessors for it. You can do this simply by deleting the appropriate lines from the source file.
Should you have any questions regarding this FAQ or the code within then please feel free to contact me using the link below.
I would also appreciate it if you could rate this FAQ, again using the links below.