If your application has to save settings, you should not count on being able to write to the system Registry. Why not use an XML file to save your settings? More and more companies are locking down the registry on users computers. You are ultimately going to run into a problem if you use VBs SaveSetting function to save your applications settings. Obviously, none of us want to go back to the stone age of .INI files, uggh! This article shows you a code class that I wrote to solve the problem with XML.
This class provides overloaded methods of VBs GetSetting and SaveSetting functionality. I have written it so that no program changes have to be made, other than to instantiate an instance of the class and place the object instance name in front of all GetSetting and SaveSetting function calls. Actually, the class could have been written as a module (C# programmers, pretend I didn't use the word Module), and then it would not have to be instantiated. However, I wrote it as a class for several reasons. First, I program in both VB.NET and CSharp, so I am attempting to consider both languages as I write new code. C# does not support modules; rather it provides Shared Classes. You can do the same thing in VB.NET by making all methods and variables Shared. But, then I would have to place the name of the class as a prefix to all references to GetSetting or SaveSetting, just as if I were instantiating it as an object. Secondly, I have written the class so that an application could have multiple XML files (setting files) if desired. Additionally, the class is designed to imitate different user profiles having their own settings. In other words, if multiple users were to share one computer, with different logon names, this class will support either a shared setting file, or a setting file for each user.
As you examine the code for the class, you will see that the SaveSetting and GetSetting methods support the calls exactly as if the user were using the built-in VB.NET functions. That was on purpose so the user does not have to change the respective calls. You will note that the constructor accepts a Boolean name "AllUsers". If this Boolean is True, an XML file will be named just using the passed AppTitle string, pased to the respective Get and Set functions. However, if the Boolean is False, the class will append the UserName from the Environment as part of the XML filename, thus allowing multiple users to share a computer and your application, while maintaining their own settings. Finally, there is a Public property called "AlternatePath", which allows the user to supply the path where they want the settings saved. Again, not only do IT departments lock down the Registry, but they also protect the directory from which an application is executed. If this is the expected case, as it should be, then your application should prompt the installer for a temporary file path where it can write an XML file.
Initially, your application may not have any XML setting file(s), so the class will return the default values that your application passes when calling GetSetting.
I have only provided three Overloaded metods for each of the respective functions, because Integer, String, and Boolean will normally cover most application settings. If you need another type of setting, simply add a pair of overloads for the needed type.
Figure 1 shows the VB.NET code for the class. I know that C# programmers don't normally have access to GetSetting and SaveSetting (which from a VB programmers perspective, are great functions), so I have taken the time to convert the class to C#. I hope it might be used by a C# programmer.
The class is straight-forward, nothing fancy, so I won't bore you with further verbage on how it works. The following few lines show how to call the two methods.
| Dim r As New CSettings(True) CRegions.InsertRegionsInNewClass = _ r.GetSetting(AppTitle, Settings, "IRNC", "N") r.SaveSetting(AppTitle, Settings, "IRNC", _ IIf(Me.optYesInsert.Checked, "Y", "N")) |
| ''' Purpose: Replacement Class for VB GetSetting and ''' ''' SaveSetting. Designed to replace the ''' saving of application Settings in the registry ''' with saving in an xml file in the installation directory. ''' Allows user to set an alternate path in case of install ''' directory lockdown. Allows user to have their own Settings ''' xml file or use one shared by all users on the same machine. ''' Allows user to have multiple "AppNames" creating multiple ''' xml files and multiple Settings (e.g., Settings, Registration, etc.) ''' Completely simulates VB GetSetting and SaveSetting by simply ''' instantiating this class and prefacing Get/SaveSetting calls with ''' the instance object name, e.g., r.GetSetting(....). ''' Author: Les Smith ''' Date Created: 01/24/2004 at 11:00:35 ''' CopyRight: KnowDotNet ''' '''*************************************** ''' Option Strict On Imports System Public Class CSettings #Region " Class Variables " Private ds As DataSet Private xmlFile As String = String.Empty Dim _AllUsers As Boolean Const XML As String = ".xml" Private _AlternatePath As String = String.Empty #End Region #Region " Public SaveSetting Overloaded Methods " Public Overloads Sub SaveSetting(ByVal AppTitle As String, _ ByVal Settings As String, _ ByVal Key As String, _ ByVal Value As Boolean) SaveSetting(AppTitle, Settings, Key, CStr(Value)) End Sub Public Overloads Sub SaveSetting(ByVal AppTitle As String, _ ByVal Settings As String, _ ByVal Key As String, _ ByVal Value As Integer) SaveSetting(AppTitle, Settings, Key, CStr(Value)) End Sub Public Overloads Sub SaveSetting(ByVal AppTitle As String, _ ByVal Settings As String, _ ByVal Key As String, _ ByVal Value As String) ' this method sets or adds the value row for the passed key Try If xmlFile.Length = 0 Then SetupXMLFileName(AppTitle) If ds Is Nothing Then ds = New DataSet Dim dt As DataTable = CreateDT(Settings, Key, Value) ds.Tables.Add(dt) Else Dim dt As DataTable = ds.Tables(Settings) If dt Is Nothing Then ' create new datatable named Settings dt = CreateDT(Settings, Key, Value) ds.Tables.Add(dt) Else Dim i As Integer Dim b As Boolean For i = 0 To dt.Rows.Count - 1 If CStr(dt.Rows(i).Item("key")) = Key Then dt.Rows(i).Item("value") = Value b = True Exit For End If Next If Not b Then AddRow(dt, Key, Value) End If End If End If ds.WriteXml(xmlFile) Catch ex As System.Exception StructuredErrorHandler(ex) End Try End Sub #End Region #Region " Public Overloaded GetSetting Methods " Public Overloads Function GetSetting(ByVal AppTitle As String, _ ByVal Settings As String, _ ByVal key As String, _ ByVal keyvalue As Integer) _ As Integer Dim o As Object = GetSetting(AppTitle, Settings, key, CStr(keyvalue)) If o Is Nothing Then Return keyvalue Else Return CType(o, Integer) End If End Function Public Overloads Function GetSetting(ByVal AppTitle As String, _ ByVal Settings As String, _ ByVal key As String, _ ByVal keyvalue As Boolean) _ As Boolean Dim o As Object = GetSetting(AppTitle, Settings, key, CStr(keyvalue)) If o Is Nothing Then Return keyvalue Else Return CType(o, Boolean) End If End Function Public Overloads Function GetSetting(ByVal AppTitle As String, _ ByVal Settings As String, _ ByVal key As String, _ ByVal keyvalue As String) _ As Object Dim i As Integer Dim dr As DataRow Dim dt As DataTable Try If xmlFile.Length = 0 Then SetupXMLFileName(AppTitle) ' this method returns the value specified by the key If ds Is Nothing Then dt = GetXml(Settings) If dt Is Nothing Then Return keyvalue Else dt = ds.Tables(Settings) End If For i = 0 To dt.Rows.Count - 1 dr = dt.Rows(i) If CStr(dr("Key")) = key Then Return dr("Value") End If Next Return keyvalue Catch ex As System.Exception StructuredErrorHandler(ex) End Try End Function #End Region #Region " Private Methods " Private Function CreateDT(ByVal Settings As String, ByVal key As String, _ ByVal value As Object) As DataTable Dim dt As DataTable dt = New DataTable(Settings) dt.Columns.Add("Key", Type.GetType("System.String")) dt.Columns.Add("Value", Type.GetType("System.String")) AddRow(dt, key, value) Return dt End Function Private Sub AddRow(ByRef dt As DataTable, ByVal key As String, _ ByVal value As Object) Dim newRow As DataRow = dt.NewRow newRow(0) = key newRow(1) = value dt.Rows.Add(newRow) End Sub Private Function GetXml(ByVal tablename As String) As DataTable If Not IO.File.Exists(xmlFile) Then Return Nothing End If ds = New DataSet ds.ReadXml(xmlFile) Dim dt As DataTable = ds.Tables(tablename) Return dt End Function Private Sub SetupXMLFileName(ByVal fn As String) ' Returns filename for xmlfile, generated by using ' AppTitle suppliied to the two public methods and then ' boolean supplied to the constructor. ' install directory may be locked so check to see if ' caller supplied an alternate directory. Dim s As String If _AlternatePath.Length = 0 Then s = IO.Path.GetDirectoryName( _ Reflection.Assembly.GetExecutingAssembly.Location()) Else s = IO.Path.GetDirectoryName(_AlternatePath) End If If _AllUsers Then xmlFile = s & "\" & fn & XML Else xmlFile = s & "\" & fn & "_" & Environ("UserName") & XML End If End Sub #End Region #Region " Constructor " Public Sub New(ByVal AllUsers As Boolean) Me._AllUsers = AllUsers End Sub #End Region #Region " Property Methods " Public Property AlternatePath() As String Get Return _AlternatePath End Get Set(ByVal Value As String) _AlternatePath = Value End Set End Property #End Region End Class |
| using System; using System.Reflection; using System.Data; namespace CSharp2003WindowsApplication1 { /// <summary> /// Summary description for CSettings. /// public class CSettings { #region " Class Variables " private DataSet ds; private string xmlFile = String.Empty; private bool m_AllUsers; const string XML = ".xml"; private string m_AlternatePath = String.Empty; #endregion #region " SaveSetting Methods " public void SaveSetting(string AppTitle, string Settings, string Key, bool Value) { SaveSetting(AppTitle, Settings, Key, Value.ToString()); } public void SaveSetting(string AppTitle, string Settings, string Key, int Value) { SaveSetting(AppTitle, Settings, Key, Value.ToString()); } public void SaveSetting(string AppTitle, string Settings, string Key, string Value) { if (xmlFile.Length==0) SetupXMLFileName(AppTitle); if (ds == null) { ds = new DataSet(); DataTable dt = CreateDT(Settings,Key,Value); ds.Tables.Add(dt); } else { DataTable dt = ds.Tables[Settings]; if (dt == null) { // create new datatable dt = CreateDT(Settings,Key,Value); ds.Tables.Add(dt); } else { bool b=false; for (int i = 0; i < (int) dt.Rows.Count;i++) { if((string)dt.Rows[i].ItemArray[0] == Key) { dt.Rows[i].ItemArray[1] = Value; b = true; break; } } if (b != true) AddRow(ref dt, Key, Value); } } ds.WriteXml(xmlFile); } #endregion #region " GetSetting Methods " public int GetSetting(string AppTitle, string Settings, string Key, int KeyValue) { string o = GetSetting(AppTitle,Settings,Key,KeyValue.ToString().ToLower()); if (o == null) return KeyValue; else return int.Parse(o); } public bool GetSetting(string AppTitle, string Settings, string Key, bool KeyValue) { string o = GetSetting(AppTitle,Settings,Key,KeyValue.ToString().ToLower()); if (o == null) return KeyValue; else return bool.Parse(o); } public string GetSetting(string AppTitle, string Settings, string Key, string KeyValue) { DataRow dr; DataTable dt; if (xmlFile.Length == 0) SetupXMLFileName(AppTitle); if (ds == null) { dt = GetXml(Settings); if (dt == null) return KeyValue; } else dt = ds.Tables[Settings]; for (int i = 0; i < dt.Rows.Count; i++)<BR> { dr = dt.Rows[i]; if ((string) dr["Key"] == Key) return (string) dr["Value"]; } return KeyValue; } #endregion #region " Private Methods " private DataTable CreateDT(string Settings,string Key,string Value) { DataTable dt; dt = new DataTable(Settings); dt.Columns.Add("Key",Type.GetType("System.String")); dt.Columns.Add("Value",Type.GetType("System.String")); AddRow(ref dt,Key,Value); return dt; } private void AddRow(ref DataTable dt, string Key, object Value) { DataRow newRow = dt.NewRow(); newRow[0] = Key; newRow[1] = Value; dt.Rows.Add(newRow); } private DataTable GetXml(string tablename) { if (!System.IO.File.Exists(xmlFile)) return null; ds = new DataSet(); ds.ReadXml(xmlFile); DataTable dt = ds.Tables[tablename]; return dt; } /* Returns filename for xmlfile, generated by using AppTitle suppliied to the two public methods and then boolean supplied to the constructor. install directory may be locked so check to see if caller supplied an alternate directory. */ private void SetupXMLFileName(string fn) { string s; if (m_AlternatePath.Length == 0) s = System.IO.Path.GetDirectoryName(System.Reflection.Assembly. GetExecutingAssembly().GetModules()[0].FullyQualifiedName); else s = System.IO.Path.GetDirectoryName(m_AlternatePath); // compact framework not supported if(m_AllUsers==true) xmlFile = s + "\\" + fn + XML; else xmlFile = s + "\\" + fn + "_" + Environment.UserName + XML; } #endregion #region " Constructor " public CSettings(bool AllUsers) { m_AllUsers = AllUsers; } #endregion #region " Public Properties " public bool AllUsers { get { return (bool) m_AllUsers; } set { bool m_AllUsers= value; } } public string AlternatePath { get { return m_AlternatePath; } set { m_AlternatePath = value; } } #endregion } } |