In the first part of the tutorial we are going to learn some basic Winsock API functions. These functions are to provide us with some essential stuff such as initializing the Winsock service, domain name resolution, error handling and so on. As you understand without that you can't move further for more interesting things: creating socket, sending and receiving data. Below is the list of the functions for the first part of the tutorial:
WSAStartup
WSACleanup
gethostbyaddr
gethostbyname
gethostname
getservbyname
getprotobynumber
getprotobyname
getservbyport
inet_addr
inet_ntoa
htons
htonl
ntohl
ntohs
In order to find out what the functions are for and how to use them we'll create about 10-12 sample applications. To make our work easier with that I suggest you to create the VB project template which will contain all the required API functions, some custom VB functions and the VB form that contains the code executed almost in every sample application we are going to develop.
Creating project
All the samples will be Standard EXE projects, so the type of the template should be Standard EXE too. Select the menu item File | New Project, in the dialog window "New Project", select the Standard EXE item and click the OK button.
Rename the project to "BasicWinsockAPI".
Rename the default form to frmMain.
Select the menu item Project | Add Module in order to add a code module to our project. That module will contain the API declarations and common custom functions.
Rename the module to modWinsock.
Inserting API declarations
Open the code editor for the modWinsock module and insert the following code. We'll do not talk about these declarations right now, all the functions will be described later in other tutorials.
Option Explicit
Public Const INADDR_NONE = &HFFFF
Public Const SOCKET_ERROR = -1
Public Const WSABASEERR = 10000
Public Const WSAEFAULT = (WSABASEERR + 14)
Public Const WSAEINVAL = (WSABASEERR + 22)
Public Const WSAEINPROGRESS = (WSABASEERR + 50)
Public Const WSAENETDOWN = (WSABASEERR + 50)
Public Const WSASYSNOTREADY = (WSABASEERR + 91)
Public Const WSAVERNOTSUPPORTED = (WSABASEERR + 92)
Public Const WSANOTINITIALISED = (WSABASEERR + 93)
Public Const WSAHOST_NOT_FOUND = 11001
Public Const WSADESCRIPTION_LEN = 257
Public Const WSASYS_STATUS_LEN = 129
Public Const WSATRY_AGAIN = 11002
Public Const WSANO_RECOVERY = 11003
Public Const WSANO_DATA = 11004
Public Type WSAData
wVersion As Integer
wHighVersion As Integer
szDescription As String * WSADESCRIPTION_LEN
szSystemStatus As String * WSASYS_STATUS_LEN
iMaxSockets As Integer
iMaxUdpDg As Integer
lpVendorInfo As Long
End Type
Public Type HOSTENT
hName As Long
hAliases As Long
hAddrType As Integer
hLength As Integer
hAddrList As Long
End Type
Public Type servent
s_name As Long
s_aliases As Long
s_port As Integer
s_proto As Long
End Type
Public Type protoent
p_name As String 'Official name of the protocol
p_aliases As Long 'Null-terminated array of alternate names
p_proto As Long 'Protocol number, in host byte order
End Type
Public Declare Function WSAStartup _
Lib "ws2_32.dll" (ByVal wVR As Long, lpWSAD As WSAData) As Long
Public Declare Function WSACleanup Lib "ws2_32.dll" () As Long
Public Declare Function gethostbyaddr _
Lib "ws2_32.dll" (addr As Long, ByVal addr_len As Long, _
ByVal addr_type As Long) As Long
Public Declare Function gethostbyname _
Lib "ws2_32.dll" (ByVal host_name As String) As Long
Public Declare Function gethostname _
Lib "ws2_32.dll" (ByVal host_name As String, _
ByVal namelen As Long) As Long
Public Declare Function getservbyname _
Lib "ws2_32.dll" (ByVal serv_name As String, _
ByVal proto As String) As Long
Public Declare Function getprotobynumber _
Lib "ws2_32.dll" (ByVal proto As Long) As Long
Public Declare Function getprotobyname _
Lib "ws2_32.dll" (ByVal proto_name As String) As Long
Public Declare Function getservbyport _
Lib "ws2_32.dll" (ByVal port As Integer, ByVal proto As Long) As Long
Public Declare Function inet_addr _
Lib "ws2_32.dll" (ByVal cp As String) As Long
Public Declare Function inet_ntoa _
Lib "ws2_32.dll" (ByVal inn As Long) As Long
Public Declare Function htons _
Lib "ws2_32.dll" (ByVal hostshort As Integer) As Integer
Public Declare Function htonl _
Lib "ws2_32.dll" (ByVal hostlong As Long) As Long
Public Declare Function ntohl _
Lib "ws2_32.dll" (ByVal netlong As Long) As Long
Public Declare Function ntohs _
Lib "ws2_32.dll" (ByVal netshort As Integer) As Integer
Public Declare Sub RtlMoveMemory _
Lib "kernel32" (hpvDest As Any, _
ByVal hpvSource As Long, _
ByVal cbCopy As Long)
Public Declare Function lstrcpy _
Lib "kernel32" Alias "lstrcpyA" (ByVal lpString1 As String, _
ByVal lpString2 As Long) As Long
Public Declare Function lstrlen _
Lib "kernel32" Alias "lstrlenA" (ByVal lpString As Any) As Long
The Winsock API functions extensively use unsigned C/C++ data types such as unsigned short (2 bytes integer) and unsigned long (4 bytes integer). Visual Basic has 2-bytes and 4-bytes integers as well - the Integer and Long data types, but unfortunately they are signed ones and there is no way to use unsigned data types in VB (excepting the Byte data type which is too small for that purpose).
Language Data Type Length Range
C/C++ u_short 2 bytes 0 to 65535
C/C++ u_long 4 bytes 0 to 4294967295
VB Integer 2 bytes -32768 to +32767
VB Long 4 bytes -2147483648 to +2147483647
Actually, since the Winsock API functions expect as arguments and return some values just as blocks of bytes, we can use the VB data types, but we need some subroutines to retrieve actual values. Fortunately, we don't need to invent anything as the Microsoft support team has already answered the question. Take a look at the article from MS Knowledge Base - HOWTO: Convert Between Signed and Unsigned Numbers. We are going to use those functions as is, just insert the following code into the modWinsock code module:
Private Const OFFSET_4 = 4294967296#
Private Const MAXINT_4 = 2147483647
Private Const OFFSET_2 = 65536
Private Const MAXINT_2 = 32767
Public Function UnsignedToLong(Value As Double) As Long
'
'The function takes a Double containing a value in the
'range of an unsigned Long and returns a Long that you
'can pass to an API that requires an unsigned Long
'
If Value < 0 Or Value >= OFFSET_4 Then Error 6 ' Overflow
'
If Value <= MAXINT_4 Then
UnsignedToLong = Value
Else
UnsignedToLong = Value - OFFSET_4
End If
'
End Function
Public Function LongToUnsigned(Value As Long) As Double
'
'The function takes an unsigned Long from an API and
'converts it to a Double for display or arithmetic purposes
'
If Value < 0 Then
LongToUnsigned = Value + OFFSET_4
Else
LongToUnsigned = Value
End If
'
End Function
Public Function UnsignedToInteger(Value As Long) As Integer
'
'The function takes a Long containing a value in the range
'of an unsigned Integer and returns an Integer that you
'can pass to an API that requires an unsigned Integer
'
If Value < 0 Or Value >= OFFSET_2 Then Error 6 ' Overflow
'
If Value <= MAXINT_2 Then
UnsignedToInteger = Value
Else
UnsignedToInteger = Value - OFFSET_2
End If
'
End Function
Public Function IntegerToUnsigned(Value As Integer) As Long
'
'The function takes an unsigned Integer from and API and
'converts it to a Long for display or arithmetic purposes
'
If Value < 0 Then
IntegerToUnsigned = Value + OFFSET_2
Else
IntegerToUnsigned = Value
End If
'
End Function
Sometimes API functions return pointers to a string that can not be extracted directly into the VB String data type. Win32API provide us the C function lstrcpy that allows us to copy a string to another variable by the string's pointer.
Public Declare Function lstrcpy Lib _
"kernel32" Alias "lstrcpyA" (ByVal lpString1 As String, _
ByVal lpString2 As Long) As Long
The lpString2 argument is a pointer to a string, and the lpString1 argument is a buffer that receives the string. That buffer has to have enough length to be able to receive all the data, so we need to know length of the string before to call that function. There is one more C function in the Win32API that can help us - lstrlen, that return just what we need to get - length of the string by its pointer.
Public Declare Function lstrlen Lib "kernel32" Alias "lstrlenA" (ByVal lpString As Any) As Long
So, now, I think, we are ready to write the StringFromPointer function that returns a string by its pointer. Put the following code into the modWinsock code module:
Public Function StringFromPointer(ByVal lPointer As Long) As String
'
Dim strTemp As String
Dim lRetVal As Long
'
'prepare the strTemp buffer
strTemp = String$(lstrlen(ByVal lPointer), 0)
'
'copy the string into the strTemp buffer
lRetVal = lstrcpy(ByVal strTemp, ByVal lPointer)
'
'return a string
If lRetVal Then StringFromPointer = strTemp
'
End Function
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
Open a designer window for the frmMain form, and place two command buttons on the form. Change properties of the buttons as shown below, in the table.
Name Caption Default Cancel
cmdGet &Get True
cmdExit E&xit True
Open a code editor for the form and put the following code into the Form_Load event procedure:
Private Sub Form_Load()
'
Dim lngRetVal As Long
Dim strErrorMsg As String
Dim udtWinsockData As WSAData
Dim lngType As Long
Dim lngProtocol As Long
'
'start up winsock service
lngRetVal = WSAStartup(&H101, udtWinsockData)
'
If lngRetVal <> 0 Then
'
'
Select Case lngRetVal
Case WSASYSNOTREADY
strErrorMsg = "The underlying network subsystem is not " & _
"ready for network communication."
Case WSAVERNOTSUPPORTED
strErrorMsg = "The version of Windows Sockets API support " & _
"requested is not provided by this particular " & _
"Windows Sockets implementation."
Case WSAEINVAL
strErrorMsg = "The Windows Sockets version specified by the " & _
"application is not supported by this DLL."
End Select
'
MsgBox strErrorMsg, vbCritical
'
End If
'
End Sub
Before to call any function of the Winsock API we need to initialize the Winsock service for our process (application). To do that we must call the WSAStartup function, that is called in the Form_Load event procedure of the form. Since we need to call this function anyway for any Winsock application, it is better to include it into the project template than to write the same code for every sample we are going to develop.
For the same reason let's include a couple of other subroutines - Form_Unload and ShowErrorMsg. The Form_Unload procedure just calls the WSACleanup function to tell the system that we don't need the Winsock service anymore, and the ShowErrorMsg is to display a message box with the Winsock error description.
Private Sub Form_Unload(Cancel As Integer)
Call WSACleanup
End Sub
Private Sub ShowErrorMsg(lngError As Long)
'
Dim strMessage As String
'
Select Case lngError
Case WSANOTINITIALISED
strMessage = "A successful WSAStartup call must occur " & _
"before using this function."
Case WSAENETDOWN
strMessage = "The network subsystem has failed."
Case WSAHOST_NOT_FOUND
strMessage = "Authoritative answer host not found."
Case WSATRY_AGAIN
strMessage = "Nonauthoritative host not found, or server failure."
Case WSANO_RECOVERY
strMessage = "A nonrecoverable error occurred."
Case WSANO_DATA
strMessage = "Valid name, no data record of requested type."
Case WSAEINPROGRESS
strMessage = "A blocking Windows Sockets 1.1 call is in " & _
"progress, or the service provider is still " & _
"processing a callback function."
Case WSAEFAULT
strMessage = "The name parameter is not a valid part of " & _
"the user address space."
Case WSAEINTR
strMessage = "A blocking Windows Socket 1.1 call was " & _
"canceled through WSACancelBlockingCall."
End Select
'
MsgBox strMessage, vbExclamation
'
End Sub
Oh, yes. Don't forget the following as well:
Private Sub cmdExit_Click()
Unload Me
End Sub
The Visual Basic project template is ordinary project saved in the special subfolder "Template/Projects" of the VB folder.So, to save our project as a template select the menu item File | Save Project As. In the file dialog window go to VB\Template\Projects folder and save the project as "Basic Winsock API.vbp" and all its components - frmMain and modWinsock. That's it. Now select menu File | New Project to display the New Project window to see the new project item in the list of projects.
下面是个例子 我自己了解也不很多 只是大概的能用这些代替WINSOCK控件.这些东西一般可以搜索C的MFC关于WINSOCKAPI的教程 这些和VB都有一定的关联......
[此贴子已经被作者于2006-8-23 10:08:26编辑过]