שתף באמצעות


Reading .ini file config VB .NET Winsock

Question

Thursday, April 23, 2015 1:31 PM

I have program 2 program in VB.Net that uses Winsock. The program is client and server. I want to make an external config in .ini file in server side for setting localport in Winsock.

The program works when I'm running it, but when I want to listen the localport I get an error.

Here is the function that reads .ini file:

Public Function GetSettingItem(ByVal File As String, ByVal Identifier As String) As String
    Dim S As New IO.StreamReader(File) : Dim Result As String = ""
    Do While (S.Peek <> -1)
        Dim Line As String = S.ReadLine
        If Line.ToLower.StartsWith(Identifier.ToLower & ":") Then
            Result = Line.Substring(Identifier.Length + 2)
        End If
    Loop
    Return Result
End Function

This it the Winsock Listen Port:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    AxWinsock1.LocalPort = GetSettingItem("D:\MainConfig.ini", "port")
    AxWinsock1.Listen()
End Sub

My ini file 

[Port Server]
;; Port Server you can set it as you want
Port : 29092

Error

An unhandled exception of type 'System.InvalidCastException' occurred in Microsoft.VisualBasic.dll

Additional information: Conversion from string "" to type 'Integer' is not valid.

Where is the problem? How to listen port in .ini files?

All replies (15)

Saturday, April 25, 2015 3:36 PM ✅Answered

I have to ask, are you creating the ini file yourself?  Usually an ini file uses an "=" between the Key name and the number or string value stored after it like this

[Section Name]
KeyName=29092

 

 In your case it would need to look like this in order for the GetPrivateProfileString or GetPrivateProfileInt Api functions to work.

[Port Server]
;; Port Server you can set it as you want
Port=29092

 

 For example, i created an ini file that was exactly the same as you show and it would not find the number no mater how i tried it using ether of the functions until i formatted it like i just showed using the "=".  If you are creating the file yourself then you can change the way it is being written to the file and just use the GetPrivateProfileInt Api function like this.

Imports System.Runtime.InteropServices

Public Class Form1
    ''' <summary>Returns an integer number from the specified Section and Key. If not successful it returns the default number.</summary>
    ''' <param name="lpAppName">The Section name.</param>
    ''' <param name="lpKeyName">The Key name.</param>
    ''' <param name="nDefault">The default number that is returned if it fails.</param>
    ''' <param name="lpFileName">The full path to the INI file.</param>
    <DllImport("kernel32.dll", EntryPoint:="GetPrivateProfileIntW")> _
    Public Shared Function GetPrivateProfileIntW(<MarshalAs(UnmanagedType.LPWStr)> ByVal lpAppName As String, <MarshalAs(UnmanagedType.LPWStr)> ByVal lpKeyName As String, ByVal nDefault As Integer, <MarshalAs(UnmanagedType.LPWStr)> ByVal lpFileName As String) As Integer
    End Function

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim iniPathName As String = "C:\TestFolder\MainConfig.ini"

        If IO.File.Exists(iniPathName) Then
            Dim num As Integer = GetPrivateProfileIntW("Port Server", "Port", 0, iniPathName)

            If num > 0 Then
                MessageBox.Show(num.ToString)
            Else
                MessageBox.Show("Failed to get number")
            End If
        End If
    End Sub

End Class

 

 If you are not creating the ini file yourself and have no control over the way it is written then you will need to do it using some .Net methods.  Make sure you are not finding the word "port" in a section that may be before the [Port Server] section.  You may need to set your file reading function up to find "[Port Server]" and then find the very next line that starts with "port" from there.

Public Class Form1

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim iniPathName As String = "C:\TestFolder\MainConfig.ini"

        Dim portnum As Integer = GetPortNum(iniPathName, "Port Server", "Port")
        If portnum > 0 Then
            MessageBox.Show(portnum.ToString)
        Else
            MessageBox.Show("Failed to get number")
        End If
    End Sub

    Private Function GetPortNum(ByVal FileName As String, ByVal SectionName As String, ByVal KeyName As String) As Integer
        Dim sectionfound As Boolean = False
        Dim pn As Integer = 0
        If IO.File.Exists(FileName) Then
            For Each s As String In IO.File.ReadAllLines(FileName)
                If sectionfound And s.StartsWith("[") Then Exit For
                If s.ToLower = "[" & SectionName.ToLower & "]" Then sectionfound = True
                If sectionfound And s.ToLower.StartsWith(KeyName.ToLower) Then
                    Dim str() As String = s.Split(":"c)
                    If str.Length > 1 Then
                        Integer.TryParse(str(1), pn)
                        Exit For
                    End If
                End If
            Next
        End If
        Return pn
    End Function
End Class

If you say it can`t be done then i`ll try it


Thursday, April 23, 2015 1:47 PM | 1 vote

Hi Andre,

do yourself a favor and get rid of the interop winsock component. In .Net, use System.Sockets, System.Net, etc. (TcpListener, TcpClient,...)

Add Option Strict On at the top of the file and fix the errors first. It will make you aware of conversions and how you want to handle them.

Armin


Thursday, April 23, 2015 1:48 PM | 1 vote

Obviously the line does not start with "Port:" because it starts with "Port :".

Armin


Thursday, April 23, 2015 2:04 PM

ini files and WinSock?  Someone was speeding in their Delorean today... ;-)


Thursday, April 23, 2015 2:55 PM

The LocalPort property is a Long data type in VB 6.0 (it's a VB 6.0 component) so you would want to convert the string value coming out of the INI file to Integer (.NET). I would just use the CInt function, but you may want to assign the value to String variable first (so you can check whether it's an empty string before converting).

Paul ~~~~ Microsoft MVP (Visual Basic)


Thursday, April 23, 2015 3:37 PM

The LocalPort property is a Long data type in VB 6.0 (it's a VB 6.0 component) so you would want to convert the string value coming out of the INI file to Integer (.NET). I would just use the CInt function, but you may want to assign the value to String variable first (so you can check whether it's an empty string before converting).

Paul ~~~~ Microsoft MVP (Visual Basic)

how i can convert from string to integer?

i don't know about this


Thursday, April 23, 2015 3:38 PM

Hi Andre,

do yourself a favor and get rid of the interop winsock component. In .Net, use System.Sockets, System.Net, etc. (TcpListener, TcpClient,...)

Add Option Strict On at the top of the file and fix the errors first. It will make you aware of conversions and how you want to handle them.

Armin

I don't know about that because I newbie in VB .NET Programing ...

can you help me to fix the error?


Thursday, April 23, 2015 3:48 PM

how i can convert from string to integer?

i don't know about this

Call Integer.Parse.

Armin


Thursday, April 23, 2015 3:56 PM

Or CInt, as I mentioned in my previous post:

 Dim PortNum As String = GetSettingItem("D:\MainConfig.ini", "port")
 If String.IsNullOrEmpty(PortNum) Then
    MsgBox("Port number not found in config file!")
 Else
    AxWinsock1.LocalPort = CInt(PortNum)
    AxWinsock1.Listen()
 End If

Paul ~~~~ Microsoft MVP (Visual Basic)


Thursday, April 23, 2015 4:00 PM | 1 vote

I don't know about that because I newbie in VB .NET Programing ...

can you help me to fix the error?

 dim setting as string
 setting = GetSettingItem("D:\MainConfig.ini", "port")
 
If setting is nothing then
     'Handle the case that the setting is not found
else
     dim port as integer
     if not integer.tryparse(setting, port) then
         Messagebox.show("a meaningful error message")
         Return
     end if
     AxWinsock1.LocalPort = port    '
end if

This is still based on your code using the Winsock control. But as already written, newer classes are recommended instead.

I assume that the function GetSettingItem returns Nothing if the settings is not found. However, I do not post the corrected code as you would additionally have to obey the section name of the Ini file ("[Port Server]" in this case) if you want to read it correctly. Consequently, if you want to use an Ini file, there are the API functions (declared obsolete but still usable) to read and write Ini files. However, I'm sure there is also a managed wrapper (a .Net way) to work with them.

Armin


Friday, April 24, 2015 6:37 PM

Try

Public Function GetSettingItem(ByVal File As String, ByVal Identifier As String) As Integer    Dim S As New IO.StreamReader(File) : Dim Result As Integer=-1
    Do While (S.Peek <> -1)
        Dim Line As String = S.ReadLine
        If Line.ToLower.StartsWith(Identifier.ToLower & ":") Then           Try            Result = CInt(Line.Substring(Identifier.Length + 2))            Exit Do           Catch           End Try        End If
    Loop
    Return Result
End Function

You need a Try in the button also when -1 is returned, even though everyone says upgrade to modern YES ITS TRUE but to exact help your problem here it is ✘

My goal of posting is to make you and I better educated programmers while solving our problems ✘


Saturday, April 25, 2015 7:55 AM

Or CInt, as I mentioned in my previous post:

 Dim PortNum As String = GetSettingItem("D:\MainConfig.ini", "port")
 If String.IsNullOrEmpty(PortNum) Then
    MsgBox("Port number not found in config file!")
 Else
    AxWinsock1.LocalPort = CInt(PortNum)
    AxWinsock1.Listen()
 End If

Paul ~~~~ Microsoft MVP (Visual Basic)

if i use your code the port always not found ....


Saturday, April 25, 2015 8:01 AM

Try

Public Function GetSettingItem(ByVal File As String, ByVal Identifier As String) As Integer    Dim S As New IO.StreamReader(File) : Dim Result As Integer=-1
    Do While (S.Peek <> -1)
        Dim Line As String = S.ReadLine
        If Line.ToLower.StartsWith(Identifier.ToLower & ":") Then           Try            Result = CInt(Line.Substring(Identifier.Length + 2))            Exit Do           Catch           End Try        End If
    Loop
    Return Result
End Function

You need a Try in the button also when -1 is returned, even though everyone says upgrade to modern YES ITS TRUE but to exact help your problem here it is ✘

My goal of posting is to make you and I better educated programmers while solving our problems ✘

if i use your code i have a new error 

An unhandled exception of type 'System.Runtime.InteropServices.COMException' occurred in AxInterop.MSWinsockLib.dll

Additional information: Exception from HRESULT: 0x800A017C (CTL_E_INVALIDPROPERTYVALUE)

Saturday, April 25, 2015 8:37 AM

 dim setting as string
 setting = GetSettingItem("D:\MainConfig.ini", "port")
 
If setting is nothing then
     'Handle the case that the setting is not found
else
     dim port as integer
     if not integer.tryparse(setting, port) then
         Messagebox.show("a meaningful error message")
         Return
     end if
     AxWinsock1.LocalPort = port    '
end if

This is still based on your code using the Winsock control. But as already written, newer classes are recommended instead.

I assume that the function GetSettingItem returns Nothing if the settings is not found. However, I do not post the corrected code as you would additionally have to obey the section name of the Ini file ("[Port Server]" in this case) if you want to read it correctly. Consequently, if you want to use an Ini file, there are the API functions (declared obsolete but still usable) to read and write Ini files. However, I'm sure there is also a managed wrapper (a .Net way) to work with them.

Armin

sorry i don't understand what you mean ...

my program still error


Saturday, April 25, 2015 11:15 AM

sorry i don't understand what you mean ...

my program still error

I meant you shall use API functions to read Ini files. Windows API functions are functions in Windows Dlls like kernel32.dll, user32.dll, etc. There is a set of functions for reading/writing Ini files. To use these functions (for example, one is named "GetPrivateProfileString"), you need to declare them (see VB's Declare statement). An alternative is a so-called "manged wrapper". It is a class that internally calls these API functions, and it is written in a manged language (like VB.Net or C#) that  offers you the same features, but you can use it more easily than directly using the API functions. So it's a kind of intermediate layer between your code and the API functions. I do not have a manged wrapper, but I'm certain you'll find one in the web. Though, as already mentioned, Ini files are considered "obsolete" by Microsoft, however, the functions are still there and working.

If you still have an error, post the current code and which error occurs in which line.

Armin