Fill WSAPROTOCOL_INFO structures instead of PROTOCOL_INFO structures.
Implement WSCEnumProtocols().
Add some tests.

diff --git a/dlls/winsock/protocol.c b/dlls/winsock/protocol.c
index bd6b71e..67e73e8 100644
--- a/dlls/winsock/protocol.c
+++ b/dlls/winsock/protocol.c
@@ -2,6 +2,7 @@
  * Protocol enumeration functions
  *
  * Copyright (C) 2001 Stefan Leichter
+ * Copyright (C) 2004 Hans Leidekker
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -46,247 +47,335 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(winsock);
 
-/* name of the protocols
- */
-static const WCHAR NameIpx[]   = {'I', 'P', 'X', '\0'};
-static const WCHAR NameSpx[]   = {'S', 'P', 'X', '\0'};
-static const WCHAR NameSpxII[] = {'S', 'P', 'X', ' ', 'I', 'I', '\0'};
-static const WCHAR NameTcp[]   = {'T', 'C', 'P', '/', 'I', 'P', '\0'};
-static const WCHAR NameUdp[]   = {'U', 'D', 'P', '/', 'I', 'P', '\0'};
+/* names of the protocols */
+static const CHAR NameIpx[]   = "IPX";
+static const CHAR NameSpx[]   = "SPX";
+static const CHAR NameSpxII[] = "SPX II";
+static const CHAR NameTcp[]   = "TCP/IP";
+static const CHAR NameUdp[]   = "UDP/IP";
+
+static const WCHAR NameIpxW[]   = {'I', 'P', 'X', '\0'};
+static const WCHAR NameSpxW[]   = {'S', 'P', 'X', '\0'};
+static const WCHAR NameSpxIIW[] = {'S', 'P', 'X', ' ', 'I', 'I', '\0'};
+static const WCHAR NameTcpW[]   = {'T', 'C', 'P', '/', 'I', 'P', '\0'};
+static const WCHAR NameUdpW[]   = {'U', 'D', 'P', '/', 'I', 'P', '\0'};
+
+/* Taken from Win2k */
+GUID ProviderId = { 0xe70f1aa0, 0xab8b, 0x11cf, { 0x8c, 0xa3, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92 } };
 
 /*****************************************************************************
- *          WINSOCK_EnterSingleProtocol [internal]
+ *          WINSOCK_EnterSingleProtocolW [internal]
  *
- *    enters the protocol informations of one given protocol into the
- *    given buffer. If the given buffer is too small only the required size for
- *    the protocols are returned.
+ *    enters the protocol information of one given protocol into the given
+ *    buffer.
  *
  * RETURNS
- *    The number of protocols entered into the buffer
+ *    1 if a protocol was entered into the buffer.
+ *    SOCKET_ERROR otherwise.
  *
  * BUGS
  *    - only implemented for IPX, SPX, SPXII, TCP, UDP
  *    - there is no check that the operating system supports the returned
  *      protocols
  */
-static INT WINSOCK_EnterSingleProtocol( INT iProtocol, PROTOCOL_INFOA* lpBuffer,
-                                        LPDWORD lpSize, BOOL unicode )
+static INT WINSOCK_EnterSingleProtocolW( INT protocol, WSAPROTOCOL_INFOW* info )
 {
-  DWORD  dwLength = 0, dwOldSize = *lpSize;
-  INT    iAnz = 1;
-  const WCHAR* lpProtName = NULL;
+    memset( info, 0, sizeof(WSAPROTOCOL_INFOW) );
+    info->iProtocol = protocol;
 
-  *lpSize = sizeof( PROTOCOL_INFOA);
-  switch (iProtocol) {
-    case WS_IPPROTO_TCP :
-        dwLength = (unicode) ? sizeof(WCHAR) * (strlenW(NameTcp)+1) :
-                               WideCharToMultiByte( CP_ACP, 0, NameTcp, -1,
-                                                    NULL, 0, NULL, NULL);
-      break;
-    case WS_IPPROTO_UDP :
-        dwLength = (unicode) ? sizeof(WCHAR) * (strlenW(NameUdp)+1) :
-                               WideCharToMultiByte( CP_ACP, 0, NameUdp, -1,
-                                                    NULL, 0, NULL, NULL);
-      break;
-    case NSPROTO_IPX :
-        dwLength = (unicode) ? sizeof(WCHAR) * (strlenW(NameIpx)+1) :
-                               WideCharToMultiByte( CP_ACP, 0, NameIpx, -1,
-                                                    NULL, 0, NULL, NULL);
-      break;
-    case NSPROTO_SPX :
-        dwLength = (unicode) ? sizeof(WCHAR) * (strlenW(NameSpx)+1) :
-                               WideCharToMultiByte( CP_ACP, 0, NameSpx, -1,
-                                                    NULL, 0, NULL, NULL);
-      break;
-    case NSPROTO_SPXII :
-        dwLength = (unicode) ? sizeof(WCHAR) * (strlenW(NameSpxII)+1) :
-                               WideCharToMultiByte( CP_ACP, 0, NameSpxII, -1,
-                                                    NULL, 0, NULL, NULL);
-      break;
+    switch (protocol)
+    {
+    case WS_IPPROTO_TCP:
+        info->dwServiceFlags1 = XP1_PARTIAL_MESSAGE | XP1_EXPEDITED_DATA |
+                                XP1_GRACEFUL_CLOSE | XP1_GUARANTEED_ORDER |
+                                XP1_GUARANTEED_DELIVERY;
+        memcpy( &info->ProviderId, &ProviderId, sizeof(GUID) );
+        info->dwCatalogEntryId = 0x3e9;
+        info->ProtocolChain.ChainLen = 1;
+        info->iVersion = 2;
+        info->iAddressFamily = WS_AF_INET;
+        info->iMaxSockAddr = 0x10;
+        info->iMinSockAddr = 0x10;
+        info->iSocketType = WS_SOCK_STREAM;
+        strcpyW( info->szProtocol, NameTcpW );
+        break;
+
+    case WS_IPPROTO_UDP:
+        info->dwServiceFlags1 = XP1_PARTIAL_MESSAGE | XP1_SUPPORT_BROADCAST |
+                                XP1_SUPPORT_MULTIPOINT | XP1_MESSAGE_ORIENTED |
+                                XP1_CONNECTIONLESS;
+        memcpy( &info->ProviderId, &ProviderId, sizeof(GUID) );
+        info->dwCatalogEntryId = 0x3ea;
+        info->ProtocolChain.ChainLen = 1;
+        info->iVersion = 2;
+        info->iAddressFamily = WS_AF_INET;
+        info->iMaxSockAddr = 0x10;
+        info->iMinSockAddr = 0x10;
+        info->iSocketType = WS_SOCK_DGRAM;
+        info->dwMessageSize = 0xffbb;
+        strcpyW( info->szProtocol, NameUdpW );
+        break;
+
+    case NSPROTO_IPX:
+        info->dwServiceFlags1 = XP1_PARTIAL_MESSAGE | XP1_SUPPORT_BROADCAST |
+                                XP1_SUPPORT_MULTIPOINT | XP1_MESSAGE_ORIENTED |
+                                XP1_CONNECTIONLESS;
+        info->iAddressFamily = WS_AF_IPX;
+        info->iMaxSockAddr = 0x10;
+        info->iMinSockAddr = 0x0e;
+        info->iSocketType = WS_SOCK_DGRAM;
+        info->dwMessageSize = 576;
+        strcpyW( info->szProtocol, NameIpxW );
+        break;
+
+    case NSPROTO_SPX:
+        info->dwServiceFlags1 = XP1_PARTIAL_MESSAGE |
+                                XP1_PSEUDO_STREAM | XP1_MESSAGE_ORIENTED |
+                                XP1_GUARANTEED_ORDER | XP1_GUARANTEED_DELIVERY;
+        info->iAddressFamily = WS_AF_IPX;
+        info->iMaxSockAddr = 0x10;
+        info->iMinSockAddr = 0x0e;
+        info->iSocketType = 5;
+        info->dwMessageSize = -1;
+        strcpyW( info->szProtocol, NameSpxW );
+        break;
+
+    case NSPROTO_SPXII:
+        info->dwServiceFlags1 = XP1_PARTIAL_MESSAGE | XP1_GRACEFUL_CLOSE |
+                                XP1_PSEUDO_STREAM | XP1_MESSAGE_ORIENTED |
+                                XP1_GUARANTEED_ORDER | XP1_GUARANTEED_DELIVERY;
+        info->iAddressFamily = WS_AF_IPX;
+        info->iMaxSockAddr = 0x10;
+        info->iMinSockAddr = 0x0e;
+        info->iSocketType = 5;
+        info->dwMessageSize = -1;
+        strcpyW( info->szProtocol, NameSpxIIW );
+        break;
+
     default:
-        *lpSize = 0;
-        if ((iProtocol == ISOPROTO_TP4) || (iProtocol == NSPROTO_SPX))
-          FIXME("Protocol <%s> not implemented\n",
-                (iProtocol == ISOPROTO_TP4) ? "ISOPROTO_TP4" : "NSPROTO_SPX");
+        if ((protocol == ISOPROTO_TP4) || (protocol == NSPROTO_SPX))
+            FIXME("Protocol <%s> not implemented\n",
+                  (protocol == ISOPROTO_TP4) ? "ISOPROTO_TP4" : "NSPROTO_SPX");
         else
-          FIXME("unknown Protocol <0x%08x>\n", iProtocol);
-      break;
-  }
-
-  *lpSize += dwLength;
-
-  if ( !lpBuffer || !*lpSize || (*lpSize > dwOldSize))
-     return 0;
-
-  memset( lpBuffer, 0, dwOldSize);
-
-  lpBuffer->lpProtocol = (LPSTR) &lpBuffer[ iAnz];
-  lpBuffer->iProtocol  = iProtocol;
-
-  switch (iProtocol) {
-    case WS_IPPROTO_TCP :
-        lpBuffer->dwServiceFlags = XP_FRAGMENTATION      | XP_EXPEDITED_DATA     |
-                                   XP_GRACEFUL_CLOSE     | XP_GUARANTEED_ORDER   |
-                                   XP_GUARANTEED_DELIVERY;
-        lpBuffer->iAddressFamily = WS_AF_INET;
-        lpBuffer->iMaxSockAddr   = 0x10;  /* NT4 SP5 */
-        lpBuffer->iMinSockAddr   = 0x10;  /* NT4 SP5 */
-        lpBuffer->iSocketType    = WS_SOCK_STREAM;
-        lpBuffer->dwMessageSize  = 0;
-        lpProtName = NameTcp;
-      break;
-    case WS_IPPROTO_UDP :
-        lpBuffer->dwServiceFlags = XP_FRAGMENTATION      | XP_SUPPORTS_BROADCAST |
-                                   XP_SUPPORTS_MULTICAST | XP_MESSAGE_ORIENTED   |
-                                   XP_CONNECTIONLESS;
-        lpBuffer->iAddressFamily = WS_AF_INET;
-        lpBuffer->iMaxSockAddr   = 0x10;  /* NT4 SP5 */
-        lpBuffer->iMinSockAddr   = 0x10;  /* NT4 SP5 */
-        lpBuffer->iSocketType    = WS_SOCK_DGRAM;
-        lpBuffer->dwMessageSize  = 65457; /* NT4 SP5 */
-        lpProtName = NameUdp;
-      break;
-    case NSPROTO_IPX :
-        lpBuffer->dwServiceFlags = XP_FRAGMENTATION      | XP_SUPPORTS_BROADCAST |
-                                   XP_SUPPORTS_MULTICAST | XP_MESSAGE_ORIENTED   |
-                                   XP_CONNECTIONLESS;
-        lpBuffer->iAddressFamily = WS_AF_IPX;
-        lpBuffer->iMaxSockAddr   = 0x10;  /* NT4 SP5 */
-        lpBuffer->iMinSockAddr   = 0x0e;  /* NT4 SP5 */
-        lpBuffer->iSocketType    = WS_SOCK_DGRAM;
-        lpBuffer->dwMessageSize  = 576;   /* NT4 SP5 */
-        lpProtName = NameIpx;
-      break;
-    case NSPROTO_SPX :
-        lpBuffer->dwServiceFlags = XP_FRAGMENTATION      |
-                                   XP_PSEUDO_STREAM      | XP_MESSAGE_ORIENTED   |
-                                   XP_GUARANTEED_ORDER   | XP_GUARANTEED_DELIVERY;
-        lpBuffer->iAddressFamily = WS_AF_IPX;
-        lpBuffer->iMaxSockAddr   = 0x10;  /* NT4 SP5 */
-        lpBuffer->iMinSockAddr   = 0x0e;  /* NT4 SP5 */
-        lpBuffer->iSocketType    = 5;
-        lpBuffer->dwMessageSize  = -1;    /* NT4 SP5 */
-        lpProtName = NameSpx;
-      break;
-    case NSPROTO_SPXII :
-        lpBuffer->dwServiceFlags = XP_FRAGMENTATION      | XP_GRACEFUL_CLOSE     |
-                                   XP_PSEUDO_STREAM      | XP_MESSAGE_ORIENTED   |
-                                   XP_GUARANTEED_ORDER   | XP_GUARANTEED_DELIVERY;
-        lpBuffer->iAddressFamily = WS_AF_IPX;
-        lpBuffer->iMaxSockAddr   = 0x10;  /* NT4 SP5 */
-        lpBuffer->iMinSockAddr   = 0x0e;  /* NT4 SP5 */
-        lpBuffer->iSocketType    = 5;
-        lpBuffer->dwMessageSize  = -1;    /* NT4 SP5 */
-        lpProtName = NameSpxII;
-      break;
-  }
-  if (unicode)
-    strcpyW( (LPWSTR)lpBuffer->lpProtocol, lpProtName);
-  else
-    WideCharToMultiByte( CP_ACP, 0, lpProtName, -1, lpBuffer->lpProtocol,
-                         dwOldSize - iAnz * sizeof( PROTOCOL_INFOA), NULL, NULL);
-
-  return iAnz;
+            FIXME("unknown Protocol <0x%08x>\n", protocol);
+        return SOCKET_ERROR;
+    }
+    return 1;
 }
 
 /*****************************************************************************
- *          WINSOCK_EnumProtocol [internal]
+ *          WINSOCK_EnterSingleProtocolA [internal]
  *
- *    Enters the information about installed protocols into a given buffer
+ *    see function WINSOCK_EnterSingleProtocolW
  *
- * RETURNS
- *    SOCKET_ERROR if the buffer is to small for the requested protocol infos
- *    on success the number of protocols inside the buffer
- *
- * NOTE
- *    NT4SP5 does not return SPX if lpiProtocols == NULL
- *
- * BUGS
- *    - NT4SP5 returns in addition these list of NETBIOS protocols
- *      (address family 17), each entry two times one for socket type 2 and 5
- *
- *      iProtocol   lpProtocol
- *      0x80000000  \Device\NwlnkNb
- *      0xfffffffa  \Device\NetBT_CBENT7
- *      0xfffffffb  \Device\Nbf_CBENT7
- *      0xfffffffc  \Device\NetBT_NdisWan5
- *      0xfffffffd  \Device\NetBT_El9202
- *      0xfffffffe  \Device\Nbf_El9202
- *      0xffffffff  \Device\Nbf_NdisWan4
- *
- *    - there is no check that the operating system supports the returned
- *      protocols
  */
-static INT WINSOCK_EnumProtocol( LPINT lpiProtocols, PROTOCOL_INFOA* lpBuffer,
-                                 LPDWORD lpdwLength, BOOL unicode )
+static INT WINSOCK_EnterSingleProtocolA( INT protocol, WSAPROTOCOL_INFOA* info )
 {
-  DWORD dwCurSize, dwOldSize = *lpdwLength, dwTemp;
-  INT   anz = 0, i;
-  INT   iLocal[] = { WS_IPPROTO_TCP, WS_IPPROTO_UDP, NSPROTO_IPX, NSPROTO_SPXII, 0};
+    memset( info, 0, sizeof(WSAPROTOCOL_INFOA) );
+    info->iProtocol = protocol;
 
-  if (!lpiProtocols) lpiProtocols = iLocal;
+    switch (protocol)
+    {
+    case WS_IPPROTO_TCP:
+        info->dwServiceFlags1 = XP1_IFS_HANDLES | XP1_EXPEDITED_DATA |
+                                XP1_GRACEFUL_CLOSE | XP1_GUARANTEED_ORDER |
+                                XP1_GUARANTEED_DELIVERY;
+        memcpy( &info->ProviderId, &ProviderId, sizeof(GUID) );
+        info->dwCatalogEntryId = 0x3e9;
+        info->ProtocolChain.ChainLen = 1;
+        info->iVersion = 2;
+        info->iAddressFamily = WS_AF_INET;
+        info->iMaxSockAddr = 0x10;
+        info->iMinSockAddr = 0x10;
+        info->iSocketType = WS_SOCK_STREAM;
+        strcpy( info->szProtocol, NameTcp );
+        break;
 
-  *lpdwLength = 0;
-  while ( *lpiProtocols )
-  {
-    dwCurSize = 0;
-    WINSOCK_EnterSingleProtocol( *lpiProtocols, NULL, &dwCurSize, unicode);
+    case WS_IPPROTO_UDP:
+        info->dwServiceFlags1 = XP1_IFS_HANDLES | XP1_SUPPORT_BROADCAST |
+                                XP1_SUPPORT_MULTIPOINT | XP1_MESSAGE_ORIENTED |
+                                XP1_CONNECTIONLESS;
+        memcpy( &info->ProviderId, &ProviderId, sizeof(GUID) );
+        info->dwCatalogEntryId = 0x3ea;
+        info->ProtocolChain.ChainLen = 1;
+        info->iVersion = 2;
+        info->iAddressFamily = WS_AF_INET;
+        info->iMaxSockAddr = 0x10;
+        info->iMinSockAddr = 0x10;
+        info->iSocketType = WS_SOCK_DGRAM;
+        info->dwMessageSize = 0xffbb;
+        strcpy( info->szProtocol, NameUdp );
+        break;
 
-    if ( lpBuffer && dwCurSize && ((*lpdwLength + dwCurSize) <= dwOldSize))
-    { /* reserve the required space for the current protocol_info after the
-       * last protocol_info before the start of the string buffer and adjust
-       * the references into the string buffer
-       */
-      memmove( &((char*)&lpBuffer[ anz])[dwCurSize],
-		  &lpBuffer[ anz],
-               *lpdwLength - anz * sizeof( PROTOCOL_INFOA));
-      for (i=0; i < anz; i++)
-        lpBuffer[i].lpProtocol += dwCurSize;
+    case NSPROTO_IPX:
+        info->dwServiceFlags1 = XP1_PARTIAL_MESSAGE | XP1_SUPPORT_BROADCAST |
+                                XP1_SUPPORT_MULTIPOINT | XP1_MESSAGE_ORIENTED |
+                                XP1_CONNECTIONLESS;
+        info->iAddressFamily = WS_AF_IPX;
+        info->iMaxSockAddr = 0x10;
+        info->iMinSockAddr = 0x0e;
+        info->iSocketType = WS_SOCK_DGRAM;
+        info->dwMessageSize = 576;
+        strcpy( info->szProtocol, NameIpx );
+        break;
 
-      dwTemp = dwCurSize;
-      anz += WINSOCK_EnterSingleProtocol( *lpiProtocols, &lpBuffer[anz],
-                                          &dwTemp, unicode);
+    case NSPROTO_SPX:
+        info->dwServiceFlags1 = XP1_PARTIAL_MESSAGE |
+                                XP1_PSEUDO_STREAM | XP1_MESSAGE_ORIENTED |
+                                XP1_GUARANTEED_ORDER | XP1_GUARANTEED_DELIVERY;
+        info->iAddressFamily = WS_AF_IPX;
+        info->iMaxSockAddr = 0x10;
+        info->iMinSockAddr = 0x0e;
+        info->iSocketType = 5;
+        info->dwMessageSize = -1;
+        strcpy( info->szProtocol, NameSpx );
+        break;
+
+    case NSPROTO_SPXII:
+        info->dwServiceFlags1 = XP1_PARTIAL_MESSAGE | XP1_GRACEFUL_CLOSE |
+                                XP1_PSEUDO_STREAM | XP1_MESSAGE_ORIENTED |
+                                XP1_GUARANTEED_ORDER | XP1_GUARANTEED_DELIVERY;
+        info->iAddressFamily = WS_AF_IPX;
+        info->iMaxSockAddr = 0x10;
+        info->iMinSockAddr = 0x0e;
+        info->iSocketType = 5;
+        info->dwMessageSize = -1;
+        strcpy( info->szProtocol, NameSpxII );
+        break;
+
+    default:
+        if ((protocol == ISOPROTO_TP4) || (protocol == NSPROTO_SPX))
+            FIXME("Protocol <%s> not implemented\n",
+                  (protocol == ISOPROTO_TP4) ? "ISOPROTO_TP4" : "NSPROTO_SPX");
+        else
+            FIXME("unknown Protocol <0x%08x>\n", protocol);
+        return SOCKET_ERROR;
+    }
+    return 1;
+}
+
+/*****************************************************************************
+ *          WSAEnumProtocolsA       [WS2_32.@]
+ *
+ *    see function WSAEnumProtocolsW
+ */
+INT WINAPI WSAEnumProtocolsA( LPINT protocols, LPWSAPROTOCOL_INFOA buffer, LPDWORD len )
+{
+    INT i = 0;
+    DWORD size = 0;
+    INT local[] = { WS_IPPROTO_TCP, WS_IPPROTO_UDP, NSPROTO_IPX, NSPROTO_SPXII, 0 };
+
+    if (!buffer)
+        return SOCKET_ERROR;
+
+    if (!protocols) protocols = local;
+
+    while (protocols[i]) i++;
+
+    size = i * sizeof(WSAPROTOCOL_INFOA);
+
+    if (*len < size)
+    {
+        *len = size;
+        return SOCKET_ERROR;
     }
 
-    *lpdwLength += dwCurSize;
-    lpiProtocols++;
-  }
-
-  if (dwOldSize < *lpdwLength) anz = SOCKET_ERROR;
-
-  return anz;
+    for (i = 0; protocols[i]; i++)
+    {
+        if (WINSOCK_EnterSingleProtocolA( protocols[i], &buffer[i] ) == SOCKET_ERROR)
+            return i;
+    }
+    return i;
 }
 
 /*****************************************************************************
- *          WSAEnumProtocolsA       [WSOCK32.1111]
+ *          WSAEnumProtocolsW       [WS2_32.@]
  *
  * Retrieves information about specified set of active network protocols.
  *
  * PARAMS
- *  lpiProtocols     [I]   Pointer to null-terminated array of protocol id's. NULL retrieves
- *                         information on all available protocols.
- *  lpProtocolBuffer [I]   Pointer to a buffer to be filled with PROTOCOL_INFO structures.
- *  lpdwBufferLength [I/O] Pointer to a variable specifying buffer size. On output the variable
- *                         holds the number of bytes needed when the specified size is too small.
+ *  protocols [I]   Pointer to null-terminated array of protocol id's. NULL
+ *                  retrieves information on all available protocols.
+ *  buffer    [I]   Pointer to a buffer to be filled with WSAPROTOCOL_INFO
+ *                  structures.
+ *  len       [I/O] Pointer to a variable specifying buffer size. On output
+ *                  the variable holds the number of bytes needed when the
+ *                  specified size is too small.
  *
  * RETURNS
- * Success: number of PROTOCOL_INFO structures in buffer.
- * Failure: SOCKET_ERROR
+ *  Success: number of WSAPROTOCOL_INFO structures in buffer.
+ *  Failure: SOCKET_ERROR
  *
  * NOTES
- * see function WINSOCK_EnumProtocol for BUGS
+ *  NT4SP5 does not return SPX if lpiProtocols == NULL
+ *
+ * BUGS
+ *  - NT4SP5 returns in addition these list of NETBIOS protocols
+ *    (address family 17), each entry two times one for socket type 2 and 5
+ *
+ *    iProtocol   szProtocol
+ *    0x80000000  \Device\NwlnkNb
+ *    0xfffffffa  \Device\NetBT_CBENT7
+ *    0xfffffffb  \Device\Nbf_CBENT7
+ *    0xfffffffc  \Device\NetBT_NdisWan5
+ *    0xfffffffd  \Device\NetBT_El9202
+ *    0xfffffffe  \Device\Nbf_El9202
+ *    0xffffffff  \Device\Nbf_NdisWan4
+ *
+ *  - there is no check that the operating system supports the returned
+ *    protocols
  */
-INT WINAPI WSAEnumProtocolsA( LPINT lpiProtocols, LPWSAPROTOCOL_INFOA lpBuffer, LPDWORD lpdwLength )
+INT WINAPI WSAEnumProtocolsW( LPINT protocols, LPWSAPROTOCOL_INFOW buffer, LPDWORD len )
 {
-   return WINSOCK_EnumProtocol( lpiProtocols, (PROTOCOL_INFOA *)lpBuffer, lpdwLength, FALSE );
+    INT i = 0;
+    DWORD size = 0;
+    INT local[] = { WS_IPPROTO_TCP, WS_IPPROTO_UDP, NSPROTO_IPX, NSPROTO_SPXII, 0 };
+
+    if (!buffer)
+        return SOCKET_ERROR;
+
+    if (!protocols) protocols = local;
+
+    while (protocols[i]) i++;
+
+    size = i * sizeof(WSAPROTOCOL_INFOW);
+
+    if (*len < size)
+    {
+        *len = size;
+        return SOCKET_ERROR;
+    }
+
+    for (i = 0; protocols[i]; i++)
+    {
+        if (WINSOCK_EnterSingleProtocolW( protocols[i], &buffer[i] ) == SOCKET_ERROR)
+            return i;
+    }
+    return i;
 }
 
 /*****************************************************************************
- *          WSAEnumProtocolsW       [WSOCK32.1112]
+ *          WSCEnumProtocols        [WS2_32.@]
  *
- *    see function WSAEnumProtocolsA
+ * PARAMS
+ *  protocols [I]   Null-terminated array of iProtocol values.
+ *  buffer    [O]   Buffer of WSAPROTOCOL_INFOW structures.
+ *  len       [I/O] Size of buffer on input/output.
+ *  errno     [O]   Error code.
+ *
+ * RETURNS
+ *  Success: number of protocols to be reported on.
+ *  Failure: SOCKET_ERROR. error is in errno.
+ *
+ * BUGS
+ *  Doesn't supply info on layered protocols.
+ *
  */
-INT WINAPI WSAEnumProtocolsW( LPINT lpiProtocols, LPWSAPROTOCOL_INFOW lpBuffer, LPDWORD lpdwLength )
+INT WINAPI WSCEnumProtocols( LPINT protocols, LPWSAPROTOCOL_INFOW buffer, LPDWORD len, LPINT errno )
 {
-   return WINSOCK_EnumProtocol( lpiProtocols, (PROTOCOL_INFOA *)lpBuffer, lpdwLength, TRUE );
+    INT ret = WSAEnumProtocolsW( protocols, buffer, len );
+
+    if (ret == SOCKET_ERROR) *errno = WSAENOBUFS;
+
+    return ret;
 }
diff --git a/dlls/winsock/tests/.cvsignore b/dlls/winsock/tests/.cvsignore
index ad8a48f..de55130 100644
--- a/dlls/winsock/tests/.cvsignore
+++ b/dlls/winsock/tests/.cvsignore
@@ -1,3 +1,4 @@
 Makefile
+protocol.ok
 sock.ok
 testlist.c
diff --git a/dlls/winsock/tests/Makefile.in b/dlls/winsock/tests/Makefile.in
index 4c0260b..dae48eb 100644
--- a/dlls/winsock/tests/Makefile.in
+++ b/dlls/winsock/tests/Makefile.in
@@ -6,6 +6,7 @@
 IMPORTS   = ws2_32
 
 CTESTS = \
+	protocol.c \
 	sock.c
 
 @MAKE_TEST_RULES@
diff --git a/dlls/winsock/tests/protocol.c b/dlls/winsock/tests/protocol.c
new file mode 100644
index 0000000..0d6fb62
--- /dev/null
+++ b/dlls/winsock/tests/protocol.c
@@ -0,0 +1,109 @@
+/*
+ * Unit test suite for protocol functions
+ *
+ * Copyright 2004 Hans Leidekker
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdarg.h>
+
+#include <windef.h>
+#include <winbase.h>
+#include <winsock2.h>
+
+#include "wine/test.h"
+#include "wine/debug.h"
+
+static void test_WSAEnumProtocolsA()
+{
+    INT ret;
+    DWORD len = 0;
+    WSAPROTOCOL_INFOA info, *buffer;
+
+    ret = WSAEnumProtocolsA( NULL, NULL, &len );
+    ok( ret == SOCKET_ERROR, "WSAEnumProtocolsA() succeeded unexpectedly: %d\n",
+        WSAGetLastError() );
+
+    len = 0;
+
+    ret = WSAEnumProtocolsA( NULL, &info, &len );
+    ok( ret == SOCKET_ERROR, "WSAEnumProtocolsA() succeeded unexpectedly: %d\n",
+        WSAGetLastError() );
+
+    buffer = HeapAlloc( GetProcessHeap(), 0, len );
+
+    if (buffer)
+    {
+        INT i;
+
+        ret = WSAEnumProtocolsA( NULL, buffer, &len );
+        ok( ret != SOCKET_ERROR, "WSAEnumProtocolsA() failed unexpectedly: %d\n",
+            WSAGetLastError() );
+
+        for (i = 0; i < ret; i++)
+        {
+            ok( strlen( buffer[i].szProtocol ), "No protocol name found\n" );
+        }
+
+        HeapFree( GetProcessHeap(), 0, buffer );
+    }
+}
+
+static void test_WSAEnumProtocolsW()
+{
+    INT ret;
+    DWORD len = 0;
+    WSAPROTOCOL_INFOW info, *buffer;
+
+    ret = WSAEnumProtocolsW( NULL, NULL, &len );
+    ok( ret == SOCKET_ERROR, "WSAEnumProtocolsW() succeeded unexpectedly: %d\n",
+        WSAGetLastError() );
+
+    len = 0;
+
+    ret = WSAEnumProtocolsW( NULL, &info, &len );
+    ok( ret == SOCKET_ERROR, "WSAEnumProtocolsW() succeeded unexpectedly: %d\n",
+        WSAGetLastError() );
+
+    buffer = HeapAlloc( GetProcessHeap(), 0, len );
+
+    if (buffer)
+    {
+        INT i;
+
+        ret = WSAEnumProtocolsW( NULL, buffer, &len );
+        ok( ret != SOCKET_ERROR, "WSAEnumProtocolsW() failed unexpectedly: %d\n",
+            WSAGetLastError() );
+
+        for (i = 0; i < ret; i++)
+        {
+            ok( lstrlenW( buffer[i].szProtocol ), "No protocol name found\n" );
+        }
+
+        HeapFree( GetProcessHeap(), 0, buffer );
+    }
+}
+
+START_TEST( protocol )
+{
+    WSADATA data;
+    WORD version = MAKEWORD( 2, 2 );
+ 
+    if (WSAStartup( version, &data )) return;
+
+    test_WSAEnumProtocolsA();
+    test_WSAEnumProtocolsW();
+}
diff --git a/dlls/winsock/ws2_32.spec b/dlls/winsock/ws2_32.spec
index fe3df27..2b676ca 100644
--- a/dlls/winsock/ws2_32.spec
+++ b/dlls/winsock/ws2_32.spec
@@ -86,7 +86,7 @@
 82  stdcall  WSAWaitForMultipleEvents(long ptr long long long) kernel32.WaitForMultipleObjectsEx
 83  stdcall  WSCDeinstallProvider(ptr ptr)
 84  stub     WSCEnableNSProvider
-85  stub     WSCEnumProtocols
+85  stdcall  WSCEnumProtocols(ptr ptr ptr ptr)
 86  stub     WSCGetProviderPath
 87  stub     WSCInstallNameSpace
 88  stdcall  WSCInstallProvider(ptr wstr ptr long ptr)
diff --git a/include/winsock2.h b/include/winsock2.h
index a14b19c..64cc433 100644
--- a/include/winsock2.h
+++ b/include/winsock2.h
@@ -176,6 +176,31 @@
     DWORD ChainEntries[MAX_PROTOCOL_CHAIN]; /* a list of dwCatalogEntryIds */
 } WSAPROTOCOLCHAIN, * LPWSAPROTOCOLCHAIN;
 
+#define XP1_CONNECTIONLESS                  0x00000001
+#define XP1_GUARANTEED_DELIVERY             0x00000002
+#define XP1_GUARANTEED_ORDER                0x00000004
+#define XP1_MESSAGE_ORIENTED                0x00000008
+#define XP1_PSEUDO_STREAM                   0x00000010
+#define XP1_GRACEFUL_CLOSE                  0x00000020
+#define XP1_EXPEDITED_DATA                  0x00000040
+#define XP1_CONNECT_DATA                    0x00000080
+#define XP1_DISCONNECT_DATA                 0x00000100
+#define XP1_SUPPORT_BROADCAST               0x00000200
+#define XP1_SUPPORT_MULTIPOINT              0x00000400
+#define XP1_MULTIPOINT_CONTROL_PLANE        0x00000800
+#define XP1_MULTIPOINT_DATA_PLANE           0x00001000
+#define XP1_QOS_SUPPORTED                   0x00002000
+#define XP1_INTERRUPT                       0x00004000
+#define XP1_UNI_SEND                        0x00008000
+#define XP1_UNI_RECV                        0x00010000
+#define XP1_IFS_HANDLES                     0x00020000
+#define XP1_PARTIAL_MESSAGE                 0x00040000
+
+#define BIGENDIAN                           0x0000
+#define LITTLEENDIAN                        0x0001
+
+#define SECURITY_PROTOCOL_NONE              0x0000
+
 #define WSAPROTOCOL_LEN  255
 typedef struct _WSAPROTOCOL_INFOA
 {