WSAEnumProtocolsA 函数 (winsock2.h)

WSAEnumProtocols 函数检索有关可用传输协议的信息。

语法

int WSAAPI WSAEnumProtocolsA(
  [in]      LPINT               lpiProtocols,
  [out]     LPWSAPROTOCOL_INFOA lpProtocolBuffer,
  [in, out] LPDWORD             lpdwBufferLength
);

参数

[in] lpiProtocols

NULL 结尾的 iProtocol 值的数组。 此参数是可选的;如果 lpiProtocolsNULL,则返回有关所有可用协议的信息。 否则,仅检索数组中列出的那些协议的信息。

[out] lpProtocolBuffer

指向填充WSAPROTOCOL_INFO结构的缓冲区 指针。

[in, out] lpdwBufferLength

输入时, lpProtocolBuffer 缓冲区中传递给 WSAEnumProtocols 的字节数。 输出时,可以传递给 WSAEnumProtocols 以检索所有请求的信息的最小缓冲区大小。 此例程无法枚举多个调用;传入的缓冲区必须足够大,才能保存所有条目,以便例程成功。 这降低了 API 的复杂性,并且不会造成问题,因为计算机上加载的协议数通常很小。

返回值

如果未发生错误, WSAEnumProtocols 将返回要报告的协议数。 否则,将返回值 SOCKET_ERROR,并且可以通过调用 WSAGetLastError 来检索特定的错误代码。

错误代码 含义
WSANOTINITIALIZED
在使用此函数之前,必须成功调用 WSAStartup
WSAENETDOWN
网络子系统发生故障。
WSAEINPROGRESS
正在阻止 Windows 套接字 1.1 调用。
WSAEINVAL
:指示指定参数之一无效。
WSAENOBUFS
缓冲区长度太小,无法接收所有相关 WSAPROTOCOL_INFO 结构和相关信息。 传入缓冲区至少与 lpdwBufferLength 中返回的值一样大。
WSAEFAULT
一个或多个 lpiProtocolslpProtocolBufferlpdwBufferLength 参数不是用户地址空间的有效部分。

注解

WSAEnumProtocols 函数用于发现有关本地计算机上安装的传输协议集合的信息。 当安装在协议链中时,只有应用程序才能使用分层协议。 不会返回有关分层协议的信息,除非在 lpProtocolBuffer 中安装了链长度为零的任何虚拟分层服务提供商 (LSP) 。

注意 分层服务提供程序已弃用。 从Windows 8和Windows Server 2012开始,请使用 Windows 筛选平台
 
lpiProtocols 参数可用作筛选器,以限制提供的信息量。 通常, lpiProtocols 将被指定为 NULL 指针,这将导致函数返回有关所有可用传输协议和协议链的信息。

WSAEnumProtocols 函数不同于 WSCEnumProtocolsWSCEnumProtocols32 函数,即 WSAEnumProtocols 函数不返回所有已安装协议WSAPROTOCOL_INFO结构。 WSAEnumProtocols 函数排除服务提供商在WSAPROTOCOL_INFO结构的 dwProviderFlags 成员中使用PFL_HIDDEN标志设置的协议,以向 Ws2_32.dll 指示不应在 WSAEnumProtocols 函数生成的结果缓冲区中返回此协议。 此外, WSAEnumProtocols 函数不会返回链长度为 1 或更大 WSAPROTOCOL_INFO 结构的数据, (LSP 提供程序) 。 WSAEnumProtocols 仅返回缺少PFL_HIDDEN标志且协议链长度不为零的基本协议和协议链的信息。

对于每个请求的协议,lpProtocolBuffer 指向的缓冲区中提供了WSAPROTOCOL_INFO结构。 如果指定的缓冲区 (不够大,如 lpdwBufferLength ) 的输入值所示,则 lpdwBufferLength 指向的值将更新为指示所需的缓冲区大小。 然后,应用程序应获取足够大的缓冲区,并再次调用 WSAEnumProtocols

WSAPROTOCOL_INFO结构在缓冲区中的出现顺序与服务提供商使用 WS2_32.DLL 注册协议条目的顺序一致,或者与通过 Windows 套接字应用程序或 DLL(为建立默认 TCP/IP 提供程序而提供)发生的任何后续重新排序一致。

Windows Phone 8:Windows Phone 8 及更高版本上的 Windows Phone Store 应用支持 WSAEnumProtocolsW 函数。

Windows 8.1Windows Server 2012 R2:Windows 8.1、Windows Server 2012 R2 及更高版本的 Windows 应用商店应用支持 WSAEnumProtocolsW 函数。

示例

以下示例演示如何使用 WSAEnumProtocols 函数检索 WSAPROTOCOL_INFO结构的数组 以获取可用的传输协议。

#ifndef UNICODE
#define UNICODE 1
#endif

#include <winsock2.h>
#include <ws2tcpip.h>
#include <objbase.h>
#include <stdio.h>

// Link with ws2_32.lib and ole32.lib
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "ole32.lib")

#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
// Note: could also use malloc() and free()

int wmain()
{

    //-----------------------------------------
    // Declare and initialize variables
    WSADATA wsaData;
    int iResult = 0;

    int iError = 0;
    INT iNuminfo = 0;

    int i;

    // Allocate a 16K buffer to retrieve all the protocol providers
    DWORD dwBufferLen = 16384;

    LPWSAPROTOCOL_INFO lpProtocolInfo = NULL;

    // variables needed for converting provider GUID to a string
    int iRet = 0;
    WCHAR GuidString[40] = { 0 };

    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        wprintf(L"WSAStartup failed: %d\n", iResult);
        return 1;
    }

    lpProtocolInfo = (LPWSAPROTOCOL_INFO) MALLOC(dwBufferLen);
    if (lpProtocolInfo == NULL) {
        wprintf(L"Memory allocation for providers buffer failed\n");
        WSACleanup();
        return 1;
    }

    iNuminfo = WSAEnumProtocols(NULL, lpProtocolInfo, &dwBufferLen);
    if (iNuminfo == SOCKET_ERROR) {
        iError = WSAGetLastError();
        if (iError != WSAENOBUFS) {
            wprintf(L"WSAEnumProtocols failed with error: %d\n", iError);
            if (lpProtocolInfo) {
                FREE(lpProtocolInfo);
                lpProtocolInfo = NULL;
            }
            WSACleanup();
            return 1;
        } else {
            wprintf(L"WSAEnumProtocols failed with error: WSAENOBUFS (%d)\n",
                    iError);
            wprintf(L"  Increasing buffer size to %d\n\n", dwBufferLen);
            if (lpProtocolInfo) {
                FREE(lpProtocolInfo);
                lpProtocolInfo = NULL;
            }
            lpProtocolInfo = (LPWSAPROTOCOL_INFO) MALLOC(dwBufferLen);
            if (lpProtocolInfo == NULL) {
                wprintf(L"Memory allocation increase for buffer failed\n");
                WSACleanup();
                return 1;
            }
            iNuminfo = WSAEnumProtocols(NULL, lpProtocolInfo, &dwBufferLen);
            if (iNuminfo == SOCKET_ERROR) {
                iError = WSAGetLastError();
                wprintf(L"WSAEnumProtocols failed with error: %d\n", iError);
                if (lpProtocolInfo) {
                    FREE(lpProtocolInfo);
                    lpProtocolInfo = NULL;
                }
                WSACleanup();
                return 1;
            }

        }
    }

    wprintf(L"WSAEnumProtocols succeeded with protocol count = %d\n\n",
            iNuminfo);
    for (i = 0; i < iNuminfo; i++) {
        wprintf(L"Winsock Catalog Provider Entry #%d\n", i);
        wprintf
            (L"----------------------------------------------------------\n");
        wprintf(L"Entry type:\t\t\t ");
        if (lpProtocolInfo[i].ProtocolChain.ChainLen == 1)
            wprintf(L"Base Service Provider\n");
        else
            wprintf(L"Layered Chain Entry\n");

        wprintf(L"Protocol:\t\t\t %ws\n", lpProtocolInfo[i].szProtocol);

        iRet =
            StringFromGUID2(lpProtocolInfo[i].ProviderId,
                            (LPOLESTR) & GuidString, 39);
        if (iRet == 0)
            wprintf(L"StringFromGUID2 failed\n");
        else
            wprintf(L"Provider ID:\t\t\t %ws\n", GuidString);

        wprintf(L"Catalog Entry ID:\t\t %u\n",
                lpProtocolInfo[i].dwCatalogEntryId);

        wprintf(L"Version:\t\t\t %d\n", lpProtocolInfo[i].iVersion);

        wprintf(L"Address Family:\t\t\t %d\n",
                lpProtocolInfo[i].iAddressFamily);
        wprintf(L"Max Socket Address Length:\t %d\n",
                lpProtocolInfo[i].iMaxSockAddr);
        wprintf(L"Min Socket Address Length:\t %d\n",
                lpProtocolInfo[i].iMinSockAddr);

        wprintf(L"Socket Type:\t\t\t %d\n", lpProtocolInfo[i].iSocketType);
        wprintf(L"Socket Protocol:\t\t %d\n", lpProtocolInfo[i].iProtocol);
        wprintf(L"Socket Protocol Max Offset:\t %d\n",
                lpProtocolInfo[i].iProtocolMaxOffset);

        wprintf(L"Network Byte Order:\t\t %d\n",
                lpProtocolInfo[i].iNetworkByteOrder);
        wprintf(L"Security Scheme:\t\t %d\n",
                lpProtocolInfo[i].iSecurityScheme);
        wprintf(L"Max Message Size:\t\t %u\n", lpProtocolInfo[i].dwMessageSize);

        wprintf(L"ServiceFlags1:\t\t\t 0x%x\n",
                lpProtocolInfo[i].dwServiceFlags1);
        wprintf(L"ServiceFlags2:\t\t\t 0x%x\n",
                lpProtocolInfo[i].dwServiceFlags2);
        wprintf(L"ServiceFlags3:\t\t\t 0x%x\n",
                lpProtocolInfo[i].dwServiceFlags3);
        wprintf(L"ServiceFlags4:\t\t\t 0x%x\n",
                lpProtocolInfo[i].dwServiceFlags4);
        wprintf(L"ProviderFlags:\t\t\t 0x%x\n",
                lpProtocolInfo[i].dwProviderFlags);

        wprintf(L"Protocol Chain length:\t\t %d\n",
                lpProtocolInfo[i].ProtocolChain.ChainLen);

        wprintf(L"\n");
    }

    if (lpProtocolInfo) {
        FREE(lpProtocolInfo);
        lpProtocolInfo = NULL;
    }
    WSACleanup();

    return 0;
}


注意

winsock2.h 标头将 WSAEnumProtocols 定义为别名,该别名根据 UNICODE 预处理器常量的定义自动选择此函数的 ANSI 或 Unicode 版本。 将非特定编码别名的使用与非非特定编码的代码混合使用可能会导致不匹配,从而导致编译或运行时错误。 有关详细信息,请参阅 函数原型的约定

要求

要求
最低受支持的客户端 Windows 8.1,Windows Vista [桌面应用 |UWP 应用]
最低受支持的服务器 Windows Server 2003 [桌面应用 | UWP 应用]
目标平台 Windows
标头 winsock2.h
Library Ws2_32.lib
DLL Ws2_32.dll

另请参阅

WSAPROTOCOL_INFO

WSCEnumProtocols

WSCEnumProtocols32

Winsock 函数

Winsock 参考