谁是 GWLP_USERDATA 单元的所有者?

RbM*_*bMm 6 windows winapi

众所周知,GWLP_USERDATA可用于将一些指针大小数据与指定窗口相关联。但谁有权这样做呢?显然,如果两段代码独立执行此操作 - 一段是覆盖另一段的数据 - 所以必须只有一个所有者。但必须明确确定一个一般规则——谁是GWLP_USERDATA细胞的所有者?它属于谁?

可以是两个内部一致的协议:

  1. 创建窗口的代码是所有者。属于窗口的创建者
  2. 实现窗口类的代码。属于窗口类实现者

必须使用这两种解决方案中的哪一种?

1. 来自MSDN

GWLP_USERDATA

设置与窗口关联的用户数据。此数据旨在供创建窗口的应用程序使用。它的值最初为零。

怎么需要明白This data is intended for use by the application that created the window

所以调用CreateWindowEx, CreateDialogParam,DialogBoxParam等的代码-只有这个代码可以使用GWLP_USERDATA. 由此也得出窗口类实现者不能使用GWLP_USERDATA. GWLP_USERDATA用于将类的实例绑定到指定窗口的大量示例是不正确的。管理应用程序状态- 官方 MSDN 示例,GWLP_USERDATA用于将数据结构绑定到窗口的位置不正确?!

SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pThis);

在这条规则下是错误的。

有什么可以说支持这个版本的?我检查了不同的 Windows 版本(从 xp 到 win10) - 我如何看到所有 Windows 内置窗口类(WC_*和其他)使用

SetWindowLongPtr(hwnd, 0, (LONG_PTR)pThis);

用于将类的实例绑定到指定的窗口。始终使用索引 0 代替GWLP_USERDATA

很多人会说——那又怎样?即使现在这是真的,未来的 Windows 版本呢?但是如果想一想,从索引 0(在所有意义上都是私有的实施者索引)迁移到什么意义GWLP_USERDATA?改变现有SetWindowLongPtr(hwnd, 0, (LONG_PTR)pThis);SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pThis);什么奖品?或额外开始使用GWLP_USERDATA索引 0 吗?这已经绝对没有意义 - 一个指针就足以将窗口绑定到数据结构,所有额外的指针都必须(如果 Windows 代码将在)已经在这个结构中。所以我个人可以假设这没有改变


也可以在文档中记录一个错误 这里SetWindowLongPtr GetWindowLongPtr

要设置的值的从零开始的偏移量。有效值在零到额外窗口内存的字节数减去整数大小的范围内

真正减去x64 上 8 个字节的指针的大小,当整数的大小始终为 4 时。


2. 看一个有信誉的博客 - GWLP_USERDATA 处的奖金窗口字节

请注意,此值...属于窗口类而不属于创建窗口的代码...只有窗口类实现者可以读取或写入这些值。

也存在接下来的两位作者评论:

有趣的。我正在检查那个。但即使它确实属于窗口的创建者,足够多的窗口类实现使用它,为了安全起见,您仍然应该远离它。

我四处询问,指导“不清楚”,尽管略微倾向于“它属于调用 CreateWindow 的人”。那么,为了安全起见,除非您可以建立明确的所有权,否则您应该避免使用它

再次查找管理应用程序状态MSDN 示例 - 使用的窗口类实现者GWLP_USERDATA

寻找ATL atlhost.h-AtlAxWindowProc使用GWLP_USERDATA

//case WM_CREATE:
::SetWindowLongPtr(hWnd, GWLP_USERDATA, (DWORD_PTR)pAxWindow);
Run Code Online (Sandbox Code Playgroud)

再次使用类实现者 GWLP_USERDATA

但是在这个协议下我们不能使用 GWLP_USERDATAwith CreateDialogParamDialogBoxParam 因为这里我们不是实现者(该DialogProc函数是一个应用程序定义的回调函数调用自DefDlgProc- 对话框的真正类实现代码 - 所以只能DefDlgProc潜在使用GWLP_USERDATA单元格)


那么创建窗口窗口类实现者的应用程序是所有者吗?


如果认为 -创建窗口的变体应用程序更合乎逻辑。窗口类实现者有两种选择:可以设置cbWndExtrasizeof(PVOID)使用索引 0 或使用GWLP_USERDATA索引。当创建窗口应用-别无选择-仅GWLP_USERDATA索引或使用另一(不太有效和更复杂的)方式等SetPropSetWindowSubclass等等,以便是合乎逻辑的,如果用于结合自身数据到窗口和窗口类实施者使用指数0离开自由GWLP_USERDATA用于代码创建了窗口。再次怎么样CreateDialogParamDialogBoxParam- 这里使用数据结构的最本地方式绑定到对话框使用GWLP_USERDATA索引,但在这里我们是窗口创建者,而不是对话框类实现者!所以能不能用GWLP_USERDATA

在所有情况下都需要考虑到足够的现有自定义窗口类实现使用 GWLP_USERDATA

我的假设:

  • 如果我们调用CreateWindowEx非 Windows 核心内置类 - 我们不能GWLP_USERDATA在这里使用
  • 如果我们打电话CreateDialogParamDialogBoxParam-我想我们可以在这里使用GWLP_USERDATA
  • 如果我们调用CreateWindowExWindows 内置类(名为 WC_*),我们也可以使用GWLP_USERDATA
  • 如果我们窗口类实现者 - 最好的选择 - 设置cbWndExtrasizeof(PVOID)并使用索引 0