View Sidebar

A Million Little Pieces Of My Mind

Organica Core: ProfileDocument class

By: Paul S. Cilwa Viewed: 5/8/2024
Posted: 8/3/2018
Page Views: 663
Topics: #Computers #Programming #Organica #VB.NET
A derived Document class to read .INI files.

When Windows was first introduced, in included a feature then called ".INI" files. These "initialization files" stored user preferences for an application, such as whether or not to display a menu, or what color they want borders to be. Later, the name was changed to "profiles", and then to "private profiles". Finally, the functionality was moved to the System Registry. But the underlying code to parse the values in a profile remains (albeit at an unusually low level); and the files themselves are trivial to create (via Notepad, for example). In addition, since they are associated with a folder that contains them (as Registry entries are not), they actually lend themselves to providing folder information to Organica.

In this chapter, then, we shall derive a class from last chapter's Document class, to deal with this type of file.

Format

The format of profile files is quite simple. In fact, the original design notion was that Notepad would be the creator of them! A Profile is divided into Sections; each Section contains zero or more Keys, each with a Value. Here's an example:

Example.ini

[Organica] IconPath=[UserPhoto] DisplayName=[UserDisplayName] UserSince=8/21/2018 [Music] Pathname=C:\Users\Paul\My Music Icon=Icons\Music.png [Pictures] Pathname=C:\Users\Paul\My Pictures Icon=Icons\Photos.png [Videos] Pathname=C:\Users\Paul\My Videos Icon=Icons\Videos.png

ProfileDocument

Because the Profile concept is so old and has been largely replaced by Windows' Registry services, there are no VB.NET procedures to access a Profile. So, in the class definition below, we must start with the neccessary Windows API function declarations.

Documents.vb (append)

Public Class ProfileDocument Inherits Document Private i_Section As String Private Declare Ansi Function GetPrivateProfileString _ Lib "kernel32.dll" Alias "GetPrivateProfileStringA" _ (ByVal AppName As String, _ ByVal KeyName As String, _ ByVal DefaultValue As String, _ ByVal Value As StringBuilder, _ ByVal Size As Integer, _ ByVal FilePath As String) As Integer Private Declare Ansi Function GetPrivateProfileSections _ Lib "kernel32.dll" Alias "GetPrivateProfileStringA" _ (p1 As Integer, p2 As String, p3 As String, Bytes As Byte(), Size As Integer, FilePath As String) As Integer Private Declare Ansi Function WritePrivateProfileString _ Lib "kernel32.dll" Alias "WritePrivateProfileStringA" _ (ByVal AppName As String, _ ByVal KeyName As String, _ ByVal Value As String, _ ByVal FilePath As String) As Integer Private Declare Ansi Function GetPrivateProfileInt _ Lib "kernel32.dll" Alias "GetPrivateProfileIntA" _ (ByVal AppName As String, _ ByVal KeyName As String, _ ByVal Value As Integer, _ ByVal FilePath As String) As Integer Private Declare Ansi Function FlushPrivateProfileString _ Lib "kernel32.dll" Alias "WritePrivateProfileStringA" _ (ByVal AppName As Integer, _ ByVal KeyName As Integer, _ ByVal Value As Integer, _ ByVal FilePath As String) As Integer
Public Sub New(ByVal Filename As String) MyBase.New(Filename) i_Section = "Organica" Visible = False End Sub Public ReadOnly Property FilePath() As String Get Return i_Pathname End Get End Property
Public Function GetSectionNames() As String() Dim maxsize As Integer = 500 While True Dim bytes As Byte() = New Byte(maxsize - 1) {} Dim size As Integer = _ GetPrivateProfileSections(0, "", "", bytes, maxsize, i_Pathname) If size < maxsize - 2 Then Dim Selected As String = _ Encoding.ASCII.GetString(bytes, 0, size - (If(size > 0, 1, 0))) Return Selected.Split(New Char() {ControlChars.NullChar}) End If maxsize *= 2 End While Return Nothing End Function
Public Function GetData(ByVal Section As String, _ ByVal Key As String, Optional ByVal DefaultValue As String = "") Dim CharCount As Integer Dim Result As New System.Text.StringBuilder(256) CharCount = GetPrivateProfileString(Section, Key, DefaultValue, Result, Result.Capacity, i_Pathname) If CharCount > 0 Then GetData = Left(Result.ToString, CharCount) Else GetData = DefaultValue End If End Function
Public Function GetData(ByVal Key As String, _ Optional ByVal DefaultValue As String = "") As String Return GetData(i_Section, Key, DefaultValue) End Function
Public Sub WriteData(ByVal Key As String, _ ByVal Value As String) WritePrivateProfileString(i_Section, Key, Value, i_Pathname) FlushPrivateProfileString(0, 0, 0, i_Pathname) End Sub
Public Sub WriteData(ByVal Section As String, _ ByVal Key As String, ByVal Value As String) WritePrivateProfileString(Section, Key, Value, i_Pathname) FlushPrivateProfileString(0, 0, 0, i_Pathname) End Sub
Public Property UserSince As Date Get Return GetData("Organica", "UserSince", "1/1/1000") End Get Set(Value As Date) WriteData("Organica", "UserSince", Value) End Set End Property
Public Sub WriteLink(ByVal LinkName As String, _ ByVal Pathname As String, ByVal IconPath As String) WriteData(LinkName, "Pathname", Pathname) WriteData(LinkName, "Icon", IconPath) End Sub
Public ReadOnly Property Sections As Collection Get Dim All As String(), One As String, Result As New Collection All = GetSectionNames() For Each One In All If One.ToLower <> "organica" Then Result.Add(One) End If Next Return Result End Get End Property
Public ReadOnly Property LinkPathname(ByVal LinkName As String) Get Return GetData(LinkName, "Pathname", Nothing) End Get End Property
Public ReadOnly Property LinkIcon(ByVal LinkName As String) Get Return GetData(LinkName, "Icon", Nothing) End Get End Property
End Class