1 Attribute VB_Name
= "modSocketMaster"
2 '**************************************************************************************
4 'modSocketMaster module 1.2
5 'Copyright (c) 2004 by Emiliano Scavuzzo <anshoku@yahoo.com>
9 '**************************************************************************************
10 'This module contains API declarations and helper functions for the CSocketMaster class
11 '**************************************************************************************
13 '==============================================================================
15 '==============================================================================
16 'Public Declare Function api_WSAGetLastError Lib "ws2_32.dll" Alias "WSAGetLastError" () As Long
17 Public Declare Sub api_CopyMemory _
19 Alias "RtlMoveMemory" (Destination
As Any
, _
22 Public Declare Function api_GlobalAlloc _
24 Alias "GlobalAlloc" (ByVal wFlags
As Long, _
25 ByVal dwBytes
As Long) As Long
26 Public Declare Function api_GlobalFree _
28 Alias "GlobalFree" (ByVal hMem
As Long) As Long
29 Private Declare Function api_WSAStartup _
31 Alias "WSAStartup" (ByVal wVersionRequired
As Long, _
32 lpWSADATA
As WSAData
) As Long
33 Private Declare Function api_WSACleanup _
35 Alias "WSACleanup" () As Long
36 Private Declare Function api_WSAAsyncGetHostByName _
38 Alias "WSAAsyncGetHostByName" (ByVal hWnd
As Long, _
40 ByVal strHostName
As String, _
42 ByVal buflen
As Long) As Long
43 Private Declare Function api_WSAAsyncSelect _
45 Alias "WSAAsyncSelect" (ByVal s
As Long, _
48 ByVal lEvent
As Long) As Long
49 Private Declare Function api_CreateWindowEx _
51 Alias "CreateWindowExA" (ByVal dwExStyle
As Long, _
52 ByVal lpClassName
As String, _
53 ByVal lpWindowName
As String, _
54 ByVal dwStyle
As Long, _
57 ByVal nWidth
As Long, _
58 ByVal nHeight
As Long, _
59 ByVal hWndParent
As Long, ByVal hMenu
As Long, ByVal hInstance
As Long, lpParam
As Any
) As Long
60 Private Declare Function api_DestroyWindow _
62 Alias "DestroyWindow" (ByVal hWnd
As Long) As Long
63 Private Declare Function api_lstrlen _
65 Alias "lstrlenA" (ByVal lpString
As Any
) As Long
66 Private Declare Function api_lstrcpy _
68 Alias "lstrcpyA" (ByVal lpString1
As String, _
69 ByVal lpString2
As Long) As Long
70 '==============================================================================
72 '==============================================================================
73 Public Const SOCKET_ERROR
As Integer = -1
74 Public Const INVALID_SOCKET
As Integer = -1
75 Public Const INADDR_NONE
As Long = &HFFFF
76 Private Const WSADESCRIPTION_LEN
As Integer = 257
77 Private Const WSASYS_STATUS_LEN
As Integer = 129
78 Private Enum WinsockVersion
79 SOCKET_VERSION_11
= &H101
80 SOCKET_VERSION_22
= &H202
82 Public Const MAXGETHOSTSTRUCT
As Long = 1024
83 Public Const AF_INET
As Long = 2
84 Public Const SOCK_STREAM
As Long = 1
85 Public Const SOCK_DGRAM
As Long = 2
86 Public Const IPPROTO_TCP
As Long = 6
87 Public Const IPPROTO_UDP
As Long = 17
88 Public Const FD_READ
As Integer = &H1
&
89 Public Const FD_WRITE
As Integer = &H2
&
90 Public Const FD_ACCEPT
As Integer = &H8
&
91 Public Const FD_CONNECT
As Integer = &H10
&
92 Public Const FD_CLOSE
As Integer = &H20
&
93 Private Const OFFSET_2
As Long = 65536
94 Private Const MAXINT_2
As Long = 32767
95 Public Const GMEM_FIXED
As Integer = &H0
96 Public Const LOCAL_HOST_BUFF
As Integer = 256
97 Public Const SOL_SOCKET
As Long = 65535
98 Public Const SO_SNDBUF
As Long = &H1001
&
99 Public Const SO_RCVBUF
As Long = &H1002
&
100 Public Const SO_MAX_MSG_SIZE
As Long = &H2003
101 Public Const SO_BROADCAST
As Long = &H20
102 Public Const FIONREAD
As Long = &H4004667F
103 '==============================================================================
105 '==============================================================================
106 Public Const WSABASEERR
As Long = 10000
107 Public Const WSAEINTR
As Long = (WSABASEERR
+ 4)
108 Public Const WSAEACCES
As Long = (WSABASEERR
+ 13)
109 Public Const WSAEFAULT
As Long = (WSABASEERR
+ 14)
110 Public Const WSAEINVAL
As Long = (WSABASEERR
+ 22)
111 Public Const WSAEMFILE
As Long = (WSABASEERR
+ 24)
112 Public Const WSAEWOULDBLOCK
As Long = (WSABASEERR
+ 35)
113 Public Const WSAEINPROGRESS
As Long = (WSABASEERR
+ 36)
114 Public Const WSAEALREADY
As Long = (WSABASEERR
+ 37)
115 Public Const WSAENOTSOCK
As Long = (WSABASEERR
+ 38)
116 Public Const WSAEDESTADDRREQ
As Long = (WSABASEERR
+ 39)
117 Public Const WSAEMSGSIZE
As Long = (WSABASEERR
+ 40)
118 Public Const WSAEPROTOTYPE
As Long = (WSABASEERR
+ 41)
119 Public Const WSAENOPROTOOPT
As Long = (WSABASEERR
+ 42)
120 Public Const WSAEPROTONOSUPPORT
As Long = (WSABASEERR
+ 43)
121 Public Const WSAESOCKTNOSUPPORT
As Long = (WSABASEERR
+ 44)
122 Public Const WSAEOPNOTSUPP
As Long = (WSABASEERR
+ 45)
123 Public Const WSAEPFNOSUPPORT
As Long = (WSABASEERR
+ 46)
124 Public Const WSAEAFNOSUPPORT
As Long = (WSABASEERR
+ 47)
125 Public Const WSAEADDRINUSE
As Long = (WSABASEERR
+ 48)
126 Public Const WSAEADDRNOTAVAIL
As Long = (WSABASEERR
+ 49)
127 Public Const WSAENETDOWN
As Long = (WSABASEERR
+ 50)
128 Public Const WSAENETUNREACH
As Long = (WSABASEERR
+ 51)
129 Public Const WSAENETRESET
As Long = (WSABASEERR
+ 52)
130 Public Const WSAECONNABORTED
As Long = (WSABASEERR
+ 53)
131 Public Const WSAECONNRESET
As Long = (WSABASEERR
+ 54)
132 Public Const WSAENOBUFS
As Long = (WSABASEERR
+ 55)
133 Public Const WSAEISCONN
As Long = (WSABASEERR
+ 56)
134 Public Const WSAENOTCONN
As Long = (WSABASEERR
+ 57)
135 Public Const WSAESHUTDOWN
As Long = (WSABASEERR
+ 58)
136 Public Const WSAETIMEDOUT
As Long = (WSABASEERR
+ 60)
137 Public Const WSAEHOSTUNREACH
As Long = (WSABASEERR
+ 65)
138 Public Const WSAECONNREFUSED
As Long = (WSABASEERR
+ 61)
139 Public Const WSAEPROCLIM
As Long = (WSABASEERR
+ 67)
140 Public Const WSASYSNOTREADY
As Long = (WSABASEERR
+ 91)
141 Public Const WSAVERNOTSUPPORTED
As Long = (WSABASEERR
+ 92)
142 Public Const WSANOTINITIALISED
As Long = (WSABASEERR
+ 93)
143 Public Const WSAHOST_NOT_FOUND
As Long = (WSABASEERR
+ 1001)
144 Public Const WSATRY_AGAIN
As Long = (WSABASEERR
+ 1002)
145 Public Const WSANO_RECOVERY
As Long = (WSABASEERR
+ 1003)
146 Public Const WSANO_DATA
As Long = (WSABASEERR
+ 1004)
147 '==============================================================================
148 'WINSOCK CONTROL ERROR CODES
149 '==============================================================================
150 Public Const sckOutOfMemory
As Long = 7
151 Public Const sckBadState
As Long = 40006
152 Public Const sckInvalidArg
As Long = 40014
153 Public Const sckUnsupported
As Long = 40018
154 Public Const sckInvalidOp
As Long = 40020
155 '==============================================================================
157 '==============================================================================
160 wHighVersion
As Integer
161 szDescription
As String * WSADESCRIPTION_LEN
162 szSystemStatus
As String * WSASYS_STATUS_LEN
163 iMaxSockets
As Integer
174 Public Type sockaddr_in
175 sin_family
As Integer
178 sin_zero(1 To 8) As Byte
180 '==============================================================================
182 '==============================================================================
183 Private m_blnInitiated
As Boolean 'specify if winsock service was initiated
184 Private m_lngSocksQuantity
As Long 'number of instances created
185 Private m_colSocketsInst
As Collection
'sockets list and instance owner
186 Private m_colAcceptList
As Collection
'sockets in queue that need to be accepted
187 Private m_lngWindowHandle
As Long 'message window handle
188 '==============================================================================
189 'SUBCLASSING DECLARATIONS
191 '==============================================================================
192 Private Declare Function api_IsWindow _
194 Alias "IsWindow" (ByVal hWnd
As Long) As Long
195 Private Declare Function api_GetWindowLong _
197 Alias "GetWindowLongA" (ByVal hWnd
As Long, _
198 ByVal nIndex
As Long) As Long
199 Private Declare Function api_SetWindowLong _
201 Alias "SetWindowLongA" (ByVal hWnd
As Long, _
202 ByVal nIndex
As Long, _
203 ByVal dwNewLong
As Long) As Long
204 Private Declare Function api_GetModuleHandle _
206 Alias "GetModuleHandleA" (ByVal lpModuleName
As String) As Long
207 Private Declare Function api_GetProcAddress _
209 Alias "GetProcAddress" (ByVal hModule
As Long, _
210 ByVal lpProcName
As String) As Long
211 Private Const PATCH_06
As Long = 106
212 Private Const PATCH_09
As Long = 137
213 Private Const GWL_WNDPROC
As Long = (-4)
214 Private Const WM_APP
As Long = 32768 '0x8000
215 Public Const RESOLVE_MESSAGE
As Long = WM_APP
216 Public Const SOCKET_MESSAGE
As Long = WM_APP
+ 1
217 Private lngMsgCntA
As Long 'TableA entry count
218 Private lngMsgCntB
As Long 'TableB entry count
219 Private lngTableA1() As Long 'TableA1: list of async handles
220 Private lngTableA2() As Long 'TableA2: list of async handles owners
221 Private lngTableB1() As Long 'TableB1: list of sockets
222 Private lngTableB2() As Long 'TableB2: list of sockets owners
223 Private hWndSub
As Long 'window handle subclassed
224 Private nAddrSubclass
As Long 'address of our WndProc
225 Private nAddrOriginal
As Long 'address of original WndProc
227 'Once we are done with the class instance we call this
228 'function to discount it and finish winsock service if
229 'it was the last one.
230 'Returns 0 if it has success.
231 Public Function FinalizeProcesses() As Long
233 On Error GoTo FinalizeProcesses_Err
235 100 FinalizeProcesses
= 0
236 101 m_lngSocksQuantity
= m_lngSocksQuantity
- 1
238 'if the service was initiated and there's no more instances
239 'of the class then we finish the service
240 102 If m_blnInitiated
And m_lngSocksQuantity
= 0 Then
241 103 If FinalizeService
= SOCKET_ERROR
Then
242 Dim lngErrorCode
As Long
243 104 lngErrorCode
= Err
.LastDllError
244 105 FinalizeProcesses
= lngErrorCode
245 106 Err
.Raise lngErrorCode
, "modSocketMaster.FinalizeProcesses", GetErrorDescription(lngErrorCode
)
247 '114 Debug.Print "OK Winsock service finalized"
250 107 Subclass_Terminate
251 108 m_blnInitiated
= False
256 FinalizeProcesses_Err:
257 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.FinalizeProcesses.Ref 12/2/2008 : 09:38:31"
262 'Return the accept instance class from a socket.
263 Public Function GetAcceptClass(ByVal lngSocket
As Long) As CSocketMaster
265 On Error GoTo GetAcceptClass_Err
267 100 Set GetAcceptClass
= m_colAcceptList("S" & lngSocket
)
271 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.GetAcceptClass.Ref 12/2/2008 : 09:38:31"
276 'This function receives a number that represents an error
277 'and returns the corresponding description string.
278 Public Function GetErrorDescription(ByVal lngErrorCode
As Long) As String
280 On Error GoTo GetErrorDescription_Err
283 100 Select Case lngErrorCode
286 101 GetErrorDescription
= "Permission denied."
288 102 Case WSAEADDRINUSE
289 103 GetErrorDescription
= "Address already in use."
291 104 Case WSAEADDRNOTAVAIL
292 105 GetErrorDescription
= "Cannot assign requested address."
294 106 Case WSAEAFNOSUPPORT
295 107 GetErrorDescription
= "Address family not supported by protocol family."
298 109 GetErrorDescription
= "Operation already in progress."
300 110 Case WSAECONNABORTED
301 111 GetErrorDescription
= "Software caused connection abort."
303 112 Case WSAECONNREFUSED
304 113 GetErrorDescription
= "Connection refused."
306 114 Case WSAECONNRESET
307 115 GetErrorDescription
= "Connection reset by peer."
309 116 Case WSAEDESTADDRREQ
310 117 GetErrorDescription
= "Destination address required."
313 119 GetErrorDescription
= "Bad address."
315 120 Case WSAEHOSTUNREACH
316 121 GetErrorDescription
= "No route to host."
318 122 Case WSAEINPROGRESS
319 123 GetErrorDescription
= "Operation now in progress."
322 125 GetErrorDescription
= "Interrupted function call."
325 127 GetErrorDescription
= "Invalid argument."
328 129 GetErrorDescription
= "Socket is already connected."
331 131 GetErrorDescription
= "Too many open files."
334 133 GetErrorDescription
= "Message too long."
337 135 GetErrorDescription
= "Network is down."
339 136 Case WSAENETRESET
340 137 GetErrorDescription
= "Network dropped connection on reset."
342 138 Case WSAENETUNREACH
343 139 GetErrorDescription
= "Network is unreachable."
346 141 GetErrorDescription
= "No buffer space available."
348 142 Case WSAENOPROTOOPT
349 143 GetErrorDescription
= "Bad protocol option."
352 145 GetErrorDescription
= "Socket is not connected."
355 147 GetErrorDescription
= "Socket operation on nonsocket."
357 148 Case WSAEOPNOTSUPP
358 149 GetErrorDescription
= "Operation not supported."
360 150 Case WSAEPFNOSUPPORT
361 151 GetErrorDescription
= "Protocol family not supported."
364 153 GetErrorDescription
= "Too many processes."
366 154 Case WSAEPROTONOSUPPORT
367 155 GetErrorDescription
= "Protocol not supported."
369 156 Case WSAEPROTOTYPE
370 157 GetErrorDescription
= "Protocol wrong type for socket."
372 158 Case WSAESHUTDOWN
373 159 GetErrorDescription
= "Cannot send after socket shutdown."
375 160 Case WSAESOCKTNOSUPPORT
376 161 GetErrorDescription
= "Socket type not supported."
378 162 Case WSAETIMEDOUT
379 163 GetErrorDescription
= "Connection timed out."
381 164 Case WSAEWOULDBLOCK
382 165 GetErrorDescription
= "Resource temporarily unavailable."
384 166 Case WSAHOST_NOT_FOUND
385 167 GetErrorDescription
= "Host not found."
387 168 Case WSANOTINITIALISED
388 169 GetErrorDescription
= "Successful WSAStartup not yet performed."
391 171 GetErrorDescription
= "Valid name, no data record of requested type."
393 172 Case WSANO_RECOVERY
394 173 GetErrorDescription
= "This is a nonrecoverable error."
396 174 Case WSASYSNOTREADY
397 175 GetErrorDescription
= "Network subsystem is unavailable."
399 176 Case WSATRY_AGAIN
400 177 GetErrorDescription
= "Non authoritative host not found."
402 178 Case WSAVERNOTSUPPORTED
403 179 GetErrorDescription
= "Winsock.dll version out of range."
406 181 GetErrorDescription
= "Unknown error."
411 GetErrorDescription_Err:
412 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.GetErrorDescription.Ref 12/2/2008 : 09:38:31"
417 'Returns the hi word from a double word.
418 Public Function HiWord(lngValue
As Long) As Long
420 On Error GoTo HiWord_Err
423 100 If (lngValue
And &H80000000
) = &H80000000
Then
424 101 HiWord
= ((lngValue
And &H7FFF0000
) \
&H10000
) Or &H8000
&
426 102 HiWord
= (lngValue
And &HFFFF0000
) \
&H10000
432 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.HiWord.Ref 12/2/2008 : 09:38:31"
437 'This function initiates the processes needed to keep
438 'control of sockets. Returns 0 if it has success.
439 Public Function InitiateProcesses() As Long
441 On Error GoTo InitiateProcesses_Err
443 100 InitiateProcesses
= 0
444 101 m_lngSocksQuantity
= m_lngSocksQuantity
+ 1
446 'if the service wasn't initiated yet we do it now
447 102 If Not m_blnInitiated
Then
448 103 Subclass_Initialize
449 104 m_blnInitiated
= True
450 Dim lngResult
As Long
451 105 lngResult
= InitiateService
453 106 If lngResult
= 0 Then
454 'Debug.Print "OK Winsock service initiated"
456 107 Debug
.Print
"ERROR trying to initiate winsock service"
457 108 Err
.Raise lngResult
, "modSocketMaster.InitiateProcesses", GetErrorDescription(lngResult
)
458 109 InitiateProcesses
= lngResult
464 InitiateProcesses_Err:
465 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.InitiateProcesses.Ref 12/2/2008 : 09:38:31"
470 'The function takes a Long containing a value in the rangeĀ
471 'of an unsigned Integer and returns an Integer that youĀ
472 'can pass to an API that requires an unsigned Integer
473 Public Function IntegerToUnsigned(Value
As Integer) As Long
475 On Error GoTo IntegerToUnsigned_Err
478 100 If Value
< 0 Then
479 101 IntegerToUnsigned
= Value
+ OFFSET_2
481 102 IntegerToUnsigned
= Value
486 IntegerToUnsigned_Err:
487 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.IntegerToUnsigned.Ref 12/2/2008 : 09:38:31"
492 'Returns True is lngSocket is registered on the
494 Public Function IsAcceptRegistered(ByVal lngSocket
As Long) As Boolean
496 On Error GoTo IsAcceptRegistered_Err
498 On Error GoTo Error_Handler
499 100 m_colAcceptList
.Item ("S" & lngSocket
)
500 101 IsAcceptRegistered
= True
503 102 IsAcceptRegistered
= False
506 IsAcceptRegistered_Err:
507 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.IsAcceptRegistered.Ref 12/2/2008 : 09:38:31"
512 'Returns TRUE si the socket that is passed is registered
513 'in the colSocketsInst collection.
514 Public Function IsSocketRegistered(ByVal lngSocket
As Long) As Boolean
516 On Error GoTo IsSocketRegistered_Err
518 On Error GoTo Error_Handler
519 100 m_colSocketsInst
.Item ("S" & lngSocket
)
520 101 IsSocketRegistered
= True
523 102 IsSocketRegistered
= False
526 IsSocketRegistered_Err:
527 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.IsSocketRegistered.Ref 12/2/2008 : 09:38:31"
532 'Returns the low word from a double word.
533 Public Function LoWord(lngValue
As Long) As Long
535 On Error GoTo LoWord_Err
537 100 LoWord
= (lngValue
And &HFFFF
&)
541 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.LoWord.Ref 12/2/2008 : 09:38:31"
546 'Assing a temporal instance of CSocketMaster to a
547 'socket and register this socket to the accept list.
548 Public Sub RegisterAccept(ByVal lngSocket
As Long)
550 On Error GoTo RegisterAccept_Err
553 100 If m_colAcceptList Is
Nothing Then
554 101 Set m_colAcceptList
= New Collection
557 Dim Socket
As CSocketMaster
558 102 Set Socket
= New CSocketMaster
559 103 Socket
.Accept lngSocket
560 104 m_colAcceptList
.Add Socket
, "S" & lngSocket
564 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.RegisterAccept.Ref 12/2/2008 : 09:38:31"
569 'Adds the socket to the m_colSocketsInst collection, and
570 'registers that socket with WSAAsyncSelect Winsock API
571 'function to receive network events for the socket.
572 'If this socket is the first one to be registered, the
573 'window and collection will be created in this function as well.
574 Public Function RegisterSocket(ByVal lngSocket
As Long, _
575 ByVal lngObjectPointer
As Long, _
576 ByVal blnEvents
As Boolean) As Boolean
578 On Error GoTo RegisterSocket_Err
581 100 If m_colSocketsInst Is
Nothing Then
582 101 Set m_colSocketsInst
= New Collection
584 102 If CreateWinsockMessageWindow
<> 0 Then
585 103 Err
.Raise sckOutOfMemory
, "modSocketMaster.RegisterSocket", "Out of memory"
588 104 Subclass_Subclass (m_lngWindowHandle
)
591 105 Subclass_AddSocketMessage lngSocket
, lngObjectPointer
593 'Do we need to register socket events?
594 106 If blnEvents
Then
595 Dim lngEvents
As Long
596 Dim lngResult
As Long
597 Dim lngErrorCode
As Long
598 107 lngEvents
= FD_READ
Or FD_WRITE
Or FD_ACCEPT
Or FD_CONNECT
Or FD_CLOSE
599 108 lngResult
= api_WSAAsyncSelect(lngSocket
, m_lngWindowHandle
, SOCKET_MESSAGE
, lngEvents
)
601 109 If lngResult
= SOCKET_ERROR
Then
602 110 Debug
.Print
"ERROR trying to register events from socket " & lngSocket
603 111 lngErrorCode
= Err
.LastDllError
604 112 Err
.Raise lngErrorCode
, "modSocketMaster.RegisterSocket", GetErrorDescription(lngErrorCode
)
608 113 m_colSocketsInst
.Add lngObjectPointer
, "S" & lngSocket
609 114 RegisterSocket
= True
613 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.RegisterSocket.Ref 12/2/2008 : 09:38:31"
618 'When a socket needs to resolve a hostname in asynchronous way
619 'it calls this function. If it has success it returns a nonzero
620 'number that represents the async task handle and register this
621 'number in the TableA list.
622 'Returns 0 if it fails.
623 Public Function ResolveHost(ByVal strHost
As String, _
624 ByVal lngHOSTENBuf
As Long, _
625 ByVal lngObjectPointer
As Long) As Long
627 On Error GoTo ResolveHost_Err
629 Dim lngAsynHandle
As Long
630 100 lngAsynHandle
= api_WSAAsyncGetHostByName(m_lngWindowHandle
, RESOLVE_MESSAGE
, strHost
, ByVal lngHOSTENBuf
, MAXGETHOSTSTRUCT
)
632 101 If lngAsynHandle
<> 0 Then Subclass_AddResolveMessage lngAsynHandle
, lngObjectPointer
633 102 ResolveHost
= lngAsynHandle
637 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.ResolveHost.Ref 12/2/2008 : 09:38:31"
642 'Receives a string pointer and it turns it into a regular string.
643 Public Function StringFromPointer(ByVal lPointer
As Long) As String
645 On Error GoTo StringFromPointer_Err
647 Dim strTemp
As String
649 100 strTemp
= String$(api_lstrlen(ByVal lPointer
), 0)
650 101 lRetVal
= api_lstrcpy(ByVal strTemp
, ByVal lPointer
)
652 102 If lRetVal
Then StringFromPointer
= strTemp
655 StringFromPointer_Err:
656 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.StringFromPointer.Ref 12/2/2008 : 09:38:31"
661 'Unregister lngSocket from the accept list.
662 Public Sub UnregisterAccept(ByVal lngSocket
As Long)
664 On Error GoTo UnregisterAccept_Err
666 100 m_colAcceptList
.Remove "S" & lngSocket
668 101 If m_colAcceptList
.Count
= 0 Then
669 102 Set m_colAcceptList
= Nothing
674 UnregisterAccept_Err:
675 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.UnregisterAccept.Ref 12/2/2008 : 09:38:31"
680 'When ResolveHost is called an async task handle is added
681 'to TableA list. Use this function to remove that record.
682 Public Sub UnregisterResolution(ByVal lngAsynHandle
As Long)
684 On Error GoTo UnregisterResolution_Err
686 100 Subclass_DelResolveMessage lngAsynHandle
689 UnregisterResolution_Err:
690 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.UnregisterResolution.Ref 12/2/2008 : 09:38:31"
695 'Removes the socket from the m_colSocketsInst collection
696 'If it is the last socket in that collection, the window
697 'and colection will be destroyed as well.
698 Public Sub UnregisterSocket(ByVal lngSocket
As Long)
700 On Error GoTo UnregisterSocket_Err
702 100 Subclass_DelSocketMessage lngSocket
704 101 m_colSocketsInst
.Remove "S" & lngSocket
706 102 If m_colSocketsInst
.Count
= 0 Then
707 103 Set m_colSocketsInst
= Nothing
708 104 Subclass_UnSubclass
709 105 DestroyWinsockMessageWindow
714 UnregisterSocket_Err:
715 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.UnregisterSocket.Ref 12/2/2008 : 09:38:31"
720 'The function takes an unsigned Integer from and API andĀ
721 'converts it to a Long for display or arithmetic purposes
722 Public Function UnsignedToInteger(Value
As Long) As Integer
724 On Error GoTo UnsignedToInteger_Err
727 100 If Value
< 0 Or Value
>= OFFSET_2
Then Error 6 ' Overflow
728 101 If Value
<= MAXINT_2
Then
729 102 UnsignedToInteger
= Value
731 103 UnsignedToInteger
= Value
- OFFSET_2
736 UnsignedToInteger_Err:
737 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.UnsignedToInteger.Ref 12/2/2008 : 09:38:31"
742 'Create a window that is used to capture sockets messages.
743 'Returns 0 if it has success.
744 Private Function CreateWinsockMessageWindow() As Long
746 On Error GoTo CreateWinsockMessageWindow_Err
748 100 m_lngWindowHandle
= api_CreateWindowEx(0&, "STATIC", "SOCKET_WINDOW", 0&, 0&, 0&, 0&, 0&, 0&, 0&, App
.hInstance
, ByVal 0&)
750 101 If m_lngWindowHandle
= 0 Then
751 102 CreateWinsockMessageWindow
= sckOutOfMemory
754 103 CreateWinsockMessageWindow
= 0
759 CreateWinsockMessageWindow_Err:
760 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.CreateWinsockMessageWindow.Ref 12/2/2008 : 09:38:31"
765 'Destroy the window that is used to capture sockets messages.
766 'Returns 0 if it has success.
767 Private Function DestroyWinsockMessageWindow() As Long
769 On Error GoTo DestroyWinsockMessageWindow_Err
771 100 DestroyWinsockMessageWindow
= 0
773 101 If m_lngWindowHandle
= 0 Then
777 Dim lngResult
As Long
778 102 lngResult
= api_DestroyWindow(m_lngWindowHandle
)
780 103 If lngResult
= 0 Then
781 104 DestroyWinsockMessageWindow
= sckOutOfMemory
782 105 Err
.Raise sckOutOfMemory
, "modSocketMaster.DestroyWinsockMessageWindow", "Out of memory"
784 '112 Debug.Print "OK Destroyed winsock message window " & m_lngWindowHandle
785 106 m_lngWindowHandle
= 0
790 DestroyWinsockMessageWindow_Err:
791 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.DestroyWinsockMessageWindow.Ref 12/2/2008 : 09:38:31"
796 'Finish winsock service calling the function
797 'api_WSACleanup and returns the result.
798 Private Function FinalizeService() As Long
800 On Error GoTo FinalizeService_Err
802 Dim lngResultado
As Long
803 100 lngResultado
= api_WSACleanup
804 101 FinalizeService
= lngResultado
808 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.FinalizeService.Ref 12/2/2008 : 09:38:31"
813 'This function initiate the winsock service calling
814 'the api_WSAStartup funtion and returns resulting value.
815 Private Function InitiateService() As Long
817 On Error GoTo InitiateService_Err
819 Dim udtWSAData
As WSAData
820 Dim lngResult
As Long
821 100 lngResult
= api_WSAStartup(SOCKET_VERSION_11
, udtWSAData
)
822 101 InitiateService
= lngResult
826 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.InitiateService.Ref 12/2/2008 : 09:38:31"
831 Public Sub Subclass_ChangeOwner(ByVal lngSocket
As Long, _
832 ByVal lngObjectPointer
As Long)
834 On Error GoTo Subclass_ChangeOwner_Err
838 100 For Count
= 1 To lngMsgCntB
840 101 If lngTableB1(Count
) = lngSocket
Then
841 102 lngTableB2(Count
) = lngObjectPointer
849 Subclass_ChangeOwner_Err:
850 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.Subclass_ChangeOwner.Ref 12/2/2008 : 09:38:31"
855 Private Sub Subclass_AddResolveMessage(ByVal lngAsync
As Long, _
856 ByVal lngObjectPointer
As Long)
858 On Error GoTo Subclass_AddResolveMessage_Err
862 100 For Count
= 1 To lngMsgCntA
864 101 Select Case lngTableA1(Count
)
867 102 lngTableA1(Count
) = lngAsync
868 103 lngTableA2(Count
) = lngObjectPointer
877 105 lngMsgCntA
= lngMsgCntA
+ 1
878 106 ReDim Preserve lngTableA1(1 To lngMsgCntA
)
879 107 ReDim Preserve lngTableA2(1 To lngMsgCntA
)
880 108 lngTableA1(lngMsgCntA
) = lngAsync
881 109 lngTableA2(lngMsgCntA
) = lngObjectPointer
882 110 Subclass_PatchTableA
885 Subclass_AddResolveMessage_Err:
886 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.Subclass_AddResolveMessage.Ref 12/2/2008 : 09:38:31"
891 'Return the address of the passed function in the passed dll
892 Private Function Subclass_AddrFunc(ByVal sDLL
As String, _
893 ByVal sProc
As String) As Long
895 On Error GoTo Subclass_AddrFunc_Err
897 100 Subclass_AddrFunc
= api_GetProcAddress(api_GetModuleHandle(sDLL
), sProc
)
900 Subclass_AddrFunc_Err:
901 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.Subclass_AddrFunc.Ref 12/2/2008 : 09:38:31"
906 'Return the address of the low bound of the passed table array
907 Private Function Subclass_AddrMsgTbl(ByRef aMsgTbl() As Long) As Long
909 On Error GoTo Subclass_AddrMsgTbl_Err
911 On Error Resume Next 'The table may not be dimensioned yet so we need protection
912 100 Subclass_AddrMsgTbl
= VarPtr(aMsgTbl(1)) 'Get the address of the first element of the passed message table
913 On Error GoTo Subclass_AddrMsgTbl_Err
'Switch off error protection
916 Subclass_AddrMsgTbl_Err:
917 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.Subclass_AddrMsgTbl.Ref 12/2/2008 : 09:38:31"
922 Private Sub Subclass_AddSocketMessage(ByVal lngSocket
As Long, _
923 ByVal lngObjectPointer
As Long)
925 On Error GoTo Subclass_AddSocketMessage_Err
929 100 For Count
= 1 To lngMsgCntB
931 101 Select Case lngTableB1(Count
)
934 102 lngTableB1(Count
) = lngSocket
935 103 lngTableB2(Count
) = lngObjectPointer
944 105 lngMsgCntB
= lngMsgCntB
+ 1
945 106 ReDim Preserve lngTableB1(1 To lngMsgCntB
)
946 107 ReDim Preserve lngTableB2(1 To lngMsgCntB
)
947 108 lngTableB1(lngMsgCntB
) = lngSocket
948 109 lngTableB2(lngMsgCntB
) = lngObjectPointer
949 110 Subclass_PatchTableB
952 Subclass_AddSocketMessage_Err:
953 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.Subclass_AddSocketMessage.Ref 12/2/2008 : 09:38:31"
958 Private Sub Subclass_DelResolveMessage(ByVal lngAsync
As Long)
960 On Error GoTo Subclass_DelResolveMessage_Err
964 100 For Count
= 1 To lngMsgCntA
966 101 If lngTableA1(Count
) = lngAsync
Then
967 102 lngTableA1(Count
) = -1
968 103 lngTableA2(Count
) = -1
976 Subclass_DelResolveMessage_Err:
977 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.Subclass_DelResolveMessage.Ref 12/2/2008 : 09:38:31"
982 Private Sub Subclass_DelSocketMessage(ByVal lngSocket
As Long)
984 On Error GoTo Subclass_DelSocketMessage_Err
988 100 For Count
= 1 To lngMsgCntB
990 101 If lngTableB1(Count
) = lngSocket
Then
991 102 lngTableB1(Count
) = -1
992 103 lngTableB2(Count
) = -1
1000 Subclass_DelSocketMessage_Err:
1001 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.Subclass_DelSocketMessage.Ref 12/2/2008 : 09:38:31"
1006 'Return whether we're running in the IDE. Public for general utility purposes
1007 Private Function Subclass_InIDE() As Boolean
1009 On Error GoTo Subclass_InIDE_Err
1011 100 Debug
.Assert
Subclass_SetTrue(Subclass_InIDE
)
1015 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.Subclass_InIDE.Ref 12/2/2008 : 09:38:31"
1020 '==============================================================================
1022 'based on code by Paul Caton
1023 '==============================================================================
1024 Private Sub Subclass_Initialize()
1026 On Error GoTo Subclass_Initialize_Err
1028 Const PATCH_01
As Long = 15 'Code buffer offset to the location of the relative address to EbMode
1029 Const PATCH_03
As Long = 76 'Relative address of SetWindowsLong
1030 Const PATCH_05
As Long = 100 'Relative address of CallWindowProc
1031 Const FUNC_EBM
As String = "EbMode" 'VBA's EbMode function allows the machine code thunk to know if the IDE has stopped or is on a breakpoint
1032 Const FUNC_SWL
As String = "SetWindowLongA" 'SetWindowLong allows the cSubclasser machine code thunk to unsubclass the subclasser itself if it detects via the EbMode function that the IDE has stopped
1033 Const FUNC_CWP
As String = "CallWindowProcA" 'We use CallWindowProc to call the original WndProc
1034 Const MOD_VBA5
As String = "vba5" 'Location of the EbMode function if running VB5
1035 Const MOD_VBA6
As String = "vba6" 'Location of the EbMode function if running VB6
1036 Const MOD_USER
As String = "user32" 'Location of the SetWindowLong & CallWindowProc functions
1037 Dim i
As Long 'Loop index
1038 Dim nLen
As Long 'String lengths
1039 Dim sHex
As String 'Hex code string
1040 Dim sCode
As String 'Binary code string
1041 'Store the hex pair machine code representation in sHex
1042 100 sHex
= "5850505589E55753515231C0EB0EE8xxxxx01x83F802742285C074258B45103D0080000074433D01800000745BE8200000005A595B5FC9C21400E813000000EBF168xxxxx02x6AFCFF750CE8xxxxx03xEBE0FF7518FF7514FF7510FF750C68xxxxx04xE8xxxxx05xC3BBxxxxx06x8B4514BFxxxxx07x89D9F2AF75B629CB4B8B1C9Dxxxxx08xEB1DBBxxxxx09x8B4514BFxxxxx0Ax89D9F2AF759729CB4B8B1C9Dxxxxx0Bx895D088B1B8B5B1C89D85A595B5FC9FFE0"
1043 101 nLen
= Len(sHex
) 'Length of hex pair string
1045 'Convert the string from hex pairs to bytes and store in the ASCII string opcode buffer
1046 102 For i
= 1 To nLen Step
2 'For each pair of hex characters
1047 103 sCode
= sCode
& ChrB
$(Val("&H" & Mid$(sHex, i
, 2))) 'Convert a pair of hex characters to a byte and append to the ASCII string
1050 104 nLen
= LenB(sCode
) 'Get the machine code length
1051 105 nAddrSubclass
= api_GlobalAlloc(0, nLen
) 'Allocate fixed memory for machine code buffer
1052 'Copy the code to allocated memory
1053 106 Call api_CopyMemory(ByVal nAddrSubclass
, ByVal StrPtr(sCode
), nLen
)
1055 107 If Subclass_InIDE
Then
1056 'Patch the jmp (EB0E) with two nop's (90) enabling the IDE breakpoint/stop checking code
1057 108 Call api_CopyMemory(ByVal nAddrSubclass
+ 12, &H9090
, 2)
1058 109 i
= Subclass_AddrFunc(MOD_VBA6
, FUNC_EBM
) 'Get the address of EbMode in vba6.dll
1060 110 If i
= 0 Then 'Found?
1061 111 i
= Subclass_AddrFunc(MOD_VBA5
, FUNC_EBM
) 'VB5 perhaps, try vba5.dll
1064 112 Debug
.Assert i
'Ensure the EbMode function was found
1065 113 Call Subclass_PatchRel(PATCH_01
, i
) 'Patch the relative address to the EbMode api function
1068 114 Call Subclass_PatchRel(PATCH_03
, Subclass_AddrFunc(MOD_USER
, FUNC_SWL
)) 'Address of the SetWindowLong api function
1069 115 Call Subclass_PatchRel(PATCH_05
, Subclass_AddrFunc(MOD_USER
, FUNC_CWP
)) 'Address of the CallWindowProc api function
1072 Subclass_Initialize_Err:
1073 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.Subclass_Initialize.Ref 12/2/2008 : 09:38:30"
1078 'Patch the machine code buffer offset with the relative address to the target address
1079 Private Sub Subclass_PatchRel(ByVal nOffset
As Long, _
1080 ByVal nTargetAddr
As Long)
1082 On Error GoTo Subclass_PatchRel_Err
1084 100 Call api_CopyMemory(ByVal (nAddrSubclass
+ nOffset
), nTargetAddr
- nAddrSubclass
- nOffset
- 4, 4)
1087 Subclass_PatchRel_Err:
1088 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.Subclass_PatchRel.Ref 12/2/2008 : 09:38:30"
1093 Private Sub Subclass_PatchTableA()
1095 On Error GoTo Subclass_PatchTableA_Err
1097 Const PATCH_07
As Long = 114
1098 Const PATCH_08
As Long = 130
1099 100 Call Subclass_PatchVal(PATCH_06
, lngMsgCntA
)
1100 101 Call Subclass_PatchVal(PATCH_07
, Subclass_AddrMsgTbl(lngTableA1
))
1101 102 Call Subclass_PatchVal(PATCH_08
, Subclass_AddrMsgTbl(lngTableA2
))
1104 Subclass_PatchTableA_Err:
1105 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.Subclass_PatchTableA.Ref 12/2/2008 : 09:38:30"
1110 Private Sub Subclass_PatchTableB()
1112 On Error GoTo Subclass_PatchTableB_Err
1114 Const PATCH_0A
As Long = 145
1115 Const PATCH_0B
As Long = 161
1116 100 Call Subclass_PatchVal(PATCH_09
, lngMsgCntB
)
1117 101 Call Subclass_PatchVal(PATCH_0A
, Subclass_AddrMsgTbl(lngTableB1
))
1118 102 Call Subclass_PatchVal(PATCH_0B
, Subclass_AddrMsgTbl(lngTableB2
))
1121 Subclass_PatchTableB_Err:
1122 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.Subclass_PatchTableB.Ref 12/2/2008 : 09:38:30"
1127 'Patch the machine code buffer offset with the passed value
1128 Private Sub Subclass_PatchVal(ByVal nOffset
As Long, _
1129 ByVal nValue
As Long)
1131 On Error GoTo Subclass_PatchVal_Err
1133 100 Call api_CopyMemory(ByVal (nAddrSubclass
+ nOffset
), nValue
, 4)
1136 Subclass_PatchVal_Err:
1137 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.Subclass_PatchVal.Ref 12/2/2008 : 09:38:30"
1142 'Worker function for InIDE - will only be called whilst running in the IDE
1143 Private Function Subclass_SetTrue(bValue
As Boolean) As Boolean
1145 On Error GoTo Subclass_SetTrue_Err
1147 100 Subclass_SetTrue
= True
1151 Subclass_SetTrue_Err:
1152 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.Subclass_SetTrue.Ref 12/2/2008 : 09:38:30"
1157 'Set the window subclass
1158 Private Function Subclass_Subclass(ByVal hWnd
As Long) As Boolean
1160 On Error GoTo Subclass_Subclass_Err
1162 Const PATCH_02
As Long = 66 'Address of the previous WndProc
1163 Const PATCH_04
As Long = 95 'Address of the previous WndProc
1165 100 If hWndSub
= 0 Then
1166 101 Debug
.Assert
api_IsWindow(hWnd
) 'Invalid window handle
1167 102 hWndSub
= hWnd
'Store the window handle
1168 'Get the original window proc
1169 103 nAddrOriginal
= api_GetWindowLong(hWnd
, GWL_WNDPROC
)
1170 104 Call Subclass_PatchVal(PATCH_02
, nAddrOriginal
) 'Original WndProc address for CallWindowProc, call the original WndProc
1171 105 Call Subclass_PatchVal(PATCH_04
, nAddrOriginal
) 'Original WndProc address for SetWindowLong, unsubclass on IDE stop
1172 'Set our WndProc in place of the original
1173 106 nAddrOriginal
= api_SetWindowLong(hWnd
, GWL_WNDPROC
, nAddrSubclass
)
1175 107 If nAddrOriginal
<> 0 Then
1176 108 nAddrOriginal
= 0
1177 109 Subclass_Subclass
= True 'Success
1181 110 Debug
.Assert Subclass_Subclass
1184 Subclass_Subclass_Err:
1185 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.Subclass_Subclass.Ref 12/2/2008 : 09:38:30"
1190 'UnSubclass and release the allocated memory
1191 Private Sub Subclass_Terminate()
1193 On Error GoTo Subclass_Terminate_Err
1195 100 Call Subclass_UnSubclass
'UnSubclass if the Subclass thunk is active
1196 101 Call api_GlobalFree(nAddrSubclass
) 'Release the allocated memory
1197 102 nAddrSubclass
= 0
1198 103 ReDim lngTableA1(1 To 1)
1199 104 ReDim lngTableA2(1 To 1)
1200 105 ReDim lngTableB1(1 To 1)
1201 106 ReDim lngTableB2(1 To 1)
1204 Subclass_Terminate_Err:
1205 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.Subclass_Terminate.Ref 12/2/2008 : 09:38:30"
1210 'Stop subclassing the window
1211 Private Function Subclass_UnSubclass() As Boolean
1213 On Error GoTo Subclass_UnSubclass_Err
1216 100 If hWndSub
<> 0 Then
1219 103 Call Subclass_PatchVal(PATCH_06
, lngMsgCntA
) 'Patch the TableA entry count to ensure no further Proc callbacks
1220 104 Call Subclass_PatchVal(PATCH_09
, lngMsgCntB
) 'Patch the TableB entry count to ensure no further Proc callbacks
1221 'Restore the original WndProc
1222 105 Call api_SetWindowLong(hWndSub
, GWL_WNDPROC
, nAddrOriginal
)
1223 106 hWndSub
= 0 'Indicate the subclasser is inactive
1224 107 Subclass_UnSubclass
= True 'Success
1229 Subclass_UnSubclass_Err:
1230 Controlar_Error Erl
, Err
.Description
, "Reseter.modSocketMaster.Subclass_UnSubclass.Ref 12/2/2008 : 09:38:30"