Solved

INI File Settings coding.

Posted on 2001-09-16
14
710 Views
Last Modified: 2012-08-13
Hi,
I am working on this INI file editing MODULE for my game which stores setting in the following format.

Width = 1024;
Height = 768;
Depth = 16;

....etc

I have done most of the code but I am having trouble with the SaveSettingINI function which is functional but if the user wants to save a setting that already exists then it will remove the line containing the setting to be replaced and then puts the replaced setting at the bottom of the file. I want the key to stay i the same position and the setting just be replaced but when I tried it I just couldn't get it right.


PS. I have left comments where about what is happening and what I want fixed.

Here is the code

Function SaveSettingINI(File As String, Key As String, Setting As String)
    On Error GoTo ErrTrap
    Dim i As Double
    Dim LPos As Double
    Dim SPos As Double
    Dim EPos As Double
    Dim Bin As String
    Dim LKey As Integer
    Dim Tmp1 As String, Tmp2 As String
   
    If Trim(Key) = vbNullString Or Trim(Setting) = vbNullString Then Err.Raise 135, "Invalid Key or Setting value"
   
    LPos = 1
    SaveSettingINI = ""
   
    Open File For Binary As 1
        Bin = Space(LOF(1))
        Get 1, , Bin
        Do
            LKey = 0
           
            'Find the name key
            LPos = InStr(LPos, Bin, Key)
            'if doesn't exist create a new entry
            If LPos = 0 Then
                Close
                GoTo MakeSetting
            End If
           
            i = LPos
           
            Do
                'Find actual length of key in INI file
                If Mid(Bin, i, 1) = " " Or Mid(Bin, i, 1)= "=" Then
                    LKey = i
                   
                End If
                i = i + 1
            Loop While LKey = 0
           
            'Length of key
            LKey = LKey - LPos
           
            'If the Key string matches the actual key in the file
            If Mid(Bin, LPos, LKey) = Key Then
                SPos = LPos
                Close
                GoTo OverwriteSetting
                Else
                'Wrong key, do another search
                LPos = LPos + 1
            End If
           
        Loop While SPos = 0
    Close
   
'If in the INI file a key already exists then the user
'wants to overwrite that with a new setting so this function will do that.
OverwriteSetting:
    Open File For Binary As 1
        'use as a starting poing for locating the line break which happens to be ";"
        EPos = SPos
       
        'Find end position of line containing the key and setting by searching for the line break ";"        
        Do
            EPos = EPos + 1
        Loop While Not Mid(Bin, EPos, 1) = ";"
       
        EPos = EPos + 1
       
        'This is the bit that I want to fix up. It gets the start of the line and the end and removes that from the INI file. Then it will later put the new key and setting down the bottom line. I would prefer if it just got the setting and replaced that with the newer one but when I tried that I had problems.

       'Get starting point for text and stop where the line containing the key and setting exists.
        If SPos - 2 > 1 Then
            Tmp1 = Mid(Bin, 1, SPos - 2)
            Else
            Tmp2 = Mid(Bin, EPos + 2, LOF(1))
            GoTo INext
        End If
       
        Get from the end of the line containing the setting and key to the end of the file.
        If EPos + 2 < LOF(1) Then
            Tmp2 = Mid(Bin, EPos + 1, LOF(1))
            Else
            Tmp1 = Mid(Bin, 1, SPos - 3)
        End If
    Close
INext:
        'combine the tmp1 & tmp2 containing the parts of the file excluding the key and setting the user wants to change
        'put the file together part one and part two without the setting and key the user wanted to update. then add the updated key and setting on the last line. I don't want this to happen. as I said before I want it to just update the setting for the key in the same position without deleting it and putting it at the bottom of the line.

        Bin = Tmp1 & Tmp2 & vbNewLine & Key & " = " & Setting & ";"
    Close
   
    'delete file
    Kill File
   
    Open File For Binary As 1
        Put 1, , Bin
        SaveSettingINI = True
    Close

Exit Function    

'This just occurs when the key the user wants to add/update doesn't exist so it creates a new key.

MakeSetting:
    Open File For Binary As 1
        'Remove any spaces not necessary
        Do
            If Bin = vbNullString Then
                Bin = Key & " = " & Setting & ";"
                GoTo EmptyFile
            End If
            If Mid(Bin, Len(Bin), 1) = ";" Then Exit Do
            Bin = Mid(Bin, 1, Len(Bin) - 1)
        Loop
       
        Bin = Bin & vbNewLine & Key & " = " & Setting & ";"
       
EmptyFile:
   
        Put 1, , Bin
       
        SaveSettingINI = True
    Close
       
Exit Function
ErrTrap:
Close
End Function

0
Comment
Question by:adam8
14 Comments
 
LVL 15

Expert Comment

by:robbert
ID: 6485738
You can use Get- and WritePrivateProfileString() to handle INI files:

Private Declare Function GetPrivateProfileString Lib "kernel32" Alias "GetPrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Long, ByVal lpFileName As String) As Long
Private Declare Function WritePrivateProfileString Lib "kernel32" Alias "WritePrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpString As Any, ByVal lpFileName As String) As Long
Private Sub Form_Load()
    'KPD-Team 1999
    'URL: http://www.allapi.net/
    'E-Mail: KPDTeam@Allapi.net
    Dim Ret As String, NC As Long
    'Write the setting to the file (c:\test.ini) under
    '   Project1 -> Keyname
    WritePrivateProfileString App.Title, "KeyName", "This is the value", "c:\test.ini"
    'Create a buffer
    Ret = String(255, 0)
    'Retrieve the string
    NC = GetPrivateProfileString(App.Title, "KeyName", "Default", Ret, 255, "C:\test.ini")
    'NC is the number of characters copied to the buffer
    If NC <> 0 Then Ret = Left$(Ret, NC)
    'Show our string
    MsgBox Ret
    'Delete the file
'    Kill "c:\test.ini"
End Sub
0
 
LVL 8

Expert Comment

by:glass_cookie
ID: 6486552
Hi!

Here's some example for you to compile/integrate together with some other ocding:

Download...
http://www.vb-helper.com/HowTo/filelist.zip
Description; Load a ListBox using the lines in a file (3K)

This code would help you to access lines more easily.  By the way, you could use the instr() function to compare/look for strings and also the mid() function to return any specified number of characters.  Then, do any changes you want in memory then replace the listbox item.

That's it!

glass cookie : )
0
 
LVL 1

Author Comment

by:adam8
ID: 6486717
If I had known this I wouldn't have had to waste hald hour coding that.\
Although it was good coding practice. I might use mine anyway because that can remove keys and settings.
0
 
LVL 1

Author Comment

by:adam8
ID: 6486721
do you think you could fix up the prob with mine, I don't really want to stop using it since I already wasted time t=making it.
0
 
LVL 1

Author Comment

by:adam8
ID: 6486728
BTW whats the diff between Left$ and Left?
0
 
LVL 8

Accepted Solution

by:
glass_cookie earned 100 total points
ID: 6486815
Well, not much of a diff, just that the $ sign is used to indicate that a string is used.

To me, uf you use Left or Left$, it doesn't make any difference.

Well, FYI I'm quite bad at reading someone elses coding.  THerefore, I've compiled the stuff for you using my coding:

Create a Listbox, then add the code.  By the way, you'll have to do your own error-checking (whether the file exists or not) and change the filepaths of the file.

Dim i As Integer

Private Sub Form_Load()
Dim F As Integer
Dim file_line As String

    F = FreeFile
    Open "C:\SomeFile.ini" For Input As F
    Do While Not EOF(F)
        Line Input #F, file_line
        List1.AddItem file_line
    Loop
    Close F

'Testing the subs
ReplaceSettings "Height", 400
SaveSettings
End Sub

'Sub used to replace a particular Key
Public Sub ReplaceSettings(SettingKey As String, Values As String)
For i = 0 To List1.ListCount - 1

If InStr(1, List1.List(i), SettingKey) <> 0 Then
Dim Count As Integer
List1.RemoveItem i
List1.AddItem SettingKey + " = " + Values, i
Exit For
End If

Next i
End Sub

'Sub used to save the settings
Public Sub SaveSettings()
If List1.ListCount = 0 Then Exit Sub

Dim Compile As String
Compile = List1.List(0) 'Grab 1st linne in listbox

If List1.ListCount > 1 Then 'If listbox has >1 lines, compile the rest
For i = 1 To List1.ListCount - 1
Compile = Compile & vbCrLf & List1.List(i)
Next i
End If

Dim F As Integer
    F = FreeFile
    Open "C:\SomeFile.ini" For Output As F
    Print #F, Compile
    Close F
End Sub

Public Sub AddNewKey(SettingKey As String, Values As String)
List1.AddItem SettingKey + " = " + Values
End Sub


That's it!

glass cookie : )
0
 
LVL 5

Expert Comment

by:gwgaw
ID: 6486816
With this code you can read and wrtie key values, add and delete keys and
sections, get all the sections in an ini file and get all the keys in a section.


Option Explicit
' This line is the declaration from win32api.txt
' Declare Function GetPrivateProfileString Lib "kernel32" Alias "GetPrivateProfileStringA" (ByVal lpApplicationName As String, lpKeyName As Any, ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Long, ByVal lpfilename As String) As Long
Declare Function GetPrivateProfileStringByKeyName Lib "kernel32" _
    Alias "GetPrivateProfileStringA" (ByVal lpApplicationName$, _
    ByVal lpszKey$, ByVal lpszDefault$, ByVal lpszReturnBuffer$, _
    ByVal cchReturnBuffer&, ByVal lpszFile$) As Long
Declare Function GetPrivateProfileStringKeys Lib "kernel32" _
    Alias "GetPrivateProfileStringA" (ByVal lpApplicationName$, _
    ByVal lpszKey&, ByVal lpszDefault$, ByVal lpszReturnBuffer$, _
    ByVal cchReturnBuffer&, ByVal lpszFile$) As Long
Declare Function GetPrivateProfileStringSections Lib "kernel32" _
    Alias "GetPrivateProfileStringA" (ByVal lpApplicationName&, _
    ByVal lpszKey&, ByVal lpszDefault$, ByVal lpszReturnBuffer$, _
    ByVal cchReturnBuffer&, ByVal lpszFile$) As Long
' This line is the declaration from win32api.txt
' Declare Function WritePrivateProfileString Lib "kernel32" Alias "WritePrivateProfileStringA" (ByVal lpApplicationName As String, lpKeyName As Any, lpString As Any, ByVal lplFileName As String) As Long
Declare Function WritePrivateProfileStringByKeyName Lib _
    "kernel32" Alias "WritePrivateProfileStringA" _
    (ByVal lpApplicationName As String, ByVal lpKeyName As String, _
    ByVal lpString As String, ByVal lplFileName As String) As Long

Public Function GetSections(stIniFile$) As String
Dim dl&, stSections$
stSections = String$(256, 0)
    ' Retrieve the list of sections in the file
dl = GetPrivateProfileStringSections(0, 0, "", stSections, 255, stIniFile)
GetSections = stSections
End Function

Public Function GetKeys(stSection$, stIniFile$) As String
Dim dl&, stKeys$
stKeys = String$(256, 0)
    ' Retrieve the list of keys in the section
dl = GetPrivateProfileStringKeys(stSection, 0, "", stKeys, 255, stIniFile)
GetKeys = stKeys
End Function

Public Sub DeleteKey(stSection$, stKey$, stIniFile$)
Dim dl&
dl = WritePrivateProfileStringByKeyName(stSection, stKey, vbNullString, stIniFile)
End Sub

Public Sub DeleteSection(stSection$, stIniFile$)
Dim dl&
dl = WritePrivateProfileStringByKeyName(stSection, vbNullString, vbNullString, stIniFile)
End Sub

Public Function GetKeyValue(stSection$, stKey$, stIniFile$) As String
Dim stKeyValue$, dl&
stKeyValue = String$(128, 0)
dl = GetPrivateProfileStringByKeyName(stSection, stKey, "", stKeyValue, 127, stIniFile)
If dl > 0 Then
    stKeyValue = Left$(stKeyValue, dl)
Else: stKeyValue = ""
End If
GetKeyValue = stKeyValue
End Function

Public Sub WriteKeyValue(stSection$, stKey$, ByVal stKeyValue$, stIniFile$)
Dim dl&
dl = WritePrivateProfileStringByKeyName(stSection, stKey, stKeyValue, stIniFile)
If dl = 0 Then
    Dim msg$
    msg$ = "Edit failed - this is typically caused by a write protected INI file"
    MsgBox msg$
End If
End Sub
0
What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

 
LVL 8

Expert Comment

by:glass_cookie
ID: 6486823
Oh yes, here's another sub to remove settings (sorry, missed that out):

Public Sub RemoveKey(SettingKey As String)
For i = 0 To List1.ListCount - 1

If InStr(1, List1.List(i), SettingKey) <> 0 Then
List1.RemoveItem i
Exit For
End If

Next i
End Sub

That's it!

glass cookie ; )
0
 
LVL 1

Author Comment

by:adam8
ID: 6486866
glass_cookie,
I am sure your code works but I have other functions already done like GetSettingINI and DeleteSettingINI so I would really need to change it around a bit.
I will just keep trying to fix up my code them
0
 
LVL 44

Expert Comment

by:Arthur_Wood
ID: 6487191
The difference between Left and Left$ is that what is returned by the function Left is of type VARIANT, whlie what is returned by Left$ is of type STRING.  True, other than that there is no difference, but you can take a slight performance hit if you use Left (or Right or Mid) rahter that Left$ (or Right$ or Mid$) because VB will need to convert the VARIANT type into a string, and that intertnally reuires some Processort cycles.  If you only do it once, no big deal. But if it happens in a loop, and the loop requires MANY MANY passes, then the excess processing to convert from VARIANT to STRING can mount up.

0
 
LVL 1

Author Comment

by:adam8
ID: 6487317
I thought it was something like that.
Anyway, I realised what I was doing wrong and fixed it up.
It was really quite basic. I must have been too tired when coding and just not picked up what I was doing wrong.

Happens to often. Next time I will have to try in the morning before posting a 100 point question :-)

0
 
LVL 8

Expert Comment

by:glass_cookie
ID: 6487618
: ) I'm glad your problem is solved.

Happy programming...

glass cookie : )
0
 
LVL 1

Author Comment

by:adam8
ID: 6489529
I will leave you the points since I am sure this solution was valid and you tried to help.

no point wasting 100 points anyway
0
 
LVL 8

Expert Comment

by:glass_cookie
ID: 6489780
Thanks for the points : )
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

There are many ways to remove duplicate entries in an SQL or Access database. Most make you temporarily insert an ID field, make a temp table and copy data back and forth, and/or are slow. Here is an easy way in VB6 using ADO to remove duplicate row…
I’ve seen a number of people looking for examples of how to access web services from VB6.  I’ve been using a test harness I built in VB6 (using many resources I found online) that I use for small projects to work out how to communicate with web serv…
As developers, we are not limited to the functions provided by the VBA language. In addition, we can call the functions that are part of the Windows operating system. These functions are part of the Windows API (Application Programming Interface). U…
Show developers how to use a criteria form to limit the data that appears on an Access report. It is a common requirement that users can specify the criteria for a report at runtime. The easiest way to accomplish this is using a criteria form that a…

757 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

21 Experts available now in Live!

Get 1:1 Help Now