文章目录
如果有错误欢迎指正批评,在此只作为科普和参考。
简介
Iphlpapi.h
是 Windows 平台的一个头文件,它提供了网络诊断和网络配置相关的函数。这个头文件定义了 Windows IP Helper API,其中包括许多用于获取网络配置信息、管理网络连接和执行网络诊断的函数。
例如,使用 Iphlpapi.h
可以执行以下操作:
- 获取网络适配器的列表和状态。
- 获取网络接口的统计信息(如发送和接收的数据包数)。
- 管理网络路由表。
- 执行网络诊断测试,如 ping 或 traceroute。
如果你正在开发一个需要这些功能的 Windows 应用程序,你可以在你的代码中包含这个头文件,并使用它定义的函数。
这里是一个简单的例子,展示如何使用 Iphlpapi.h
来获取网络适配器的信息:
#include <windows.h>
#include <iphlpapi.h>
#include <stdio.h>
int main() {
ULONG outBufLen = 0;
IP_ADAPTER_INFO *pAdapterInfo;
// 首先调用GetAdaptersInfo以确定需要的缓冲区大小
DWORD dwRetVal = GetAdaptersInfo(NULL, &outBufLen);
if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
pAdapterInfo = (IP_ADAPTER_INFO *)malloc(outBufLen);
if(pAdapterInfo == NULL) {
printf("Memory allocation failed for IP_ADAPTER_INFO.\n");
return 1;
}
}
// 再次调用GetAdaptersInfo以获取网络适配器信息
dwRetVal = GetAdaptersInfo(pAdapterInfo, &outBufLen);
if (dwRetVal == NO_ERROR) {
// 输出网络适配器信息
for (pAdapterInfo; pAdapterInfo != NULL; pAdapterInfo = pAdapterInfo->Next) {
printf("\tAdapter name: %s\n", pAdapterInfo->AdapterName);
printf("\tAdapter description: %s\n", pAdapterInfo->Description);
printf("\tAdapter address: ");
for (int i = 0; i < pAdapterInfo->AddressLength; i++) {
printf("%02X ", pAdapterInfo->Address[i]);
}
printf("\n");
}
} else {
printf("Call to GetAdaptersInfo failed.\n");
}
// 释放内存
free(pAdapterInfo);
return 0;
}
这段代码首先调用 GetAdaptersInfo
函数来确定需要的缓冲区大小,然后分配内存并再次调用该函数来获取网络适配器的信息。最后,它遍历链表并打印每个适配器的名称、描述和地址。
详解
路径
iphlpapi.h
是 Windows 操作系统中用于网络诊断和配置的一组 API 的头文件。它包含在 Windows SDK 中,通常位于以下路径:
C:\Program Files (x86)\Windows Kits\10\Include\10.0.*\um\iphlpapi.h
这里的 10.0.*
可能会根据你安装的 Windows SDK 版本而有所不同。你可以通过 Windows SDK 安装目录找到相应的头文件。如果你的系统上安装了 Visual Studio 或其他开发工具,它们通常会包含这些 SDK 文件。
头文件的开头部分
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
Module Name:
iphlpapi.h
Abstract:
Header file for functions to interact with the IP Stack for MIB-II and
related functionality
--*/
#ifndef __IPHLPAPI_H__
#define __IPHLPAPI_H__
#if _MSC_VER > 1000
#pragma once
#endif
#include <winapifamily.h>
这段代码是 iphlpapi.h
头文件的开头部分。它包含了几个关键部分:
- 版权声明:声明了 Microsoft Corporation 对该文件拥有版权。
- 模块名称:指出了文件名
iphlpapi.h
。 - 摘要:简要描述了这个头文件的作用,即提供与 IP 堆栈交互的函数,用于 MIB-II(管理信息库版本 2)和相关功能的实现。
接下来是一些预处理指令:
- #ifndef IPHLPAPI_H:这是一个预处理指令,用于防止头文件被多次包含。它检查是否已经定义了
__IPHLAPI_H__
,如果没有定义,则继续包含文件的内容。 - #define IPHLPAPI_H:定义了
__IPHLAPI_H__
,确保这个头文件的内容只会被包含一次。 - #if _MSC_VER > 1000:这是一个条件编译指令,用于检查使用的编译器版本。
_MSC_VER
是 Microsoft Visual C++ 编译器的版本号。如果版本号大于 1000(即 Visual Studio .NET 2002 或更高版本),则执行#pragma once
。 - #pragma once:这是一个非标准的编译器指令,告诉编译器这个文件只包含一次。它在 Visual Studio 中有效,但不是所有编译器都支持。
- #include <winapifamily.h>:包含 Windows API 家族定义的头文件。这个文件定义了不同的 Windows 平台和 API 可用性。
这些指令和包含确保了头文件在编译时被正确处理,并且只包含一次。这对于避免编译错误和确保代码的一致性非常重要。
可移植性和兼容性
//
// //
// Establish DLL function linkage if supported by the current build //
// environment and not previously defined. //
// //
//
#ifndef IPHLPAPI_DLL_LINKAGE
#ifdef DECLSPEC_IMPORT
#define IPHLPAPI_DLL_LINKAGE DECLSPEC_IMPORT
#else
#define IPHLPAPI_DLL_LINKAGE
#endif
#endif
#pragma region Application Family or OneCore Family or Games Family
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES)
#ifdef __cplusplus
extern "C" {
#endif
这段代码是 C/C++ 编程中常见的宏定义和编译器指令,用于在 Windows 平台上处理 DLL(动态链接库)的函数链接,以及确保代码在不同 Windows API 家族间的兼容性。下面是对这些代码的具体解释:
-
条件编译:通过一系列宏定义来确定是否需要为 DLL 函数导出或导入,这取决于编译器是否支持
DECLSPEC_IMPORT
(用于指定导入符号)。#ifndef IPHLPAPI_DLL_LINKAGE #ifdef DECLSPEC_IMPORT #define IPHLPAPI_DLL_LINKAGE DECLSPEC_IMPORT #else #define IPHLPAPI_DLL_LINKAGE #endif #endif
#ifndef IPHLPAPI_DLL_LINKAGE
检查是否已经定义了IPHLPAPI_DLL_LINKAGE
。#ifdef DECLSPEC_IMPORT
检查编译器是否定义了DECLSPEC_IMPORT
(通常由编译器自动定义,例如,当你在创建 DLL 时作为导出项目编译)。- 如果
DECLSPEC_IMPORT
可用,则IPHLPAPI_DLL_LINKAGE
被定义为DECLSPEC_IMPORT
,这将导入 DLL 中的函数。 - 如果
DECLSPEC_IMPORT
不可用,则IPHLPAPI_DLL_LINKAGE
被定义为空,这意味着没有特定的链接属性。
-
Windows API 家族分区:使用
WINAPI_PARTITION
宏来确定代码应该在哪些 Windows API 家族中可用。#pragma region Application Family or OneCore Family or Games Family #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES)
#pragma region
是一个编译器指令,用于标识一个代码区域的开始。在这个例子中,它被用来标识与特定 Windows API 家族相关的代码区域。WINAPI_FAMILY_PARTITION
宏用于在编译时确定是否应该包含这段代码。这里,它检查是否应该为应用程序家族(WINAPI_PARTITION_APP
)、系统家族(WINAPI_PARTITION_SYSTEM
)或游戏家族(WINAPI_PARTITION_GAMES
)编译这段代码。
-
C++ 外部链接符号:当在 C++ 项目中使用 C 风格的函数时,需要使用
extern "C"
来确保链接符号的正确性。#ifdef __cplusplus extern "C" { #endif
#ifdef __cplusplus
检查是否在 C++ 环境中编译代码。extern "C"
指示编译器接下来的函数应该使用 C 语言的链接规则,这对于 C/C++ 混编非常重要,因为它允许 C++ 编译器正确链接 C 函数。
这些代码段是构建跨平台 Windows 应用程序时常见的做法,确保了代码的可移植性和兼容性。
设置和获取网络信息的 MIB
//
// //
// IPRTRMIB.H has the definitions of the structures used to set and get //
// information //
// //
//
#include <iprtrmib.h>
#include <ipexport.h>
#include <iptypes.h>
#include <tcpestats.h>
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES) */
#pragma endregion
#pragma region Desktop Family or OneCore Family or Games Family
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES)
这段代码继续说明了一些 C/C++ 编程概念,特别是在 Windows 平台开发中使用的一些技术和宏。下面是对这段代码的详细解释:
-
文件用途注释:注释首先指明了这个文件包含用于设置和获取网络信息的
MIB
(Management Information Base)结构的定义。 -
包含其他头文件:
#include <iprtrmib.h>
:包含了定义 MIB-II 管理信息结构的头文件。#include <ipexport.h>
:包含了 IP 相关函数的导出声明。#include <iptypes.h>
:包含了 IP 地址相关的类型和常量定义。#include <tcpestats.h>
:包含了 TCP 统计信息的结构定义。
-
结束平台分区宏定义:
#endif /* WINAPI_FAMILY_PARTITION(...) */
:这部分代码是结束之前#if
或#ifdef
语句的条件编译块,确保只有当编译环境符合指定的 Windows 平台家族时才包含这部分代码。
-
结束区域定义指令:
#pragma endregion
:指示编译器结束当前定义的区域。
-
开始新的平台分区宏定义:
#pragma region Desktop Family or OneCore Family or Games Family
:定义了一个新的代码区域,并命名它为与桌面、OneCore 或游戏相关的家族。#if WINAPI_FAMILY_PARTITION(...)
:使用WINAPI_FAMILY_PARTITION
宏来包含适用于桌面、系统或游戏家族的代码,这是 Windows 8 引入的用于编译特定平台代码的方法。
这段代码是典型的 Windows SDK 编程风格,使用宏和预处理指令来控制不同版本的 Windows 平台之间的代码。这种方式允许开发者编写可在多个 Windows 平台上运行的代码,同时确保了对特定平台特性的支持。
GetNumberOfInterfaces:检索系统中网络接口的数量
//
// //
// The GetXXXTable APIs take a buffer and a size of buffer. If the buffer //
// is not large enough, the APIs return ERROR_INSUFFICIENT_BUFFER and //
// *pdwSize is the required buffer size //
// The bOrder is a BOOLEAN, which if TRUE sorts the table according to //
// MIB-II (RFC XXXX) //
// //
//
//
// //
// Retrieves the number of interfaces in the system. These include LAN and //
// WAN interfaces //
// //
//
IPHLPAPI_DLL_LINKAGE
DWORD
WINAPI
GetNumberOfInterfaces(
_Out_ PDWORD pdwNumIf
);
这段注释和函数声明是Windows网络编程中的一部分,说明了如何使用API来获取系统中网络接口的数量。这里是对代码段的解释:
-
注释部分:
- 第一个注释块描述了
GetXXXTable
系列API的通用行为。这些API需要一个缓冲区和缓冲区大小作为参数。如果提供缓冲区不够大,API将返回ERROR_INSUFFICIENT_BUFFER
错误,并设置*pdwSize
为所需的缓冲区大小。 - 第二个注释块提到了
bOrder
参数,这是一个布尔值,如果设为TRUE
,则会根据MIB-II标准(RFC XXXX,这里的 XXXX 可能是特定RFC文档的编号)对表格进行排序。
- 第一个注释块描述了
-
函数声明:
- 声明了
GetNumberOfInterfaces
函数,该函数是iphlpapi.dll
库中的一个导出函数,用于检索系统中网络接口的数量,包括本地局域网(LAN)和广域网(WAN)接口。
- 声明了
-
函数细节:
IPHLPAPI_DLL_LINKAGE
是一个链接指示符,指定了这个函数是DLL的一部分。DWORD WINAPI GetNumberOfInterfaces(_Out_ PDWORD pdwNumIf);
这行声明了一个函数,其返回类型是DWORD
类型,这是Windows API中常用的一个无符号32位整型,用于表示函数的错误代码或返回值。_Out_ PDWORD pdwNumIf
是该函数的参数,_Out_
指的是输出参数,PDWORD
是指向DWORD
的指针,pdwNumIf
将会存储系统中网络接口的数量。
使用这个函数时,你会提供一个 DWORD
类型的指针,函数会将系统中网络接口的数量写入这个指针指向的内存地址。如果调用成功,返回值将为 ERROR_SUCCESS
(通常定义为0),表示没有错误发生。如果返回值不是0,则表示调用失败,可以通过查阅相应的错误代码来确定失败的原因。
GetIfEntry:获取特定网络接口的 MIB-II ifEntry 信息
//
// //
// Gets the MIB-II ifEntry //
// The dwIndex field of the MIB_IFROW should be set to the index of the //
// interface being queried //
// //
//
IPHLPAPI_DLL_LINKAGE
DWORD
WINAPI
GetIfEntry(
_Inout_ PMIB_IFROW pIfRow
);
这段注释和函数声明描述了如何使用 Windows 平台的 IP Helper API 来获取特定网络接口的 MIB-II ifEntry 信息。
-
注释部分:
- 注释说明了
GetIfEntry
函数的用途,即获取特定网络接口的 MIB-II ifEntry 信息。MIB-II 是一个网络管理的标准,ifEntry 是其中的一个部分,代表网络接口的相关信息。 - 指出
MIB_IFROW
结构体的dwIndex
字段需要被设置为查询的接口的索引。这个索引通常是从1开始的,代表系统中的第一个网络接口。
- 注释说明了
-
函数声明:
GetIfEntry
函数是iphlpapi.dll
库中的一个导出函数,用于获取特定网络接口的详细信息。IPHLPAPI_DLL_LINKAGE
是一个宏,用于指示该函数是 DLL 的一部分,确保正确的导出和导入。
-
函数参数:
_Inout_ PMIB_IFROW pIfRow
是GetIfEntry
函数的参数,其中:_Inout_
是 SAL(Source Annotation Language)注解,表示这个参数既被读取也被修改。PMIB_IFROW
是指向MIB_IFROW
结构体的指针,MIB_IFROW
包含了网络接口的详细信息。pIfRow
是这个指针的变量名,它指向一个已经初始化了dwIndex
字段的结构体实例。
-
函数返回值:
- 函数返回一个
DWORD
类型的值,表示操作的结果。如果操作成功,返回ERROR_SUCCESS
(值通常为0)。如果操作失败,返回值将是一个错误代码,可以通过查阅 Windows API 文档来获取具体的错误信息。
- 函数返回一个
使用 GetIfEntry
函数时,你需要先初始化一个 MIB_IFROW
结构体,设置其 dwIndex
字段为你想查询的网络接口的索引。然后,将这个结构体的地址传递给 GetIfEntry
函数。如果调用成功,MIB_IFROW
结构体将被填充,包含所查询接口的详细信息,如接口的索引、名称、类型、物理地址、操作状态等。