WNetEnumResource 枚举网络资源

这篇文章介绍了如何通过WNetEnumResource函数在Windows环境中枚举本地工作组内的主机,并获取它们的IP地址,以便于实现自动化连接。作者结合WSAStartup和gethostbyname函数,展示了完整的实现过程和关键代码片段。

使用WNetEnumResource函数实现枚举工作组内的主机及其IP

TFBOYSer

发布日期: 1 年前浏览量: 793收藏:3

评分:

star star star star star star star star star_border star_border

*转载请注明来自write-bug.com

背景

之所以会学习到这方面的知识,是因为那段时间正在帮一个游戏工作室开发一个游戏自动登录并创建角色的游戏脚本。当时,我就是使用VS去开发。因为它要求要有一个控制端可以所有的控制端,所以,就分别写了一个客户端程序和控制端程序。客户端都运行在虚拟机内,和控制端在同一网段里。

当时,我就想让客户端在虚拟机里运行,主动去扫描工作组内的主机,那么它工作组内就会有两个主机,一个是虚拟机自己,另一个就是外面的主机。主机上运行则控制端,所以,这样就可以获取主机的IP地址,并自动建立反向连接,传输数据。

所以,当时使用扫描方法,就是使用本文介绍的这个使用 WNetEnumResource 函数的方法。现在,我就把实现原理和过程写成文档,分享给大家。

函数介绍

WNetOpenEnum 函数

WNetOpenEnum函数启动网络资源或现有连接的枚举。 您可以通过调用WNetEnumResource函数继续枚举。

函数声明

 
  1. DWORD WNetOpenEnum(
  2. _In_ DWORD dwScope,
  3. _In_ DWORD dwType,
  4. _In_ DWORD dwUsage,
  5. _In_ LPNETRESOURCE lpNetResource,
  6. _Out_ LPHANDLE lphEnum
  7. );

参数

  • dwScope [in]
    枚举范围。 此参数可以是以下值之一:
VALUEMEANING
RESOURCE_CONNECTED枚举所有当前连接的资源。 该函数忽略dwUsage参数。
RESOURCE_CONTEXT仅枚举调用者网络上下文中的资源。 为“网络邻居”视图指定此值。 该函数忽略dwUsage参数
RESOURCE_GLOBALNET枚举网络上的所有资源
RESOURCE_REMEMBERED枚举所有记住(持久)连接。 该函数忽略dwUsage参数
  • dwType [in]
    要枚举的资源类型。 此参数可以是以下值的组合:
VALUEMEANING
RESOURCETYPE_ANY所有资源。 此值不能与RESOURCETYPE_DISK或RESOURCETYPE_PRINT组合
RESOURCETYPE_DISK所有磁盘资源
RESOURCETYPE_PRINT所有打印资源
  • dwUsage [in]
    要枚举的资源使用类型。 此参数可以是以下值的组合:
VALUEMEANING
0所有资源
RESOURCEUSAGE_CONNECTABLE所有可连接的资源
RESOURCEUSAGE_CONTAINER所有容器资源
RESOURCEUSAGE_ATTACHED如果用户未通过身份验证,设置此值将强制WNetOpenEnum失败。 即使网络允许枚举而不进行身份验证,该功能也会失败
RESOURCEUSAGE_ALL设置此值相当于设置RESOURCEUSAGE_CONNECTABLE,RESOURCEUSAGE_CONTAINER和RESOURCEUSAGE_ATTACHED
  • pNet资源[in]
    指向指定要枚举的容器的NETRESOURCE结构。 如果dwScope参数不是RESOURCE_GLOBALNET,则此参数必须为NULL。

  • lphEnum [out]
    指向可以在随后调用WNetEnumResource中使用的枚举句柄的指针。

返回值

  • 如果函数成功,返回值为NO_ERROR。
  • 如果函数失败,则返回值是系统错误代码。

WNetEnumResource 函数

WNetEnumResource功能继续列出通过调用WNetOpenEnum函数启动的网络资源。

函数声明

 
  1. DWORD WNetEnumResource(
  2. _In_ HANDLE hEnum,
  3. _Inout_ LPDWORD lpcCount,
  4. _Out_ LPVOID lpBuffer,
  5. _Inout_ LPDWORD lpBufferSize
  6. );

参数

  • hEnum [in]
    标识枚举实例的句柄。这个句柄必须由WNetOpenEnum函数返回。
  • lpcCount [in,out]
    指向指定所请求条目数的变量的指针。如果所请求的号码为-1,则该函数返回尽可能多的条目。如果函数成功,返回此参数指向的变量包含实际读取的条目数。
  • lpBuffer [out]
    指向接收枚举结果的缓冲区的指针。结果作为NETRESOURCE结构的数组返回。请注意,您分配的缓冲区必须足够大以容纳结构,加上其成员指向的字符串。有关详细信息,请参阅以下备注部分。
  • lpBufferSize [in,out]
    指向变量的指针,该变量指定lpBuffer参数的大小(以字节为单位)。如果缓冲区太小而不能接收一个条目,则此参数将接收所需的缓冲区大小。

返回值

  • 执行成功,返回 NO_ERROR 或者 ERROR_NO_MORE_ITEMS;
  • 否则,错误。

gethostbyname 函数

gethostbyname函数从主机数据库中检索与主机名对应的主机信息。

函数声明

 
  1. struct hostent* FAR gethostbyname(
  2. _In_ const char *name
  3. );

参数

  • name[in]

    指向要解析的主机的以NULL结尾的名称的指针。

返回值

  • 如果没有发生错误,gethostbyname返回一个指向上述主机结构的指针。 否则,它返回一个空指针,并且可以通过调用WSAGetLastError来检索特定的错误号。

inet_ntoa 函数

inet_ntoa函数将(Ipv4)Internet网络地址转换为Internet标准点分十进制格式的ASCII字符串。

函数声明

 
  1. char* FAR inet_ntoa(
  2. _In_ struct in_addr in
  3. );

参数

  • in[in]

    一个表示Internet主机地址的in_addr结构。

返回值

  • 如果没有发生错误,则inet_ntoa返回一个字符指针,指向包含标准“。”表示法中的文本地址的静态缓冲区,否则返回NULL。

实现原理

本文要实现的功能就是遍历网络邻居,获取工作组内的所有在线主机名以及根据主机名获取的IP地址。实现过程如下:

  1. 首先,我们通过 WSAStartup 函数完成对 Winsock 服务的初始化,因为下面我们会使用到 Socket 函数。
  2. 然后,我们使用 WNetOpenEnum 设置枚举的范围为本工作组内 RESOURCE_CONTEXT,并获取枚举句柄。
  3. 接着,我们便调用 WNetEnumResource 函数按照设置的范围去枚举资源,并获取枚举结果。
  4. 然后,遍历枚举结果,并设置过滤标志 RESOURCEUSAGE_CONTAINER 和 RESOURCETYPE_ANY。通过过滤之后,可以根据远程主机名调用函数gethostbyname 去获取IP地址信息,并通过 inet_ntoa 函数将(Ipv4) Internet网络地址转换为Internet标准点分十进制格式的ASCII字符串。
  5. 最后,释放内存以及枚举句柄。

这样,整个程序的实现原理和流程就结束了。需要特别注意一点就是,在函数开头一定要先初始化 Winsock 服务!

编码实现

加载库函数

 
  1. #include <Winnetwk.h>
  2. #pragma comment(lib, "Mpr.lib")
  3. #pragma comment(lib, "Ws2_32.lib")

枚举工作组内的网络资源

 
  1. BOOL EnumNetResource()
  2. {
  3. NETRESOURCE *NetResource = NULL;
  4. HANDLE hEnum;
  5. unsigned int i;
  6. char szHostName[MAX_PATH] = { 0 };
  7. hostent *host = NULL;
  8. char *lpszIP = NULL;
  9. // 通过WSAStartup函数完成对Winsock服务的初始化
  10. WSADATA wsaData = { 0 };
  11. ::WSAStartup(MAKEWORD(2, 2), &wsaData);
  12. // 指定枚举范围, 获取枚举句柄
  13. ::WNetOpenEnum(RESOURCE_CONTEXT, NULL, NULL, NULL, &hEnum);
  14. if (hEnum)
  15. {
  16. DWORD Count = 0xFFFFFFFF;
  17. DWORD BufferSize = 2048;
  18. BYTE *pBuffer = new BYTE[2048];
  19. // 根据设置的枚举返回, 获取枚举信息
  20. ::WNetEnumResource(hEnum, &Count, pBuffer, &BufferSize);
  21. NetResource = (NETRESOURCE*)pBuffer;
  22. for (i = 0; i < BufferSize / sizeof(NETRESOURCE); i++, NetResource++)
  23. {
  24. // 判断资源类型是否是所有资源 以及 判断资源使用类型是否是容器资源
  25. if (NetResource->dwUsage == RESOURCEUSAGE_CONTAINER &&
  26. NetResource->dwType == RESOURCETYPE_ANY)
  27. {
  28. if (NetResource->lpRemoteName)
  29. {
  30. // 获取远程主机名
  31. ::RtlZeroMemory(szHostName, MAX_PATH);
  32. ::lstrcpy(szHostName, (char *)((DWORD64)NetResource->lpRemoteName + 2));
  33. // 根据主机名获取IP地址信息
  34. host = ::gethostbyname(szHostName);
  35. if (host == NULL)
  36. {
  37. printf("Error Code:%d\n", ::GetLastError());
  38. continue;
  39. }
  40. // 将(Ipv4)Internet网络地址转换为Internet标准点分十进制格式的ASCII字符串
  41. lpszIP = ::inet_ntoa(*(in_addr *)host->h_addr_list[0]);
  42. // 显示
  43. printf("NetResource->lpRemoteName = %s\n", NetResource->lpRemoteName);
  44. printf("NetResource->lpLocalName = %s\n", NetResource->lpLocalName);
  45. printf("ComputerName = %s\n", szHostName);
  46. printf("ComputerIP = %s\n", lpszIP);
  47. }
  48. }
  49. }
  50. // 释放内存并关闭句柄
  51. delete[]pBuffer;
  52. pBuffer = NULL;
  53. ::WNetCloseEnum(hEnum);
  54. }
  55. return TRUE;
  56. }

WNetEnumResource 枚举网络资源

分类:

2006-06-14 16:20:59

WNetEnumResource
VB声明
Declare Function WNetEnumResource Lib "mpr.dll" Alias "WNetEnumResourceA" (ByVal hEnum As Long, lpcCount As Long, lpBuffer As Any, lpBufferSize As Long) As Long
说明
枚举网络资源
返回值
Long,零表示成功。ERROR_NO_MORE_ITEMS表示不剩下可以枚举的条目。ERROR_MORE_DATA表示条目不能装入lpBuffer。会设置GetLastError。如GetLastError是ERROR_EXTENDED_ERROR,则可用WNetGetLastError取得额外的错误信息
参数表
参数类型及说明
hEnumLong,从WNetOpenEnum函数返回的一个句柄
lpcCountLong,最初设为要枚举的最大资源数量;或设为-1,表示枚举尽可能多的资源。一旦返回,就会设为实际枚举的资源数量
lpBufferAny,通常是一个字节缓冲区的首字节。该缓冲区装载了枚举信息(可按引用声明为Byte)
lpBufferSizeLong,以字节为单位指定lpBuffer数组的长度。如缓冲区不够大,则设为需要的缓冲区长度
注解
枚举网络条目时,最好用vb一次枚举一个资源。尽量不要使用这个函数同时枚举许多网络资源的功能

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿峰的编程博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值