Monday 7 January 2019

VBA - Redis - Sockets - Low level TCP/IP code to interop with Redis

I'm going to show you some low level TCP/IP code to interoperate with Redis which is an open-source in-memory key-value store. Redis is a often used as a database cache to make cloud based applications more scalable by relieving the load on a relational database. I will give both C++ and VBA code that call a group of Win-32 Api functions known as Windows Sockets2 or Winsock.

Click here for separate Youtube window

This post follows on from the previous post where I detailed (both in text and video) ...

  1. How to install Redis
  2. How to get some data into and out of Redis using the command line tool, redis-cli
  3. How to call Redis from a VB.NET console application
  4. How to call Redis from VBA via a VB.Net COM Dll Interop Assembly

This post shows a solution that skips the .NET component and instead scripts directly against the Windows Sockets 2 Api.

Background to Sockets - TCP/IP

Redis does not have an HTTP interface and so we have to drop down a few layers and program Sockets. If you are new to Sockets then here is a little explanation. When I say drop down a few layers, the diagram below is very useful. It illustrates the OSI model. When dealing with HTTP we deal with the top layer of the OSI model, the Application layer or layer 7. Programming sockets means programming the Transport layer or layer 4 of the OSI model. If you program a lower layer then you can expect the code to be more complicated (unless of course you are given a high level abstraction like .NET framework does).

Wwww2

Forewarned of the increased complexity let's look at some sample code.

Starting with C++

So Windows API functions (except .NET platform) are 99% designed to be used by C++ developers. Typically when reading a Windows API documentation page the sample code will be given in C++. It is a useful skill therefore to be able to get the C++ sample up running so that you can step through and understand the code. You are best trying to run a sample from the most recently updated documentation page. Any compile errors can be googled and, of course, stackoverflow.com is your friend.

The C++ sample I began with was the recv defined in winsock.h and housed in ws2_32.dll.

Sometimes you need to disable warnings so in the sample code for the recv function I needed to added the following line at the top

#pragma warning(disable:4996)   //https://stackoverflow.com/questions/36683785/inet-addr-use-inet-pton-or-inetpton-instead-or-define-winsock-deprecated/47397620

Here is the full C++ code for pasting into a Win32 C++ Console program

  1. // Win32CppWinSockets2Play.cpp : This file contains the 'main' function. Program execution begins and ends there.
  2. //
  3.  
  4. #include "pch.h"
  5. #include <iostream>
  6.  
  7. #include <winsock2.h>
  8. #include <Ws2tcpip.h>
  9. #include <stdio.h>
  10.  
  11. // Link with ws2_32.lib
  12. #pragma comment(lib"Ws2_32.lib")
  13.  
  14. #define DEFAULT_BUFLEN 512
  15. #define DEFAULT_PORT 6379
  16.  
  17. //#define _WINSOCK_DEPRECATED_NO_WARNINGS
  18. #pragma warning(disable:4996)   //https://stackoverflow.com/questions/36683785/inet-addr-use-inet-pton-or-inetpton-instead-or-define-winsock-deprecated/47397620
  19.  
  20. int main()
  21. {
  22.         //----------------------
  23.         // Declare and initialize variables.
  24.         int iResult;
  25.         WSADATA wsaData;
  26.  
  27.         SOCKET ConnectSocket = INVALID_SOCKET;
  28.         struct sockaddr_in clientService;
  29.  
  30.         int recvbuflen = DEFAULT_BUFLEN;
  31.         char *sendbuf = (char *)"keys *\r\n";
  32.         char recvbuf[DEFAULT_BUFLEN] = "";
  33.  
  34.         //----------------------
  35.         // Initialize Winsock
  36.         iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
  37.         if (iResult != NO_ERROR) {
  38.                 wprintf(L"WSAStartup failed with error: %d\n", iResult);
  39.                 return 1;
  40.         }
  41.  
  42.         //----------------------
  43.         // Create a SOCKET for connecting to server
  44.         ConnectSocket = socket(AF_INETSOCK_STREAMIPPROTO_TCP);
  45.         if (ConnectSocket == INVALID_SOCKET) {
  46.                 wprintf(L"socket failed with error: %ld\n", WSAGetLastError());
  47.                 WSACleanup();
  48.                 return 1;
  49.         }
  50.  
  51.         //----------------------
  52.         // The sockaddr_in structure specifies the address family,
  53.         // IP address, and port of the server to be connected to.
  54.         clientService.sin_family = AF_INET;
  55.  
  56.         clientService.sin_addr.s_addr = inet_addr("127.0.0.1");
  57.  
  58.         clientService.sin_port = htons(DEFAULT_PORT);
  59.  
  60.         //----------------------
  61.         // Connect to server.
  62.         iResult = connect(ConnectSocket, (SOCKADDR*)&clientService, sizeof(clientService));
  63.         if (iResult == SOCKET_ERROR) {
  64.                 wprintf(L"connect failed with error: %d\n", WSAGetLastError());
  65.                 closesocket(ConnectSocket);
  66.                 WSACleanup();
  67.                 return 1;
  68.         }
  69.  
  70.         //----------------------
  71.         // Send an initial buffer
  72.         iResult = send(ConnectSocket, sendbuf, (int)strlen(sendbuf), 0);
  73.         if (iResult == SOCKET_ERROR) {
  74.                 wprintf(L"send failed with error: %d\n", WSAGetLastError());
  75.                 closesocket(ConnectSocket);
  76.                 WSACleanup();
  77.                 return 1;
  78.         }
  79.  
  80.         printf("Bytes Sent: %d\n", iResult);
  81.  
  82.         // shutdown the connection since no more data will be sent
  83.         iResult = shutdown(ConnectSocket, SD_SEND);
  84.         if (iResult == SOCKET_ERROR) {
  85.                 wprintf(L"shutdown failed with error: %d\n", WSAGetLastError());
  86.                 closesocket(ConnectSocket);
  87.                 WSACleanup();
  88.                 return 1;
  89.         }
  90.  
  91.         // Receive until the peer closes the connection
  92.         do {
  93.  
  94.                 iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
  95.                 if (iResult > 0)
  96.                         wprintf(L"Bytes received: %d\n", iResult);
  97.                 else if (iResult == 0)
  98.                         wprintf(L"Connection closed\n");
  99.                 else
  100.                         wprintf(L"recv failed with error: %d\n", WSAGetLastError());
  101.  
  102.         } while (iResult > 0);
  103.  
  104.  
  105.         // close the socket
  106.         iResult = closesocket(ConnectSocket);
  107.         if (iResult == SOCKET_ERROR) {
  108.                 wprintf(L"close failed with error: %d\n", WSAGetLastError());
  109.                 WSACleanup();
  110.                 return 1;
  111.         }
  112.  
  113.         WSACleanup();
  114.         return 0;
  115.     std::cout << "Hello World!\n"
  116. }
  117.  
  118. // Run program: Ctrl + F5 or Debug > Start Without Debugging menu
  119. // Debug program: F5 or Debug > Start Debugging menu
  120.  
  121. // Tips for Getting Started: 
  122. //   1. Use the Solution Explorer window to add/manage files
  123. //   2. Use the Team Explorer window to connect to source control
  124. //   3. Use the Output window to see build output and other messages
  125. //   4. Use the Error List window to view errors
  126. //   5. Go to Project > Add New Item to create new code files, or Project > Add Existing Item to add existing code files to the project
  127. //   6. In the future, to open this project again, go to File > Open > Project and select the .sln file
  128.  

Transcribing from C++ to VBA

So Windows API functions are 99.9% designed to be used by C++ developers. VBA Developers must find function declarations with compatible signatures that match. for this Google is your friend but after a while one can get familiar with passing pointers by using VarPtr, StrPtr and ObjPtr.

  1. Option Explicit
  2. Option Private Module
  3.  
  4.  
  5. 'reference Windows Sockets 2 - Windows applications _ Microsoft Docs
  6. 'http://msdn.microsoft.com/en-us/library/windows/desktop/ms740673(v=vs.85).aspx
  7. Private Const INVALID_SOCKET = -1
  8. Private Const WSADESCRIPTION_LEN = 256
  9. Private Const SOCKET_ERROR As Long = -1 'const #define SOCKET_ERROR            (-1)
  10.  
  11. Private Enum AF
  12.     AF_UNSPEC = 0
  13.     AF_INET = 2
  14.     AF_IPX = 6
  15.     AF_APPLETALK = 16
  16.     AF_NETBIOS = 17
  17.     AF_INET6 = 23
  18.     AF_IRDA = 26
  19.     AF_BTH = 32
  20. End Enum
  21.  
  22. Private Enum sock_type
  23.     SOCK_STREAM = 1
  24.     SOCK_DGRAM = 2
  25.     SOCK_RAW = 3
  26.     SOCK_RDM = 4
  27.     SOCK_SEQPACKET = 5
  28. End Enum
  29.  
  30. Private Enum Protocol
  31.     IPPROTO_ICMP = 1
  32.     IPPROTO_IGMP = 2
  33.     BTHPROTO_RFCOMM = 3
  34.     IPPROTO_TCP = 6
  35.     IPPROTO_UDP = 17
  36.     IPPROTO_ICMPV6 = 58
  37.     IPPROTO_RM = 113
  38. End Enum
  39.  
  40. 'Private Type sockaddr
  41. '    sa_family As Integer
  42. '    sa_data(0 To 13) As Byte
  43. 'End Type
  44.  
  45. Private Type sockaddr_in
  46.     sin_family As Integer
  47.     sin_port(0 To 1) As Byte
  48.     sin_addr(0 To 3) As Byte
  49.     sin_zero(0 To 7) As Byte
  50. End Type
  51.  
  52.  
  53. 'typedef UINT_PTR        SOCKET;
  54. Private Type udtSOCKET
  55.     pointer As Long
  56. End Type
  57.  
  58.  
  59.  
  60. ' typedef struct WSAData {
  61. '  WORD           wVersion;
  62. '  WORD           wHighVersion;
  63. '  char           szDescription[WSADESCRIPTION_LEN+1];
  64. '  char           szSystemStatus[WSASYS_STATUS_LEN+1];
  65. '  unsigned short iMaxSockets;
  66. '  unsigned short iMaxUdpDg;
  67. '  char FAR       *lpVendorInfo;
  68. '} WSADATA, *LPWSADATA;
  69.  
  70. Private Type udtWSADATA
  71.     wVersion As Integer
  72.     wHighVersion As Integer
  73.     szDescription(0 To WSADESCRIPTION_LEN) As Byte
  74.     szSystemStatus(0 To WSADESCRIPTION_LEN) As Byte
  75.     iMaxSockets As Integer
  76.     iMaxUdpDg As Integer
  77.     lpVendorInfo As Long
  78. End Type
  79.  
  80. 'int errorno = WSAGetLastError()
  81. Private Declare Function WSAGetLastError Lib "Ws2_32" () As Integer
  82.  
  83. '   int WSAStartup(
  84. '  __in   WORD wVersionRequested,
  85. '  __out  LPWSADATA lpWSAData
  86. ');
  87. Private Declare Function WSAStartup Lib "Ws2_32" _
  88.     (ByVal wVersionRequested As IntegerByRef lpWSAData As udtWSADATA) As winsockErrorCodes2
  89.  
  90.  
  91. '    SOCKET WSAAPI socket(
  92. '  __in  int af,
  93. '  __in  int type,
  94. '  __in  int protocol
  95. ');
  96.  
  97. Private Declare Function ws2_socket Lib "Ws2_32" Alias "socket" _
  98.     (ByVal AF As LongByVal stype As LongByVal Protocol As LongAs LongPtr
  99.  
  100. Private Declare Function ws2_closesocket Lib "Ws2_32" Alias "closesocket" _
  101.     (ByVal socket As LongAs Long
  102.  
  103. 'int recv(
  104. '  SOCKET s,
  105. '  char   *buf,
  106. '  int    len,
  107. '  int    flags
  108. ');
  109. Private Declare Function ws2_recv Lib "Ws2_32" Alias "recv" _
  110.     (ByVal socket As LongByVal buf As LongPtr, _
  111.      ByVal length As LongByVal flags As LongAs Long
  112.  
  113. 'int WSAAPI connect(
  114. '  SOCKET         s,
  115. '  const sockaddr *name,
  116. '  int            namelen
  117. ');
  118.  
  119. Private Declare Function ws2_connect Lib "Ws2_32" Alias "connect" _
  120.     (ByVal As LongPtr, ByRef name As sockaddr_in, ByVal namelen As LongAs Long
  121.  
  122. 'int WSAAPI send(
  123. '  SOCKET     s,
  124. '  const char *buf,
  125. '  int        len,
  126. '  int        flags
  127. ');
  128. Private Declare Function ws2_send Lib "Ws2_32" Alias "send" _
  129.     (ByVal As LongPtr, ByVal buf As LongPtr, ByVal buflen As LongByVal flags As LongAs Long
  130.  
  131.  
  132. Private Declare Function ws2_shutdown Lib "Ws2_32" Alias "shutdown" _
  133.         (ByVal As LongByVal how As LongAs Long
  134.  
  135. Private Declare Sub WSACleanup Lib "Ws2_32" ()
  136.  
  137. Private Enum eShutdownConstants
  138.     SD_RECEIVE = 0  '#define SD_RECEIVE      0x00
  139.     SD_SEND = 1     '#define SD_SEND         0x01
  140.     SD_BOTH = 2     '#define SD_BOTH         0x02
  141. End Enum
  142.  
  143. Private Sub TestWS2SendAndReceive()
  144.  
  145.     Dim sResponse As String
  146.     If WS2SendAndReceive("KEYS *" & vbCrLf, sResponse) Then
  147.         Debug.Print VBA.Join(RedisResponseToTypedVariable(sResponse), ";")
  148.     End If
  149.  
  150.     If WS2SendAndReceive("GET foo" & vbCrLf, sResponse) Then
  151.         Debug.Print RedisResponseToTypedVariable(sResponse)
  152.     End If
  153.  
  154.     If WS2SendAndReceive("SET baz Barry" & vbCrLf, sResponse) Then
  155.         Debug.Assert RedisResponseToTypedVariable(sResponse) = "OK"
  156.     End If
  157.  
  158.     If WS2SendAndReceive("SET foo BAR" & vbCrLf, sResponse) Then
  159.         Debug.Assert RedisResponseToTypedVariable(sResponse) = "OK"
  160.     End If
  161.  
  162.     If WS2SendAndReceive("DEL baz" & vbCrLf, sResponse) Then
  163.         Debug.Print RedisResponseToTypedVariable(sResponse)
  164.     End If
  165.  
  166.  
  167.     If WS2SendAndReceive("GET baz" & vbCrLf, sResponse) Then
  168.         Debug.Print RedisResponseToTypedVariable(sResponse)
  169.     End If
  170.  
  171.     If WS2SendAndReceive("GET foo" & vbCrLf, sResponse) Then
  172.         Debug.Print RedisResponseToTypedVariable(sResponse)
  173.     End If
  174.  
  175.  
  176.     If WS2SendAndReceive("KEYS *" & vbCrLf, sResponse) Then
  177.         Debug.Print VBA.Join(RedisResponseToTypedVariable(sResponse), ";")
  178.     End If
  179.  
  180.  
  181.     If WS2SendAndReceive("SET count 0" & vbCrLf, sResponse) Then
  182.         Debug.Assert RedisResponseToTypedVariable(sResponse) = "OK"
  183.     End If
  184.  
  185.     If WS2SendAndReceive("INCR count" & vbCrLf, sResponse) Then
  186.         Debug.Assert RedisResponseToTypedVariable(sResponse) = "1"
  187.     End If
  188.  
  189.  
  190.  
  191.  
  192. End Sub
  193.  
  194. Public Function WS2SendAndReceive(ByVal sCommand As StringByRef psResponse As StringAs Boolean
  195.     'https://docs.microsoft.com/en-gb/windows/desktop/api/winsock/nf-winsock-recv
  196.  
  197.     psResponse = ""
  198.     '//----------------------
  199.     '// Declare and initialize variables.
  200.     Dim iResult As Integer : iResult = 0
  201.     Dim wsaData As udtWSADATA
  202.  
  203.     Dim ConnectSocket As LongPtr
  204.  
  205.     Dim clientService As sockaddr_in
  206.  
  207.     Dim sendBuf() As Byte
  208.     sendBuf = StrConv(sCommand, vbFromUnicode)
  209.  
  210.     Const recvbuflen As Long = 512
  211.     Dim recvbuf(0 To recvbuflen - 1) As Byte
  212.  
  213.     '//----------------------
  214.     '// Initialize Winsock
  215.     Dim eResult As winsockErrorCodes2
  216.     eResult = WSAStartup(&H202, wsaData)
  217.     If eResult <> 0 Then
  218.         Debug.Print "WSAStartup failed with error: " & eResult
  219.         WS2SendAndReceive = False
  220.         GoTo SingleExit
  221.     End If
  222.  
  223.  
  224.     '//----------------------
  225.     '// Create a SOCKET for connecting to server
  226.     ConnectSocket = ws2_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
  227.     If ConnectSocket = INVALID_SOCKET Then
  228.         Dim eLastError As winsockErrorCodes2
  229.         eLastError = WSAGetLastError()
  230.         Debug.Print "socket failed with error: " & eLastError
  231.         Call WSACleanup
  232.         WS2SendAndReceive = False
  233.         GoTo SingleExit
  234.     End If
  235.  
  236.  
  237.     '//----------------------
  238.     '// The sockaddr_in structure specifies the address family,
  239.     '// IP address, and port of the server to be connected to.
  240.     clientService.sin_family = AF_INET
  241.  
  242.     clientService.sin_addr(0) = 127
  243.     clientService.sin_addr(1) = 0
  244.     clientService.sin_addr(2) = 0
  245.     clientService.sin_addr(3) = 1
  246.  
  247.     clientService.sin_port(1) = 235 '* 6379
  248.     clientService.sin_port(0) = 24
  249.  
  250.     '//----------------------
  251.     '// Connect to server.
  252.  
  253.     iResult = ws2_connect(ConnectSocket, clientService, LenB(clientService))
  254.     If (iResult = SOCKET_ERROR) Then
  255.  
  256.         eLastError = WSAGetLastError()
  257.  
  258.         Debug.Print "connect failed with error: " & eLastError
  259.         Call ws2_closesocket(ConnectSocket)
  260.         Call WSACleanup
  261.         WS2SendAndReceive = False
  262.         GoTo SingleExit
  263.     End If
  264.  
  265.     '//----------------------
  266.     '// Send an initial buffer
  267.     Dim sendbuflen As Long
  268.     sendbuflen = UBound(sendBuf) - LBound(sendBuf) + 1
  269.     iResult = ws2_send(ConnectSocket, VarPtr(sendBuf(0)), sendbuflen, 0)
  270.     If (iResult = SOCKET_ERROR) Then
  271.         eLastError = WSAGetLastError()
  272.         Debug.Print "send failed with error: " & eLastError
  273.  
  274.         Call ws2_closesocket(ConnectSocket)
  275.         Call WSACleanup
  276.         WS2SendAndReceive = False
  277.         GoTo SingleExit
  278.     End If
  279.  
  280.     'Debug.Print "Bytes Sent: ", iResult
  281.  
  282.     '// shutdown the connection since no more data will be sent
  283.     iResult = ws2_shutdown(ConnectSocket, SD_SEND)
  284.     If (iResult = SOCKET_ERROR) Then
  285.  
  286.         eLastError = WSAGetLastError()
  287.         Debug.Print "shutdown failed with error: " & eLastError
  288.  
  289.         Call ws2_closesocket(ConnectSocket)
  290.         Call WSACleanup
  291.         WS2SendAndReceive = False
  292.         GoTo SingleExit
  293.     End If
  294.  
  295.     ' receive only one message (TODO handle when buffer is not large enough)
  296.  
  297.     iResult = ws2_recv(ConnectSocket, VarPtr(recvbuf(0)), recvbuflen, 0)
  298.     If (iResult > 0) Then
  299.         'Debug.Print "Bytes received: ", iResult
  300.     ElseIf (iResult = 0) Then
  301.         Debug.Print "Connection closed"
  302.         WS2SendAndReceive = False
  303.         Call ws2_closesocket(ConnectSocket)
  304.         Call WSACleanup
  305.         GoTo SingleExit
  306.     Else
  307.         eLastError = WSAGetLastError()
  308.         Debug.Print "recv failed with error: " & eLastError
  309.     End If
  310.  
  311.     psResponse = Left$(StrConv(recvbuf, vbUnicode), iResult)
  312.  
  313.     'Debug.Print psResponse
  314.  
  315.     '// close the socket
  316.     iResult = ws2_closesocket(ConnectSocket)
  317.     If (iResult = SOCKET_ERROR) Then
  318.  
  319.         eLastError = WSAGetLastError()
  320.         Debug.Print "close failed with error: " & eLastError
  321.  
  322.         Call WSACleanup
  323.         WS2SendAndReceive = False
  324.         GoTo SingleExit
  325.     End If
  326.  
  327.     Call WSACleanup
  328.     WS2SendAndReceive = True
  329.  
  330. SingleExit:
  331.     Exit Function
  332. ErrHand:
  333.  
  334. End Function
  335.  
  336. Public Function RedisResponseToTypedVariable(ByVal sResponse As String)
  337.  
  338.     Dim lTotalLength As Long
  339.     lTotalLength = Len(sResponse)
  340.     Debug.Assert lTotalLength > 0
  341.  
  342.     Dim vSplitResponse As Variant
  343.     vSplitResponse = VBA.Split(sResponse, vbCrLf)
  344.  
  345.     Dim lReponseLineCount As Long
  346.     lReponseLineCount = UBound(vSplitResponse) - LBound(vSplitResponse)
  347.  
  348.     Select Case Left(sResponse, 1)
  349.         Case "$"
  350.  
  351.             RedisResponseToTypedVariable = vSplitResponse(1)
  352.  
  353.         Case "+"
  354.             RedisResponseToTypedVariable = Mid$(vSplitResponse(0), 2)
  355.  
  356.         Case ":"
  357.             '* response is an integer
  358.             RedisResponseToTypedVariable = CLng(Mid$(vSplitResponse(0), 2))
  359.  
  360.         Case "-"
  361.             '* response is an error
  362.             Err.Raise vbObjectError, , Mid$(vSplitResponse(0), 2)
  363.         'Stop
  364.         Case "*"
  365.             '* multiple responses, build an array to return
  366.             Dim lResponseCount As Long
  367.             lResponseCount = CLng(Mid$(vSplitResponse(0), 2))
  368.             If lResponseCount > 0 Then
  369.                 Debug.Assert lResponseCount = (lReponseLineCount - 1) / 2
  370.         ReDim vReturn(0 To lResponseCount - 1)
  371.                 Dim lLoop As Long
  372.                 For lLoop = 0 To lResponseCount - 1
  373.                     vReturn(lLoop) = vSplitResponse((lLoop + 1) * 2)
  374.                 Next lLoop
  375.             End If
  376.             RedisResponseToTypedVariable = vReturn
  377.  
  378.         Case Else
  379.             Stop  '* this should not happen
  380.     End Select
  381.  
  382. End Function
  383.  
  384.  

Appendix A - Useful Enums

So it turned out I did not need these enumerations as such but I may in the future so parking here for safekeeping

modGlobalEnums Standard Module

  1. Option Explicit
  2.  
  3. Public Enum sckState
  4.     sckClosed = 0            ' Default. Closed
  5.     sckOpen = 1              ' Open
  6.     sckListening = 2         ' Listening
  7.     sckConnectionPending = 3 ' Connection pending
  8.     sckResolvingHost = 4     ' Resolving host
  9.     sckHostResolved = 5      ' Host resolved
  10.     sckConnecting = 6        ' Connecting
  11.     sckConnected = 7         ' Connected
  12.     sckClosing = 8           ' Peer is closing the connection
  13.     sckError = 9             ' Error
  14.  
  15. End Enum
  16.  
  17. ''https://docs.microsoft.com/en-gb/windows/desktop/WinSock/windows-sockets-error-codes-2
  18.  
  19. Public Enum winsockErrorCodes2
  20.     WSA_SUCCESS = 0
  21.     WSA_INVALID_HANDLE = 6
  22.     WSA_NOT_ENOUGH_MEMORY = 8
  23.     WSA_INVALID_PARAMETER = 87
  24.     WSA_OPERATION_ABORTED = 995
  25.     WSA_IO_INCOMPLETE = 996
  26.     WSA_IO_PENDING = 997
  27.     WSA_E_INTR = 10004
  28.     WSA_E_BADF = 10009
  29.     WSA_E_ACCES = 10013
  30.     WSA_E_FAULT = 10014
  31.     WSA_E_INVAL = 10022
  32.     WSA_E_MFILE = 10024
  33.     WSA_E_WOULDBLOCK = 10035
  34.     WSA_E_INPROGRESS = 10036
  35.     WSA_E_ALREADY = 10037
  36.     WSA_E_NOTSOCK = 10038
  37.     WSA_E_DESTADDRREQ = 10039
  38.     WSA_E_MSGSIZE = 10040         '* Message too long.
  39.     WSA_E_PROTOTYPE = 10041
  40.     WSA_E_NOPROTOOPT = 10042
  41.     WSA_E_PROTONOSUPPORT = 10043
  42.     WSA_E_SOCKTNOSUPPORT = 10044
  43.     WSA_E_OPNOTSUPP = 10045
  44.     WSA_E_PFNOSUPPORT = 10046
  45.     WSA_E_AFNOSUPPORT = 10047
  46.     WSA_E_ADDRINUSE = 10048
  47.     WSA_E_ADDRNOTAVAIL = 10049
  48.     WSA_E_NETDOWN = 10050
  49.     WSA_E_NETUNREACH = 10051
  50.     WSA_E_NETRESET = 10052
  51.     WSA_E_CONNABORTED = 10053
  52.     WSA_E_CONNRESET = 10054       '* Connection reset by peer.
  53.     WSA_E_NOBUFS = 10055
  54.     WSA_E_ISCONN = 10056
  55.     WSA_E_NOTCONN = 10057
  56.     WSA_E_SHUTDOWN = 10058
  57.     WSA_E_TOOMANYREFS = 10059
  58.     WSA_E_TIMEDOUT = 10060
  59.     WSA_E_CONNREFUSED = 10061
  60.     WSA_E_LOOP = 10062
  61.     WSA_E_NAMETOOLONG = 10063
  62.     WSA_E_HOSTDOWN = 10064
  63.     WSA_E_HOSTUNREACH = 10065
  64.     WSA_E_NOTEMPTY = 10066
  65.     WSA_E_PROCLIM = 10067
  66.     WSA_E_USERS = 10068
  67.     WSA_E_DQUOT = 10069
  68.     WSA_E_STALE = 10070
  69.     WSA_E_REMOTE = 10071
  70.     WSASYSNOTREADY = 10091
  71.     WSAVERNOTSUPPORTED = 10092
  72.     WSANOTINITIALISED = 10093
  73.     WSA_E_DISCON = 10101
  74.     WSA_E_NOMORE = 10102
  75.     WSA_E_CANCELLED = 10103
  76.     WSA_E_INVALIDPROCTABLE = 10104
  77.     WSA_E_INVALIDPROVIDER = 10105
  78.     WSA_E_PROVIDERFAILEDINIT = 10106
  79.     WSASYSCALLFAILURE = 10107
  80.     WSASERVICE_NOT_FOUND = 10108
  81.     WSATYPE_NOT_FOUND = 10109
  82.     WSA_E_NO_MORE = 10110
  83.     WSA_E_CANCELLED_2 = 10111
  84.     WSA_E_REFUSED = 10112
  85.     WSAHOST_NOT_FOUND = 11001
  86.     WSATRY_AGAIN = 11002
  87.     WSANO_RECOVERY = 11003
  88.     WSANO_DATA = 11004
  89.     WSA_QOS_RECEIVERS = 11005
  90.     WSA_QOS_SENDERS = 11006
  91.     WSA_QOS_NO_SENDERS = 11007
  92.     WSA_QOS_NO_RECEIVERS = 11008
  93.     WSA_QOS_REQUEST_CONFIRMED = 11009
  94.     WSA_QOS_ADMISSION_FAILURE = 11010
  95.     WSA_QOS_POLICY_FAILURE = 11011
  96.     WSA_QOS_BAD_STYLE = 11012
  97.     WSA_QOS_BAD_OBJECT = 11013
  98.     WSA_QOS_TRAFFIC_CTRL_ERROR = 11014
  99.     WSA_QOS_GENERIC_ERROR = 11015
  100.     WSA_QOS_ESERVICETYPE = 11016
  101.     WSA_QOS_EFLOWSPEC = 11017
  102.     WSA_QOS_EPROVSPECBUF = 11018
  103.     WSA_QOS_EFILTERSTYLE = 11019
  104.     WSA_QOS_EFILTERTYPE = 11020
  105.     WSA_QOS_EFILTERCOUNT = 11021
  106.     WSA_QOS_EOBJLENGTH = 11022
  107.     WSA_QOS_EFLOWCOUNT = 11023
  108.     WSA_QOS_EUNKOWNPSOBJ = 11024
  109.     WSA_QOS_EPOLICYOBJ = 11025
  110.     WSA_QOS_EFLOWDESC = 11026
  111.     WSA_QOS_EPSFLOWSPEC = 11027
  112.     WSA_QOS_EPSFILTERSPEC = 11028
  113.     WSA_QOS_ESDMODEOBJ = 11029
  114.     WSA_QOS_ESHAPERATEOBJ = 11030
  115.     WSA_QOS_RESERVED_PETYPE = 11031
  116. End Enum

2 comments:

  1. Hello! Congrats on your blog! It covers a lot of topics! I saw one of your older posts (and commented it too) and was wondering if you can help me out with some JavaScript code I can't crack..

    ReplyDelete
  2. Great ,
    Dim ConnectSocket As LongPtr i changed to long and works well.
    thx

    ReplyDelete