- 示例工程
【免费下载链接】Windows-classic-samples
This repo contains samples that demonstrate the API used in Windows classic desktop applications.
导读
本文以 Windows-classic-samples 仓库中的 EnumRelationship 示例 为主线,系统讲解 Windows DHCP Server 管理 API 中DhcpV4FailoverEnumRelationship的完整用法:包括分页枚举的调用模式、返回值语义、结果数据的读取与内存释放,以及它在 DHCP 故障转移(Failover)管理 API 家族中的定位。读完本文,你将掌握如何用 C++ 遍历一台 DHCP 服务器上的全部故障转移关系,并能在此基础上扩展到创建、查询、修改、删除关系的配套 API。
一、示例背景:DHCP 与故障转移关系
DHCP(Dynamic Host Configuration Protocol)是一种标准化协议,允许客户端被动态分配 IP 地址、子网掩码、默认网关等关键网络配置参数。DHCP 服务器集中管理这些配置数据,由网络管理员针对特定网络环境进行设置,并通过 DHCP 消息与客户端通信(见 README.md 的说明)。
在多服务器部署场景中,Windows DHCP 服务支持故障转移(Failover):两台服务器(主服务器 Primary Server 与辅助服务器 Secondary Server)通过一条"故障转移关系"(Failover Relationship)共享一个或多个作用域(Scope)。当其中一台服务器不可用时,另一台接管地址分配。从本仓库 CreateRelationship 示例源码 可以看到,一条关系包含以下关键属性:
RelationshipName:关系名称(如"test");PrimaryServer/SecondaryServer:主、辅服务器 IP 地址(源码中0xa000001即10.0.0.1);PrimaryServerName/SecondaryServerName:主、辅服务器名称;Mode:关系模式,取LoadBalance(负载均衡)或HotStandby(热备);Mclt:Maximum Client Lead Time,客户端最大前导时间(示例中0xe10= 3600 秒);SafePeriod:安全期(0x258= 600 秒);Percentage:负载均衡百分比(0x32= 50%);SharedSecret:主辅服务器间的共享机密;pScopes:该关系所包含的作用域 IP 数组(DHCP_IP_ARRAY结构)。
EnumRelationship 示例正是解决"如何枚举一台服务器上已存在的所有这类关系"这一问题,它所调用的DhcpV4FailoverEnumRelationship属于DHCP Server Management API中Dhcpv4Failover系列函数。
二、示例工程结构与系统要求
2.1 文件布局
该示例在仓库中的目录结构如下:
| 路径 | 作用 |
|---|---|
| Samples/DHCP/EnumRelationship/README.md | 示例说明文档 |
| Samples/DHCP/EnumRelationship/cpp/EnumRelationship.cpp | 唯一源码文件,完整演示枚举调用 |
| Samples/DHCP/EnumRelationship/cpp/EnumRelationship.sln | Visual Studio 解决方案文件 |
| Samples/DHCP/EnumRelationship/cpp/EnumRelationship.vcxproj | 项目文件 |
2.2 操作系统与开发环境要求
README 明确列出的环境要求为:
- 客户端:Windows 8.1;
- 服务器:Windows Server 2012 R2;
- 开发工具:Visual Studio Express 2013 for Windows 8.1 或更新版本(README 同时说明,多数情况下使用更高版本工具链可无修改运行)。
从 EnumRelationship.vcxproj 可以进一步确认工程级配置:
- 仅提供x64平台的 Debug / Release 两个配置;
- 工具集
PlatformToolset为v110(对应 Visual Studio 2012/2013 工具链); CharacterSet为Unicode,预处理器定义包含WIN32_LEAN_AND_MEAN、UNICODE、_UNICODE等;- 链接器通过
AdditionalOptions显式引入dhcpsapi.lib(DHCP Server 管理 API 的导入库),子系统为Console(控制台程序); - 编译警告级别为 Level4,并将警告视为错误(
TreatWarningAsError=true)。
这些配置意味着:示例是一个面向 x64、Unicode 字符集、依赖dhcpsapi.h头文件的控制台应用,运行前必须保证目标 Windows 具备 DHCP Server 管理 API 支持。
三、核心原理:分页式的枚举调用模式
DhcpV4FailoverEnumRelationship与常见的 Windows 枚举类 API(如EnumServicesStatusEx)一样,采用"分页(paging)"协议:服务器不会一次返回全部数据,而是按批返回,调用方通过循环持续拉取直到取完。
从 EnumRelationship.cpp 主函数 可以看出实际调用形式:
dwError = DhcpV4FailoverEnumRelationship( pwszServer, // 服务器 IP 地址;NULL 表示当前本机 &resumeHandle, // 断点句柄,首次调用为 0,后续调用回传更新值 preferredMax, // 单批期望最大条数;DWORD_MAX 表示采用服务器默认分页大小 &enumRelationInfo, // 输出:本次返回的关系数组 &dwElementsRead, // 输出:本次实际读取到的关系条数 &dwElementsTotal); // 输出:服务器上关系总数各参数含义归纳如下:
| 参数 | 方向 | 说明 |
|---|---|---|
ServerIpAddress(pwszServer) | 入 | 目标 DHCP 服务器的 IP 地址字符串;传NULL代表当前执行程序所在的服务器 |
ResumeHandle(resumeHandle) | 入/出 | 分页续传句柄。首轮调用置 0,之后由 API 写入新值,下一轮调用原样回传 |
PreferredMaximum(preferredMax) | 入 | 调用方期望单批返回的最大条数;示例传DWORD_MAX,即不限制,交由服务器决定 |
EnumRelationshipInfo(enumRelationInfo) | 出 | 指向LPDHCP_FAILOVER_RELATIONSHIP_ARRAY,接收本批关系数据 |
ElementsRead(dwElementsRead) | 出 | 本批实际读到的关系条数 |
ElementsTotal(dwElementsTotal) | 出 | 服务器上关系总数(用于判断是否已取完) |
3.1 返回值语义与循环终止条件
示例 源码的错误处理段 展示了三种关键返回码的配合:
ERROR_SUCCESS(NO_ERROR):本批成功返回;ERROR_MORE_DATA:还有更多数据未取完,应携带更新的resumeHandle继续循环;ERROR_NO_MORE_ITEMS:已无更多条目,枚举结束。
循环逻辑为:
for(;;) { dwError = DhcpV4FailoverEnumRelationship(...); // 1) 除上述三种返回码外的任何错误,打印后直接终止 if ((NO_ERROR != dwError) && (ERROR_MORE_DATA != dwError) && (ERROR_NO_MORE_ITEMS != dwError )) { wprintf(L"Error in enumerating relationships. Error = %d\n", dwError); break; } // 2) 处理本批数据(见下文第四节) if (dwElementsRead && enumRelationInfo) { ... FreeDhcpFailoverRelationshipArray(enumRelationInfo); enumRelationInfo = NULL; } // 3) 取完的标志:返回 ERROR_NO_MORE_ITEMS,或 SUCCESS 且总数为 0 if (ERROR_NO_MORE_ITEMS == dwError || (dwError == ERROR_SUCCESS && dwElementsTotal == 0)) { dwError = ERROR_SUCCESS; break; } // 4) 重置计数,进入下一轮 dwElementsRead = 0; dwElementsTotal = 0; }这段代码是"分页枚举"的通用模板:每轮处理完数据后立即释放输出内存,随后依据返回码决定是否继续,直到收到ERROR_NO_MORE_ITEMS或确认总数已取尽。dwElementsRead在本批没有数据时为 0,enumRelationInfo也为 NULL,因此示例用if (dwElementsRead && enumRelationInfo)双重判断后再进入数据处理分支,避免对空指针解引用。
四、完整源码逐段精讲
4.1 头文件与依赖
EnumRelationship.cpp 顶部包含:
#include<windows.h> #include<stdio.h> #include<intsafe.h> // 安全整数运算辅助头 #include<dhcpsapi.h> // DHCP Server 管理 API 声明,如 DhcpV4FailoverEnumRelationship其中dhcpsapi.h是使用本系列 API 的必经头文件,它声明了DHCP_FAILOVER_RELATIONSHIP、DHCP_FAILOVER_RELATIONSHIP_ARRAY、DHCP_IP_ARRAY等数据结构以及DhcpV4Failover*系列函数原型。
4.2 内存释放辅助函数
API 通过 RPC 返回的数据使用DhcpRpcFreeMemory释放,这是 DHCP Server 管理 API 家族的通用约定。示例为此编写了三个层次分明的释放函数:
- FreeIPArray:释放
LPDHCP_IP_ARRAY,先释放内部Elements数组,再释放结构本身; - FreeDhcpFailoverRelationship:释放单条关系。先逐个释放
RelationshipName、PrimaryServerName、SecondaryServerName、pScopes、SharedSecret等字符串与数组成员,再释放关系结构本体(重载了"按值"与"按指针"两种形式); - FreeDhcpFailoverRelationshipArray:遍历
DHCP_FAILOVER_RELATIONSHIP_ARRAY的pRelationships数组,逐条调用上面的释放函数,最后释放数组本体。
这一组函数是枚举示例的关键配套代码:凡是 API 输出的堆内存,都必须用DhcpRpcFreeMemory精确释放,否则会产生内存泄漏。可以对照 GetRelationship 示例 中结构相同的FreeRelationshipMemory佐证这一内存管理约定。
4.3 枚举结果的处理
示例对每批返回的数据做了最简示范——打印每条关系的名称:
for ( dwIdx = 0; dwIdx < enumRelationInfo->NumElements; dwIdx++ ) { wprintf(L"Relationship name = %s\n", enumRelationInfo->pRelationships[dwIdx].RelationshipName); }DHCP_FAILOVER_RELATIONSHIP_ARRAY结构的两个字段在此处被使用:
NumElements:本数组中关系条数;pRelationships:DHCP_FAILOVER_RELATIONSHIP数组指针,每个元素即一条完整的关系描述(含名称、主辅服务器、模式、MCLT、SafePeriod、百分比、共享机密、作用域列表等字段)。
实际业务中,你可以在循环内根据RelationshipName做筛选、比对或驱动后续操作,例如进一步调用DhcpV4FailoverGetRelationship获取单条关系明细、调用DhcpV4FailoverSetRelationship修改参数等。处理完毕后务必调用FreeDhcpFailoverRelationshipArray释放本批内存并将指针置 NULL。
五、DhcpV4Failover 关系 API 家族与本示例的定位
DhcpV4FailoverEnumRelationship并非孤立 API,它属于 DHCP Server Management API 中管理故障转移关系的一组函数。Windows-classic-samples 仓库在 Samples/DHCP 目录下为这一家族提供了成系列的配套示例,可作为枚举结果的"后续动作"参考:
| 示例目录 | 使用的 API | 源码要点 |
|---|---|---|
| GetRelationship | DhcpV4FailoverGetRelationship | 按关系名"test"查询单条关系,演示DhcpRpcFreeMemory释放模式 |
| SetRelationship | DhcpV4FailoverGetRelationship+DhcpV4FailoverSetRelationship | 先取回关系,再通过dwFlags(MODE、SAFEPERIOD、MCLT、PERCENTAGE位)指定要修改的字段 |
| CreateRelationship | DhcpV4FailoverCreateRelationship/DhcpV4FailoverDeleteRelationship | 完整构造DHCP_FAILOVER_RELATIONSHIP(含pScopes作用域数组),并在主辅服务器上先后建关系 |
| DeleteRelationship | DhcpV4FailoverGetRelationship+DhcpV4FailoverDeleteRelationship | 删除前先停用相关作用域,主、辅服务器分别删除 |
| GetScopeRelationship | DhcpV4FailoverGetScopeRelationship | 按作用域子网地址(如10.0.0.0)反查所属关系 |
从这些源码可以推断:一条完整的关系生命周期通常是"创建(Create)→ 枚举(Enum)→ 查询(Get)→ 修改(Set)→ 删除(Delete)",而EnumRelationship 示例正是"枚举"环节的标准实现范本,其分页循环与内存释放模式可以被其他枚举类 DHCP 管理 API(如DhcpV4EnumPolicies对应仓库中的 EnumPolicy 示例)直接复用。
六、构建与运行
6.1 构建
按 README.md 的说明:
- 使用 Visual Studio Express 2013 for Windows 8.1 或更高版本打开解决方案文件 EnumRelationship.sln;
- 从顶部菜单执行Build → Build Solution(Visual Studio 2013 中为 F6,其余版本通常为 F7);
- 编译产物默认输出到
Debug或Release目录(本工程为 x64 平台下的x64\Debug或x64\Release)。
工程使用v110工具集并链接dhcpsapi.lib,构建时需确保 Windows SDK 提供 DHCP 管理头文件与导入库;更高版本 Visual Studio 打开工程后如提示工具集升级,可按默认处理。
6.2 运行
在 Visual Studio 中按F5(启用调试运行)或Ctrl+F5(不启用调试运行),也可通过Debug菜单选择相应选项。
运行前提与限制(README 与源码共同确认):
- 操作系统需为 Windows 8.1 / Windows Server 2012 R2 及兼容版本;
- 目标机器需具备 DHCP 服务器管理能力(本 API 由 DHCP Server 管理服务承载);
pwszServer传NULL时枚举的是当前执行程序所在机器的 DHCP 服务器,如需枚举远程服务器,可将该参数改为目标服务器的 IP 地址字符串;- 程序以控制台方式运行,枚举结果(关系名称)逐条打印到标准输出;返回码
ERROR_NO_MORE_ITEMS或ERROR_SUCCESS且总数为 0 时正常结束。
七、总结
DhcpV4FailoverEnumRelationship是 Windows DHCP 故障转移管理中的核心枚举接口。通过 EnumRelationship 示例 可以学到一套可复用的标准模式:
- 分页调用:
resumeHandle配合ERROR_MORE_DATA循环拉取,直到ERROR_NO_MORE_ITEMS; - 输出约束:
preferredMax = DWORD_MAX交由服务器决定批次大小,ElementsRead/ElementsTotal用于统计与终止判断; - 内存纪律:所有输出结构必须经
DhcpRpcFreeMemory逐层释放; - 家族协同:与
DhcpV4FailoverGetRelationship、DhcpV4FailoverSetRelationship、DhcpV4FailoverCreateRelationship、DhcpV4FailoverDeleteRelationship、DhcpV4FailoverGetScopeRelationship共同构成关系管理的完整闭环。
后续可在仓库 Samples/DHCP 目录下继续研读上述配套示例,将枚举结果接入真实的运维与自动化管理流程。
- 示例工程
【免费下载链接】Windows-classic-samples
This repo contains samples that demonstrate the API used in Windows classic desktop applications.
相关推荐
Windows-classic-samples 实战:使用 DhcpV4FailoverCreateRelationship API 创建 DHCP 服务器故障转移关系
Windows classic samples 实战:使用 DhcpV4FailoverCreateRelationship API 创建 DHCP 服务器故障
示例工程Windows-classic-samples 实战:使用 DhcpV4FailoverAddScopeToRelationship 将 DHCP 作用域加入故障转移关系
Windows classic samples 实战:使用 DhcpV4FailoverAddScopeToRelationship 将 DHCP 作用域加入故
示例工程Windows DHCP Server 策略枚举实战:DhcpV4EnumPolicies API 用法详解(Windows-classic-samples)
Windows DHCP Server 策略枚举实战:DhcpV4EnumPolicies API 用法详解(Windows classic samples)
示例工程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考