Winsock Tutorial 2
Giving the user options ...
In our previous *winsock tutorial*, we hard-coded into the application
the RemoteHost and RemotePort that we'll be using.
But what if we want to give the user the choice ?
Well we can just use text boxes and command buttons for this.
Add to a new form a winsock control, 2 textboxes, a listbox,
and a command button.
Name them as follows ;
You may also want to stick a few labels onto your form to tell the userCode:Winsock Control; sock
TextBoxes ; txtPort and txtHost
ListBox ; lstInfo
CommandButton ; cmdConnect
what the textboxes and listbox are for.
Change cmdConnect's caption to "Connect"
Now, everything is going to happen when the user hits cmdConnect,
so lets start coding its Event Sub ;
VB Code:
Private Sub cmdConnect_Click() End Sub
We want to have the winsock control (called sock) connect to some host&port.
The host and port are contained in txtHost and txtPort.
So we just grab their .Text properties ;
VB Code:
Private Sub cmdConnect_Click() sock.Connect txtHost.Text, txtPort.Text End Sub
Now as before we're going to need other Event Subs ;
VB Code:
Private Sub sock_Connect() lstInfo.AddItem "Connected to : " & sock.RemoteHost End Sub Private Sub sock_Error(ByVal Number As Integer, Description As String, ByVal Scode As Long, ByVal Source As String, ByVal HelpFile As String, ByVal HelpContext As Long, CancelDisplay As Boolean) lstInfo.Additem Scode & ":" & Description End Sub Private Sub sock_DataArrival(ByVal bytesTotal As Long) Dim strBuff As String sock.GetData strBuff, vbString lstInfo.Additem strBuff End Sub
So, what does the above code do ?
Well, when we connect (Connect()), we're adding a line to a listbox saying
that we have connected to the RemoteHost.
If there's an error (Error()), we're adding it again to the listbox.
And when Data Arrives (DataArrival()), we're putting it in the listbox.
So we've given the user the choice to connect to any arbitrary host
on any port.
Lets also give them the ability to disconnect from that host.
Add to your form a command button called cmdDisconnect.
We can use the .Close() method of a Winsock Control to close the connection
if one has been established, so code the cmdDisconnect Click Sub as follows ;
VB Code:
Private Sub cmdDisconnect_Click() sock.Close lstInfo.AddItem "Disconnected !" End Sub
In our above code samples, we're assuming the user is going to enter a host
and a port that is okay (ie. host : port = mail!!.?.#tcd.ie : -7)
It is generally not a good idea to completely trust the user when giving
you input, because the user does have a tendency to enter wrong information.
So how can we check the information they entered into our textboxes ?
Well there are two ways I would think of doing it.
We could make sure that they only enter numbers, periods and characters into
the textbox by checking the contents of the textbox in its Change() Sub.
Or, we could do the checking in one go in the cmdConnect() Sub.
If we're doing the checking in the cmdConnect(), there is a major advantage.
Though it may be a little advanced or this tutorial, there is a Windows API that
will tell you if a hostname as supplied is valid or not.
So why not use that to tell us ?
So as to not confuse those of you not used to dealing with API calls, or networking
related code, I have wrapped everything up into one simple Function call.
Now, there are a few ugly looking declarations.
Those are everything before "Private Function ...", and they go at the top
of your Form's code just below "Option Explicit" (if its written up there).
Then the Function itself can go anywhere in your form's code
VB Code:
Option Explicit 'Declarations Private Declare Function gethostbyname Lib "WSOCK32.DLL" (ByVal szHost As String) As Long Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (hpvDest As Any, ByVal hpvSource As Long, ByVal cbCopy As Long) Private Declare Function WSAStartup Lib "WSOCK32.DLL" (ByVal VersionReq As Long, WSADataReturn As WSADATA) As Long Private Declare Function inet_addr Lib "WSOCK32.DLL" (ByVal s As String) As Long Private Type WSADATA wVersion As Integer wHighVersion As Integer szDescription(0 To 256) As Byte szSystemStatus(0 To 128) As Byte wMaxSockets As Long wMaxUDPDG As Long dwVendorInfo As Long End Type 'Function itself Private Function isHostNameValid(ByVal strHost As String) As Boolean Dim WSAD As WSADATA, ipFromHostname As String Dim nbytes As Long, ptrHosent As Long, ptrName As Long Dim ptrAddress As Long, ptrIPAddress As Long, sAddress As String If WSAStartup(&H101, WSAD) = 0 Then sAddress = Space$(4) ptrHosent = gethostbyname(strHost & vbNullChar) If ptrHosent <> 0 Then ptrName = ptrHosent ptrAddress = ptrHosent + 12 CopyMemory ptrName, ByVal ptrName, 4 CopyMemory ptrAddress, ByVal ptrAddress, 4 CopyMemory ptrIPAddress, ByVal ptrAddress, 4 CopyMemory ByVal sAddress, ByVal ptrIPAddress, 4 ipFromHostname = CStr(Asc(sAddress)) & _ "." & CStr(Asc(Mid$(sAddress, 2, 1))) & _ "." & CStr(Asc(Mid$(sAddress, 3, 1))) & _ "." & CStr(Asc(Mid$(sAddress, 4, 1))) If (inet_addr(ipFromHostname) <> &HFFFFFFFF) Then isHostNameValid = True End If End If End If End Function
So how do we use the function ?
Well below is some error checking code that you can see in action ;
VB Code:
Private Sub cmdConnect_Click() If (CLng(txtPort.Text) > 0) And (CLng(txtPort.Text) < 65535) Then ' so the port number is ok. ' but what about the host they've entered ? If isHostNameValid(txtHost.Text) Then ' The HostName in txtHost.Text is ok! ' So lets connect then sock.Connect txtHost.Text, txtPort.Text Else MsgBox "Invalid hostname !", vbCritical End If Else MsgBox "Port should be in the rang 0 - 65535", vbCritical End If End Sub
So we've now just written an application that will allow a user to connect
to any given host on any given port, and we've added in code to make sure
that the HostName and Port Number are ok.
In further tutorials, I will not bother adding in the code to check if the
host and port are ok.
You should do that yourself in all of your applications that utilize winsock,
but for these tutorials I'll just cut to the chase as it were.
Jamie Plenderleith
[email protected]
09 / 02 / 02
