Well, in my previous thread i needed help deleting arrays, for the codes i use its here: http://www.daniweb.com/software-development/vbnet/threads/426588/how-to-move-arrays-1-place-down-

But now i need help saving the arrays, i can save all the arrays to ini file like this:

Ini module:

Option Strict On
Module INIAccess

#Region "API Calls"
    ' standard API declarations for INI access
    ' changing only "As Long" to "As Int32" (As Integer would work also)
    Private Declare Unicode Function WritePrivateProfileString Lib "kernel32" _
    Alias "WritePrivateProfileStringW" (ByVal lpApplicationName As String, _
    ByVal lpKeyName As String, ByVal lpString As String, _
    ByVal lpFileName As String) As Int32

    Private Declare Unicode Function GetPrivateProfileString Lib "kernel32" _
    Alias "GetPrivateProfileStringW" (ByVal lpApplicationName As String, _
    ByVal lpKeyName As String, ByVal lpDefault As String, _
    ByVal lpReturnedString As String, ByVal nSize As Int32, _
    ByVal lpFileName As String) As Int32
#End Region

    Public Function INIRead(ByVal INIPath As String, _
    ByVal SectionName As String, ByVal KeyName As String, _
    ByVal DefaultValue As String) As String
        ' primary version of call gets single value given all parameters
        Dim n As Int32
        Dim sData As String
        sData = Space$(1024) ' allocate some room 
        n = GetPrivateProfileString(SectionName, KeyName, DefaultValue, _
        sData, sData.Length, INIPath)
        If n > 0 Then ' return whatever it gave us
            INIRead = sData.Substring(0, n)
        Else
            INIRead = ""
        End If
    End Function

#Region "INIRead Overloads"
    Public Function INIRead(ByVal INIPath As String, _
    ByVal SectionName As String, ByVal KeyName As String) As String
        ' overload 1 assumes zero-length default
        Return INIRead(INIPath, SectionName, KeyName, "")
    End Function

    Public Function INIRead(ByVal INIPath As String, _
    ByVal SectionName As String) As String
        ' overload 2 returns all keys in a given section of the given file
        Return INIRead(inipath, sectionname, Nothing, "")
    End Function

    Public Function INIRead(ByVal INIPath As String) As String
        ' overload 3 returns all section names given just path
        Return INIRead(INIPath, Nothing, Nothing, "")
    End Function
#End Region

    Public Sub INIWrite(ByVal INIPath As String, ByVal SectionName As String, _
    ByVal KeyName As String, ByVal TheValue As String)
        Call WritePrivateProfileString(SectionName, KeyName, TheValue, INIPath)
    End Sub

    Public Sub INIDelete(ByVal INIPath As String, ByVal SectionName As String, _
    ByVal KeyName As String) ' delete single line from section
        Call WritePrivateProfileString(SectionName, KeyName, Nothing, INIPath)
    End Sub

    Public Sub INIDelete(ByVal INIPath As String, ByVal SectionName As String)
        ' delete section from INI file
        Call WritePrivateProfileString(SectionName, Nothing, Nothing, INIPath)
    End Sub

End Module

To save the arrays:

        Dim iniPath As String = Application.StartupPath & "\Configs\SilkroadR.ini"

        For i = 0 To CurrentAcc.Count - 2
            INIWrite(iniPath, "Account " & i, "Version", CurrentAcc(i).Version)
            INIWrite(iniPath, "Account " & i, "Login", CurrentAcc(i).Login)
            INIWrite(iniPath, "Account " & i, "Username", CurrentAcc(i).Username)
            INIWrite(iniPath, "Account " & i, "Password", CurrentAcc(i).Password)
            INIWrite(iniPath, "Account " & i, "Character", CurrentAcc(i).Character)
            INIWrite(iniPath, "Account " & i, "Server", CurrentAcc(i).Server)
            INIWrite(iniPath, "Account " & i, "ReturnLogin", CurrentAcc(i).ReturnLogin)
            INIWrite(iniPath, "Account " & i, "LoginStart", CurrentAcc(i).LoginStart)
            INIWrite(iniPath, "Account " & i, "RelogDisco", CurrentAcc(i).RelogDisco)
            INIWrite(iniPath, "Account " & i, "DisMap", CurrentAcc(i).DisMap)
            INIWrite(iniPath, "Account " & i, "SpecialAcc", CurrentAcc(i).SpecialAcc)

        Next

Well, i want to save my array to a file that will be encrypted and then i could read it, example when i have my arrays in the application and i save it, i close my application and then i open it again i would like to load all the arrays and all the items in the "DomainUpDown" with a button, which will be read from the file, but i don't want the file to be seen from the users for secure reasons, i would like it to be encrypted.

What i had in mind was saving it as ini file, encrypting the file to another extension, and encrypt it to binary, but to do that i would use the special folder in the AppData, is there a better way for me to save the arrays and encrypt it and be able to read it again and load it in my application ?

Recommended Answers

All 25 Replies

Well, my textfile has this:

Silkroad International
Random
user1
pass1
char1
Aquarius
False
False
False
False
False
Silkroad International
Random
user2
pass2
char2
Aquarius
False
False
False
False
False
Silkroad International
Random
user3
pass3
char3
Aquarius
False
False
False
False
False

And this part:

Silkroad International
Random
user1
pass1
char1
Aquarius
False
False
False
False
False

is 1 array, my array is like CurrentAcc(0).Version, .Login, .Username, .Password, .Character, .Server, etc, so how can i match all of them from the textfile ? then go to the next array CurrentAcc(1) and then CurrentAcc(2) and so on ?

To add encryption of the ini file you could try changing the IO code as follows

Public Function INIRead(ByVal INIPath As String, ByVal SectionName As String, _
    ByVal KeyName As String, ByVal DefaultValue As String) As String

    ' primary version of call gets single value given all parameters

    Dim n As Int32
    Dim sData As String

    sData = Space$(1024) ' allocate some room
    n = GetPrivateProfileString(SectionName, KeyName, DefaultValue, sData, sData.Length, INIPath)

    INIRead = IIF(n > 0, Decrypt(sData.Substring(0, n)), "")

End Function

Public Sub INIWrite(ByVal INIPath As String, ByVal SectionName As String, _
    ByVal KeyName As String, ByVal TheValue As String)

    Call WritePrivateProfileString(Encrypt(SectionName), Encrypt(KeyName), Encrypt(TheValue), INIPath)

End Sub

Public Sub INIDelete(ByVal INIPath As String, ByVal SectionName As String, _
    ByVal KeyName As String) ' delete single line from section

    Call WritePrivateProfileString(Encrypt(SectionName), Encrypt(KeyName), Nothing, INIPath)

End Sub

Public Sub INIDelete(ByVal INIPath As String, ByVal SectionName As String)

    Call WritePrivateProfileString(Encrypt(SectionName), Nothing, Nothing, INIPath)

End Sub    

using the Encrypt/Decrypt code you already have. Or you may only want to encrypt the actual values in which case you could see the ini file in a form that would allow you to ensure it is well formatted bur still obfuscate the values. You may have to modify the encrypt/decrypt code to handle the case where a value is "Nothing"

There's always a value, but the thing is if i convert all to ini, i will have [Account 0] 2, 3, 4, 5 etc, how can i load it back again to the application ? Like For i = 0 to CurrentAcc.Count - 1, will do the trick to save but how can i count each "Section" in the ini file ?

If I might offer a suggestion, a typical ini file has the form

[section]
setting=value
setting=value
[section]
setting=value
.
.
.

This form lends itself to a structure that can be easily represented using two nested dictionaries. If you are not familiar with dictionaries, they are objects consisting of key-value pairs. You can think of a dictionary as a type of array but where the index can be of any type and the value is the associated data. In this case, the outer one can be defined as

Dictionary(Of String, <settings>)

where the key is the section name and "?" will be the settings from the ini file from within that section. Because the settings are also key-value pairs, they can also be stored as a dictionary except this dictionary will consist of a pair of strings. So the complete ini file can be stored in the following

Dim inifile As New Dictionary(Of String, Dictionary(Of String, String))

To add an item to a Dictionary you use the Add method. So to add a new section (let's call it "[FolderList]") you use

inifile.Add("FolderList]", New Dictionary(Of String, String))

Let's say there is a setting under this section such as

LastUsed=D:\Temp

To add this setting to inifile you code

inifile("[FolderList]").Add("LastUsed","D:\Temp")

I've written a simple class to do a couple of the operations. The Write method writes only to the debug window, not to the actual file. Note that it encrypts the "value" portion only. The inifile class also does minimal error checking. Dictionaries also support a Remove method for deleting settings or entire sections.

Public Class inifile

    Private m_inifile As New Dictionary(Of String, Dictionary(Of String, String))

    Public Function GetValue(section As String, setting As String) As String

        'return the value of <setting> in [section]
        'return Nothing if not defined

        If m_inifile.ContainsKey(section) Then
            If m_inifile(section).ContainsKey(setting) Then
                Return m_inifile(section)(setting)
            End If
        End If

        Return Nothing

    End Function

    Public Sub SetValue(section As String, setting As String, value As String)

        'set the value of <setting> in [section]

        'create [section] if not defined

        If Not m_inifile.ContainsKey(section) Then
            m_inifile.Add(section, New Dictionary(Of String, String))
        End If

        'create <setting> if not defined and set value

        If Not m_inifile(section).ContainsKey(setting) Then
            m_inifile(section).Add(setting, value)
        Else
            m_inifile(section)(setting) = value
        End If

    End Sub

    Public Function Read(filename As String) As Boolean

        Dim section As String = Nothing    'section name (includes [])
        Dim setting As String = Nothing    'setting name
        Dim value As String = Nothing      'setting value
        Dim equals As Integer              'index of first "="

        'get rid of any existing entries

        m_inifile.Clear()

        For Each line As String In System.IO.File.ReadAllLines("d:\utils\temp\test.ini")

            'process either a section "[" or a setting
            'settings are split at the first "=" into setting=value pairs

            If line.StartsWith("[") Then
                section = Trim(line)
                m_inifile.Add(section, New Dictionary(Of String, String))
            Else
                equals = InStr(line, "=")
                setting = line.Substring(0, equals - 1)
                value = line.Substring(equals)
                m_inifile(section).Add(setting, value)
            End If

        Next

        Return True

    End Function

    Public Function Write(filename As String) As Boolean
        Return True
    End Function

    Public Function Write() As Boolean

        'write the entire inifile structure

        For Each section As String In m_inifile.Keys
            Debug.WriteLine(section)
            For Each setting As String In m_inifile(section).Keys
                Debug.WriteLine(setting & "=" & Encrypt(m_inifile(section)(setting)))
            Next
        Next

        Return True

    End Function

End Class

It was a dark and stormy night. OK. Not so stormy but it did rain and I was awake so I expanded on my earlier post. I'm going to post this code in three sections.

Part one is a rudimentary inifile Class. This class contains methods for reading/writing/maintaining an ini file. It could use some bulletproofing and such (see comments) but should be a good starting place for anyone who wants to tailor it to specific needs. Sections are identified by

[section]
setting=value
setting=value
.
.
.

blank lines and comments are not allowed. This is left as an excercise for the student (I hated that phrase when I was a student).

Imports System.IO

Public Class inifile

    '------------------------------------------------
    '  Name:
    '
    '    inifile.vb
    '
    '  Description:
    '
    '    Simple minded implementation of an inifile reader/writer class. The functionality is all
    '    here except that error checking is minimal, everythinig is case sensitive and there is
    '    no provision to maintain blank lines or comments.
    '
    '  Properties:
    '
    '    status - String - blank or a string indicating the nature of the error
    '
    '  Methods:
    '
    '    Read(filename)
    '
    '        Read the given inifile into memory
    '
    '    Write()
    '
    '        Write the in-memory inifile to the last read inifile on disk
    '
    '    Write(filename)
    '
    '        Write the in0memory inifile to the given file and make it the current file
    '
    '    GetValue(section,setting)
    '
    '        Return the value of the given setting in the given section
    '
    '    SetValue(section,setting,value)
    '
    '        Set the given setting in the given section to the given valaue (create as needed)
    '
    '    Delete(section)
    '
    '        Delete the given section and all of its settings
    '
    '    Delete(section,setting)
    '
    '        Delete the given setting ini the given section
    '
    '    Serialize()
    '
    '        Convert the in-memory inifile to a string (lines end with vbCrLf) with encryption
    '
    '    Serialize2()
    '
    '        Convert the in-memory inifile to a string (lines end with vbCrLf) without encryption
    '
    '  Notes:
    '
    '    The in-memory inifile is maintained as nested dictionaries. Each section is a dictionary
    '    where the key is the setting name and the value is the string value of the setting. The
    '    entire structure is also a dictionary where the key is the section name (including the [
    '    and ] delimiters) and the value is the dictionary of the associated settings.
    '
    '  Audit:
    '
    '    2012-07-01  RevJ  original code
    '------------------------------------------------

    Public status As String = ""

    Private m_inifile As New Dictionary(Of String, Dictionary(Of String, String))
    Private m_filename As String = ""

    Public Function GetValue(section As String, setting As String) As String

        'return the value of <setting> in [section]
        'return Nothing if not defined

        status = ""

        If Not m_inifile.ContainsKey(section) Then
            status = section & " not found"
            Return Nothing
        End If

        If Not m_inifile(section).ContainsKey(setting) Then
            status = section & setting & " not found"
            Return Nothing
        End If

        Return m_inifile(section)(setting)

    End Function

    Public Sub SetValue(section As String, setting As String, value As String)

        'set the value of <setting> in [section]

        status = ""

        'create [section] if not defined

        If Not section.StartsWith("[") Then
            section = "[" & section
        End If

        If Not section.EndsWith("]") Then
            section &= "]"
        End If

        If Not m_inifile.ContainsKey(section) Then
            m_inifile.Add(section, New Dictionary(Of String, String))
        End If

        'create <setting> if not defined and set value

        If Not m_inifile(section).ContainsKey(setting) Then
            m_inifile(section).Add(setting, value)
        Else
            m_inifile(section)(setting) = value
        End If

    End Sub

    Public Function Delete(section As String) As Boolean

        'delete the given section and all of its settings

        status = ""

        If Not m_inifile.ContainsKey(section) Then
            status = section & " not found"
            Return False
        End If

        m_inifile.Remove(section)

        Return True

    End Function

    Public Function Delete(section As String, setting As String) As Boolean

        'delete the given setting from the given section

        status = ""

        If Not m_inifile.ContainsKey(section) Then
            status = section & " not found"
            Return False
        End If

        If Not m_inifile(section).ContainsKey(setting) Then
            status = section & setting & " not found"
            Return False
        End If

        m_inifile(section).Remove(setting)
        Return True

    End Function

    Public Function Read(filename As String) As Boolean

        'read the given ini file

        Dim section As String = Nothing
        Dim setting As String = Nothing
        Dim value As String = Nothing
        Dim equals As Integer

        status = ""

        If Not My.Computer.FileSystem.FileExists(filename) Then
            status = filename & " not found"
            Return False
        End If

        'get rid of any existing entries

        m_inifile.Clear()
        m_filename = filename

        For Each line As String In System.IO.File.ReadAllLines(m_filename)

            'process either a section "[" or a setting

            If line.StartsWith("[") Then
                section = Trim(line)
                m_inifile.Add(section, New Dictionary(Of String, String))
            Else
                equals = InStr(line, "=")
                setting = Trim(line.Substring(0, equals - 1))
                value = Decrypt(Trim(line.Substring(equals)))
                m_inifile(section).Add(setting, value)
            End If

        Next

        Return True

    End Function

    Public Function Write(filename As String) As Boolean

        'write the inifile to the given filename and set filename as
        'the current inifile

        status = ""

        Try
            File.WriteAllText(filename, Serialize())
            m_filename = filename
        Catch ex As Exception
            status = ex.Message
            Return False
        End Try

        Return True

    End Function

    Public Function Write() As Boolean

        'write the inifile to the current file

        Return IIf(m_filename = "", False, Write(m_filename))

    End Function

    Public Function Serialize() As String

        'convert the in-memory inifile to a string

        Dim builder As New System.Text.StringBuilder

        For Each section As String In m_inifile.Keys
            builder.Append(section & vbCrLf)
            For Each setting As String In m_inifile(section).Keys
                builder.Append(setting & "=" & Encrypt(m_inifile(section)(setting)) & vbCrLf)
            Next
        Next

        Return builder.ToString

    End Function

    Public Function Serialize2() As String

        'convert the in-memory inifile to a string (no encryption)

        Dim builder As New System.Text.StringBuilder

        For Each section As String In m_inifile.Keys
            builder.Append(section & vbCrLf)
            For Each setting As String In m_inifile(section).Keys
                builder.Append(setting & "=" & m_inifile(section)(setting) & vbCrLf)
            Next
        Next

        Return builder.ToString

    End Function

End Class

Part two is the Encryption/Decryption code. It's been documented to the extent that I understand it.

Imports System.Security
Imports System.Security.Cryptography
Imports System.IO
Imports System.Runtime.InteropServices
Imports System.Text.RegularExpressions
Imports System.Text

Module EncryptDecrypt

    Public Function Encrypt(ByVal plainText As String) As String

        Dim passPhrase As String = "yourPassPhrase"
        Dim saltValue As String = "mySaltValue"
        Dim hashAlgorithm As String = "SHA1"

        Dim passwordIterations As Integer = 2
        Dim initVector As String = "@1B2c3D4e5F6g7H8"
        Dim keySize As Integer = 256

        Dim initVectorBytes As Byte() = Encoding.ASCII.GetBytes(initVector)
        Dim saltValueBytes As Byte() = Encoding.ASCII.GetBytes(saltValue)

        Dim plainTextBytes As Byte() = Encoding.UTF8.GetBytes(plainText)

        Dim password As New PasswordDeriveBytes(passPhrase, saltValueBytes, hashAlgorithm, passwordIterations)

        Dim keyBytes As Byte() = password.GetBytes(keySize \ 8)
        Dim symmetricKey As New RijndaelManaged()

        symmetricKey.Mode = CipherMode.CBC

        Dim encryptor As ICryptoTransform = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes)

        Dim memoryStream As New MemoryStream()
        Dim cryptoStream As New CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)

        cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length)
        cryptoStream.FlushFinalBlock()

        Dim cipherTextBytes As Byte() = memoryStream.ToArray()

        memoryStream.Close()
        cryptoStream.Close()

        Dim cipherText As String = Convert.ToBase64String(cipherTextBytes)

        Return cipherText

    End Function

    Public Function Decrypt(ByVal cipherText As String) As String

        Dim passPhrase As String = "yourPassPhrase"
        Dim saltValue As String = "mySaltValue"
        Dim hashAlgorithm As String = "SHA1"

        Dim passwordIterations As Integer = 2
        Dim initVector As String = "@1B2c3D4e5F6g7H8"
        Dim keySize As Integer = 256

        'Convert strings defining encryption key characteristics into byte
        'arrays. Let us assume that strings only contain ASCII codes.
        'If strings include Unicode characters, use Unicode, UTF7, or UTF8
        'encoding.

        Dim initVectorBytes As Byte() = Encoding.ASCII.GetBytes(initVector)
        Dim saltValueBytes As Byte() = Encoding.ASCII.GetBytes(saltValue)

        'Convert our ciphertext into a byte array.

        Dim cipherTextBytes As Byte() = Convert.FromBase64String(cipherText)

        'First, we must create a password, from which the key will be
        'derived. This password will be generated from the specified
        'passphrase and salt value. The password will be created using
        'the specified hash algorithm. Password creation can be done in
        'several iterations.

        Dim password As New PasswordDeriveBytes(passPhrase, saltValueBytes, hashAlgorithm, passwordIterations)

        'Use the password to generate pseudo-random bytes for the encryption
        'key. Specify the size of the key in bytes (instead of bits).

        Dim keyBytes As Byte() = password.GetBytes(keySize \ 8)

        'Create uninitialized Rijndael encryption object.

        Dim symmetricKey As New RijndaelManaged()

        'It is reasonable to set encryption mode to Cipher Block Chaining
        '(CBC). Use default options for other symmetric key parameters.

        symmetricKey.Mode = CipherMode.CBC

        'Generate decryptor from the existing key bytes and initialization
        'vector. Key size will be defined based on the number of the key
        'bytes.

        Dim decryptor As ICryptoTransform = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes)

        'Define memory stream which will be used to hold encrypted data.

        Dim memoryStream As New MemoryStream(cipherTextBytes)

        'Define cryptographic stream (always use Read mode for encryption).

        Dim cryptoStream As New CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)

        'Since at this point we don't know what the size of decrypted data
        'will be, allocate the buffer long enough to hold ciphertext;
        'plaintext is never longer than ciphertext.

        Dim plainTextBytes As Byte() = New Byte(cipherTextBytes.Length - 1) {}

        'Start decrypting.

        Dim decryptedByteCount As Integer = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length)

        'Close both streams.

        memoryStream.Close()
        cryptoStream.Close()

        'Convert decrypted data into a string.
        'Let us assume that the original plaintext string was UTF8-encoded.

        Dim plainText As String = Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount)

        'Return decrypted string.

        Return plainText

    End Function

End Module

Part three is a simple front end to play around with the above modules.

Public Class Form1

    '----------------------------------------------
    '
    '  Name:
    '
    '    IniReadWrite.vb
    '
    '  Description:
    '
    '    GUI front end for testing the inifile Class
    '
    '  Audit:
    '
    '    2012-07-01  RevJ  original code
    '
    '----------------------------------------------

    Private ini As New inifile

    Private Sub UpdateDisplay()
        Me.Text = ini.status
        txtIni.Text = ini.Serialize2()
    End Sub

    Private Sub btnRead_Click(sender As System.Object, e As System.EventArgs) Handles btnRead.Click
        ini.Read(txtReadFile.Text)
        UpdateDisplay()
    End Sub

    Private Sub btnWrite_Click(sender As System.Object, e As System.EventArgs) Handles btnWrite.Click

        If txtWriteFile.Text = "" Then
            ini.Write()
        Else
            ini.Write(txtWriteFile.Text)
            txtReadFile.Text = txtWriteFile.Text
            txtWriteFile.Text = ""
        End If

        UpdateDisplay()
    End Sub

    Private Sub btnAdd_Click(sender As System.Object, e As System.EventArgs) Handles btnAdd.Click

        If txtSection.Text <> "" And txtSetting.Text <> "" And txtValue.Text <> "" Then
            ini.SetValue(txtSection.Text, txtSetting.Text, txtValue.Text)
            UpdateDisplay()
        Else
            MsgBox("you must enter values for section, setting and value")
        End If

    End Sub

    Private Sub btnDelete_Click(sender As System.Object, e As System.EventArgs) Handles btnDelete.Click

        Dim delim As Integer = InStr(txtDelete.Text, "]")

        If txtDelete.Text.StartsWith("[") And delim > 0 Then

            If txtDelete.Text.EndsWith("]") Then
                'delete section
                ini.Delete(txtDelete.Text)
            Else
                'delete setting
                Dim section As String = txtDelete.Text.Substring(0, delim)
                Dim setting As String = txtDelete.Text.Substring(delim)
                ini.Delete(section, setting)
            End If

            UpdateDisplay()

        Else
            MsgBox("delete string must contain a section as [section]")
        End If

    End Sub

End Class

I'll try to post a picture of the form but I haven't been having much luck with that lately.

inifile

Ok, i was playing with it, i can write it to the textbox, its the same as what i had before to read/write ini files, the thing is im not worried about encrypting right now.

What im trying to accomplish is save the .ini file(which i have right now), and then be able to read that ini file and put it back to its array.

Example:

[Account 0]
Version=Silkroad International
Login=Random
Username=ID1
Password=PASS1
Character=Char1
Server=Aquarius
ReturnLogin=False
LoginStart=False
RelogDisco=False
DisMap=False
SpecialAcc=False
[Account 1]
Version=SilkroadR
Login=Random
Username=User2
Password=Pass2
Character=Char2
Server=Gobi
ReturnLogin=True
LoginStart=False
RelogDisco=True
DisMap=False
SpecialAcc=True

Ok, i closed my application and i re-opened it and all the arrays are gone (which i want that to happen) and then with 1 button i want to load the arrays back,

example, for each [Account] i needs to create 1 item in the DomainUpDown, thats how i switch between my accounts(arrays), so Account 0, the first array should be like CurrentAcc(0).Version = Silkroad International, as it reads the ini file, then go to Account 1, so it should be like CurrentAcc(1).Version = SilkroadR, and so on, i want to recreat all my arrays by reading the ini file, when im able to acomplish that then ill want to encrypt but first i want to be able to recreate my arrays.

In the case where you have parallel sections like [Account 0], [Account 1], etc and each section has the same settings, you could modify the inifile class with a new method to return the parallel items as arrays. It would look something like

    Public Function GetAllValues(sectionStarts As String, setting As String) As String()

        'create an array of all settings with the given setting name in sections
        'that start with the given string

        Dim settings As String = ""

        For Each section As String In m_inifile.Keys
            If section.StartsWith(sectionStarts) Then
                If m_inifile(section).ContainsKey(setting) Then
                    settings = settings & vbLf & m_inifile(section)(setting)
                End If
            End If
        Next

        Return settings.Substring(1).Split(vbLf)

    End Function

Note that with this code you would get the info as in

Dim versions() As String = ini.GetAllValues("[Account","Version)

Which returns an array of all version settings in sections which start with "[Account"

The return statement might look a little odd. It strips off the first vbLf before splitting to avoid returning an ampty element (you have to have one fewer delimiters than you have elements).

That INIFile class is weird, the thing i use to write/read/delete is

Option Strict On
Module INIAccess

#Region "API Calls"
    ' standard API declarations for INI access
    ' changing only "As Long" to "As Int32" (As Integer would work also)
    Private Declare Unicode Function WritePrivateProfileString Lib "kernel32" _
    Alias "WritePrivateProfileStringW" (ByVal lpApplicationName As String, _
    ByVal lpKeyName As String, ByVal lpString As String, _
    ByVal lpFileName As String) As Int32

    Private Declare Unicode Function GetPrivateProfileString Lib "kernel32" _
    Alias "GetPrivateProfileStringW" (ByVal lpApplicationName As String, _
    ByVal lpKeyName As String, ByVal lpDefault As String, _
    ByVal lpReturnedString As String, ByVal nSize As Int32, _
    ByVal lpFileName As String) As Int32
#End Region

    Public Function INIRead(ByVal INIPath As String, _
    ByVal SectionName As String, ByVal KeyName As String, _
    ByVal DefaultValue As String) As String
        ' primary version of call gets single value given all parameters
        Dim n As Int32
        Dim sData As String
        sData = Space$(1024) ' allocate some room 
        n = GetPrivateProfileString(SectionName, KeyName, DefaultValue, _
        sData, sData.Length, INIPath)
        If n > 0 Then ' return whatever it gave us
            INIRead = sData.Substring(0, n)
        Else
            INIRead = ""
        End If
    End Function

#Region "INIRead Overloads"
    Public Function INIRead(ByVal INIPath As String, _
    ByVal SectionName As String, ByVal KeyName As String) As String
        ' overload 1 assumes zero-length default
        Return INIRead(INIPath, SectionName, KeyName, "")
    End Function

    Public Function INIRead(ByVal INIPath As String, _
    ByVal SectionName As String) As String
        ' overload 2 returns all keys in a given section of the given file
        Return INIRead(inipath, sectionname, Nothing, "")
    End Function

    Public Function INIRead(ByVal INIPath As String) As String
        ' overload 3 returns all section names given just path
        Return INIRead(INIPath, Nothing, Nothing, "")
    End Function
#End Region

    Public Sub INIWrite(ByVal INIPath As String, ByVal SectionName As String, _
ByVal KeyName As String, ByVal TheValue As String)
        Call WritePrivateProfileString(SectionName, KeyName, TheValue, INIPath)
    End Sub

    Public Sub INIDelete(ByVal INIPath As String, ByVal SectionName As String, _
    ByVal KeyName As String) ' delete single line from section
        Call WritePrivateProfileString(SectionName, KeyName, Nothing, INIPath)
    End Sub

    Public Sub INIDelete(ByVal INIPath As String, ByVal SectionName As String)
        ' delete section from INI file
        Call WritePrivateProfileString(SectionName, Nothing, Nothing, INIPath)
    End Sub

End Module

Like, i can't do anything with the INIFile class that you provided me

Try this

Public Class Form1

    Const INIFILE = "d:\utils\temp\test.ini"

    Structure Account
        Dim AcctName As String
        Dim Version As String
        Dim Login As String
        Dim Username As String
        Dim Password As String
        Dim Character As String
        Dim Server As String
        Dim ReturnLogin As String
        Dim LoginStart As String
        Dim RelogDisco As String
        Dim DisMap As String
        Dim SpecialAcc As String
    End Structure

    Private Accounts() As Account

    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load

    End Sub

    Private Sub btnRead_Click(sender As System.Object, e As System.EventArgs) Handles btnRead.Click

        Dim accts() As String = INIRead(INIFILE).Split(Chr(0))
        ReDim Accounts(UBound(accts) - 1)

        For i As Integer = 0 To UBound(accts) - 1
            Accounts(i).AcctName = accts(i)
            Accounts(i).Version = INIRead(INIFILE, accts(i), "Version")
            Accounts(i).Login = INIRead(INIFILE, accts(i), "Login")
            Accounts(i).Username = INIRead(INIFILE, accts(i), "Username")
            Accounts(i).Password = INIRead(INIFILE, accts(i), "Password")
            Accounts(i).Character = INIRead(INIFILE, accts(i), "Character")
            Accounts(i).Server = INIRead(INIFILE, accts(i), "Server")
            Accounts(i).ReturnLogin = INIRead(INIFILE, accts(i), "ReturnLogin")
            Accounts(i).LoginStart = INIRead(INIFILE, accts(i), "LoginStart")
            Accounts(i).RelogDisco = INIRead(INIFILE, accts(i), "RelogDisco")
            Accounts(i).DisMap = INIRead(INIFILE, accts(i), "DisMap")
            Accounts(i).SpecialAcc = INIRead(INIFILE, accts(i), "SpecialAcc")
        Next

    End Sub

    Private Sub btnWrite_Click(sender As System.Object, e As System.EventArgs) Handles btnWrite.Click

        For Each acct As Account In Accounts
            INIWrite(INIFILE, acct.AcctName, "Version", acct.Version)
            INIWrite(INIFILE, acct.AcctName, "Login", acct.Login)
            INIWrite(INIFILE, acct.AcctName, "Username", acct.Username)
            INIWrite(INIFILE, acct.AcctName, "Password", acct.Password)
            INIWrite(INIFILE, acct.AcctName, "Character", acct.Character)
            INIWrite(INIFILE, acct.AcctName, "Server", acct.Server)
            INIWrite(INIFILE, acct.AcctName, "ReturnLogin", acct.ReturnLogin)
            INIWrite(INIFILE, acct.AcctName, "LoginStart", acct.LoginStart)
            INIWrite(INIFILE, acct.AcctName, "RelogDisco", acct.RelogDisco)
            INIWrite(INIFILE, acct.AcctName, "DisMap", acct.DisMap)
            INIWrite(INIFILE, acct.AcctName, "SpecialAcc", acct.SpecialAcc)
        Next

    End Sub

End Class

You can always add Encryption/Decrption to just the Password field if you like.

What i had in mind was saving it as ini file, encrypting the file to another extension, and encrypt it to binary, but to do that i would use the special folder in the AppData, is there a better way for me to save the arrays and encrypt it and be able to read it again and load it in my application?

Hi,

I don’t know if this is a better way, but I’ll leave it to you to decide. It totally changes the way you are managing your data.

Basically what you have is a set of account records that you wish to store and retrieve. You also want to obfuscate the data so users can not see sensitive data.

Two alternatives that immediately come to mind are first a database and second one is to store the data in a user-setting. Personally, I would opt for the database, but some people some to find them to be difficult to work with particularly in getting them stored in the proper location so that they can be written back to without bumping into security issues. The user-setting option alleviates the issue of dealing with the file location as .Net will handle this for you, so that is the route that I plan to show you below.

Since your have a defined Account record format, it makes sense to use a datatable to store each record. You can add a datatable to the user-settings as shown in the this picture. Under "Type" select browse, and select "System.Data.DataTable".

UserSettingDT
In the example code shown below, I have implemented a bindingsource and bindingsourcenavigator (the toolbar at the top of the form) to allow you to add and delete records to the datatable. I typically use a datagridview to display a datatable and have implemented this in the example. However, I believe that you may be using textboxes to display the records. I have added a single textbox for the version field to demonstrate how to do that. I also seen from your other post that you are using a listbox to navigate the records. If you wish to do this versus the using the bindingnavigator, I have also include an example with the listbox populated with the version field to demonstrate how to do this as well. As part of the listbox, I showed code for adding and deleting a record.

For your encryption needs, I have used a basic XOR encryption on the string fields. You may what a stronger method, but this is simple to use.

To test this code, just open a new WinForm project and replace the Form1.vb code with that shown. It will create all the controls on the fly.

'For info on location of the user.config file see: http://msdn.microsoft.com/en-us/library/8eyb2ct1.aspx
Public Class Form1
    Private AccountsBindingSource As New BindingSource
    Private WithEvents AccountsBindingNavigator As New BindingNavigator(True)
    Private dgvAccounts As New DataGridView
    Private lblVersion As New Label With {.Text = "Version", .Parent = Me, .Width = 75}
    Private WithEvents tbVersion As New TextBox With {.Parent = Me}
    Private WithEvents lboxSelect As New ListBox
    Private WithEvents btnRemoveCurrent As New Button With {.Text = "Delete Selected Record", .Parent = Me}
    Private WithEvents btnAddRecord As New Button With {.Text = "Add Record", .Parent = Me}

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.ClientSize = New Size(700, 500)

        AccountsBindingNavigator.Parent = Me
        With dgvAccounts
            .Parent = Me
            .ScrollBars = ScrollBars.Both
            .Location = New Point(5, AccountsBindingNavigator.Height + 1)
            .Size = New Size(690, 240)
        End With

        If My.Settings.AccountsTable Is Nothing Then
            'Table has not yet been stored, or has been set to Nothing
            My.Settings.AccountsTable = New AccountsDT
            My.Settings.AccountsTable.TableName = "Accounts"
        Else
            'unscramble the strings of the table
            ScrambleAccountTable()
        End If
        AccountsBindingSource.DataSource = My.Settings.AccountsTable
        AccountsBindingNavigator.BindingSource = AccountsBindingSource
        dgvAccounts.DataSource = AccountsBindingSource

        'This is just to show how to use a textbox to display values if you do not want to use the datagridview
        lblVersion.Location = New Point(5, dgvAccounts.Location.Y + dgvAccounts.Height + 3)
        tbVersion.Location = New Point(lblVersion.Location.X + lblVersion.Width + 5, lblVersion.Location.Y)
        tbVersion.DataBindings.Add("Text", AccountsBindingSource, "Version", False, DataSourceUpdateMode.OnPropertyChanged)


        'this is to demonstrate how a listbox could be used to navigate the records
        With lboxSelect
            .Location = New Point(tbVersion.Location.X + tbVersion.Width + 5, tbVersion.Location.Y)
            .ScrollAlwaysVisible = True
            .Size = New Size(150, 200)
            .Parent = Me
            .DataSource = AccountsBindingSource
            .DisplayMember = "Version"
        End With

        'this button replaces the bindingnaviogator delete (X) button
        btnRemoveCurrent.Location = New Point(lboxSelect.Location.X + lboxSelect.Width + 5, lboxSelect.Location.Y)

        'this button replaces the bindingnavigator add (+) button
        btnAddRecord.Location = New Point(btnRemoveCurrent.Location.X, btnRemoveCurrent.Location.Y + btnRemoveCurrent.Height + 5)

    End Sub

    Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
        'save the data before the application closes
        Me.Validate()
        AccountsBindingSource.EndEdit() 'finalize any remaining inputs
        My.Settings.AccountsTable.AcceptChanges()
        ScrambleAccountTable()
        My.Settings.Save()
    End Sub

    Private Sub ScrambleAccountTable()
        For Each row As DataRow In My.Settings.AccountsTable.Rows
            For i As Int32 = 0 To UBound(row.ItemArray)
                If TypeOf row.Item(i) Is String Then
                    Dim scramble As String = scramblestring(CStr(row.Item(i)))
                    row.Item(i) = scramble
                End If
            Next i
        Next row
        My.Settings.AccountsTable.AcceptChanges()
    End Sub

    Public Function scramblestring(ByVal val As String, Optional ByVal key As Byte = 2) As String
        'A Simple XOR encryption.  Key can range from 0 to 255. A value of 0 does not scramble the text
        'call to scramble/unscramble based on key value
        Dim sb As New System.Text.StringBuilder(val.Length)
        For i As Integer = 0 To val.Length - 1
            sb.Append(Chr(CByte(Asc(val(i))) Xor key))
        Next
        Return sb.ToString
    End Function

    Private Sub lboxSelect_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles lboxSelect.SelectedIndexChanged
        If lboxSelect.SelectedIndex <> -1 Then
            AccountsBindingSource.Position = lboxSelect.SelectedIndex
        End If
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
        AccountsBindingSource.RemoveCurrent()
    End Sub

    Private Sub btnAddRecord_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnAddRecord.Click
        AccountsBindingSource.AddNew()
    End Sub
End Class

Public Class AccountsDT
    Inherits System.Data.DataTable
    Public Sub New()
        With Me.Columns
            .Add(New DataColumn("Version", GetType(String)))
            .Add(New DataColumn("Username", GetType(String)))
            .Add(New DataColumn("Password", GetType(String)))
            .Add(New DataColumn("Character", GetType(String)))
            .Add(New DataColumn("Server", GetType(String)))
            .Add(New DataColumn("Login", GetType(String)))
            .Add(New DataColumn("ReturnLogin", GetType(Boolean)))
            .Add(New DataColumn("LoginStart", GetType(Boolean)))
            .Add(New DataColumn("RelogDisco", GetType(Boolean)))
            .Add(New DataColumn("DisMap", GetType(Boolean)))
            .Add(New DataColumn("SpecialAcc", GetType(Boolean)))
        End With
    End Sub
End Class

Edit: nvm, i think that code you provided me jim its working, im testing

i think its solved now :) thank you so much !! ill be testing tomorrow, for now ill make the thread solved

Jim, could you help me update:

Dim accts() As String = INIRead(INIFILE).Split(Chr(0))
         ReDim Accounts(UBound(accts) - 1)
         For i As Integer = 0 To UBound(accts) - 1
             Accounts(i).AcctName = accts(i)
             Accounts(i).Version = INIRead(INIFILE, accts(i), "Version")
             Accounts(i).Login = INIRead(INIFILE, accts(i), "Login")
             Accounts(i).Username = INIRead(INIFILE, accts(i), "Username")
             Accounts(i).Password = INIRead(INIFILE, accts(i), "Password")
             Accounts(i).Character = INIRead(INIFILE, accts(i), "Character")
             Accounts(i).Server = INIRead(INIFILE, accts(i), "Server")
             Accounts(i).ReturnLogin = INIRead(INIFILE, accts(i), "ReturnLogin")
             Accounts(i).LoginStart = INIRead(INIFILE, accts(i), "LoginStart")
             Accounts(i).RelogDisco = INIRead(INIFILE, accts(i), "RelogDisco")
             Accounts(i).DisMap = INIRead(INIFILE, accts(i), "DisMap")
             Accounts(i).SpecialAcc = INIRead(INIFILE, accts(i), "SpecialAcc")
         Next

to be able to work with this new method im using to write INIs:

Imports System.Runtime.InteropServices
Imports System.Text

Public Class INIAccess
    <DllImport("kernel32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
    Public Shared Function WritePrivateProfileString(ByVal lpApplicationName As String, ByVal lpKeyName As String, ByVal lpString As String, ByVal lpFileName As String) As Integer
    End Function

    <DllImport("kernel32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
    Public Shared Function GetPrivateProfileString(ByVal lpApplicationName As String, ByVal lpKeyName As String, ByVal lpDefault As String, ByVal lpReturnedString As StringBuilder, ByVal nSize As Integer, ByVal lpFileName As String) As Integer
    End Function
End Class

To read is like this:

Dim str As New StringBuilder(256)
GetPrivateProfileString("Section", "KeyName", "Value", str, str.Capacity, INIPath)

I got it half of it working:

Public Function LoadAccounts()
        Try
            If File.Exists(INIFileR) Then
                My.Forms.Main_frm.AccNumber.Items.Clear()
                My.Forms.Main_frm.AccNumber.Items.Add("1")
                My.Forms.Main_frm.AccNumber.SelectedIndex = (0)

                Dim str As New StringBuilder()
                Dim CountAccs() As String = My.Computer.FileSystem.ReadAllText(INIFileR).Split()

                ReDim Preserve Accounts(UBound(CountAccs) - 1)

                For i As Integer = 0 To UBound(CountAccs) - 1
                    Accounts(i).AcctName = CountAccs(i)
                    GetPrivateProfileString("Account " & i, "Version", "", str, str.Capacity, INIFileR)
                    Accounts(i).Version = str.ToString
                    GetPrivateProfileString("Account " & i, "Login", "", str, str.Capacity, INIFileR)
                    Accounts(i).Login = str.ToString
                    GetPrivateProfileString("Account " & i, "Username", "", str, str.Capacity, INIFileR)
                    Accounts(i).Username = str.ToString
                    GetPrivateProfileString("Account " & i, "Password", "", str, str.Capacity, INIFileR)
                    Accounts(i).Password = str.ToString
                    GetPrivateProfileString("Account " & i, "Character", "", str, str.Capacity, INIFileR)
                    Accounts(i).Character = str.ToString
                    GetPrivateProfileString("Account " & i, "Server", "", str, str.Capacity, INIFileR)
                    Accounts(i).Server = str.ToString
                    GetPrivateProfileString("Account " & i, "ReturnLogin", "", str, str.Capacity, INIFileR)
                    Accounts(i).ReturnLogin = str.ToString
                    GetPrivateProfileString("Account " & i, "LoginStart", "", str, str.Capacity, INIFileR)
                    Accounts(i).LoginStart = str.ToString
                    GetPrivateProfileString("Account " & i, "RelogDisco", "", str, str.Capacity, INIFileR)
                    Accounts(i).RelogDisco = str.ToString
                    GetPrivateProfileString("Account " & i, "DisMap", "", str, str.Capacity, INIFileR)
                    Accounts(i).DisMap = str.ToString
                    GetPrivateProfileString("Account " & i, "SpecialAcc", "", str, str.Capacity, INIFileR)
                    Accounts(i).SpecialAcc = str.ToString

                    If i >= 1 Then
                        My.Forms.Main_frm.AccNumber.Items.Add(i + 1)
                    End If
                Next

                My.Forms.Main_frm.AccNumber.Items.Add(My.Forms.Main_frm.AccNumber.Items.Count + 1)
                phFunctions.SelectedAccount()

                ReDim Preserve Accounts(Accounts.GetUpperBound(0) + 1)

                Accounts(Accounts.Count - 1).Version = "Silkroad International"
                Accounts(Accounts.Count - 1).Login = "Random"
                Accounts(Accounts.Count - 1).Username = ""
                Accounts(Accounts.Count - 1).Password = ""
                Accounts(Accounts.Count - 1).Character = ""
                Accounts(Accounts.Count - 1).Server = ""
                Accounts(Accounts.Count - 1).ReturnLogin = "False"
                Accounts(Accounts.Count - 1).LoginStart = "False"
                Accounts(Accounts.Count - 1).RelogDisco = "False"
                Accounts(Accounts.Count - 1).DisMap = "False"
                Accounts(Accounts.Count - 1).SpecialAcc = "False"
            End If
        Catch ex As Exception
            MessageBox.Show(ex.Message, "phBot Account Manager", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try

        Return Nothing
    End Function

After it counts i it shoudl keep adding 1 item to the DomainUpDown, before it was working, but when i do this with this code it does add it, but the problem is it adds extra items, i have 2 accounts, so there should be 3 items, (acc1, acc2, and the blank acc to add more accs), i used a msgbox to count how many items there were in the domainupdown and there was 52 items, so i think the problem is in the spliting:

Dim CountAccs() As String = My.Computer.FileSystem.ReadAllText(INIFileR).Split()

Any help ?

What is "DomainUpDown"? Can you please post the current working contents of your ini file? The statement

My.Computer.FileSystem.ReadAllText(INIFileR).Split()

will read the entire ini file and split it into tokens at each blank. I don't think this is what you want.

its like a combobox, its in the toolbox

and the ini file looks like?

Perhaps we are going about this the wrong way. You started out by deciding that you should use the APIs (and interface code) for reading/writing ini files, but that may not be what you need based on the type on information you are trying to save/restore. Ini files typically deal with more or less fixed sections and parameters rather than variable length sections. Your situation is more like a recordset (a repeating number of similar records). Maybe we should take another look at a custom read/save class. Then your ini file would look like

Silkroad International,Random,user1,pass1,char1,Aquarius,False,False,False,False,False
Silkroad International,Random,user2,pass2,char2,Aquarius,False,False,False,False,False
Silkroad International,Random,user3,pass3,char3,Aquarius,False,False,False,False,False
.
.
.

If you change your ini file format to the above then you can simplify the code to

Public Class Form1

    Private Accounts As New List(Of Account)

    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        ReadAccounts("d:\temp\silkroad.txt", Accounts)
        WriteAccounts("d:\temp\silkroad.txt", Accounts)
    End Sub

    Private Sub ReadAccounts(filename As String, Accounts As List(Of Account))

        For Each line As String In System.IO.File.ReadAllLines(filename)
            Accounts.Add(New Account(line.Split(",")))
        Next

    End Sub

    Private Sub WriteAccounts(filename As String, Accounts As List(Of Account))

        Dim lines As String = ""

        For Each acct As Account In Accounts
            lines &= acct.ToString() & vbCrLf
        Next

        System.IO.File.WriteAllText(filename, lines)

    End Sub

End Class

Public Class Account

    Public Version As String
    Public Login As String
    Public Username As String
    Public Password As String
    Public Character As String
    Public Server As String
    Public ReturnLogin As Boolean
    Public LoginStart As Boolean
    Public RelogDisco As Boolean
    Public DisMap As Boolean
    Public SpecialAcc As Boolean

    Public Sub New(fields() As String)
        Me.Version = fields(0)
        Me.Login = fields(1)
        Me.Username = fields(2)
        Me.Password = fields(3)
        Me.Character = fields(4)
        Me.Server = fields(5)
        Me.ReturnLogin = fields(6) = "True"
        Me.LoginStart = fields(7) = "True"
        Me.RelogDisco = fields(8) = "True"
        Me.DisMap = fields(9) = "True"
        Me.SpecialAcc = fields(10) = "True"

    End Sub

    Public Overrides Function ToString() As String

        Return Me.Version & "," &
                Me.Login & "," &
                Me.Username & "," &
                Me.Password & "," &
                Me.Character & "," &
                Me.Server & "," &
                IIf(Me.ReturnLogin, "True", "False") & "," &
                IIf(Me.LoginStart, "True", "False") & "," &
                IIf(Me.RelogDisco, "True", "False") & "," &
                IIf(Me.DisMap, "True", "False") & "," &
                IIf(Me.SpecialAcc, "True", "False")

    End Function

End Class

By translating the last five values between string and boolean on read/write you can write your code as

If Accounts(2).DisMap Then

rather than

If Accounts(2).DisMap = "True" Then

And, of course, you should add some error checking to the read/write code.

Edit: i didn't notice the above post, ill try that, because what ima do is use .txt instead, and encrypt the file and the do a binary encryption too, and when i need to read it i will try to decrypt the binary to then decrypt the next encryption and then read.

it could look like:

SilkroadR,30,MyUser1514,Passwordtt435,iFrolox,Aquarius,True,False,True,False,True

Where it says:
Silkroad International it could be either that or SilkroadR.
Random could be 26 or 27, or 28 or 29, 30, or Random.
Username could be anything (The user's ID)
Password could be anything (The user's PW)
Character could be anything (The user's game character)
Aquarius could be what its in a combobox (The server names)
and all the Boolean are based on the checkedstate of the checkboxes.

Im using:

Private Declare Auto Function WritePrivateProfileString Lib "kernel32" (ByVal lpAppName As String, ByVal lpKeyName As String, ByVal lpString As String, ByVal lpFileName As String) As Boolean

Private Declare Auto Function GetPrivateProfileString Lib "kernel32" (ByVal lpAppName As String, ByVal lpKeyName As String, ByVal lpDefault As String, ByVal lpReturnedString As StringBuilder, ByVal nSize As Integer, ByVal lpFileName As String) As Integer

Saving the accounts:

    Public Function SaveAccounts() As String
        For Each AccInfo As Account In Accounts
            WritePrivateProfileString(AccInfo.AcctName, "Version", AccInfo.Version, INIFileR)
            WritePrivateProfileString(AccInfo.AcctName, "Login", AccInfo.Login, INIFileR)
            WritePrivateProfileString(AccInfo.AcctName, "Username", AccInfo.Username, INIFileR)
            WritePrivateProfileString(AccInfo.AcctName, "Password", AccInfo.Password, INIFileR)
            WritePrivateProfileString(AccInfo.AcctName, "Character", AccInfo.Character, INIFileR)
            WritePrivateProfileString(AccInfo.AcctName, "Server", AccInfo.Server, INIFileR)
            WritePrivateProfileString(AccInfo.AcctName, "ReturnLogin", AccInfo.ReturnLogin, INIFileR)
            WritePrivateProfileString(AccInfo.AcctName, "LoginStart", AccInfo.LoginStart, INIFileR)
            WritePrivateProfileString(AccInfo.AcctName, "RelogDisco", AccInfo.RelogDisco, INIFileR)
            WritePrivateProfileString(AccInfo.AcctName, "DisMap", AccInfo.DisMap, INIFileR)
            WritePrivateProfileString(AccInfo.AcctName, "SpecialAcc", AccInfo.SpecialAcc, INIFileR)
        Next

        Return Nothing
    End Function

Loading the accounts:

Public Function LoadAccounts() As String
        Try
            If File.Exists(INIFileR) Then
                My.Forms.Main_frm.AccNumber.Items.Clear()
                My.Forms.Main_frm.AccNumber.Items.Add("1")
                My.Forms.Main_frm.AccNumber.SelectedIndex = (0)

                Dim str As New StringBuilder()
                Dim CountAccs() As String = IO.File.ReadAllText(INIFileR).Split(CChar("["))

                ReDim Preserve Accounts(UBound(CountAccs) - 1)

                For i As Integer = 0 To UBound(CountAccs) - 1
                    GetPrivateProfileString("Account " & i, "Version", "", str, str.Capacity, INIFileR)
                    Accounts(i).Version = str.ToString
                    GetPrivateProfileString("Account " & i, "Login", "", str, str.Capacity, INIFileR)
                    Accounts(i).Login = str.ToString
                    GetPrivateProfileString("Account " & i, "Username", "", str, str.Capacity, INIFileR)
                    Accounts(i).Username = str.ToString
                    GetPrivateProfileString("Account " & i, "Password", "", str, str.Capacity, INIFileR)
                    Accounts(i).Password = str.ToString
                    GetPrivateProfileString("Account " & i, "Character", "", str, str.Capacity, INIFileR)
                    Accounts(i).Character = str.ToString
                    GetPrivateProfileString("Account " & i, "Server", "", str, str.Capacity, INIFileR)
                    Accounts(i).Server = str.ToString
                    GetPrivateProfileString("Account " & i, "ReturnLogin", "", str, str.Capacity, INIFileR)
                    Accounts(i).ReturnLogin = str.ToString
                    GetPrivateProfileString("Account " & i, "LoginStart", "", str, str.Capacity, INIFileR)
                    Accounts(i).LoginStart = str.ToString
                    GetPrivateProfileString("Account " & i, "RelogDisco", "", str, str.Capacity, INIFileR)
                    Accounts(i).RelogDisco = str.ToString
                    GetPrivateProfileString("Account " & i, "DisMap", "", str, str.Capacity, INIFileR)
                    Accounts(i).DisMap = str.ToString
                    GetPrivateProfileString("Account " & i, "SpecialAcc", "", str, str.Capacity, INIFileR)
                    Accounts(i).SpecialAcc = str.ToString

                    If i >= 1 Then
                        My.Forms.Main_frm.AccNumber.Items.Add(i + 1)
                    End If
                Next

                My.Forms.Main_frm.AccNumber.Items.Add(My.Forms.Main_frm.AccNumber.Items.Count + 1)
                phFunctions.SelectedAccount()

                ReDim Preserve Accounts(Accounts.GetUpperBound(0) + 1)

                Accounts(Accounts.Count - 1).Version = CStr((0))
                Accounts(Accounts.Count - 1).Login = CStr((My.Forms.Main_frm.LServer.Items.Count - 1))
                Accounts(Accounts.Count - 1).Username = ""
                Accounts(Accounts.Count - 1).Password = ""
                Accounts(Accounts.Count - 1).Character = ""
                Accounts(Accounts.Count - 1).Server = CStr((0))
                Accounts(Accounts.Count - 1).ReturnLogin = "False"
                Accounts(Accounts.Count - 1).LoginStart = "False"
                Accounts(Accounts.Count - 1).RelogDisco = "False"
                Accounts(Accounts.Count - 1).DisMap = "False"
                Accounts(Accounts.Count - 1).SpecialAcc = "False"
            End If
        Catch ex As Exception
            MessageBox.Show(ex.Message, "phBot Account Manager", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try

        Return Nothing
    End Function

And the outcome of the ini file:

[Account 0]
Version=0
Login=5
Username=1
Password=1
Character=1
Server=0
ReturnLogin=False
LoginStart=False
RelogDisco=False
DisMap=False
SpecialAcc=False
[Account 1]
Version=1
Login=5
Username=2
Password=2
Character=2
Server=0
ReturnLogin=True
LoginStart=True
RelogDisco=True
DisMap=True
SpecialAcc=True
[Account 2]
Version=0
Login=5
Username=3
Password=3
Character=3
Server=2
ReturnLogin=False
LoginStart=False
RelogDisco=False
DisMap=False
SpecialAcc=False
[Account 3]
Version=1
Login=4
Username=4
Password=4
Character=4
Server=1
ReturnLogin=False
LoginStart=False
RelogDisco=False
DisMap=False
SpecialAcc=False
[Account 4]
Version=0
Login=5
Username=1
Password=1
Character=1
Server=0
ReturnLogin=False
LoginStart=False
RelogDisco=False
DisMap=False
SpecialAcc=False

Well, but now i need to update this code:

Public Function NewAccount(ByVal wIndex As Integer) As String
        ReDim Preserve Accounts(Accounts.GetUpperBound(0) + 1)

        If My.Forms.Main_frm.AccNumber.Text = "" Then
            Accounts(0).Version = CStr((0))
            Accounts(0).Login = CStr((My.Forms.Main_frm.LServer.Items.Count - 1))
            Accounts(0).Username = ""
            Accounts(0).Password = ""
            Accounts(0).Character = ""
            Accounts(0).Server = CStr((0))
            Accounts(0).ReturnLogin = "False"
            Accounts(0).LoginStart = "False"
            Accounts(0).RelogDisco = "False"
            Accounts(0).DisMap = "False"
            Accounts(0).SpecialAcc = "False"

            My.Forms.Main_frm.AccNumber.Items.Add("1")
            My.Forms.Main_frm.AccNumber.SelectedIndex = (0)
        Else
            Accounts(CInt(My.Forms.Main_frm.AccNumber.Text) + wIndex).Version = CStr((0))
            Accounts(CInt(My.Forms.Main_frm.AccNumber.Text) + wIndex).Login = CStr((My.Forms.Main_frm.LServer.Items.Count - 1))
            Accounts(CInt(My.Forms.Main_frm.AccNumber.Text) + wIndex).Username = ""
            Accounts(CInt(My.Forms.Main_frm.AccNumber.Text) + wIndex).Password = ""
            Accounts(CInt(My.Forms.Main_frm.AccNumber.Text) + wIndex).Character = ""
            Accounts(CInt(My.Forms.Main_frm.AccNumber.Text) + wIndex).Server = CStr((0))
            Accounts(CInt(My.Forms.Main_frm.AccNumber.Text) + wIndex).ReturnLogin = "False"
            Accounts(CInt(My.Forms.Main_frm.AccNumber.Text) + wIndex).LoginStart = "False"
            Accounts(CInt(My.Forms.Main_frm.AccNumber.Text) + wIndex).RelogDisco = "False"
            Accounts(CInt(My.Forms.Main_frm.AccNumber.Text) + wIndex).DisMap = "False"
            Accounts(CInt(My.Forms.Main_frm.AccNumber.Text) + wIndex).SpecialAcc = "False"
        End If

        Return Nothing
    End Function

The error is here: ReDim Preserve Accounts(Accounts.GetUpperBound(0) + 1)
How can i redim the next account ?

i need little help with:

Dim lines As String = ""
        For Each acct As Account In Accounts
            lines &= acct.ToString() & vbCrLf
        Next
        System.IO.File.WriteAllText(filename, lines)

It works but i just need to change it to write all except the last account (which is the blank one)

also the reading the accounts i get:

Argument not specified for parameter 'mUsername' of 'Public Sub New(mVersion As String, mLogin As String, mUsername As String, mPassword As String, mCharacter As String, mServer As String, mReturnLogin As String, mLoginStart As String, mRelogDisco As String, mDisMap As String, mSpecialAcc As String)'.

Reverend Jim, I want to ask U write input source in the reading field.

I was trying by different ways to write it - but haven't succed.
(I am asking about 3 parts source code, where info from ini file goes to the Dictionary)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.