- 图形学
- 桌面应用
【免费下载链接】RGF_CJ
RGF是仓颉Windows系统下的通用渲染框架(兼应用开发框架)。RGF仓颉版(后续简称"RGF")基于RGF(C/C++版)封装优化而来。RGF为开发者提供轻量化、安全、高性能以及高度一致性的2D渲染能力以及常用的桌面应用开发工具,并且提供对接Direct3D的相关接口,以满足开发者对3D画面渲染的需求。在Windows开发方面,RGF在子包内也提供开箱即用的Windows API,确保熟悉Win32的开发者快速上手。此外,RGF还提供一些常用功能的封装(如XAudio2、MF),以辅助开发者实现音频、摄像头等扩展功能的管理。
本文围绕rgf.win_def子包中的tagSTYLESTRUCT结构体展开,讲解它在 Win32 窗口风格变更消息(WM_STYLECHANGING/WM_STYLECHANGED)中的作用、字段含义与内存布局,并结合 RGF 仓颉版的核心事件分发源码,演示如何通过EvStyleChange事件对象拦截窗口风格变更、修正新风格值并将其写回系统。读完后你将掌握在 RGF 中监听、干预窗口风格(如WS_VISIBLE、WS_THICKFRAME等)位变化的完整链路。
tagSTYLESTRUCT 的结构定义与字段
tagSTYLESTRUCT是 Win32 窗口风格变更消息的核心参数结构体,在 RGF 中以@C标注的 C 兼容结构体形式定义于 src/win_def/hwinuser.cj:
@C public struct tagSTYLESTRUCT { public var styleOld:DWORD = 0; public var styleNew:DWORD = 0; } public type STYLESTRUCT = tagSTYLESTRUCT public type LPSTYLESTRUCT = CPointer<tagSTYLESTRUCT>其完整定义见 API 文档 doc/api/rgf.win_def/结构体/tagSTYLESTRUCT.md。各成员含义如下:
| 成员 | 类型 | 默认值 | 说明 |
|---|---|---|---|
styleOld | DWORD | 0 | 窗口被更改的旧风格值(窗口风格或扩展风格) |
styleNew | DWORD | 0 | 窗口即将被设置的新风格值,在WM_STYLECHANGING阶段可被应用修改 |
由于使用了@C标注,该结构体具有 C 的内存布局(两个 32 位无符号整数、按声明顺序排列、无填充),可直接与 Windows 系统通过LPARAM传入的原始指针互操作。仓库同时提供了两个类型别名:
STYLESTRUCT:tagSTYLESTRUCT的等价类型名,与 Windows SDK 命名习惯保持一致;LPSTYLESTRUCT:CPointer<tagSTYLESTRUCT>,即指向该结构体的指针类型,用于在事件处理中解引用系统传入的lParam。
关联的 Win32 消息与 wParam 语义
tagSTYLESTRUCT只在两类窗口消息中出现,两者均定义于 src/win_def/hwinuser.cj:
public const WM_STYLECHANGING:UInt32 = 0x007C public const WM_STYLECHANGED:UInt32 = 0x007D两者的消息参数约定一致(这也是该结构体存在的意义):
wParam:指出被修改的风格索引。取值为 GWL_STYLE或 GWL_EXSTYLE,常量定义见 src/win_def/hwinuser.cj:const GWL_STYLE:Int32 = -16 const GWL_EXSTYLE:Int32 = -20lParam:指向一个STYLESTRUCT结构体的指针,由系统填充旧风格(styleOld)与拟应用的新风格(styleNew)。
两条消息的时机差异是关键:
WM_STYLECHANGING在风格即将被修改前发送。此时应用可以检查styleNew中的位,必要时修正它,从而让系统最终应用修正后的值——这是唯一能“干预”风格变更的窗口期;WM_STYLECHANGED在风格修改完成后发送,仅作为只读通知,结构体内容不再影响系统行为。
RGF 的封装:EvStyleChange 事件对象
RGF 没有让开发者直接操作lParam裸指针,而是在rgf.rgf_core中提供了事件参数类EvStyleChange(文档见 doc/api/rgf.rgf_core/类/EvStyleChange.md),其实现在 src/rgf_core/rgf_proc.cj#L2505-L2535:
/** @brief 窗口风格变更 - 事件参数 */ public open class EvStyleChange <: EvCore{ // 窗口扩展风格被更改 public let changeExStyle:Bool; // 窗口风格被更改 public let changeStyle:Bool; // 旧风格 public var styleOld:UInt32; // 新风格 public var styleNew:UInt32; internal let ptr:CPointer<STYLESTRUCT>; internal var Obj:STYLESTRUCT; @OverflowWrapping public init(uMsg:UInt32, wParam:UInt64, lParam:Int64) { super(uMsg, wParam,lParam) ptr = CPointer<STYLESTRUCT>(ruUllToPtr(ruInt64SafeToUIntNative(lParam))) Obj = unsafe{ ptr.read() } changeExStyle = (wParam & ruRedefBit<Int64,UInt64>(-20)/*GWL_EXSTYLE*/) != 0 changeStyle = (wParam & ruRedefBit<Int64,UInt64>(-16)/*GWL_STYLE*/) != 0 styleOld = Obj.styleOld styleNew = Obj.styleNew } public func postProcess(){ Obj.styleNew = styleNew Obj.styleOld = styleOld unsafe{ ptr.write(Obj) } } }从源码结构看,EvStyleChange采用了“值拷贝 + 写回”的安全模式:
- 构造阶段:先把
lParam(Int64)经ruUllToPtr转为CPointer<STYLESTRUCT>,再用unsafe读一次完整结构体到成员Obj,随后把styleOld/styleNew提升为可直接读写的UInt32字段;同时根据wParam的位计算changeStyle(GWL_STYLE)与changeExStyle(GWL_EXSTYLE)两个布尔标记,省去开发者手动判断 wParam 的负担; - 写回阶段:
postProcess()把开发者修改过的styleOld/styleNew写回Obj,再整体write回系统传入的内存地址。由于@C结构体按声明顺序存放两个DWORD,这里整体写回是安全的,也保证了只有显式调用postProcess()才会真正影响系统行为。
消息分发链路
tagSTYLESTRUCT的消费入口在rgf.rgf_core的窗口过程分发中(src/rgf_core/rgf_proc.cj#L5039-L5051):
case 0x007C /*WM_STYLECHANGING*/ =>{=> let eObj:EvStyleChange = EvStyleChange(0x007C,wParam,lParam) onStyleChanging(eObj) if(eObj.isOverride){ eObj.postProcess() } return (0,eObj.isOverride) } case 0x007D /*WM_STYLECHANGED*/ =>{=> let eObj:EvStyleChange = EvStyleChange(0x007D,wParam,lParam) onStyleChanged(eObj) return (0,eObj.isOverride) }要点:
- 两条消息共用同一个
EvStyleChange参数类型,开发者可以用同一套字段处理“变更中”与“已变更”两个阶段; - 对
WM_STYLECHANGING,只有当处理函数把e.isOverride置为true时,RGF 才会调用postProcess()把修改后的styleNew写回系统结构体,进而使修正生效; - 框架默认的
onStyleChanging/onStyleChanged实现(src/rgf_core/rgf_proc.cj#L6242-L6249)只是把isOverride置为false,即默认不干预、不拦截。
此外,仓库的宏代码生成器 src/rgf_core/macros/rgf_proc_utils.cj#L299-L309 会为纯事件绑定模式生成对应的bindStyleChanging/bindStyleChanged分支:
case ("bindStyleChanging","EvStyleChange","Unit") => ##" case 0x007C /*WM_STYLECHANGING*/ =>{=> let eObj:EvStyleChange = EvStyleChange(0x007C,wParam,lParam) onStyleChanging(eObj) eObj.postProcess() return 0 }"##从宏生成代码看,绑定式接口IBindEvent中也提供了bindStyleChanging、bindStyleChanged两个Option属性,用于以闭包方式订阅风格变更,与重写onStyleChanging/onStyleChanged方法互为替代。
实战:在 RGF 窗口类中拦截风格变更
结合上述实现,在 RGF 中响应风格变更有两种典型写法。
方式一:重写窗口事件方法。在继承自WinPure的窗口类中重写onStyleChanging,修改e.styleNew后必须把e.isOverride置为true,否则修改不会写回:
override func onStyleChanging(e:EvStyleChange) { if (e.changeStyle) { // 只处理窗口风格,忽略扩展风格 // 例如:确保新风格保留 WS_VISIBLE 位 e.styleNew = e.styleNew | WinStyle.Visible.e2n() e.isOverride = true // 标记已干预,触发 postProcess() 写回 } }方式二:事件绑定。通过IBindEvent提供的bindStyleChanging属性挂接闭包:
win.bindStyleChanging = (e:EvStyleChange) => { e.styleNew = e.styleNew & (~WinStyle.ThickFrame.e2n()) // 去掉边框调整能力 e.isOverride = true } win.bindStyleChanged = (e:EvStyleChange) => { // 风格已变更完成,此处只做只读记录 }风格位的语义由 WinStyle 枚举承载,它与 Win32 窗口风格一一对应,涵盖Border、Caption、SysMenu、ThickFrame、Maximize、Minimize、HScroll、VScroll、Visible等常用位。该枚举重载了|与&运算符(返回UInt32),并提供e2n()/n2e()完成枚举值与数值的互转,因此在上面的示例中可以直接用位运算拼出新的styleNew。判断本次变更针对的是普通风格还是扩展风格时,优先使用e.changeStyle与e.changeExStyle两个布尔标记,它们正是源码中对wParam按GWL_STYLE/GWL_EXSTYLE判位的结果。
小结与参考资料
tagSTYLESTRUCT本身只有styleOld、styleNew两个DWORD字段,但它是WM_STYLECHANGING/WM_STYLECHANGED两条消息中唯一承载风格前后取值的载体。RGF 通过@C结构体保证与 Windows 内存布局兼容,再用EvStyleChange的“值拷贝 +postProcess()写回”机制,把 Win32 裸指针操作收敛为安全的强类型字段访问。
延伸阅读(均位于当前仓库):
- 结构体定义:doc/api/rgf.win_def/结构体/tagSTYLESTRUCT.md
- Win32 类型与常量:src/win_def/hwinuser.cj
- 事件参数实现:src/rgf_core/rgf_proc.cj
- 事件分发与默认处理:src/rgf_core/rgf_proc.cj、src/rgf_core/rgf_proc.cj
- 事件绑定接口:doc/api/rgf.rgf_core/接口/IBindEvent.md
- 窗口风格枚举:doc/api/rgf.rgf_core/枚举/WinStyle.md
- 图形学
- 桌面应用
【免费下载链接】RGF_CJ
RGF是仓颉Windows系统下的通用渲染框架(兼应用开发框架)。RGF仓颉版(后续简称"RGF")基于RGF(C/C++版)封装优化而来。RGF为开发者提供轻量化、安全、高性能以及高度一致性的2D渲染能力以及常用的桌面应用开发工具,并且提供对接Direct3D的相关接口,以满足开发者对3D画面渲染的需求。在Windows开发方面,RGF在子包内也提供开箱即用的Windows API,确保熟悉Win32的开发者快速上手。此外,RGF还提供一些常用功能的封装(如XAudio2、MF),以辅助开发者实现音频、摄像头等扩展功能的管理。
相关推荐
RGF 仓颉版 FLASHWINFO 结构体详解:Win32 窗口闪烁 API 在 rgf.win_def 中的封装与使用
RGF 仓颉版 FLASHWINFO 结构体详解:Win32 窗口闪烁 API 在 rgf.win_def 中的封装与使用 RGF 仓颉版(RGF_CJ)在子包
图形学桌面应用RGF 仓颉版 Win32 接口解析:tagMDICREATESTRUCTW 结构体与 MDI 多文档窗口事件联动
RGF 仓颉版 Win32 接口解析:tagMDICREATESTRUCTW 结构体与 MDI 多文档窗口事件联动 本文围绕 RGF(仓颉版通用渲染框架,仓库
图形学桌面应用RGF 仓颉版 tagMSG:Win32 消息结构、消息泵函数与 RGF 事件循环的源码解析
RGF 仓颉版 tagMSG:Win32 消息结构、消息泵函数与 RGF 事件循环的源码解析 tagMSG 是 RGF 仓颉版(RGF_CJ) rgf.win_
图形学桌面应用
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考