样例深度解析:从 DLL 源码到注册与 .ini 配置的完整实战)
示例工程【免费下载链接】Windows-classic-samplesThis repo contains samples that demonstrate the API used in Windows classic desktop applications.项目地址https://gitcode.com/gh_mirrors/wi/Windows-classic-samples点击查看免费下载本文围绕 Windows-classic-samples 仓库中的 FilterProvider 样例 展开讲解如何在 Windows Deployment ServicesWDS的 PXE Server 上用 C 编写一个过滤器型 PXE Provider DLL它在有序的 Provider 列表最前端充当闸门根据一个纯文本 .ini 文件中的策略决定哪些 PXE 客户端被放行给下游如 WDSDCPXE/BINL继续服务、哪些被直接拒绝。读完本文你将掌握 PXE Provider 的注册表注册方式、PxeProviderInitialize/PxeProviderRecvRequest等核心回调的写法、配置文件格式以及完整的端到端部署流程。WDS 与 PXE Provider 插件模型过滤器 Provider 的定位WDS 网络安装场景Windows Deployment ServicesWDS用于通过网络完成 Windows 操作系统的批量部署客户端机器可以基于网络启动PXE Boot进入 Windows PE 安装环境从而无需管理员逐台访问每台机器、也无需使用 CD/DVD 介质逐台安装。WDS 服务器承担了引导映像分发、安装映像管理以及 PXE 网络引导等核心职责。PXE Server 与 PXE Provider 双层结构从实现上看WDS 的 PXE Server 可以被拆分为两个部分PXE Server与PXE Provider插件PXE Server负责核心网络能力包括监听网络、解析 DHCP/PXE 报文、维护与客户端的网络会话等PXE Provider是一组插件plug-in官方文档将其称为PXE Providers。PXE Server 对外暴露插件接口允许开发者在复用同一套 PXE Server 核心网络代码的基础上开发自定义的 PXE 解决方案。标准 WDS 服务器自带WDSDCPXE提供程序负责将请求交给 BINL 等上层服务处理。插件模型的意义在于你可以编写自己的 Provider DLL与WDSDCPXE并存运行甚至替换它。过滤器 ProviderProvider 列表中的闸门在注册表中PXE Provider 按ProvidersOrder组成一个有序列表WDSPXE 会把进来的 PXE 请求依次交给列表中的 Provider。本样例实现的是一个filter provider过滤器提供程序它被放在列表最前面位于WDSDCPXE或任何其他 PXE Provider之前像一个闸门如果希望自己的 Provider总是拥有应答 PXE 请求的第一机会就应把它排在列表首位过滤器 Provider 自身不提供真正的引导/下载服务它只裁决这个客户端的请求是否允许流向下一个 Provider与标准实现把数据存放在 Active Directory 中不同本样例把过滤数据存放在一个纯文本文件里见 cpp/README.txt便于直接查看和修改。样例文件清单与工程构成样例位于 Samples/WindowsDeploymentServices/FilterProvidercpp子目录下共 5 个文件各自职责如下文件说明FilterProv.cpp主 DLL 源码文件包含全部必需的 DLL 入口点与辅助函数实现FilterProv.h头文件包含所需头文件并定义辅助数据结构与常量FilterProv.sln解决方案文件用 Visual Studio 打开后即可生成 DLLFilterProv.vcxprojVisual Studio 项目文件记录工具集版本、平台/配置与项目属性FilterProv.def模块定义文件声明 DLL 必须导出的函数供 WDS PXE Server 加载从 FilterProv.vcxproj 可以看到工程的关键属性配置类型为DynamicLibrary即产出 DLL字符集为Unicode四种构建组合Debug/Release × Win32/x64工具集为v110链接器依赖wdspxe.libWDS PXE 提供程序 API 的导入库这是编写 PXE Provider 必需的链接项通过ModuleDefinitionFilefilterprov.def/ModuleDefinitionFile指定模块定义文件。FilterProv.def 的内容极简但关键——它导出唯一的入口函数LIBRARY FilterProv EXPORTS PxeProviderInitializeWDSPXE 在加载 Provider DLL 时正是通过查找并调用这个PxeProviderInitialize导出函数来完成初始化的。核心源码解析一个过滤器 Provider 的完整实现DllMain保存模块实例句柄FilterProv.cpp 中的DllMain在DLL_PROCESS_ATTACH时把模块实例句柄保存到全局变量g_hInstance供后续构造配置文件路径时使用GetModuleFileName需要这个句柄。PxeProviderInitialize初始化、回调注册与请求过滤属性PxeProviderInitialize是 WDSPXE 调用的第一个函数FilterProv.cpp其工作分四步读取策略配置调用InitializeConfiguration()构造配置文件路径并校验全局策略注册关闭回调PxeRegisterCallback(hProvider, PXE_CALLBACK_SHUTDOWN, PxeProviderShutdown, NULL)当 WDSPXE 需要关闭 Provider 时回调PxeProviderShutdown注册请求处理回调PxeRegisterCallback(hProvider, PXE_CALLBACK_RECV_REQUEST, PxeProviderRecvRequest, NULL)注册接收客户端请求的处理函数声明只处理 PXE 类型的请求调用PxeProviderSetAttribute(hProvider, PXE_PROV_ATTR_FILTER, uFilter, sizeof(uFilter))其中uFilter PXE_PROV_FILTER_PXE_ONLY。从源码注释看该属性表示 Provider只接收合法 DHCP 报文且包含 Option 60 PXEClient的请求从而避免处理无关的 DHCP 流量。最后把 Provider 句柄存入全局g_hFilterProvider供PxeTrace日志输出使用。PxeProviderRecvRequest逐请求决策这是过滤器 Provider 的核心决策函数FilterProv.cpp。每次收到 PXE 请求时WDSPXE 同步调用它处理流程如下通过GetClientMacAddress()从 DHCP 报文中提取客户端 MAC 地址并格式化为字符串用GetPrivateProfileString()在配置文件的[Devices]段中查找该 MAC若命中读取对应的设备级策略Allow1/Deny0并校验取值合法性非法值一律按Deny处理若未命中则使用全局策略g_uFilterPolicy来自[Configuration]段的Policy键进行裁决。最终决策以PXE_BOOT_ACTION形式写入输出参数pAction同时把各参数的忽略意图写得很清楚hClientRequest、uPacketLen、pLocalAddress、pRemoteAddress、pContext在本实现中均未使用UNREFERENCED_PARAMETER全部决策只依赖报文中的 MAC 与配置文件。GetClientMacAddress从 DHCP 报文提取并格式化 MACGetClientMacAddressFilterProv.cpp把PXE_DHCP_MESSAGE中的硬件地址转换为定长字符串DHCP 报文中的HardwareAddress字段长度不定由HardwareAddressLength给出函数先用MoveMemory把它右对齐放入长度为PXE_DHCP_HWAADR_SIZE的缓冲区左侧自动补零随后逐字节将高 4 位、低 4 位转成十六进制字符0-9、A-F字母为大写。结合 FilterProv.h 中的定义MAX_MAC_ADDR_STRING_LEN PXE_DHCP_HWAADR_SIZE * 2 1以及 README 中MAC 字符串必须为 32 个字符的要求可以推断PXE_DHCP_HWAADR_SIZE为 16DHCPchaddr字段大小16 字节展开为 32 个十六进制字符外加一个终止符。这也正是配置文件[Devices]段键名必须是 32 字符12 位 MAC 前补 20 个0的原因——源码生成的字符串格式必须与配置文件键名精确一致。InitializeConfiguration配置文件路径构造与策略校验InitializeConfigurationFilterProv.cpp负责用GetModuleFileName取得 DLL 的完整路径用StringCchCat追加后缀FILTER_CONFIG_FILE_SUFFIX在 FilterProv.h 中定义为L.filter.ini从而得到配置文件filterprov.dll.filter.ini——配置文件永远与 DLL 同目录、以 DLL 名 .filter.ini命名用GetFileAttributes确认配置文件存在不存在则报错读取[Configuration]段的Policy键将其解析为整数并校验只接受 0 或 1其余值视为数据无效通过PxeTrace(g_hFilterProvider, PXE_TRACE_INFO, ...)输出日志策略为Deny时记录Filter Policy: Exclude为Allow时记录Filter Policy: Include。决策逻辑对照表结合 README 的语义描述与源码映射完整决策逻辑如下客户端状态配置取值源码返回动作FilterProv.cpp效果README.txt 描述MAC 命中[Devices]1AllowPXE_BA_REJECTED放行请求被转发给有序列表中的下一个 ProviderMAC 命中[Devices]0DenyPXE_BA_IGNORE拒绝请求不被应答也不转发给下一个 ProviderMAC 未命中Policy1AllowPXE_BA_REJECTED放行未知设备被允许继续流向下一个 ProviderMAC 未命中Policy0DenyPXE_BA_IGNORE拒绝未知设备被拒绝 PXE 服务请求就此终止需要说明的是README.txt 站在管理员意图角度描述 Deny/Allow 的最终效果而 FilterProv.cpp 将允许映射为返回PXE_BA_REJECTED、将拒绝映射为返回PXE_BA_IGNOREPXE_BOOT_ACTION枚举值由 WDSPXE 在运行时解释若需要精确的行为语义请以 WDS PXE API 文档为准。注册 Provider让 WDSPXE 认识你的 DLL根据 cpp/README.txt 的说明注册一个 Provider 需要两个步骤第一步创建代表你的 Provider 的注册表键在以下路径下创建一个新键键名自定例如FilterProviderHKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WDSServer\Providers\WDSPXE\Providers在该新键下创建一个值指定 Provider DLL 的路径属性取值名称NameProviderDLL类型TypeREG_EXPAND_SZ值Value自定义 Provider DLL 的完整路径与文件名第二步指定 Provider 在有序列表中的位置修改父键HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WDSServer\Providers\WDSPXE\Providers在该键下创建一个多字符串值属性取值名称NameProvidersOrder类型TypeREG_MULTI_SZ值Value第一步中创建的键名如FilterProviderWDSPXE 会按照ProvidersOrder中列出的顺序把收到的 PXE 请求依次交给注册的 Provider想让自己的 Provider 永远拥有应答请求的第一机会就把它排在列表最前面。以管理员身份在 WDS 服务器上执行的等效命令示例如下依据 README 描述的注册表结构整理reg add HKLM\SYSTEM\CurrentControlSet\Services\WDSServer\Providers\WDSPXE\Providers\FilterProvider /v ProviderDLL /t REG_EXPAND_SZ /d C:\WDS\filterprov.dll /f reg add HKLM\SYSTEM\CurrentControlSet\Services\WDSServer\Providers\WDSPXE\Providers /v ProvidersOrder /t REG_MULTI_SZ /d FilterProvider /f配置文件 filterprov.dll.filter.ini 详解命名与位置规则编译产物必须是 DLL 形式例如filterprov.dll配置文件必须命名为filterprov.dll.filter.ini且与 DLL 放在同一目录。命名规则由源码中的FILTER_CONFIG_FILE_SUFFIXL.filter.ini强制保证。[Configuration] 段Policy 键该段只有一个键Policy决定未知设备不在[Devices]段中的设备是否继续流向有序列表中的下一个 Provider取值语义效果0Deny拒绝所有未知设备被样例 Provider 拒绝 PXE 服务请求不被应答也不转发给有序列表中的下一个 PXE Provider1Allow允许所有未知设备被放行请求被转发给有序列表中的下一个 PXE Provider[Devices] 段按 MAC 的设备级策略该段列出所有已知设备键名设备的 MAC 地址字符串长度必须为32 个字符12 位十六进制 MAC 地址前补 20 个0值0 或 1含义与全局Policy一致——0Deny拒绝请求且不转发给下一个 Provider、1Allow把请求转发给有序列表中的下一个 Provider由下游 Provider 决定是否提供服务。由于源码在转换 MAC 时使用大写A-F配置文件中 MAC 的字母部分应使用大写以保证精确匹配。官方文档示例中的 MAC 位数略有出入实际配置时应填写完整的 12 位十六进制 MAC使键名严格保持 32 字符。完整配置示例一仅放行指定设备白名单模式[Configuration] Policy0 [Devices] 00000000000000000000FEFEDEBCBA1 00000000000000000000123456789AB1Policy0意味着默认拒绝所有未知设备[Devices]中值为1的两台设备被放行。净效果是只有列出的设备能到达下一个 Provider 并获得 PXE 服务。完整配置示例二仅拒绝指定设备黑名单模式[Configuration] Policy1 [Devices] 00000000000000000000FEFEDEBCBA0 00000000000000000000123456789AB0Policy1意味着默认放行所有未知设备[Devices]中值为0的两台设备被拒绝。净效果是除列出的设备外其余设备都流向下一个 Provider列出的设备被拒绝 PXE 服务。端到端运行流程Walkthrough使用该样例过滤器 Provider 的完整操作步骤如下把样例代码编译成 DLL如filterprov.dll按上述格式创建 .ini 配置文件命名为filterprov.dll.filter.ini并放在与 DLL 相同的目录将样例 Provider 注册为有序 Provider 列表中的第一个用 PXE 启动一台客户端机器。此时决策链路为a. PXE Server 把请求交给有序列表中的第一个 Provider按第 3 步即本样例 Providerb. 样例 Provider 在文件[Devices]段中查找引导中的设备若命中则遵循该设备指定的策略Allow/Denyc. 若未命中则读取[Configuration]段的Policy值并遵循之d. 任何没有被样例 Provider 过滤掉的请求都会被传递给有序列表中的下一个已注册 Provider。环境要求、构建与运行系统要求角色要求客户端无受支持的系统本样例面向服务器端开发服务器Windows Server 2012 R2准备 WDS 服务器除安装服务器角色外完成本样例还需要在 Windows Server 2012 R2 上安装 Windows Deployment Services 服务器角色初始化 WDS 服务器向服务器添加引导映像Boot.wim。Boot.wim 是一份 Windows PE 映像客户端机器可引导进入其中以安装操作系统该文件位于 Windows 产品 DVD 上。构建启动 Visual Studio选择File Open Project/Solution进入样例目录双击打开FilterProv.sln按F7Visual Studio 2013 为 F6或使用Build Build Solution构建样例产出filterprov.dllDebug/Release、Win32/x64 四种组合均可工程已通过wdspxe.lib链接 WDS PXE API。运行与调试README 中 F5Debug Start Debugging与 CtrlF5Debug Start Without Debugging是 Visual Studio 调试运行的一般流程就本样例而言产物是供 WDSPXE 加载的 DLL并没有独立可执行入口实际运行是将其注册到ProviderDLL指向的路径后由 WDS PXE Server 进程加载再通过 PXE 客户端触发请求来验证过滤效果。更详细的运行说明请参阅随样例附带的 cpp/README.txt。小结Windows-classic-samples 中的 FilterProvider 样例完整演示了一条自定义 WDS PXE Provider 的研发链路从 FilterProv.def 导出PxeProviderInitialize到 FilterProv.cpp 中实现初始化、回调注册、请求裁决与配置加载再到注册表ProvidersOrder排序与.filter.ini文本配置。理解这个样例后你可以在此基础上扩展更复杂的过滤逻辑例如结合数据库、AD 查询或策略服务在完全复用 WDS PXE Server 核心网络能力的前提下构建属于自己企业的 PXE 准入与分发方案。赞分享示例工程【免费下载链接】Windows-classic-samplesThis repo contains samples that demonstrate the API used in Windows classic desktop applications.项目地址https://gitcode.com/gh_mirrors/wi/Windows-classic-samples点击查看免费下载相关推荐Windows-classic-samples EAPHost 客户端方法示例深度解析从 DLL 注册到认证状态机的完整实现Windows classic samples EAPHost 客户端方法示例深度解析从 DLL 注册到认证状态机的完整实现 本文基于 EapHostClie示例工程Windows-classic-samples深度解析从DirectX到UIAutomation的完整API参考Windows classic samples深度解析从DirectX到UIAutomation的完整API参考 Windows经典桌面应用程序开发从未如此简示例工程Windows-classic-samples 实战通过 InitialSessionState 向 Runspace 注册自定义 CmdletRunspace10 示例解析Windows classic samples 实战通过 InitialSessionState 向 Runspace 注册自定义 CmdletRunspa示例工程上一篇5个实用案例设计师如何用Inpaint-web浏览器工具提升工作流效率下一篇Eventos Tech Brasil 国际化域名为何选择.eventostechbrasil.com而非其他创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考