You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Win11下DirectDraw Clipper调用SetHWnd绑定窗口偶发访问冲突

问题复现

核心实现代码如下:

m_ddraw->CreateClipper(0, &m_clipper, NULL);
m_clipper->SetHWnd(0, wnd);
m_primarySurface->SetClipper(m_clipper);

上述代码在Windows 10系统运行完全正常,Windows 11下偶发触发访问冲突异常:
0xC0000005: 读取位置 0x0000000000000014 时发生访问冲突
测试确认,调用SetHWnd(0,NULL)不传入具体窗口句柄时,异常不会触发。

问题原因

该异常是Windows 11更新DirectDraw兼容层逻辑后引入的时序与校验问题,本质是DX7及更早版本的遗留DirectDraw接口中,Clipper组件的Win11实现与Win10存在行为差异:

  • Win10的DirectDraw兼容实现对传入SetHWnd的窗口句柄未做严格状态校验,即便窗口未完成初始化、正处于DWM(桌面窗口管理器)异步重定向状态,内部也会兜底返回默认矩形参数,不会触发访问冲突。
  • Win11调整了兼容层逻辑:当SetHWnd传入有效窗口句柄时,内部会立刻读取窗口对应内核对象的客户区结构,报错信息中偏移0x14的位置正好对应客户区矩形的左边界成员。如果此时窗口未完成首次显示、处于最小化状态、或者DWM正在对窗口执行圆角/透明边框重定向,内部拿到的窗口结构指针为空,就会触发0xC0000005空指针访问。
  • 部分老旧代码未正确处理DirectDraw Clipper的COM引用计数,Win11下主表面绑定Clipper后会在窗口状态变化时异步回调Clipper接口,如果提前释放了Clipper指针,也会触发同位置的野指针崩溃。

调用SetHWnd(0, NULL)时Clipper工作在全屏无窗口绑定模式,不需要读取任何窗口相关结构,因此不会触发异常。

修复方案

按优先级从高到低落地以下修改即可解决问题:

  • 调整调用时序:禁止在CreateWindowEx返回后立刻创建Clipper并调用SetHWnd,必须等窗口收到WM_SHOWWINDOW消息(wParam为TRUE,即窗口首次完成显示)、或者收到第一个WM_PAINT消息后,再执行Clipper创建、绑定窗口、挂载到主表面的全流程逻辑。
  • 增加调用前校验:每次调用SetHWnd前,先通过IsWindow(wnd)校验句柄有效性,再调用GetClientRect(wnd, &rc)确认可以正常读取客户区矩形,校验失败则延后100~200ms重试,禁止在窗口未就绪时强行调用接口。
  • 修正COM引用计数:CreateClipper拿到m_clipper指针后,手动调用一次m_clipper->AddRef(),直到主表面完全释放、程序退出前再调用m_clipper->Release(),禁止因为主表面会持有Clipper引用就提前释放自身持有的接口指针,避免异步回调时触发野指针访问。
  • 关闭DWM特殊重定向:窗口模式运行的程序,可在窗口初始化时调用DwmSetWindowAttribute,将窗口的DWMWA_NCRENDERING_POLICY属性设为DWMNCRP_ENABLED,关闭Win11默认给老旧程序加的圆角/透明边框重定向优化,避免Clipper读取窗口位置时拿到无效值。

内容的提问来源于stack exchange,提问作者psxc233

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 17:01:19