今天看到《windows网络编程》第二版里面有一个函数, 在第一次按照说明使用的时候没有成功. 以下是对应的技术说明.
#include <winsock2.h>
int WSAAPI WSAEnumProtocols ( LPINT lpdwProtocols,
LPWSAPROTOCOL_INFO lpProtocolBuffer,
LPDWORD lpdwBufferLength);
lpdwProtocols:一个以NULL结尾的协议标识号数组。本参数可选;如果lpdwProtocols为 NULL,则返回所有可用协议的信息,否则的话只返回数组中所开列的协议信息。
lpProtocolBuffer:一个用PROTOCOL_INFO结构填充的缓冲区。参见下文中对PROTOCOL_INFO结构的具体描述。
lpdwBufferLength:输入时,存有传递给WSAEnumProtocols()函数的lpProtocolBuffer缓冲区长度。输出时,表示为获取所有信息需传递给WSAEnumProtocols()函数的缓冲区长度。本函数不能重复调用;传入的缓冲区必须足够大以能存放所有的元素。这个规定降低了该函数的复杂度。由于一个机器上装载的协议数目往往是很小的,所以并不会产生问题。
返回值:
若无错误发生,WSAEnumProtocols()返回协议的数目。否则的话,将返回INVALID_SOCKET错误,应用程序可通过WSAGetLastError()来获取相应的错误代码。
错误代码:
WSANOTINITIALISED 在调用本API之前应成功调用WSAStartup()。
WSAENETDOWN 网络子系统失效。
WSAEINPROGRESS 一个阻塞WinSock调用正在进行。
WSAEINVAL 参数中有非法值。
WSAENOBUFS 缓冲区太小,无法保存所有PROTOCOL_INFO结构及其相关信息。传入的缓冲区大小至少应等于lpdwBufferLength中返回的值。
通常需要两次调用WSAEnumProtocols()函数以获取特定的协议信息,第一次调用时指定lpdwProtocols为 NULL,调用肯定是失败的,但参数lpdwBufferLength包含了所以协议信息需要的缓冲区长度。我们知道了这个准确长度就可以进行第二次调用了!
后来查找到原因, 因为我只做局部测试代码, 没有加载socket的DLL, 造成失败调用. 贴一段正确使用的代码:
//代码来源为:http://blog.csdn.net/chshji666666/article/details/6758260
#include <Winsock2.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")
void main(void)
{
WSADATA wsaData;
WSAStartup( MAKEWORD( 2, 2 ), &wsaData );
LPWSAPROTOCOL_INFO info = NULL;
DWORD dwLen;
//因为info还未分配内存,第一次调用必定会失败,但能够得到dwLen的值
if (SOCKET_ERROR == WSAEnumProtocols(NULL, info, &dwLen))
{
int iErrorCode = GetLastError();
if (WSAENOBUFS != iErrorCode)
{
WSACleanup();
return;
}
}
if (dwLen > 0)
{
//如果没有分配内存这一步,将会出错,只传递 &inof是没有用的,注意指针的用法
info = (LPWSAPROTOCOL_INFO)GlobalAlloc(GPTR, dwLen);
if (info == NULL)
{
printf("Allocate memory failed! ErrorCode is %d", GetLastError());
WSACleanup();
return;
}
//第二次调用
int iProtocolCounts = WSAEnumProtocols(NULL, info, &dwLen);
if (SOCKET_ERROR == iProtocolCounts)
{
printf("WSCEnumProtocols Error: %d", GetLastError());
GlobalFree(info);
WSACleanup();
return;
}
//打印本机安装的协议信息
for (int i=0; i<iProtocolCounts; i++)
{
printf("\ni=%d\nProtocolDescription:%s\n", i, info[i].szProtocol);
}
GlobalFree(info);
}
WSACleanup();
}