Dwarfsoft [GPA]

Ini File Handler for VBScript

by on Feb.27, 2009, under Scripting, Work


Print This Post Print This Post

I was recently working on an issue to do with managing .ini files in VBScript. I know what you are all going to say now: Why would you use an INI file when the registry is available for use?! Well, there is one instance that you may wish to use another form of configuration or information passing. In this instance we have an initiation of the Ghost Store method for the System Volume. To achieve a store on the system volume we require the PC to be rebooted and it then boots up into a BartPE environment to run the Ghost Store, and perform a few custom tasks. Therefore, the System Volumes Registry is not present (or requires mounting then reading, which has proven somewhat unreliable for me in the past).

So, the reason it came to developing the Ini file handler class is due to the need to provide some more controlled smarts into the store/restore system. Clusters, such as the one I work within, can be more proactive in their maintenance, and therefore require more advanced features than the corporate stock-standard release is likely to contain. As such the area in which I work is constantly involved in working towards a very automated maintenance process. My skills, lying within scripting, programming, and automation in particular, come in handy in this regard. I regularly disassemble the corporate releases to ensure that they will not break when released out into the wild of our corporate machines.

The store/restore process was one that I had previously tackled and modified due to the limitations of the corporate model. Unfortunately this modification was temporary, as the updated software that was released from corporate changed the model under which the store/restore process was to operate, and caused the modifications we had made locally to break.

The easiest way of reading Ini files in Windows is to use the Word.Application Object (as gathered quickly for demonstration from here):

Set objWord = CreateObject("Word.application")
WinDir = objWord.System.PrivateProfileString(FileName , Section , Key)

This, however, does not work in BartPE. Instead, I have developed a class that can be added into a VBScript and used very easily. It utilizes Dictionaries to keep the settings organised. This means that if it reads two settings in the same section with the same name, the value will reflect the last one (the one closest to the end of the file).

The full source of the IniFile handler are as follows:

Class IniFile
   Private mIniFile
   '
   '----------------------- Sub Load -------------------------------
   Public Sub Load(Filename)
      LoadIni FileName,False
   End Sub
   '-------------------- End of Sub Load ---------------------------
 
   Public Sub LoadIni(Filename,JustDefaults)
     Dim objFSO, objDictionary, objSubDictionary, file, ini, arr, line, splitline, tmpsplit  
     Set objFSO = CreateObject("Scripting.FileSystemObject")
 
     Set objDictionary = mIniFile
     Set objDictionary = CreateObject("Scripting.Dictionary")
     Set objSubDictionary = Nothing
     Set mIniFile = objDictionary
     If JustDefaults Then
        Read = False
     Else
        Read = True
     End If
 
     If objFSO.FileExists(Filename) Then
        Set file = objFSO.OpenTextFile(Filename)
        ini = file.ReadAll()
        file.Close 
 
        arr = Split(ini,vbCrLf)
        For Each line in arr
           If line = "##STARTDEFAULT" Then
              Read = True
           End If
           If Read Then
              If Left(Trim(Line),1) = "[" And Right(Trim(Line),1) = "]" Then
                 line = replace(replace(line,"[",""),"]","")
                 If Not IsEmpty(objDictionary.Item(line)) Then
                    Set objSubDictionary = objDictionary.Item(line)
                 Else
 
                    Set objSubDictionary = CreateObject("Scripting.Dictionary")
                    'objDictionary.Add line, objSubDictionary
                    set objDictionary.Item(line) = objSubDictionary
                 End If
              Else
                 If TypeName(objSubDictionary) = "Nothing" or IsEmpty(objSubDictionary) Then
                    Set objSubDictionary = CreateObject("Scripting.Dictionary")
                    objDictionary.Add "[]",objSubDictionary
                    Set objDictionary.Item("[]") = objSubDictionary
                 End If
                 If Left(Trim(line),1) = "#" Then
                    objSubDictionary.Item( "[" & objSubDictionary.Count & "]") = Trim(line)
                 Else
                    splitline = split(Trim(line),"=")
 
                    If TypeName(splitline) <> "Nothing" Then
                       If UBound(splitline) = 1 Then
                          tmpsplit = split(splitline(1), "#")
                          ' Resolve a <value>=<blank> error
                          If UBound(tmpsplit) >= 0 Then
                             objSubDictionary.Item(Trim(splitline(0))) = Trim(tmpsplit(0)) 
                          Else
                             objSubDictionary.Item(Trim(splitline(0))) = ""
                          End If
                       Else
                         'Error
                       End If
                    End If
                 End If
              End If
              If line = "##ENDDEFAULT" And JustDefaults Then
            MsgBox "End Default"
                 Read = False
                 Exit Sub
              End If
           End If
        Next
     Else 
       Exit Sub
     End If
   End Sub
   '------------------- End of Sub LoadIni -------------------------
 
   '----------------------- Function GetValue -------------------------------
   Public Function GetValue(Section, Value)
      Set objDictionary = mIniFile
      If IsSection(Section) Then
         Set objSubDictionary = objDictionary.Item(Section)
         If IsEmpty(objSubDictionary.Item(Value)) Then
            objSubDictionary.Remove(Value)
         Else
            GetValue = objSubDictionary.Item(Value)
         End If
      End If
   End Function
   '-------------------- End of Function GetValue ---------------------------
 
   '----------------------- Function IsSection ------------------------------
   Public Function IsSection(Section)
      Set objDictionary = mIniFile
      If IsEmpty(objDictionary.Item(Section)) Then
         objDictionary.Remove(Section)
         IsSection = False
      Else
        IsSection = True
      End If
   End Function
   '-------------------- End of Function IsSection --------------------------
 
   '----------------------- Function IsSection ------------------------------
   Public Function Save(FileName)
      Set objDictionary = mIniFile
      Set objFSO = CreateObject("Scripting.FileSystemObject")
      Set Outfile = objFSO.CreateTextFile(FileName)
      If TypeName(objDictionary) <> "Nothing" Then
         If Not IsEmpty(objDictionary.Keys) Then
            For Each Key in objDictionary.Keys
               If Key = "[]" Then
               ElseIf Key = "" Then
               Else
                  Outfile.WriteLine("[" & Key & "]")
               End If
               Set objSubDictionary = Nothing
               If Not IsEmpty(objDictionary.Item(Key)) Then
                  Set objSubDictionary = objDictionary.Item(Key)
               End If
               If TypeName(objSubDictionary) <> "Nothing" Then
                  If Not IsEmpty(objSubDictionary.Keys) Then
                     For Each subKey in objSubDictionary.Keys
                        If Left(subKey,1) = "[" Then
                           OutFile.WriteLine(objSubDictionary.Item(subKey))
                        Else
                           OutFile.WriteLine(subKey & "=" & objSubDictionary.Item(subKey))
                        End If
                     Next
                  End If
               End If
               OutFile.WriteLine
            Next
         End If
      End If
   End Function
   '-------------------- End of Function IsSection --------------------------
 
   '--------------------- Function AddNextNumeric ---------------------------
   Public Function AddNextNumeric(Section,Value)
      Set objDictionary = mIniFile
      If IsEmpty(objDictionary.Item(Section)) Then
         Set objSubDictionary = CreateObject("Scripting.Dictionary")
         Set objDictionary.Item(Section) = objSubDictionary
         objSubDictionary.Item("1") = Value
         AddNextNumeric = 1
      Else
        Set objSubDictionary = objDictionary.Item(Section)
        Number = 1
        Do While IsEmpty(objSubDictionary.Item("" & Number)) 
          Number = Number + 1
        Loop
        objSubDictionary.Item("" & Number) = Value
        AddNextNumeric = Number
      End If
   End Function
   '------------------ End of Function AddNextNumeric -----------------------
 
   '--------------------------- CONSTRUCTOR ---------------------------------
   Private Sub Class_Initialize
      ' Calss Constructor
      ' Initialization goes here
      Set mIniFile = Nothing
' MsgBox TypeName(mIniFile)
   End Sub
   '------------------------- END CONSTRUCTOR -------------------------------
 
   '---------------------------- DESTRUCTOR ---------------------------------
   Private Sub Class_Terminate
      ' Calss Destructor
      ' Cleanup goes here
' MsgBox TypeName(mIniFile)
      Set mIniFile = Nothing
   End Sub
   '-------------------------- END DESTRUCTOR -------------------------------
End Class

Usage of the class for reading Ini files is as follows:

set ifile = New IniFile
ifile.Load("filename.ini")
Variable = ifile.GetValue("Section","Variable")

There are obviously functions in the class that allow for writing out the Ini File and modifying the values. Feel free to play with the code, but please remember to link back to here. I do love my popularity, so any of you who want to link here, please do so.

Cheers, Chris.

:, , , , ,

3 Comments for this entry

  • Geoff

    Thanks, Chris. This has saved me a lot of trouble.

    I have added a few methods GetSections and GetKeys(Section) that should be self explanatory.

    I have also renamed LoadIni to LoadIniOptionalComments and added an additional boolean parameter to control whether Comments are included.

    LoadIni now call LoadIniOptionalComments with IncludeComments = True for backward compatibility.

    Another new method LoadWithoutComments(Filename) calls LoadIniOptionalComments with IncludeComments = False.

    Sample Code to use the new class:

    Set ifile = New IniFile
     
    ifile.LoadWithoutComments "\\Somewhere\Something.ini" ' or ifile.Load "\\Somewhere\Something.ini"
    
    For Each Section in ifile.GetSections()
        MsgBox Section
        For Each Key in ifile.GetKeys(Section)
            MsgBox Section &amp; ": " &amp; Key &amp; ": " &amp; ifile.GetValue(Section, Key)
        Next
    Next

    And the modified Class:

    Class IniFile
       Private mIniFile
       '
       '----------------------- Sub Load -------------------------------
       Public Sub Load(Filename)
          LoadIni FileName, False
       End Sub
     
       Public Sub LoadWithoutComments(Filename)
          LoadIniOptionalComments FileName, False, False
       End Sub
     
       '-------------------- End of Sub Load ---------------------------
       Public Sub LoadIni(Filename,JustDefaults)
         LoadIniOptionalComments  Filename, JustDefaults, True
       End Sub
     
       Public Sub LoadIniOptionalComments(Filename,JustDefaults, IncludeComments)
         Dim objFSO, objDictionary, objSubDictionary, file, ini, arr, line, splitline, tmpsplit
         Set objFSO = CreateObject("Scripting.FileSystemObject")
     
         Set objDictionary = mIniFile
         Set objDictionary = CreateObject("Scripting.Dictionary")
         Set objSubDictionary = Nothing
         Set mIniFile = objDictionary
         If JustDefaults Then
            Read = False
         Else
            Read = True
         End If
     
         If objFSO.FileExists(Filename) Then
            Set file = objFSO.OpenTextFile(Filename)
            ini = file.ReadAll()
            file.Close
     
            arr = Split(ini,vbCrLf)
            For Each line in arr
               If line = "##STARTDEFAULT" Then
                  Read = True
               End If
               If Read Then
                  If Left(Trim(Line),1) = "[" And Right(Trim(Line),1) = "]" Then
                     line = replace(replace(line,"[",""),"]","")
                     If Not IsEmpty(objDictionary.Item(line)) Then
                        Set objSubDictionary = objDictionary.Item(line)
                     Else
     
                        Set objSubDictionary = CreateObject("Scripting.Dictionary")
                        'objDictionary.Add line, objSubDictionary
                        set objDictionary.Item(line) = objSubDictionary
                     End If
                  Else
                     If TypeName(objSubDictionary) = "Nothing" or IsEmpty(objSubDictionary) Then
                        Set objSubDictionary = CreateObject("Scripting.Dictionary")
                        objDictionary.Add "[]",objSubDictionary
                        Set objDictionary.Item("[]") = objSubDictionary
                     End If
                     If Left(Trim(line),1) = "#" and IncludeComments Then
                        objSubDictionary.Item( "[" &amp; objSubDictionary.Count &amp; "]") = Trim(line)
                     ElseIf Left(Trim(line),1)  "#" then
                        splitline = split(Trim(line),"=")
     
                        If TypeName(splitline)  "Nothing" Then
                           If UBound(splitline) = 1 Then
                              tmpsplit = split(splitline(1), "#")
                              ' Resolve a = error
                              If UBound(tmpsplit) &gt;= 0 Then
                                 objSubDictionary.Item(Trim(splitline(0))) = Trim(tmpsplit(0))
                              Else
                                 objSubDictionary.Item(Trim(splitline(0))) = ""
                              End If
                           Else
                             'Error
                           End If
                        End If
                     End If
                  End If
                  If line = "##ENDDEFAULT" And JustDefaults Then
                MsgBox "End Default"
                     Read = False
                     Exit Sub
                  End If
               End If
            Next
         Else
           Exit Sub
         End If
       End Sub
       '------------------- End of Sub LoadIni -------------------------
    
       '----------------------- Function GetValue -------------------------------
       Public Function GetValue(Section, Value)
          Set objDictionary = mIniFile
          If IsSection(Section) Then
             Set objSubDictionary = objDictionary.Item(Section)
             If IsEmpty(objSubDictionary.Item(Value)) Then
                objSubDictionary.Remove(Value)
             Else
                GetValue = objSubDictionary.Item(Value)
             End If
          End If
       End Function
       '-------------------- End of Function GetValue ---------------------------
    
       '----------------------- Function GetSections -------------------------------
       Public Function GetSections()
          Set objDictionary = mIniFile
          GetSections = objDictionary.Keys
       End Function
       '-------------------- End of Function GetKeys ---------------------------
    
       '----------------------- Function GetKeys -------------------------------
       Public Function GetKeys(Section)
          Set objDictionary = mIniFile
          If IsSection(Section) Then
             Set objSubDictionary = objDictionary.Item(Section)
             GetKeys = objSubDictionary.Keys
          End If
       End Function
       '-------------------- End of Function GetKeys ---------------------------
    
       '----------------------- Function IsSection ------------------------------
       Public Function IsSection(Section)
          Set objDictionary = mIniFile
          If IsEmpty(objDictionary.Item(Section)) Then
             objDictionary.Remove(Section)
             IsSection = False
          Else
            IsSection = True
          End If
       End Function
       '-------------------- End of Function IsSection --------------------------
    
       '----------------------- Function IsSection ------------------------------
       Public Function IsComment(Section)
          Set objDictionary = mIniFile
          If IsEmpty(objDictionary.Item(Section)) Then
             objDictionary.Remove(Section)
             IsSection = False
          Else
            IsSection = True
          End If
       End Function
       '-------------------- End of Function IsSection --------------------------
    
       '----------------------- Function IsSection ------------------------------
       Public Function Save(FileName)
          Set objDictionary = mIniFile
          Set objFSO = CreateObject("Scripting.FileSystemObject")
          Set Outfile = objFSO.CreateTextFile(FileName)
          If TypeName(objDictionary)  "Nothing" Then
             If Not IsEmpty(objDictionary.Keys) Then
                For Each Key in objDictionary.Keys
                   If Key = "[]" Then
                   ElseIf Key = "" Then
                   Else
                      Outfile.WriteLine("[" &amp; Key &amp; "]")
                   End If
                   Set objSubDictionary = Nothing
                   If Not IsEmpty(objDictionary.Item(Key)) Then
                      Set objSubDictionary = objDictionary.Item(Key)
                   End If
                   If TypeName(objSubDictionary)  "Nothing" Then
                      If Not IsEmpty(objSubDictionary.Keys) Then
                         For Each subKey in objSubDictionary.Keys
                            If Left(subKey,1) = "[" Then
                               OutFile.WriteLine(objSubDictionary.Item(subKey))
                            Else
                               OutFile.WriteLine(subKey &amp; "=" &amp; objSubDictionary.Item(subKey))
                            End If
                         Next
                      End If
                   End If
                   OutFile.WriteLine
                Next
             End If
          End If
       End Function
       '-------------------- End of Function IsSection --------------------------
    
       '--------------------- Function AddNextNumeric ---------------------------
       Public Function AddNextNumeric(Section,Value)
          Set objDictionary = mIniFile
          If IsEmpty(objDictionary.Item(Section)) Then
             Set objSubDictionary = CreateObject("Scripting.Dictionary")
             Set objDictionary.Item(Section) = objSubDictionary
             objSubDictionary.Item("1") = Value
             AddNextNumeric = 1
          Else
            Set objSubDictionary = objDictionary.Item(Section)
            Number = 1
            Do While IsEmpty(objSubDictionary.Item("" &amp; Number))
              Number = Number + 1
            Loop
            objSubDictionary.Item("" &amp; Number) = Value
            AddNextNumeric = Number
          End If
       End Function
       '------------------ End of Function AddNextNumeric -----------------------
    
       '--------------------------- CONSTRUCTOR ---------------------------------
       Private Sub Class_Initialize
          ' Calss Constructor
          ' Initialization goes here
          Set mIniFile = Nothing
    ' MsgBox TypeName(mIniFile)
       End Sub
       '------------------------- END CONSTRUCTOR -------------------------------
    
       '---------------------------- DESTRUCTOR ---------------------------------
       Private Sub Class_Terminate
          ' Calss Destructor
          ' Cleanup goes here
    ' MsgBox TypeName(mIniFile)
          Set mIniFile = Nothing
       End Sub
       '-------------------------- END DESTRUCTOR -------------------------------
    End Class
  • Geoff

    Oops

    That lost all my Rich Text and Indentation.

    If you are interested – I can email the code in more readable format.

  • dwarfsoft

    Thanks for the updates. I didn’t need to worry too much about the comments, which left me with a code that really only worked for the machine readable part of things.

    The formatting should be fine now. The indents were still there, just needed the appropriate pre tags around it all ;)

    It’s good to know that people out there are still using this kind of thing years after I first wrote it :D

    Cheers, Chris

1 Trackback or Pingback for this entry

Leave a Reply

You must be logged in to post a comment.

Looking for something?

Use the form below to search the site:

Still not finding what you're looking for? Drop a comment on a post or contact us so we can take care of it!