上一篇:WindowsAPI|每天了解几个winAPI接口之网络配置相关文档Iphlpapi.h详细分析八
如果有错误欢迎指正批评,在此只作为科普和参考。
C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\um\iphlpapi.h
文章目录
- [GetBestInterfaceEx:同时支持 IPv4 和 IPv6,用来查询"到指定目的地址时,本机应该把包从哪块网卡发出去"](#GetBestInterfaceEx:同时支持 IPv4 和 IPv6,用来查询“到指定目的地址时,本机应该把包从哪块网卡发出去”)
-
-
- [1. 与 `GetBestInterface` 区别](#1. 与
GetBestInterface
区别) - [2. 函数原型](#2. 函数原型)
- [3. 最小示例(IPv4)](#3. 最小示例(IPv4))
- [4. 最小示例(IPv6)](#4. 最小示例(IPv6))
- [5. 常见错误码](#5. 常见错误码)
- [6. 使用场景](#6. 使用场景)
- [1. 与 `GetBestInterface` 区别](#1. 与
-
- [GetBestRoute:给定一个 IPv4 目标地址(以及可选的源地址),把系统路由表里『最长前缀匹配 + 最低 Metric』的那条路由整行取出来](#GetBestRoute:给定一个 IPv4 目标地址(以及可选的源地址),把系统路由表里『最长前缀匹配 + 最低 Metric』的那条路由整行取出来)
-
-
- [1. 函数原型](#1. 函数原型)
- [2. 与 GetBestInterface/Ex 的区别](#2. 与 GetBestInterface/Ex 的区别)
- [3. MIB_IPFORWARDROW 关键字段](#3. MIB_IPFORWARDROW 关键字段)
- [4. 行为细节](#4. 行为细节)
- [5. 最小示例](#5. 最小示例)
- [6. 使用场景](#6. 使用场景)
-
- [NotifyAddrChange:给我一个异步事件,只要本机任何 IPv4/IPv6 地址(或接口状态)发生增删改,立刻通知我](#NotifyAddrChange:给我一个异步事件,只要本机任何 IPv4/IPv6 地址(或接口状态)发生增删改,立刻通知我)
-
-
- [1. 函数原型](#1. 函数原型)
- [2. 两种使用模式](#2. 两种使用模式)
- [3. 事件触发场景](#3. 事件触发场景)
- [4. 最小示例(同步阻塞)](#4. 最小示例(同步阻塞))
- [5. 最小示例(异步 IOCP)](#5. 最小示例(异步 IOCP))
- [6. 清理](#6. 清理)
- [7. 与相关 API 区别](#7. 与相关 API 区别)
-
- [NotifyRouteChange:给我一个异步事件,只要本机 IPv4 路由表发生任何增、删、改,就立刻通知我](#NotifyRouteChange:给我一个异步事件,只要本机 IPv4 路由表发生任何增、删、改,就立刻通知我)
-
-
- [1. 函数原型](#1. 函数原型)
- [2. 触发场景](#2. 触发场景)
- [3. 使用模式](#3. 使用模式)
- [4. 最小示例(同步阻塞)](#4. 最小示例(同步阻塞))
- [5. 取消与清理](#5. 取消与清理)
- [6. 与相关 API 对照](#6. 与相关 API 对照)
-
- [CancelIPChangeNotify:"取消"之前通过 异步方式 注册的 IP 地址或路由变化通知](#CancelIPChangeNotify:“取消”之前通过 异步方式 注册的 IP 地址或路由变化通知)
-
-
- [1. 函数原型](#1. 函数原型)
- [2. 使用场景](#2. 使用场景)
- [3. 典型调用流程](#3. 典型调用流程)
- [4. 注意事项](#4. 注意事项)
-
- [GetAdapterIndex:把网卡的『友好名称』(Unicode 字符串) 转换成对应的接口索引 (ifIndex)](#GetAdapterIndex:把网卡的『友好名称』(Unicode 字符串) 转换成对应的接口索引 (ifIndex))
-
-
- [1. 函数原型](#1. 函数原型)
- [2. 友好名称是什么?](#2. 友好名称是什么?)
- [3. 最小示例](#3. 最小示例)
- [4. 常见用途](#4. 常见用途)
- [5. 注意点](#5. 注意点)
-
- [AddIPAddress:把指定的 IPv4 地址/掩码临时添加到某块网卡上,立刻生效,重启后失效](#AddIPAddress:把指定的 IPv4 地址/掩码临时添加到某块网卡上,立刻生效,重启后失效)
-
-
- [1. 函数原型](#1. 函数原型)
- [2. 关键概念:NTEContext / NTEInstance](#2. 关键概念:NTEContext / NTEInstance)
- [3. 生命周期](#3. 生命周期)
- [4. 最小示例](#4. 最小示例)
- [5. 删除临时地址](#5. 删除临时地址)
- [6. 常见错误码](#6. 常见错误码)
- [7. 典型用途](#7. 典型用途)
-
- [DeleteIPAddress:把之前用 AddIPAddress 临时添加的 IPv4 地址立即删除](#DeleteIPAddress:把之前用 AddIPAddress 临时添加的 IPv4 地址立即删除)
GetBestInterfaceEx:同时支持 IPv4 和 IPv6,用来查询"到指定目的地址时,本机应该把包从哪块网卡发出去"
cpp
#pragma region Application Family or OneCore Family or Games Family
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES)
#pragma warning(push)
#pragma warning(disable:4115)
IPHLPAPI_DLL_LINKAGE
DWORD
WINAPI
GetBestInterfaceEx(
_In_ struct sockaddr *pDestAddr,
_Out_ PDWORD pdwBestIfIndex
);
#pragma warning(pop)
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES) */
#pragma endregion
GetBestInterfaceEx
是 GetBestInterface
的"升级版"------同时支持 IPv4 和 IPv6,用来查询"到指定目的地址时,本机应该把包从哪块网卡发出去"。
1. 与 GetBestInterface
区别
特性 | GetBestInterface | GetBestInterfaceEx |
---|---|---|
地址族 | 仅 IPv4 (IPAddr ) |
IPv4 / IPv6 通用 (sockaddr ) |
结构体 | IPAddr |
sockaddr_in / sockaddr_in6 |
适用平台 | 桌面、系统、游戏 | 额外支持 UWP/商店应用 |
2. 函数原型
c
DWORD WINAPI GetBestInterfaceEx(
_In_ struct sockaddr *pDestAddr, // 指向 IPv4 或 IPv6 地址
_Out_ PDWORD pdwBestIfIndex
);
- pDestAddr
传入sockaddr_in
(IPv4)或sockaddr_in6
(IPv6),需先填充地址族和端口(端口可为 0)。 - pdwBestIfIndex
返回最佳接口的 接口索引 (与GetAdaptersAddresses
中的IfIndex
对应)。
3. 最小示例(IPv4)
cpp
sockaddr_in dest4 = {};
dest4.sin_family = AF_INET;
dest4.sin_port = 0; // 不关心端口
inet_pton(AF_INET, "8.8.8.8", &dest4.sin_addr);
DWORD bestIf;
DWORD err = GetBestInterfaceEx((sockaddr*)&dest4, &bestIf);
if (err == NO_ERROR)
printf("Best IPv4 interface = %lu\n", bestIf);
else
printf("Error: %lu\n", err);
4. 最小示例(IPv6)
cpp
sockaddr_in6 dest6 = {};
dest6.sin6_family = AF_INET6;
inet_pton(AF_INET6, "2001:4860:4860::8888", &dest6.sin6_addr);
DWORD bestIf6;
DWORD err = GetBestInterfaceEx((sockaddr*)&dest6, &bestIf6);
if (err == NO_ERROR)
printf("Best IPv6 interface = %lu\n", bestIf6);
5. 常见错误码
错误码 | 含义 |
---|---|
NO_ERROR |
成功 |
ERROR_INVALID_PARAMETER |
地址族非法或指针为空 |
ERROR_NOT_FOUND |
找不到有效路由(例如路由表为空) |
6. 使用场景
- 网络诊断工具:判断目标走哪条链路。
- VPN/代理:在添加路由前探测真实出口。
- UWP 应用 :由于
GetBestInterface
仅限桌面分区,GetBestInterfaceEx
是 UWP 中唯一可用的"最佳接口"查询函数。
一句话总结:
GetBestInterfaceEx
是跨协议(IPv4/IPv6)、跨平台(含 UWP)的"路由查询"函数:给它一个 sockaddr
,它告诉你数据包会从哪块网卡出去。
GetBestRoute:给定一个 IPv4 目标地址(以及可选的源地址),把系统路由表里『最长前缀匹配 + 最低 Metric』的那条路由整行取出来
cpp
#pragma region Desktop Family or OneCore Family or Games Family
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES)
//////////////////////////////////////////////////////////////////////////////
// //
// Gets the best (longest matching prefix) route for the given destination //
// If the source address is also specified (i.e. is not 0x00000000), and //
// there are multiple "best" routes to the given destination, the returned //
// route will be one that goes out over the interface which has an address //
// that matches the source address //
// //
//////////////////////////////////////////////////////////////////////////////
IPHLPAPI_DLL_LINKAGE
DWORD
WINAPI
GetBestRoute(
_In_ DWORD dwDestAddr,
_In_opt_ DWORD dwSourceAddr,
_Out_ PMIB_IPFORWARDROW pBestRoute
);
GetBestRoute 功能一句话
"给定一个 IPv4 目标地址(以及可选的源地址),把系统路由表里『最长前缀匹配 + 最低 Metric』的那条路由整行取出来。"
1. 函数原型
c
DWORD WINAPI GetBestRoute(
_In_ DWORD dwDestAddr, // 目标 IPv4(网络字节序)
_In_opt_ DWORD dwSourceAddr, // 源 IPv4(可为 0)
_Out_ PMIB_IPFORWARDROW pBestRoute // 整条路由信息
);
返回值
NO_ERROR
(0) -- 成功ERROR_INVALID_PARAMETER
-- 地址非法或指针空ERROR_NO_DATA
-- 找不到匹配路由
2. 与 GetBestInterface/Ex 的区别
API | 输出内容 | 协议族 | 额外信息 |
---|---|---|---|
GetBestInterface | 仅接口索引 | IPv4 | ❌ |
GetBestInterfaceEx | 仅接口索引 | IPv4/6 | ❌ |
GetBestRoute | 完整 MIB_IPFORWARDROW 路由行 |
IPv4 | ✅ |
3. MIB_IPFORWARDROW 关键字段
c
typedef struct _MIB_IPFORWARDROW {
DWORD dwForwardDest; // 目的网络
DWORD dwForwardMask; // 子网掩码
DWORD dwForwardPolicy; // 策略 (通常 0)
DWORD dwForwardNextHop; // 下一跳网关
DWORD dwForwardIfIndex; // 出口接口
DWORD dwForwardType; // 路由类型 (3=direct, 4=remote)
DWORD dwForwardProto; // 路由协议
DWORD dwForwardAge; // 生存时间
DWORD dwForwardNextHopAS; // 自治系统号
DWORD dwForwardMetric1; // 路由度量
// ... 还有 Metric2-5
} MIB_IPFORWARDROW, *PMIB_IPFORWARDROW;
4. 行为细节
- 如果
dwSourceAddr == 0
,系统只按 最长前缀 + 最小 Metric 选路。 - 如果
dwSourceAddr != 0
,且出现多条"最优"路由,则优先选择 源地址所在子网 所在接口的那条路由。 - 目标地址就是主机地址时,返回 主机路由 (掩码
255.255.255.255
)。
5. 最小示例
cpp
MIB_IPFORWARDROW best;
DWORD ret = GetBestRoute(inet_addr("8.8.8.8"), 0, &best);
if (ret == NO_ERROR) {
struct in_addr dest, mask, hop;
dest.S_un.S_addr = best.dwForwardDest;
mask.S_un.S_addr = best.dwForwardMask;
hop.S_un.S_addr = best.dwForwardNextHop;
printf("Route: Dest=%s Mask=%s NextHop=%s If=%lu Metric=%lu\n",
inet_ntoa(dest), inet_ntoa(mask), inet_ntoa(hop),
best.dwForwardIfIndex, best.dwForwardMetric1);
}
6. 使用场景
- 网络诊断:显示"到某 IP 实际走哪条路由、下一跳是谁"。
- VPN/多出口:比较不同源地址时的选路差异。
- 路由可视化工具:替代
route print
的逐行解析。
一句话总结
GetBestRoute
把"路由表里真正会被选中的那一条"完整取出来,让你不仅能知道出口接口,还能直接看到下一跳网关、子网掩码和路由度量。
NotifyAddrChange:给我一个异步事件,只要本机任何 IPv4/IPv6 地址(或接口状态)发生增删改,立刻通知我
cpp
IPHLPAPI_DLL_LINKAGE
DWORD
WINAPI
NotifyAddrChange(
_Out_ PHANDLE Handle,
_In_ LPOVERLAPPED overlapped
);
NotifyAddrChange
的作用一句话:
"给我一个异步事件,只要本机任何 IPv4/IPv6 地址(或接口状态)发生增删改,立刻通知我。"
1. 函数原型
c
DWORD WINAPI NotifyAddrChange(
_Out_ PHANDLE Handle, // 返回事件句柄(同步模式)或 NULL(异步)
_In_ LPOVERLAPPED overlapped // 异步 I/O 用;同步模式可填 NULL
);
- 返回值
NO_ERROR
(0) ------ 成功注册ERROR_IO_PENDING
------ 异步已排队(与OVERLAPPED
配合)- 其他 Win32 错误码(权限不足等)
2. 两种使用模式
模式 | Handle | overlapped | 等待方式 | 典型代码 |
---|---|---|---|---|
同步 | 非 NULL | NULL | WaitForSingleObject(Handle, INFINITE) |
简单阻塞等一次 |
异步 | NULL | 有效 OVERLAPPED* |
GetQueuedCompletionStatus / ReadDirectoryChangesW 风格 |
服务/驱动长时间监听 |
3. 事件触发场景
- 任何接口新增/删除 IPv4 或 IPv6 单播地址
- DHCP 分配/续租/释放
- 用户手动改 IP、启用/禁用网卡
- VPN、拨号连接建立/断开
- 不报告 路由表、DNS 服务器变化(需
NotifyRouteChange
/NotifyUnicastIpAddressChange
等)
4. 最小示例(同步阻塞)
cpp
HANDLE hEvent;
DWORD err = NotifyAddrChange(&hEvent, NULL);
if (err == NO_ERROR) {
printf("Waiting for address change...\n");
WaitForSingleObject(hEvent, INFINITE);
printf("Detected address change!\n");
CloseHandle(hEvent);
}
5. 最小示例(异步 IOCP)
cpp
HANDLE hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
OVERLAPPED ovl = {};
DWORD err = NotifyAddrChange(NULL, &ovl);
if (err == ERROR_IO_PENDING) {
DWORD bytes;
ULONG_PTR key;
LPOVERLAPPED pov;
GetQueuedCompletionStatus(hIOCP, &bytes, &key, &pov, INFINITE);
// 这里收到通知
}
6. 清理
- 同步句柄用
CloseHandle
。 - 异步调用可用
CancelIoEx
取消挂起的通知。
7. 与相关 API 区别
API | 触发条件 | 协议族 |
---|---|---|
NotifyAddrChange |
IP 地址变化 | IPv4/IPv6 |
NotifyRouteChange |
路由表变化 | IPv4 |
NotifyUnicastIpAddressChange |
单播地址变化 | IPv4/IPv6(细粒度回调) |
一句话总结:
NotifyAddrChange
让你用 事件或异步 I/O 实时监听"本机 IP 地址发生任何变化"这一事件,常用于网络配置守护、VPN 客户端、零配置服务等。
NotifyRouteChange:给我一个异步事件,只要本机 IPv4 路由表发生任何增、删、改,就立刻通知我
cpp
IPHLPAPI_DLL_LINKAGE
DWORD
WINAPI
NotifyRouteChange(
_Out_ PHANDLE Handle,
_In_ LPOVERLAPPED overlapped
);
NotifyRouteChange
的作用可以一句话概括:
"给我一个异步事件,只要本机 IPv4 路由表发生任何增、删、改,就立刻通知我。"
1. 函数原型
c
DWORD WINAPI NotifyRouteChange(
_Out_ PHANDLE Handle, // 返回事件句柄(同步)或 NULL(异步)
_In_ LPOVERLAPPED overlapped // 异步 I/O 用;同步可填 NULL
);
2. 触发场景
- 新增路由(
route add
、DHCP、VPN、拨号、路由协议) - 删除路由(
route delete
、接口禁用、DHCP 释放、路由老化) - 修改路由(Metric、网关、出接口变化)
- 仅 IPv4 路由表 ;IPv6 需用
NotifyRouteChange2
(或NotifyIpInterfaceChange
)。
3. 使用模式
模式 | 调用方式 | 等待方式 |
---|---|---|
同步 | Handle != NULL , overlapped == NULL |
WaitForSingleObject 阻塞一次 |
异步 | Handle == NULL , 提供有效 OVERLAPPED |
GetQueuedCompletionStatus / 回调 |
4. 最小示例(同步阻塞)
cpp
HANDLE hEvent;
DWORD ret = NotifyRouteChange(&hEvent, NULL);
if (ret == NO_ERROR) {
wprintf(L"等待路由变化...\n");
WaitForSingleObject(hEvent, INFINITE);
wprintf(L"路由表已变动!\n");
CloseHandle(hEvent);
}
5. 取消与清理
- 同步句柄:
CloseHandle(hEvent)
- 异步:
CancelIoEx(NULL, &ov)
或关闭线程池 IOCP
6. 与相关 API 对照
API | 监听内容 | 协议 | 粒度 |
---|---|---|---|
NotifyRouteChange |
路由表变动 | IPv4 | 整表 |
NotifyRouteChange2 |
路由表变动 | IPv4/IPv6 | 可过滤地址族 |
NotifyAddrChange |
IP 地址变动 | IPv4/IPv6 | - |
NotifyUnicastIpAddressChange |
单播地址变动 | IPv4/IPv6 | 细粒度回调 |
一句话总结:
NotifyRouteChange
是"路由表监视器"------注册一次,就能在 IPv4 路由发生任何变化时立即得到事件通知。
CancelIPChangeNotify:"取消"之前通过 异步方式 注册的 IP 地址或路由变化通知
cpp
IPHLPAPI_DLL_LINKAGE
BOOL
WINAPI
CancelIPChangeNotify(
_In_ LPOVERLAPPED notifyOverlapped
);
CancelIPChangeNotify
用来"取消"之前通过 异步方式 注册的 IP 地址或路由变化通知。
一句话:
把已经挂起的 NotifyAddrChange
或 NotifyRouteChange
异步请求立即撤销。
1. 函数原型
c
BOOL WINAPI CancelIPChangeNotify(
_In_ LPOVERLAPPED notifyOverlapped // 指向当初传给 Notify*Change 的那个 OVERLAPPED
);
- 返回值
TRUE
-- 成功取消
FALSE
-- 失败(调用GetLastError
查看原因)
2. 使用场景
- 长驻服务 / 托盘程序 在退出前,确保不再收到后续通知。
- UI 应用 切换页面/停止监控时,避免 IOCP/线程池仍在等待。
- 防止句柄泄漏:异步请求一旦取消,可以安全释放相关资源。
3. 典型调用流程
cpp
OVERLAPPED gOv = {}; // 全局或成员变量
HANDLE gIOCP = nullptr; // 完成端口
// 1. 启动异步通知
DWORD err = NotifyAddrChange(NULL, &gOv);
if (err == ERROR_IO_PENDING) {
// 2. 稍后在某个时刻取消
CancelIPChangeNotify(&gOv);
}
4. 注意事项
- 只能取消 异步模式 (
Handle == NULL
且传了OVERLAPPED
)的请求;
同步模式(Handle != NULL
)直接用CloseHandle
即可。 - 取消后,对应的
OVERLAPPED
会收到一次ERROR_OPERATION_ABORTED
完成通知。 - 与
CancelIoEx(NULL, &ov)
效果相同,但CancelIPChangeNotify
语义更清晰,代码可读性更好。
一句话总结:
CancelIPChangeNotify
就是"把之前用 NotifyAddrChange
/ NotifyRouteChange
挂起的异步通知立即撤掉",防止程序退出后仍被系统回调。
GetAdapterIndex:把网卡的『友好名称』(Unicode 字符串) 转换成对应的接口索引 (ifIndex)
cpp
IPHLPAPI_DLL_LINKAGE
DWORD
WINAPI
GetAdapterIndex(
_In_ LPWSTR AdapterName,
_Inout_ PULONG IfIndex
);
GetAdapterIndex
的功能一句话:
"把网卡的『友好名称』(Unicode 字符串) 转换成对应的接口索引 (ifIndex)。"
1. 函数原型
c
DWORD WINAPI GetAdapterIndex(
_In_ LPWSTR AdapterName, // 输入:网卡友好名,如 L"Ethernet"
_Inout_ PULONG IfIndex // 输出:接口索引
);
- 返回值
NO_ERROR
(0) ------ 成功ERROR_INVALID_PARAMETER
------ 名称空或指针空ERROR_DEV_NOT_EXIST
------ 找不到该名称的接口
2. 友好名称是什么?
- 就是你在"网络连接"窗口看到的名称,例如
"Ethernet"
、"Wi-Fi"
、"vEthernet (Default Switch)"
- 与设备管理器里的硬件描述不同,也不同于注册表里的 GUID。
3. 最小示例
cpp
ULONG idx = 0;
DWORD ret = GetAdapterIndex(L"Ethernet", &idx);
if (ret == NO_ERROR)
wprintf(L"Interface index of 'Ethernet' = %lu\n", idx);
else
wprintf(L"Error: %lu\n", ret);
4. 常见用途
- 用户界面让用户选"网卡名称",内部用索引做后续 API 调用(如
SetIpNetEntry
、CreateProxyArpEntry
)。 - 脚本/工具把配置文件里的可读名称转换成系统索引。
- 与
GetInterfaceInfo
/GetAdaptersAddresses
返回的名称直接对应。
5. 注意点
- 区分大小写:名称必须完全一致,包括空格。
- 支持重命名 :如果用户把网卡重命名为
"LAN #2"
,就必须用新名称。 - 仅限 IPv4 接口:名称必须对应已启用 IPv4 的适配器,纯 IPv6 或禁用的找不到。
一句话总结:
GetAdapterIndex
就是"把用户看得懂的网卡名字翻译成系统看得懂的接口索引"。
AddIPAddress:把指定的 IPv4 地址/掩码临时添加到某块网卡上,立刻生效,重启后失效
cpp
IPHLPAPI_DLL_LINKAGE
DWORD
WINAPI
AddIPAddress(
_In_ IPAddr Address,
_In_ IPMask IpMask,
_In_ DWORD IfIndex,
_Out_ PULONG NTEContext,
_Out_ PULONG NTEInstance
);
AddIPAddress 功能一句话
"把指定的 IPv4 地址/掩码临时添加到某块网卡上,立刻生效,重启后失效。"
1. 函数原型
c
DWORD WINAPI AddIPAddress(
_In_ IPAddr Address, // IPv4 地址(网络字节序)
_In_ IPMask IpMask, // 子网掩码(网络字节序)
_In_ DWORD IfIndex, // 接口索引
_Out_ PULONG NTEContext, // 返回的上下文句柄
_Out_ PULONG NTEInstance // 返回的实例号
);
- 返回值
NO_ERROR
(0) 成功;其它为 Win32 错误码(如ERROR_INVALID_PARAMETER
、ERROR_DUP_DOMAINNAME
等)。
2. 关键概念:NTEContext / NTEInstance
NTEContext
和NTEInstance
共同构成 "网络表项句柄" ,后续调用DeleteIPAddress
时必须原样传入才能删除这条临时地址。- 这两个值仅由系统生成,不要自己猜测。
3. 生命周期
- 临时性 :地址在 当前会话 中有效,重启或禁用/启用接口后消失。
- 不写入注册表 :等同于命令行
netsh interface ip add address ...
的临时模式。 - 可与静态/ DHCP 地址共存。
4. 最小示例
cpp
ULONG ctx, inst;
DWORD ret = AddIPAddress(
inet_addr("192.168.50.100"),
inet_addr("255.255.255.0"),
7, // 接口索引 7
&ctx, &inst);
if (ret == NO_ERROR) {
printf("Added temp IP 192.168.50.100/24, ctx=%lu inst=%lu\n", ctx, inst);
} else {
printf("AddIPAddress failed: %lu\n", ret);
}
5. 删除临时地址
cpp
DeleteIPAddress(ctx); // 用 AddIPAddress 返回的 ctx
6. 常见错误码
错误码 | 说明 |
---|---|
ERROR_INVALID_PARAMETER |
地址/掩码/索引非法 |
ERROR_DUP_DOMAINNAME |
地址已在接口上存在 |
ERROR_DEV_NOT_EXIST |
接口索引不存在 |
7. 典型用途
- 网络调试/测试:脚本快速给网卡加第二地址,用完即删。
- VPN/代理工具:临时为 TAP 接口分配地址。
- 零配置服务:发现冲突时可回滚。
一句话总结
AddIPAddress
是"程序级别"的临时 IPv4 地址注入器:立刻生效、重启即失,需用 DeleteIPAddress
配合清理。
DeleteIPAddress:把之前用 AddIPAddress 临时添加的 IPv4 地址立即删除
cpp
IPHLPAPI_DLL_LINKAGE
DWORD
WINAPI
DeleteIPAddress(
_In_ ULONG NTEContext
);
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES) */
#pragma endregion
DeleteIPAddress
的作用一句话:
把之前用 AddIPAddress
临时添加的 IPv4 地址立即删除。
函数原型
c
DWORD WINAPI DeleteIPAddress(
_In_ ULONG NTEContext // 必须是 AddIPAddress 返回的 NTEContext
);
- 返回值
NO_ERROR
(0) ------ 删除成功ERROR_INVALID_PARAMETER
------ 传入的 NTEContext 无效 / 不存在- 其他 Win32 错误码
使用要点
- 只能删除"临时地址" ------ 即通过
AddIPAddress
加入、重启会消失的地址。 - 必须提供
NTEContext
------ 与AddIPAddress
返回的完全一致;不能删静态或 DHCP 地址。 - 立即生效 ------ 删除后接口不再拥有该地址,ARP/路由表同步更新。
- 无需管理员权限 ------ 只要
AddIPAddress
成功,同一进程即可删除;跨进程需权限匹配。
最小示例
cpp
ULONG ctx, inst;
// 先添加
AddIPAddress(inet_addr("192.168.88.10"),
inet_addr("255.255.255.0"),
7, &ctx, &inst);
// 用完即删
DWORD ret = DeleteIPAddress(ctx);
if (ret == NO_ERROR)
printf("Temp IP deleted.\n");
else
printf("Delete failed: %lu\n", ret);
一句话总结:
DeleteIPAddress
就是"撤销" AddIPAddress
的专用清理函数,把临时 IPv4 地址从接口上立刻移除。