VBA – Read Write INI Files

Looking through an old database I had created I came across some code I had put together a while back to read and write INI files.

If you’ve searched online a little, I’m sure you’ve found APIs such as the GetPrivateProfileString function, that can be used to do this, but as much as I can, I try to minimize my use of ActiveX and APIs and this is one case where an API is not required to perform basic text search and writing, because after all an INI file is nothing more than a text file.

As time has passed, I’ve also learnt the value of using INI files to store user preferences.  While it is possible to store such data in the database front-end itself, it is lost upon updating.  Another option would be to use the registry, but I dislike using the registry except for registration information and the likes.  Beyond which, registry settings cannot easily be pushed out to other new computers.  By using a simple INI file, you can store any information you choose, it remains intact when updates are performed and can be transferred with great ease to other computers so the user can retain their settings.
 

What Information Might We Store In a INI File?

Here are a few random examples of the types of things that one might save as part of a user’s INI File:

  • Default output directory (for reports/exports)
  • Default input directory (file imports, images, …)
  • Theme
  • Font (family, size, …)
  • Prefered Date/Time format
  • Preferred Currency format
  • Language
  • etc.

Just be careful never to store sensitive/confidential information after all the INI file is a text file and anyone can open it, or even edit it. So don’t store information relating to usernames, passwords, security level settings, … at least not without first encrypting the data.
 

Working With INI Files Using Pure VBA

Enough with the talk, below are the functions involved.

Public bSectionExists         As Boolean
Public bKeyExists             As Boolean

'---------------------------------------------------------------------------------------
' Procedure : Ini_ReadKeyVal
' Author    : Daniel Pineault, CARDA Consultants Inc.
' Website   : http://www.cardaconsultants.com
' Purpose   : Read an INI file's Key
' Copyright : The following is release as Attribution-ShareAlike 4.0 International
'             (CC BY-SA 4.0) - https://creativecommons.org/licenses/by-sa/4.0/
' Req'd Refs: Uses Late Binding, so none required
'             No APIs either! 100% VBA
'
' Input Variables:
' ~~~~~~~~~~~~~~~~
' sIniFile  : Full path and filename of the INI file to read
' sSection  : INI Section to search for the Key to read the Key from
' sKey      : Name of the Key to read the value of
'
' Usage:
' ~~~~~~
' ? Ini_Read(Application.CurrentProject.Path & "\MyIniFile.ini", "LINKED TABLES", "Path")
'
' Revision History:
' Rev       Date(yyyy/mm/dd)        Description
' **************************************************************************************
' 1         2012-08-09              Initial Release
' 2         2025-06-03              Updated Copyright.
'---------------------------------------------------------------------------------------
Function Ini_ReadKeyVal(ByVal sIniFile As String, _
                        ByVal sSection As String, _
                        ByVal sKey As String) As String
    On Error GoTo Error_Handler
    Dim sIniFileContent       As String
    Dim aIniLines()           As String
    Dim sLine                 As String
    Dim i                     As Long

    sIniFileContent = ""
    bSectionExists = False
    bKeyExists = False

    'Validate that the file actually exists
    If FileExist(sIniFile) = False Then
        MsgBox "The specified ini file: " & vbCrLf & vbCrLf & _
               sIniFile & vbCrLf & vbCrLf & _
               "could not be found.", vbCritical + vbOKOnly, "File not found"
        GoTo Error_Handler_Exit
    End If

    sIniFileContent = ReadFile(sIniFile)    'Read the file into memory
    aIniLines = Split(sIniFileContent, vbCrLf)
    For i = 0 To UBound(aIniLines)
        sLine = Trim(aIniLines(i))
        If bSectionExists = True And Left(sLine, 1) = "[" And Right(sLine, 1) = "]" Then
            Exit For    'Start of a new section
        End If
        If sLine = "[" & sSection & "]" Then
            bSectionExists = True
        End If
        If bSectionExists = True Then
            If Len(sLine) > Len(sKey) Then
                If Left(sLine, Len(sKey) + 1) = sKey & "=" Then
                    bKeyExists = True
                    Ini_ReadKeyVal = Mid(sLine, InStr(sLine, "=") + 1)
                End If
            End If
        End If
    Next i

Error_Handler_Exit:
    On Error Resume Next
    Exit Function

Error_Handler:
    'Err.Number = 75 'File does not exist, Permission issues to write is denied,
    MsgBox "The following error has occurred" & vbCrLf & vbCrLf & _
           "Error Number: " & Err.Number & vbCrLf & _
           "Error Source: Ini_ReadKeyVal" & vbCrLf & _
           "Error Description: " & Err.Description & _
           Switch(Erl = 0, "", Erl <> 0, vbCrLf & "Line No: " & Erl) _
           , vbOKOnly + vbCritical, "An Error has Occurred!"
    Resume Error_Handler_Exit
End Function

'---------------------------------------------------------------------------------------
' Procedure : Ini_WriteKeyVal
' Author    : Daniel Pineault, CARDA Consultants Inc.
' Website   : http://www.cardaconsultants.com
' Purpose   : Writes a Key value to the specified INI file's Section
'               If the file does not exist, it will be created
'               If the Section does not exist, it will be appended to the existing content
'               If the Key does not exist, it will be appended to the existing Section content
' Copyright : The following is release as Attribution-ShareAlike 4.0 International
'             (CC BY-SA 4.0) - https://creativecommons.org/licenses/by-sa/4.0/
' Req'd Refs: Uses Late Binding, so none required
'             No APIs either! 100% VBA
'
' Input Variables:
' ~~~~~~~~~~~~~~~~
' sIniFile  : Full path and filename of the INI file to edit
' sSection  : INI Section to search for the Key to edit
' sKey      : Name of the Key to edit
' sValue    : Value to associate to the Key
'
' Usage:
' ~~~~~~
' Call Ini_WriteKeyVal(Application.CurrentProject.Path & "\MyIniFile.ini", "LINKED TABLES", "Paths", "D:\")
'
' Revision History:
' Rev       Date(yyyy/mm/dd)        Description
' **************************************************************************************
' 1         2012-08-09              Initial Release
' 2         2025-06-03              Updated version to address 2 bugs found in previous
'                                   version (Thanks to Xavier Batlle for bringing 1 of
'                                   the bugs to my attention).
'                                   Updated Copyright.
'---------------------------------------------------------------------------------------
Function Ini_WriteKeyVal(ByVal sIniFile As String, _
                         ByVal sSection As String, _
                         ByVal sKey As String, _
                         ByVal sValue As String) As Boolean
    On Error GoTo Error_Handler

    Dim sIniFileContent       As String
    Dim aIniLines()           As String
    Dim sLine                 As String
    Dim sNewLine              As String
    Dim i                     As Long
    Dim bFileExist            As Boolean
    Dim bInSection            As Boolean
    Dim bSectionExists        As Boolean
    Dim bKeyExists            As Boolean
    Dim bKeyAdded             As Boolean

    sIniFileContent = ""
    bSectionExists = False
    bKeyExists = False
    bKeyAdded = False
    bInSection = False

    ' Validate that the file actually exists
    bFileExist = FileExist(sIniFile)
    If bFileExist Then
        sIniFileContent = ReadFile(sIniFile)    ' Read the file into memory
        If Len(sIniFileContent) > 0 Then
            aIniLines = Split(sIniFileContent, vbCrLf)    ' Break the content into individual lines
        Else
            ReDim aIniLines(0)
            aIniLines(0) = ""
        End If
    Else
        ' File does not exist, start with empty lines
        ReDim aIniLines(0)
        aIniLines(0) = ""
    End If

    sIniFileContent = ""    ' Reset it

    For i = 0 To UBound(aIniLines)
        sLine = Trim(aIniLines(i))
        sNewLine = ""

        ' Detect section
        If sLine = "[" & sSection & "]" Then
            bSectionExists = True
            bInSection = True
        ElseIf Left(sLine, 1) = "[" And Right(sLine, 1) = "]" Then
            ' If we were in the target section and hit a new section, check if key was added
            If bInSection And Not bKeyExists Then
                If Len(sIniFileContent) > 0 Then sIniFileContent = sIniFileContent & vbCrLf
                sIniFileContent = sIniFileContent & sKey & "=" & sValue
                bKeyAdded = True
            End If
            bInSection = False
        End If

        ' If inside the target section, check for the key
        If bInSection And Not bKeyExists Then
            If InStr(1, sLine, sKey & "=", vbTextCompare) = 1 Then
                sNewLine = sKey & "=" & sValue
                bKeyExists = True
                bKeyAdded = True
            End If
        End If

        ' Build the new content
        If Len(sIniFileContent) > 0 Then sIniFileContent = sIniFileContent & vbCrLf
        If sNewLine = "" Then
            sIniFileContent = sIniFileContent & sLine
        Else
            sIniFileContent = sIniFileContent & sNewLine
        End If
    Next i

    ' If section was not found, add it and the key at the end
    If Not bSectionExists Then
        If Len(sIniFileContent) > 0 Then sIniFileContent = sIniFileContent & vbCrLf
        sIniFileContent = sIniFileContent & "[" & sSection & "]" & vbCrLf & sKey & "=" & sValue
    ElseIf Not bKeyAdded Then
        ' Section exists, but key was not found, so add it at the end of the section
        If Right(sIniFileContent, 2) <> vbCrLf Then sIniFileContent = sIniFileContent & vbCrLf
        sIniFileContent = sIniFileContent & sKey & "=" & sValue
    End If

    ' Write to the ini file the new content
    Call OverwriteTxt(sIniFile, sIniFileContent)
    Ini_WriteKeyVal = True

Error_Handler_Exit:
    On Error Resume Next
    Exit Function

Error_Handler:
    MsgBox "The following error has occurred" & vbCrLf & vbCrLf & _
           "Error Number: " & Err.Number & vbCrLf & _
           "Error Source: Ini_WriteKeyVal" & vbCrLf & _
           "Error Description: " & Err.Description, _
           vbOKOnly + vbCritical, "An Error has Occurred!"
    Resume Error_Handler_Exit
End Function

The above also requires the following helper functions

'---------------------------------------------------------------------------------------
' Procedure : FileExist
' DateTime  : 2007-Mar-06 13:51
' Author    : CARDA Consultants Inc.
' Website   : http://www.cardaconsultants.com
' Purpose   : Test for the existance of a file; Returns True/False
'
' Input Variables:
' ~~~~~~~~~~~~~~~~
' strFile - name of the file to be tested for including full path
'---------------------------------------------------------------------------------------
Function FileExist(strFile As String) As Boolean
    On Error GoTo Err_Handler

    FileExist = False
    If Len(Dir(strFile)) > 0 Then
        FileExist = True
    End If

Exit_Err_Handler:
    Exit Function

Err_Handler:
    MsgBox "The following error has occurred." & vbCrLf & vbCrLf & _
            "Error Number: " & Err.Number & vbCrLf & _
            "Error Source: FileExist" & vbCrLf & _
            "Error Description: " & Err.Description, _
            vbCritical, "An Error has Occurred!"
    GoTo Exit_Err_Handler
End Function

'---------------------------------------------------------------------------------------
' Procedure : OverwriteTxt
' Author    : Daniel Pineault, CARDA Consultants Inc.
' Website   : http://www.cardaconsultants.com
' Purpose   : Output Data to an external file (*.txt or other format)
'             ***Do not forget about access' DoCmd.OutputTo Method for
'             exporting objects (queries, report,...)***
'             Will overwirte any data if the file already exists
' Copyright : The following may be altered and reused as you wish so long as the
'             copyright notice is left unchanged (including Author, Website and
'             Copyright).  It may not be sold/resold or reposted on other sites (links
'             back to this site are allowed).
'
' Input Variables:
' ~~~~~~~~~~~~~~~~
' sFile - name of the file that the text is to be output to including the full path
' sText - text to be output to the file
'
' Usage:
' ~~~~~~
' Call OverwriteTxt("C:\Users\Vance\Documents\EmailExp2.txt", "Text2Export")
'
' Revision History:
' Rev       Date(yyyy/mm/dd)        Description
' **************************************************************************************
' 1         2012-Jul-06                 Initial Release
'---------------------------------------------------------------------------------------
Function OverwriteTxt(sFile As String, sText As String)
On Error GoTo Err_Handler
    Dim FileNumber As Integer
 
    FileNumber = FreeFile                   ' Get unused file number
    Open sFile For Output As #FileNumber    ' Connect to the file
    Print #FileNumber, sText;                ' Append our string
    Close #FileNumber                       ' Close the file
 
Exit_Err_Handler:
    Exit Function
 
Err_Handler:
    MsgBox "The following error has occurred." & vbCrLf & vbCrLf & _
            "Error Number: " & Err.Number & vbCrLf & _
            "Error Source: OverwriteTxt" & vbCrLf & _
            "Error Description: " & Err.Description, _
            vbCritical, "An Error has Occurred!"
    GoTo Exit_Err_Handler
End Function

'---------------------------------------------------------------------------------------
' Procedure : ReadFile
' Author    : CARDA Consultants Inc.
' Website   : http://www.cardaconsultants.com
' Purpose   : Faster way to read text file all in RAM rather than line by line
' Copyright : The following may be altered and reused as you wish so long as the
'             copyright notice is left unchanged (including Author, Website and
'             Copyright).  It may not be sold/resold or reposted on other sites (links
'             back to this site are allowed).
' Input Variables:
' ~~~~~~~~~~~~~~~~
' strFile - name of the file that is to be read
'
' Usage Example:
' ~~~~~~~~~~~~~~~~
' MyTxt = ReadText("c:\tmp\test.txt")
' MyTxt = ReadText("c:\tmp\test.sql")
' MyTxt = ReadText("c:\tmp\test.csv")
'---------------------------------------------------------------------------------------
Function ReadFile(ByVal strFile As String) As String
On Error GoTo Error_Handler
    Dim FileNumber  As Integer
    Dim sFile       As String 'Variable contain file content
 
    FileNumber = FreeFile
    Open strFile For Binary Access Read As FileNumber
    sFile = Space(LOF(FileNumber))
    Get #FileNumber, , sFile
    Close FileNumber
 
    ReadFile = sFile
 
Error_Handler_Exit:
    On Error Resume Next
    Exit Function
 
Error_Handler:
    MsgBox "The following error has occurred." & vbCrLf & vbCrLf & _
            "Error Number: " & Err.Number & vbCrLf & _
            "Error Source: ReadFile" & vbCrLf & _
            "Error Description: " & Err.Description, _
            vbCritical, "An Error has Occurred!"
    Resume Error_Handler_Exit
End Function

With the above code, you can now easily read any INI file key value and write/update key values by doing something like

Sub TestReadKey()
    MsgBox "INI File: " & Application.CurrentProject.Path & "\MyIniFile.ini" & vbCrLf & _
           "Section: SETTINGS" & vbCrLf & _
           "Section Exist: " & bSectionExists & vbCrLf & _
           "Key: License" & vbCrLf & _
           "Key Exist: " & bKeyExists & vbCrLf & _
           "Key Value: " & Ini_ReadKeyVal(Application.CurrentProject.Path & "\MyIniFile.ini", "SETTINGS", "License")
    'You can validate the value by checking the bSectionExists and bKeyExists variable to ensure they were actually found in the ini file
End Sub

Sub TestWriteKey()
    If Ini_WriteKeyVal(Application.CurrentProject.Path & "\MyIniFile.ini", "SETTINGS", "License", "JBXR-HHTY-LKIP-HJNB-GGGT") = True Then
        MsgBox "The key was written"
    Else
        MsgBox "An error occurred!"
    End If
End Sub

 

Working With INI Files Using APIs

For the sake of completeness, I thought I’d briefly demonstrate the usage of the Windows APIs for manipulating INI Files.

The basic code could look like:

#If VBA7 Then
    Private Declare PtrSafe Function GetPrivateProfileStringA Lib "kernel32" ( _
            ByVal lpApplicationName As String, _
            ByVal lpKeyName As String, _
            ByVal lpDefault As String, _
            ByVal lpReturnedString As String, _
            ByVal nSize As Long, _
            ByVal lpFileName As String) As Long
    Private Declare PtrSafe Function WritePrivateProfileStringA Lib "kernel32" ( _
            ByVal lpApplicationName As String, _
            ByVal lpKeyName As String, _
            ByVal lpString As String, _
            ByVal lpFileName As String) As Long
#Else
    Private Declare Function GetPrivateProfileStringA Lib "kernel32" ( _
            ByVal lpApplicationName As String, _
            ByVal lpKeyName As String, _
            ByVal lpDefault As String, _
            ByVal lpReturnedString As String, _
            ByVal nSize As Long, _
            ByVal lpFileName As String) As Long
    Private Declare Function WritePrivateProfileStringA Lib "kernel32" ( _
            ByVal lpApplicationName As String, _
            ByVal lpKeyName As String, _
            ByVal lpString As String, _
            ByVal lpFileName As String) As Long
#End If


Function ReadIniValue(ByVal sFile As String, _
                      ByVal sSection As String, _
                      ByVal sKey As String, _
                      Optional ByVal sDefault As String = "") As String
    Dim sBuffer               As String
    Dim lRet                  As Long

    sBuffer = String$(1024, vbNullChar)    ' Buffer for the result
    lRet = GetPrivateProfileStringA(sSection, sKey, sDefault, sBuffer, Len(sBuffer), sFile)
    If lRet > 0 Then
        ReadIniValue = Left$(sBuffer, lRet)
    Else
        ReadIniValue = sDefault
    End If
End Function

Function WriteIniValue(ByVal sFile As String, _
                       ByVal sSection As String, _
                       ByVal sKey As String, _
                       ByVal sValue As String) As Boolean
    Dim lRet As Long

    lRet = WritePrivateProfileStringA(sSection, sKey, sValue, sFile)
    WriteIniValue = (lRet <> 0)
End Function

Function DeleteIniKey(ByVal sFile As String, _
                      ByVal sSection As String, _
                      ByVal sKey As String) As Boolean
    'Supplying a vbNullString actually deletes the key and/or section!
    Dim lRet As Long
    lRet = WritePrivateProfileStringA(sSection, sKey, vbNullString, sFile)
    DeleteIniKey = (lRet <> 0)
End Function

Function DeleteIniSection(ByVal sFile As String, _
                          ByVal sSection As String) As Boolean
    Dim lRet As Long
    lRet = WritePrivateProfileStringA(sSection, vbNullString, vbNullString, sFile)
    DeleteIniSection = (lRet <> 0)
End Function

and below are a couple examples of how they are used:

Sub WriteIniValue_Test()
    ' If the Ini file does not already exist, it will be created automatically
    Debug.Print WriteIniValue(Application.CurrentProject.Path & "\MyIniFile.ini", "Settings", "Licenses", "MyValue")
End Sub
Sub ReadIniValue_Test()
    Debug.Print ReadIniValue(Application.CurrentProject.Path & "\MyIniFile.ini", "Settings", "Licenses")
End Sub
Sub DeleteIniKey_Test()
    Debug.Print DeleteIniKey(Application.CurrentProject.Path & "\MyIniFile.ini", "Settings", "License")
End Sub
Sub DeleteIniSection_Test()
    Debug.Print DeleteIniSection(Application.CurrentProject.Path & "\MyIniFile.ini", "Settings")
End Sub

 

Page History

Date Summary of Changes
2017-01-30 Initial Release
2025-06-03 Updated Ini_WriteKeyVal
Added the API Approach section

25 responses on “VBA – Read Write INI Files

  1. shlomo

    why not store the user preferences in the database Back-end itself (with userId column of course)?
    this what it’s has all the benefit of INI file, and it’s not limited to specific computer

      1. Mário

        Dear sir
        I no nothing of basic, i just staed a few days ago. Well! It’s a beat hard.
        A demo of *.INI file will help.
        Best regards

        1. Daniel Pineault Post author

          Just perform a search on your own PC, you’ll find hundreds of ini files as examples.

          Here’s an fictitious example:

          [LINKED TABLES]
          paths=d:\
          MaxNoAttempts=3
          [Settings]
          MaxNoUsers=2
          MaxNo=2
          [CARDA]
          License=2222-R4
          Date=45487854
  2. kirby

    Excellent example for avoiding API. Had issue with running in Excel 2010, replaced ‘Application.CurrentProject.Path’ with ActiveWorkbook.path (or Application.ActiveWorkbook.Path) to fix.

  3. Paul

    Hi there! Thank you very much for these super useful code snippets!

    May I ask under which license (eg. MIT) you’re releasing this code?

    Thank you

  4. Harry Wellner

    Hi,
    When a new section1 as added with appropiate key and another section2 with key is added I come up with the following. After above adding (1+2) another new key is added for section1. However, this key for section1 is not inserted under the embrella of section1 but added at the end of the ini file resulting in storing the key under the latest section
    Example:
    [Test1]
    Value1=aaa
    [Test2]
    Value2=bbbb

    When I add Value11=cccc as key for section [Test1] the file consist of the following:
    [Test1]
    Value1=aaa
    [Test2]
    Value2=bbbb
    Valu11=ccc

    Any idea what to change in the source of the splendid VBA source btw. I like the idea in skipping API’s.

      1. Stefan Waldherr

        Love the code and use it extensively. Similar problem, and its probably easy to replicate.
        You have an ini file with some sections, say
        [foo]
        [bar]
        Now you write something to [foo] that has not existed before in [foo].
        Ini_WriteKeyVal(LOCALSETTINGS_FILE, “foo”, “somedate”, Date)
        Now oddly somedate=24.01.2020 is not inserted to [foo] but rather placed at the end of the file (also ending up in section [bar]). That’s not what I would expect. Any idea?
        Best, Stefan

        1. Daniel Pineault Post author

          I have updated the code for the Ini_WriteKeyVal() function and I believe the issue to be resolved, but haven’t had the opportunity to do a lot of testing to confirm it.

  5. Maurizio Moretti

    Small inconsistency found in Ini_WriteKeyVal:
    ——————————————————
    1) If bInSection = True Then
    2) If sLine “[” & sSection & “]” Then
    3) If Left(sLine, 1) = “[” And Right(sLine, 1) = “]” Then
    4) ‘Our section exists, but the key wasn’t found, so append it
    5) sNewLine = sKey & “=” & sValue
    6) i = i – 1
    7) bInSection = False ‘ we’re switching section
    8) bKeyAdded = True
    9) End If
    10) End If
    11) If Len(sLine) > Len(sKey) Then
    12) If Left(sLine, Len(sKey) + 1) = sKey & “=” Then
    13) sNewLine = sKey & “=” & sValue
    14) bKeyExists = True
    15) bKeyAdded = True
    16) End If
    17) End If
    18) End If
    ———————————————————————
    Line (4) has to be
    4) If Left(sLine, 1) = “[” And Right(sLine, 1) = “]” And And bKeyAdded = False Then

    needs to check for “bKeyAdded” otherwise on top of updating the key a new key (a replica) will be every time appended to the section.

      1. redchilli

        this is not fixing it for me somehow. It just makes for every section, which has the attribute is changed. I dont get why.

  6. Andries

    Works excellent at first ! Added this code to a new module and starts using it from my existing code. Thanks !

    Added this code and created the option on storing some setting outside of excel for a common user to change some list he should maintain.
    As this excel overwrites some formules after executing vba code, changing was prohibited for normal users. and I had to change this each time for them

  7. Anthony

    Hello,
    I’m getting an error when trying to launch this code in Word VBA, on this line:
    sFile = Space(LOF(FileNumber))
    of this function:
    Function ReadFile(ByVal strFile As String) As String
    The error I’m getting says “Error: Expected Array”

    I googled the “LOF” function and the “Space” function to check what their inputs are, and I don’t understand what array VBA could be talking about.

    Thank you for the code posted here. Looking forward to using it!

      1. Anthony

        Hi Daniel. When I click Debug > Compile, I get the same error message stating “Compile Error: Expecting Array” with “Space” highlighted in the VBA window.

        I copy / pasted all of the code you posted into a separate Module from anything else, so that nothing I have could interfere with this code and visa versa.

        Any ideas? Does the code require any kind of Reference Library to be added other than the typical ones? Thank you for any help, Anthony

          1. Anthony

            Hello again! Thank you for taking the time to try it yourself and send that file over. Does this code only work in Access? I was trying to run it in Word, maybe that’s where I’m going wrong lol.

          2. Anthony

            Hi Daniel,
            Using an entirely separate dotm file, the code is working just fine, so there must be something in another module causing the issue. I should have thought to try that first, my apologies. Thank you for the tremendous help and awesome code.

  8. Garry Smith

    Thanks again Daniel for another great subject matter.
    I implemented this same thing in my last project, only in a much more primitive way.
    I like this better than storing this in the backend DB. Although some keys are also stored in the DB for other reasons.
    I agree with Mário, a YouTube video would be a good watch.