GetAdaptersInfo 和 GetAdaptersAddressess BufferLength 参数

Posted

技术标签:

【中文标题】GetAdaptersInfo 和 GetAdaptersAddressess BufferLength 参数【英文标题】:GetAdaptersInfo and GetAdaptersAddressess BufferLength Param 【发布时间】:2010-11-07 09:46:38 【问题描述】:

我这里有一些 C++ 遗留代码,这些代码做了一些我不理解的事情。我在运行 Windows XP 的机器上以 Visual C++ 2008 Express Edition 运行它。

代码使用了一些 Windows 函数:GetAdaptersInfo 和 GetAdaptersAddressess。我意识到这两个参数的最后一个参数是指向缓冲区大小的指针,并且由于它是 in_out,它可以在函数内更改。

我的问题是:这些函数是否应该改变缓冲区长度?

在我的代码中,每次调用这些函数时,缓冲区长度变量都会初始化为零,调用函数后,它仍然是0。

【问题讨论】:

【参考方案1】:

您的代码需要如下所示:

// First get the desired size.
unsigned long outBufLen = 0;
DWORD dwResult = GetAdaptersInfo(NULL, &outBufLen);
if (dwResult == ERROR_BUFFER_OVERFLOW)  // This is what we're expecting

    // Now allocate a structure of the requried size.
    PIP_ADAPTER_INFO pIpAdapterInfo = (PIP_ADAPTER_INFO) malloc(outBufLen);
    dwResult = GetAdaptersInfo(pIpAdapterInfo, &outBufLen);
    if (dwResult == ERROR_SUCCESS)
    
        // Yay!

编辑:另请参阅 Jeremy Friesner 的回答,了解为什么此代码还不够。

【讨论】:

所以 GetAdaptersInfo 获取 pIpAdapterInfo 元素在第一次调用中的大小,然后在第二次调用中实际获取适配器信息?那很有意思。感谢您的澄清。 是的。填充缓冲区的 Windows API 以这种方式工作是很常见的。【参考方案2】:

确实,使用 Visual Studio 6,我曾经通过以下方式获取适配器的数量:

DWORD drc = GetAdaptersInfo(NULL, &(Buflen = 0L));

if (drc == ERROR_BUFFER_OVERFLOW)
  n = Buflen / sizeof(IP_ADAPTER_INFO);

没关系,例如 2 个适配器,Buflen 设置为 1280,sizeof(IP_ADAPTER_INFO) 设置为 640。

现在我使用 Visual C++ 2008 Express,结果被截断,因为该函数仍将 Buflen 设置为 1280,但 sizeof(IP_ADAPTER_INFO) 的值现在是 648!

这是一个错误还是我遗漏了什么?

【讨论】:

我知道这是一个老问题,但我在 MinGW 构建中遇到了同样的问题。所以也许这对将来的某人有帮助。原因是time_t 类型的大小。见msdn.microsoft.com/en-us/library/windows/desktop/… 重要部分:“使用 Visual Studio 2005 及更高版本时,time_t 数据类型默认为 8 字节数据类型,而不是 32 位上用于 LeaseObtained 和 LeaseExpires 成员的 4 字节数据类型平台。要在 32 位平台上正确使用 IP_ADAPTER_INFO 结构,请在编译应用程序时定义 _USE_32BIT_TIME_T(例如,使用 -D _USE_32BIT_TIME_T 作为选项)以强制 time_t 数据类型为 4 字节数据类型。"【参考方案3】:

当然,@RichieHindle's answer 中的示例代码包含一个竞争条件......如果 Windows 想要返回的结构的大小在第一次调用 GetAdaptersInfo() 之后但在第二次调用 GetAdaptersInfo() 之前增长,对 GetAdaptersInfo() 的第二次调用也将失败并显示 ERROR_BUFFER_OVERFLOW,并且您的函数将无法正常工作。

是的,这确实发生在现实生活中——我也遇到过。如果您希望代码可靠,则需要在循环中调用 GetAdaptersInfo(),根据需要多次增加缓冲区大小,直到调用成功。

必须有一种不太容易出错的方法来构造 API……不幸的是,微软还没有找到它。 :^P

【讨论】:

+1 好点。哇,你被那个抓住真是太不幸了!

以上是关于GetAdaptersInfo 和 GetAdaptersAddressess BufferLength 参数的主要内容,如果未能解决你的问题,请参考以下文章

GetAdaptersInfo & GetAdaptersAddresses

请教下为何MSDN里查不到GetAdaptersInfo这个API,

vb.net 第一节 获取本机网络适配器的信息 GetAdaptersInfo

VC 电脑的有线网卡与无线网卡的IP区别

如何在 C++ 中读取 Windows 默认网关 IP 地址

RecyclerView ItemTouchHelper getAdapterPosition() 在快速滑动时返回错误值