ReactOS 图形系统分析(15):窗口对象 — EWNDOBJ(engwindow.c)
ReactOS 图形系统分析15窗口对象 — EWNDOBJengwindow.c1. 概述engwindow.c位于win32ss/gdi/eng/engwindow.c是 GDI 引擎的窗口对象WNDOBJ/EWNDOBJ管理模块。它让显示驱动能够跟踪窗口的位置与可见区域变化从而优化窗口表面的绘制如硬件加速、合成器。ntuser (WND 窗口对象位置/尺寸/可见区域) ↓ VIS_ComputeVisibleRegion 计算可见区域 engwindow.c (EWNDOBJ 管理 ← 本分析对象) ├── EngCreateWnd / EngDeleteWnd 生命周期 ├── IntEngWndUpdateClipObj 从 WND 更新裁剪对象 ├── IntEngWindowChanged 窗口变化通知回调驱动 └── WNDOBJ_bEnum / cEnumStart 可见区域矩形枚举 ↓ 显示驱动 (通过 WNDOBJCHANGEPROC 接收变化通知)核心思想驱动创建窗口表面时调用EngCreateWnd获得 WNDOBJ之后窗口移动/改变大小时引擎通过WNDOBJCHANGEPROC回调通知驱动驱动可据此高效更新例如只重绘露出部分或跟踪精灵位置。2. 核心数据结构2.1 EWNDOBJ扩展窗口对象[engobjects.h](file:///d:/reactos/win32ss/gdi/eng/engobjects.h#L92-L105)typedefstruct_EWNDOBJ:_XCLIPOBJ// 继承CLIPOBJ RWNDOBJ 裁剪私有字段{/* 扩展窗口对象部分 */HWND Hwnd;// 关联的窗口句柄WNDOBJCHANGEPROC ChangeProc;// 变化回调驱动注册FLONG Flags;// 关心的变化标志intPixelFormat;// 像素格式OpenGL 用}EWNDOBJ,*PEWNDOBJ;2.2 WNDOBJDDI 公开部分 CLIPOBJ RWNDOBJtypedefstruct_RWNDOBJ{PVOID pvConsumer;// 驱动私有数据RECTL rclClient;// 客户区矩形SURFOBJ*psoOwner;// 所有者表面}RWNDOBJ;/* WNDOBJ CLIPOBJ RWNDOBJ通过 _WNDOBJ 别名引用 */WNDOBJ 本质是一个特殊的 CLIPOBJ它的裁剪区域 窗口的可见客户区。驱动通过WNDOBJ_bEnum/WNDOBJ_cEnumStart枚举可见矩形复用 CLIPOBJ 机制见《ReactOS 图形系统分析_8.md》。2.3 变化标志驱动请求的标志WO_*EngCreateWnd 的 fl 参数标志含义WO_RGN_CLIENT客户区变化通知WO_RGN_CLIENT_DELTA客户区增量变化WO_RGN_SURFACE表面区域变化WO_RGN_SURFACE_DELTA表面区域增量变化WO_DRAW_NOTIFY绘制通知WO_SPRITE_NOTIFY精灵重叠通知WO_RGN_WINDOW / WO_RGN_DESKTOP_COORD / WO_RGN_UPDATE_ALL未实现FIXME引擎触发的回调标志WOC_*标志含义WOC_RGN_CLIENT客户区可见区域已更新WOC_CHANGED窗口已变化WOC_DELETE窗口对象将被删除WOC_DRAWN已绘制WOC_SPRITE_OVERLAP / WOC_SPRITE_NO_OVERLAP精灵重叠/不重叠3. 核心函数分析3.1 创建 — EngCreateWnd是否失败失败EngCreateWnd(pso, hWnd, pfn, fl, iPixelFormat)UserEnterExclusive(用户子系统独占锁)fl 含未支持标志?(WO_RGN_WINDOW 等)FIXME 警告继续UserGetWindowObject(hWnd)获取窗口对象退出返回 NULL分配 EWNDOBJEngAllocMemIntEngInitClipObj(Rects 指向内嵌 rclBounds)IntEngWndUpdateClipObj用窗口可见区域填充裁剪对象释放内存填充 DDI 公开部分psoOwner pso, pvConsumer NULL填充内部字段Hwnd/ChangeProc/Flags/PixelFormatUserSetProp 关联到窗口(AtomWndObj 属性)gcountPWOUserLeave 返回 WNDOBJ关键代码WNDOBJ*APIENTRYEngCreateWnd(SURFOBJ*pso,HWND hWnd,WNDOBJCHANGEPROC pfn,FLONG fl,intiPixelFormat){WindowUserGetWindowObject(hWnd);// 1. 取窗口对象if(WindowNULL)gotoExit;ClipEngAllocMem(FL_ZERO_MEMORY,sizeof(EWNDOBJ),GDITAG_WNDOBJ);IntEngInitClipObj((XCLIPOBJ*)Clip);// 2. 初始化裁剪对象/* 3. 用窗口可见区域填充裁剪对象 */if(!IntEngWndUpdateClipObj(Clip,Window)){EngFreeMem(Clip);gotoExit;}/* 4. 填充 DDI 公开部分 */WndObjUser(WNDOBJ*)Clip;WndObjUser-psoOwnerpso;WndObjUser-pvConsumerNULL;/* 5. 填充内部字段 */Clip-HwndhWnd;Clip-ChangeProcpfn;Clip-Flagsfl(WO_RGN_CLIENT_DELTA|WO_RGN_CLIENT|WO_RGN_SURFACE_DELTA|WO_RGN_SURFACE|WO_DRAW_NOTIFY);if(flWO_SPRITE_NOTIFY)Clip-Flags|WOC_SPRITE_OVERLAP|WOC_SPRITE_NO_OVERLAP;Clip-Flags|WOC_CHANGED|WOC_DELETE;// 始终发送Clip-PixelFormatiPixelFormat;/* 6. 通过窗口属性关联到窗口 */UserSetProp(Window,AtomWndObj,Clip,TRUE);gcountPWO;returnWndObjUser;}要点只保存驱动请求的标志fl WO_*回调时按此过滤WOC_CHANGED/WOC_DELETE始终加入 Flags这些通知必须发送通过AtomWndObj窗口属性把 EWNDOBJ 挂到窗口上窗口变化时能找回3.2 从窗口更新裁剪对象 — IntEngWndUpdateClipObjBOOLEAN FASTCALLIntEngWndUpdateClipObj(EWNDOBJ*Clip,PWND Window){/* 计算窗口的可见区域考虑兄弟窗口遮挡 */visRgnVIS_ComputeVisibleRegion(Window,TRUE,TRUE,TRUE);if(visRgn!NULLvisRgn-rdh.nCount0){/* 可见区域 → 裁剪对象多矩形 → DC_COMPLEX */IntEngUpdateClipRegion((XCLIPOBJ*)Clip,visRgn-rdh.nCount,visRgn-Buffer,visRgn-rdh.rcBound);REGION_Delete(visRgn);}else{/* 退化为客户区矩形 */IntEngUpdateClipRegion((XCLIPOBJ*)Clip,1,Window-rcClient,Window-rcClient);}/* 更新客户区矩形和唯一性标志 */Clip-rclClientWindow-rcClient;Clip-iUniq;returnTRUE;}要点VIS_ComputeVisibleRegion计算窗口的真实可见区域扣除被覆盖部分——多矩形时裁剪对象变为DC_COMPLEX驱动用WNDOBJ_bEnum枚举可见矩形只绘制可见部分。3.3 窗口变化通知 — IntEngWindowChanged窗口移动/改变尺寸/删除时由 ntuser 调用VOID FASTCALLIntEngWindowChanged(PWND Window,FLONG flChanged){ClipUserGetProp(Window,AtomWndObj,TRUE);// 找回 WNDOBJif(!Clip)return;switch(flChanged){caseWOC_RGN_CLIENT:/* 更新裁剪对象和客户区 */IntEngWndUpdateClipObj(Clip,Window);break;caseWOC_DELETE:/* FIXME: WNDOBJ 由 win32k 还是驱动删除 */break;}/* 调用驱动回调 */IntEngWndCallChangeProc(Clip,flChanged);/* HACK: WOC_RGN_CLIENT 后再发 WOC_CHANGED */if(flChangedWOC_RGN_CLIENT)IntEngWndCallChangeProc(Clip,WOC_CHANGED);}3.4 回调调度 — IntEngWndCallChangeProcVOID FASTCALLIntEngWndCallChangeProc(EWNDOBJ*Clip,FLONG flChanged){if(Clip-ChangeProcNULL)return;/* 按驱动请求的标志过滤 */flChangedClip-Flags;if(flChanged0)return;/* WOC_CHANGED 无矩形数据传 NULL其余传 WNDOBJ 指针 */if(flChangedWOC_CHANGED)Clip-ChangeProc(NULL,flChanged);elseClip-ChangeProc((WNDOBJ*)Clip,flChanged);}3.5 删除 — EngDeleteWndVOID APIENTRYEngDeleteWnd(WNDOBJ*pwo){Clip(EWNDOBJ*)pwo;/* 从窗口移除属性 */WindowUserGetWindowObject(Clip-Hwnd);if(Window)UserRemoveProp(Window,AtomWndObj,TRUE);--gcountPWO;/* 释放资源Rects 堆数组 对象本身 */IntEngFreeClipResources((XCLIPOBJ*)Clip);EngFreeMem(Clip);}3.6 DDI 枚举函数驱动侧/* 枚举可见矩形转给 CLIPOBJ_bEnum */BOOL APIENTRYWNDOBJ_bEnum(WNDOBJ*pwo,ULONG cj,ULONG*pul){returnCLIPOBJ_bEnum(pwo-coClient,cj,pul);}/* 枚举初始化转给 CLIPOBJ_cEnumStart */ULONG APIENTRYWNDOBJ_cEnumStart(WNDOBJ*pwo,ULONG iType,ULONG iDirection,ULONG cLimit){returnCLIPOBJ_cEnumStart(pwo-coClient,FALSE,iType,iDirection,cLimit);}要点WNDOBJ 的枚举完全复用 CLIPOBJ 机制——WNDOBJ 本质就是带窗口语义的 CLIPOBJ。3.7 设置消费者 — WNDOBJ_vSetConsumerVOID APIENTRYWNDOBJ_vSetConsumer(WNDOBJ*pwo,PVOID pvConsumer){Hack(pwo-pvConsumerNULL);pwo-pvConsumerpvConsumer;// 保存驱动私有数据/* HACK: 首次设置时补发初始状态MSDN 要求创建后回调最近状态 */if(Hack){IntEngWndCallChangeProc(Clip,WOC_RGN_CLIENT);IntEngWndCallChangeProc(Clip,WOC_CHANGED);IntEngWndCallChangeProc(Clip,WOC_DRAWN);}}4. 数据流窗口变化 → 驱动收到通知显示驱动engwindow.cntuser (WND 窗口)显示驱动engwindow.cntuser (WND 窗口)驱动创建窗口表面窗口移动/改变尺寸驱动处理销毁EngCreateWnd (pso, hWnd, ChangeProc, fl)UserGetWindowObject VIS_ComputeVisibleRegionWNDOBJ (含可见区域 CLIPOBJ)IntEngWindowChanged (WOC_RGN_CLIENT)VIS_ComputeVisibleRegion (重新计算)IntEngWndUpdateClipObj (更新裁剪对象 iUniq)ChangeProc(WNDOBJ, WOC_RGN_CLIENT)ChangeProc(NULL, WOC_CHANGED)WNDOBJ_cEnumStart / WNDOBJ_bEnum (枚举可见矩形)可见矩形列表只重绘可见区域 (硬件加速)EngDeleteWndUserRemoveProp (解除关联)5. 设计特点总结WNDOBJ 即特殊 CLIPOBJ窗口对象继承 CLIPOBJ裁剪区域 窗口可见区域枚举完全复用 CLIPOBJ 机制。可见区域计算VIS_ComputeVisibleRegion计算扣除遮挡后的真实可见区域多矩形 → DC_COMPLEX。回调过滤只发送驱动请求的标志flChanged Clip-Flags减少无关通知。窗口属性关联通过AtomWndObj属性把 WNDOBJ 挂到窗口窗口变化可快速找回。iUniq 失效标记裁剪区域每次更新iUniq驱动可据此判断缓存是否失效。HACK 兼容创建/设置消费者时补发初始状态通知符合 MSDN 对 WNDOBJCHANGEPROC 的约定。精灵通知预留WO_SPRITE_NOTIFY支持精灵重叠跟踪未完整实现。6. 源码索引位置关键内容[engwindow.c](file:///d:/reactos/win32ss/gdi/eng/engwindow.c#L18-L44)IntEngWndCallChangeProc回调过滤调度[engwindow.c](file:///d:/reactos/win32ss/gdi/eng/engwindow.c#L49-L92)IntEngWndUpdateClipObj可见区域 → 裁剪对象[engwindow.c](file:///d:/reactos/win32ss/gdi/eng/engwindow.c#L97-L138)IntEngWindowChanged窗口变化通知[engwindow.c](file:///d:/reactos/win32ss/gdi/eng/engwindow.c#L143-L214)EngCreateWnd创建[engwindow.c](file:///d:/reactos/win32ss/gdi/eng/engwindow.c#L220-L250)EngDeleteWnd删除[engwindow.c](file:///d:/reactos/win32ss/gdi/eng/engwindow.c#L256-L317)WNDOBJ_bEnum / cEnumStart / vSetConsumer[engobjects.h](file:///d:/reactos/win32ss/gdi/eng/engobjects.h#L42-L46)RWNDOBJ 结构[engobjects.h](file:///d:/reactos/win32ss/gdi/eng/engobjects.h#L92-L105)EWNDOBJ 结构关联模块[eng/clip.c](file:///d:/reactos/win32ss/gdi/eng/clip.c) — CLIPOBJ 机制WNDOBJ 的继承基础[ntuser/window.c](file:///d:/reactos/win32ss/user/ntuser/window.c) — WND 窗口对象上游[ntuser/vis.c](file:///d:/reactos/win32ss/user/ntuser/vis.c) — VIS_ComputeVisibleRegion 可见区域计算关联文档《ReactOS 图形系统分析_4.md》— GDI 引擎整体架构本文件是窗口对象子模块《ReactOS 图形系统分析_8.md》— 裁剪管理WNDOBJ 复用的 CLIPOBJ 机制本文档基于 ReactOS 源代码win32ss/gdi/eng/engwindow.c分析2026 年 8 月

相关新闻

大语言模型指令遵循难题:技术根源与高级提示工程解决方案

大语言模型指令遵循难题:技术根源与高级提示工程解决方案

这次我们来看一个关于大语言模型(LLM)行为模式的技术分析。你有没有遇到过这种情况:你向ChatGPT、Claude或者任何本地部署的模型提出了一个明确的问题或指令,但它的回答却完全跑偏,或者自作主张地添加了你没要求的内容…

2026/10/17 21:40:03 阅读更多 →
Sublime Text 4 超详细安装与高效配置指南:从下载到插件生态

Sublime Text 4 超详细安装与高效配置指南:从下载到插件生态

1. 为什么你需要一个“超详细”的安装教程? 如果你在搜索引擎里敲下“Sublime Text4 安装”,大概率会得到一堆千篇一律的“三步走”指南:下载、安装、打开。这没错,但往往也仅此而已。作为一个从Sublime Text 2时代就开始用的老用…

2026/10/10 19:18:32 阅读更多 →
Zotero重复文献清理完整指南:用ZoteroDuplicatesMerger一键合并,30分钟让文献库恢复清爽

Zotero重复文献清理完整指南:用ZoteroDuplicatesMerger一键合并,30分钟让文献库恢复清爽

Zotero重复文献清理完整指南:用ZoteroDuplicatesMerger一键合并,30分钟让文献库恢复清爽 【免费下载链接】ZoteroDuplicatesMerger A zotero plugin to automatically merge duplicate items 项目地址: https://gitcode.com/gh_mirrors/zo/ZoteroDupli…

2026/10/16 13:14:37 阅读更多 →

最新新闻

算法习题答案背后的机制:递归、复杂度与工程避坑

算法习题答案背后的机制:递归、复杂度与工程避坑

简介:《数据结构与算法分析(Java语言描述)》第三版教材的配套习题答案文档,适合正在系统学习数据结构和算法、需要用习题检验自身理解的Java学习者与备考学生。文档覆盖文件处理与递归调用、递归算法设计(如求整数二进…

2026/10/17 21:39:43 阅读更多 →
MySQL学生成绩管理系统数据库设计与建表实战指南

MySQL学生成绩管理系统数据库设计与建表实战指南

简介:一套完整的基于Python Flask与MySQL数据库的学生成绩管理系统课程设计报告,适用于计算机科学与技术、软件工程等专业的学生,也适合自学Web开发并需要完成数据库课程设计任务的人。系统围绕学生成绩管理核心业务展开,覆盖在线…

2026/10/17 21:39:43 阅读更多 →
语音识别中的CTC与RNN-T:端到端对齐与工程选型详解

语音识别中的CTC与RNN-T:端到端对齐与工程选型详解

如果你正好在啃语音识别的经典教材或者课程,大概率会在前几章就碰到 CTC 和 RNN-T 这两个名字。我当年第一次看到这两个缩写,脑子里全是问号:CTC 不是通讯技术么,RNN-T 和 RNN 又差在哪?后来在几个语音项目里真正把这两…

2026/10/17 21:39:43 阅读更多 →
144页Transformer讲义精读指南:从注意力机制到工程实践

144页Transformer讲义精读指南:从注意力机制到工程实践

简介:这份144页PPT配套视频课程,面向希望系统掌握Transformer架构的NLP学习者、算法工程师与高校师生,从序列建模的经典方法讲起,逐步深入到注意力机制、大语言模型与高效Transformer等前沿内容。包内共1个PDF文件,约5…

2026/10/17 21:39:43 阅读更多 →
Kafka接入AI的三种路线:MCP提案、会话记忆与实时上下文

Kafka接入AI的三种路线:MCP提案、会话记忆与实时上下文

1. 从一条业务问题说起:Kafka 和 AI 之间到底缺了什么我大概从 2016 年开始重度使用 Kafka,最开始是帮一家电商公司搭日志管道,后来陆续做过金融风控事件流、IoT 设备数据上报、实时数仓同步,再到近两年开始给大模型应用做数据底座…

2026/10/17 21:39:43 阅读更多 →
Python Flask+MySQL学生成绩管理系统:数据库设计与触发器实践

Python Flask+MySQL学生成绩管理系统:数据库设计与触发器实践

简介:围绕 MySQL 学生成绩管理系统展开的数据库课程设计文档,完整覆盖系统总体设计、需求分析、概要设计、系统实现与测试总结全流程,适合计算机专业学生用于数据库课设、毕业设计或 FlaskMySQL 入门实践。文档以华东交通大学课程设计报告为原…

2026/10/17 21:38:42 阅读更多 →

日新闻

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

简介:《DeepSeek使用方法.pdf》是一份面向DeepSeek入门及进阶用户的完整使用指南,重点围绕V3与R1两款模型的能力差异与适用场景展开,帮助读者根据任务类型与成本选择合适的模型。资源共1个PDF文件,压缩包大小约311KB,篇…

2026/10/17 0:00:25 阅读更多 →
200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

简介:这是一份聚焦DeepSeek提示词优化的《200Deepseek润色指令》PDF文档,共收录两百余条可直接套用的润色指令,涵盖语法修正、风格统一、逻辑梳理、表达精炼等维度,并针对商务写作、学术论文、广告文案等场景给出差异化建议。文档…

2026/10/17 0:00:25 阅读更多 →
OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

简介:本资源是一份基于OpenCV的本科课程设计完整报告,面向计算机视觉初学者、图像处理学习者及高校通信/信息类专业学生,解决物体智能计数与检测结果结构化记录的实际问题。项目覆盖图像预处理、轮廓检测、边界框绘制、轨迹栏交互式参数调节、…

2026/10/17 0:00:25 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/16 21:35:51 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/17 1:44:59 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/16 15:04:24 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 21:54:38 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 14:23:36 阅读更多 →