I have one project with function to read .ini files. I can not display the contents of .ini file that I want to.
My code to read .ini file
Public Fun
Example ini file:
[MAIN]
Setting_1=something
a. Create a class clsINI
Public Class clsIni
' API functions
Private Declare Ansi Function GetPrivateProfileString _
Lib "kernel32.dll" Alias "GetPrivateProfileStringA" _
(ByVal lpApplicationName As String, _
ByVal lpKeyName As String, ByVal lpDefault As String, _
ByVal lpReturnedString As System.Text.StringBuilder, _
ByVal nSize As Integer, ByVal lpFileName As String) _
As Integer
Private Declare Ansi Function WritePrivateProfileString _
Lib "kernel32.dll" Alias "WritePrivateProfileStringA" _
(ByVal lpApplicationName As String, _
ByVal lpKeyName As String, ByVal lpString As String, _
ByVal lpFileName As String) As Integer
Private Declare Ansi Function GetPrivateProfileInt _
Lib "kernel32.dll" Alias "GetPrivateProfileIntA" _
(ByVal lpApplicationName As String, _
ByVal lpKeyName As String, ByVal nDefault As Integer, _
ByVal lpFileName As String) As Integer
Private Declare Ansi Function FlushPrivateProfileString _
Lib "kernel32.dll" Alias "WritePrivateProfileStringA" _
(ByVal lpApplicationName As Integer, _
ByVal lpKeyName As Integer, ByVal lpString As Integer, _
ByVal lpFileName As String) As Integer
Dim strFilename As String
' Constructor, accepting a filename
Public Sub New(ByVal Filename As String)
strFilename = Filename
End Sub
' Read-only filename property
ReadOnly Property FileName() As String
Get
Return strFilename
End Get
End Property
Public Function GetString(ByVal Section As String, _
ByVal Key As String, ByVal [Default] As String) As String
' Returns a string from your INI file
Dim intCharCount As Integer
Dim objResult As New System.Text.StringBuilder(256)
intCharCount = GetPrivateProfileString(Section, Key, [Default], objResult, objResult.Capacity, strFilename)
If intCharCount > 0 Then
GetString = Left(objResult.ToString, intCharCount)
Else
GetString = ""
End If
End Function
Public Function GetInteger(ByVal Section As String, _
ByVal Key As String, ByVal [Default] As Integer) As Integer
' Returns an integer from your INI file
Return GetPrivateProfileInt(Section, Key, _
[Default], strFilename)
End Function
Public Function GetBoolean(ByVal Section As String, _
ByVal Key As String, ByVal [Default] As Boolean) As Boolean
' Returns a boolean from your INI file
Return (GetPrivateProfileInt(Section, Key, _
CInt([Default]), strFilename) = 1)
End Function
Public Sub WriteString(ByVal Section As String, _
ByVal Key As String, ByVal Value As String)
' Writes a string to your INI file
WritePrivateProfileString(Section, Key, Value, strFilename)
Flush()
End Sub
Public Sub WriteInteger(ByVal Section As String, _
ByVal Key As String, ByVal Value As Integer)
' Writes an integer to your INI file
WriteString(Section, Key, CStr(Value))
Flush()
End Sub
Public Sub WriteBoolean(ByVal Section As String, _
ByVal Key As String, ByVal Value As Boolean)
' Writes a boolean to your INI file
WriteString(Section, Key, CStr(CInt(Value)))
Flush()
End Sub
Private Sub Flush()
' Stores all the cached changes to your INI file
FlushPrivateProfileString(0, 0, 0, strFilename)
End Sub
End Class
b. Instantiate the class:
Dim objIniFile As New clsIni(path_of_your_file)
c. Get the setting:
Dim x As String
x = objIniFile.GetString("MAIN", "Setting_1", "")
d. Update / Create a setting:
objIniFile.WriteString("MAIN", "Setting_1", "new_setting")
Edit:
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim objIniFile As New clsIni("D:\WorldInfo.ini")
Label1.Text = objIniFile.GetString("B_Empty_IndexList", "Count", "")
Label2.Text = objIniFile.GetString("B_Use_IndexList", "Count", "")
End Sub
There is no point rolling your own method to do this. Use the Windows API method GetPrivateProfileString to do it:
Imports System.Runtime.InteropServices
Imports System.Text
<DllImport("kernel32")>
Private Shared Function GetPrivateProfileString(ByVal section As String, ByVal key As String, ByVal def As String, ByVal retVal As StringBuilder, ByVal size As Integer, ByVal filePath As String) As Integer
End Function
Public Function GetIniValue(section As String, key As String, filename As String, Optional defaultValue As String = "") As String
Dim sb As New StringBuilder(500)
If GetPrivateProfileString(section, key, defaultValue, sb, sb.Capacity, filename) > 0 Then
Return sb.ToString
Else
Return defaultValue
End If
End Function
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
Debug.WriteLine(GetIniValue("B_Empty_IndexList", "Count", My.Application.Info.DirectoryPath & "\WorldInfo.ini"))
Debug.WriteLine(GetIniValue("B_Use_IndexList", "Count", My.Application.Info.DirectoryPath & "\WorldInfo.ini"))
End Sub
Note some background reading if using this approach: Could there be encoding-related problems when storing unicode strings in ini files?
Those suggested Windows API have been deprecated for a long time now and they are really bad, you see on each GetPrivateProfile call you are reading and parsing the INI content all over again...
As an alternative try using my MadMilkman.Ini library, like this:
Imports MadMilkman.Ini
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim ini As New IniFile()
ini.Load("D:\WorldInfo.ini")
Label1.Text = ini.Sections("B_Empty_IndexList").Keys("Count").Value
Label2.Text = ini.Sections("B_Use_IndecList").Keys("Count").Value
End Sub
You can download the library from here: https://github.com/MarioZ/MadMilkman.Ini
EDIT
I was asked to elaborate more the discussion that I had with IInspectable in the comments below.
IInspectable: "Your solution doesn't appear to account for surrogate pairs."
Mario Z: "I have no idea why you assume that library doesn't support Unicode, it does and its quite simple... just use the appropriate encoding."
So here it goes, in short .NET's String represents an array of Chars and Char represents 16-bit character. When faced with a string that contains a 32-bit character it will use a so called "surrogate pair" (two characters that represent one). Now when working with this kind of string an issue that can happen for example is that we can make an invalid substring of that string if we cut it in the middle of that "surrogate pair". Also another issue that can happen is when working with the string indexer and not taking into account that a "surrogate pair" will consist of two indexed chars in that string.
However that is all not the case with MadMilkman.Ini, the library directly manipulates only with a specific set of characters while the rest of the string is left as it is (string is a self-consistent type with a full Unicode support). The characters that are targeted and manipulated are [, ], =, etc.
As an example here is a writing test sample:
Dim textWithSurrogatePairs =
"sample content " + Char.ConvertFromUtf32(Int32.Parse("22222", NumberStyles.HexNumber))
Dim ini = New IniFile(
New IniOptions() With {.Encoding = Encoding.Unicode})
ini.Sections.Add(
New IniSection(ini, "sample section",
New IniKey(ini, "sample key", textWithSurrogatePairs)))
ini.Save("sample file.ini")
The following is the content of "textWithSurrogatePairs" variable:
The following is the generated output "sample file.ini" file:
Also here is reading test sample:
Dim ini = New IniFile(
New IniOptions() With {.Encoding = Encoding.Unicode})
ini.Load("sample file.ini")
Dim readValue = ini.Sections("sample section").Keys("sample key").Value
The following is the "readValue" variable:
So in short the .NET framework itself handles the surrogate pairs, the only thing that we need to be aware of is to use an appropriate Encoding (as shown above).
Unfortunately this is something that IInspectable fails to realize and I failed to properly explain to him.