Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Saving an application's settings without using the Registry

Persisting Data

Saving an application's settings without using the Registry

by  williamu  Posted    (Edited  )
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 [link http://wurquhart.co.uk/ConfigDemo.zip]here[/link].

Code:
VERSION 1.0 CLASS
BEGIN
  MultiUse = -1  'True
  Persistable = 0  'NotPersistable
  DataBindingBehavior = 0  'vbNone
  DataSourceBehavior  = 0  'vbNone
  MTSTransactionMode  = 0  'NotAnMTSObject
END
Attribute VB_Name = "Config"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Attribute VB_Description = "Configuration Data Persistance"
Attribute VB_Ext_KEY = "SavedWithClassBuilder6" ,"No"
Attribute VB_Ext_KEY = "Top_Level" ,"Yes"
Option Explicit

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

' Const Values used for above.
Private Const INVALID_HANDLE_VALUE = -1
Private Const GENERIC_READ = &H80000000
Private Const GENERIC_WRITE = &H40000000
Private Const FILE_SHARE_READ = &H1
Private Const FILE_SHARE_WRITE = &H2
Private Const CREATE_ALWAYS = 2
Private Const CREATE_NEW = 1
Private Const OPEN_ALWAYS = 4
Private Const OPEN_EXISTING = 3
Private Const TRUNCATE_EXISTING = 5
Private Const FILE_ATTRIBUTE_NORMAL = &H80

' 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.

m_Config.Initialise

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.
Register to rate this FAQ  : BAD 1 2 3 4 5 6 7 8 9 10 GOOD
Please Note: 1 is Bad, 10 is Good :-)

Part and Inventory Search

Back
Top