窗口句柄(HWND)是否是唯一的,还是会被重用?

8

我在思考是否存在相同值的句柄?

为了澄清我的问题,假设我打开记事本,输入一些文本,保存并关闭记事本。如果我重复这个过程一千次(甚至更多),我是否有机会看到用于记事本主窗口的相同窗口句柄(HWND)值被第一次使用? 如果是这样,为什么?


我不明白任何事情,你能解释一下你的问题吗? - Qchmqs
谢谢您的帖子,如果您不理解也没关系,请忽略并阅读其他人发布的内容,如果有任何有趣的想法,请多加留意。我相信您很快就会上瘾的 :-D - Aussay Marshal
4
“没关系,如果你不理解。”?!不,不是这样的:如果你在 Stack Overflow 上发布一个好的问题,那会为这个优秀的编程资源增值。但是,如果你在 Stack Overflow 上发布一个糟糕或者难以理解的问题,那实际上会损害 Stack Overflow 的可用性(即使只是一点点)。因此,请尽力用最好的措辞提出你的问题,为社区着想!(顺便说一下,我稍微编辑了一下你的问题。) - stakx - no longer contributing
5个回答

7
是的。句柄可以表示的值是有限的,所以Windows最终会重复使用它们。
一旦一个句柄被关闭,它就消失了,你不能对它做任何事情,它不存在,你甚至不应该看它。
如果你随后打开了另一个句柄,那么Windows有可能会重复使用先前关闭的句柄值。

谢谢,有没有一种机制可以传递句柄以打开窗口?如果您能分享的话,那是什么? - Aussay Marshal
我想知道是否有一种方法可以将句柄值传递给每个打开的窗口?我没有意图获取已关闭窗口的句柄。我的Windows知识不好,所以我提出了这个问题。 - Aussay Marshal
没有GUI句柄有引用计数器。因此只有一个句柄值,您无法执行“DuplicateHandle”之类的操作。这是一种设计错误,就像UNIX使用进程ID值一样。 - Lothar

4
理论上是可以的。但实际上,与进程和线程id频繁重用相比,这种情况的概率几乎为零。
在当前实现中,HWND 的低16位用作Windows句柄表中的索引,因此当前最多可以创建64K个窗口。接下来的16位用作重用索引。当单元格第一次被使用时,该索引为1。当此单元格被重新使用时,索引增加1。结果是为了在窗口上获得相同的HWND,需要创建并销毁至少64k个窗口。但这仅在所有这些窗口将使用相同的单元格的情况下成立。但我们有64k个单元格。所以实际最小值要高得多。不完全是2^32,但足够大。
即使实现发生改变,我也不认为新实现会使HWND比当前更不唯一。

3
是的,窗口句柄会被重复使用。 IsWindow函数的文档说明如下:

一个线程不应该对它没有创建的窗口使用IsWindow函数,因为在此函数调用后窗口可能已经被销毁。而且,由于窗口句柄会被回收,句柄甚至可能指向不同的窗口


我的回答基于@CodyGray的评论。我只是想让这个事实更加突出。 - Alexey Ivanov

2
根据鸽巢原理,是的,它们不可能是唯一的。
由于与32位进程(WoW64)的兼容性,即使在64位操作系统上,句柄也不能使用整个64位——想象一下64位进程传递句柄给32位子进程,或获取由32位进程打开的窗口的句柄。这使得它们真正的空间非常小,因此重复使用的可能性非常大。

2
只有部分回答是正确的。窗口句柄并不保持与16位Windows的兼容性。它们是指针,这意味着它们的大小取决于架构。在64位Windows版本中,它们是64位值。在32位Windows版本中,它们是32位值。请查看Windows头文件以获取详细信息。 - Cody Gray
1
HANDLE 类型不再是 void* 的 typedef 了;已经过去了 很多年。显然 MSDN 文档的某些部分自那时以来就没有更新,但这并不能使假设变得更正确。此外,这甚至不是你链接的文章所说的。它只是说每个会话有 65,536 个用户句柄的限制。这并没有说明用于存储句柄的数据类型。你做出的结论既不是明确陈述的,也是不合理的。 - Cody Gray
1
如果你仍在使用VC 6附带的头文件,那么你已经过时了。我不知道还有什么可以告诉你的了。在任何现代版本的SDK中都没有这样定义。我真的不明白你想从MSDN得到什么。你想要一个链接,说MSDN是错的,来自MSDN?抱歉,这是不可能的。在线文档中并不是每一页都会定期更新,即使有更新,也会有遗漏。Raymond Chen写了一整个关于这个问题的博客。你提供了一个与GDI句柄无关的不相关文章的链接,这与HWND值无关。 - Cody Gray
5
请记住,我们谈论的不是 HANDLE,而是 HWND。我不明白为什么你还在谈论完全无关的事情,比如 GDI 句柄和 HANDLE 类型。问题标题非常清楚地说了“窗口句柄”。我并没有编造这个。而且我已经解释过,表格对这个讨论来说是相当无关紧要的。最后,我们进入了你的论点的核心,这完全是错误的。Win16 应用程序 无法在 64 位版本的 Windows 上运行。结束。 - Cody Gray
3
MSDN中提到了typedef HANDLE HWND;typedef PVOID HANDLE;typedef void *PVOID;。而User Objects的文章提到了HWND,而非GDI对象。 GDI对象在导航中有一个单独的article列出。最后,还有一个关于句柄表的简要参考。 - Afriza N. Arief
显示剩余5条评论

1

我建议您不要对句柄值做任何假设。

在实际应用中,您不应该考虑具体的句柄值。句柄应被视为其他东西的不透明占位符。您可以传递句柄以引用某些内容(例如窗口),而无需引用真正的内容,但您不应该查看句柄本身。它是一个数字值应被视为实现细节,即不重要(除非您进行某种低级系统编程)。

话虽如此,我支持@jalf的答案:句柄值可能会被重复使用。如果我必须对此做出任何假设,我会假设句柄值随时可能被重复使用。


谢谢,你的帖子和他的(ybungabol)都非常有帮助。他先发了帖子,所以我投票支持他的回答。我的声望目前只有12分,如果我们有机会再次见面,我下次会给你点赞。 - Aussay Marshal
@Serious,不要像ybungalobill的回答一样说“点赞”或者像我的回答一样说“非常有帮助”,只需要在问题左侧按上箭头即可! - stakx - no longer contributing
3
你一定要假设句柄值可以被重用,这不是一个“可能”的事情。 IsWindow()函数的文档明确指出: “线程不应使用IsWindow来检查它没有创建的窗口,因为在调用此函数后窗口可能已经被销毁。此外,由于窗口句柄会被循环利用,所以句柄甚至可能指向不同的窗口。” - Cody Gray
@Cody,你说得对,我可能过于谨慎了。;-) 我已经更新了我的答案。 - stakx - no longer contributing
2
问题不在于句柄的表示,而在于句柄的生命周期。 - Lothar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接