窗口句柄 (HWND) 是唯一的吗?或者它们是否会被重用?

问题描述 投票:0回答:6

我在想是否有相同值的句柄?

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

windows window-handles
6个回答
7
投票

是的。句柄只能表示有限数量的值,因此 Windows 最终必须重用它们。

一旦关闭句柄,它就消失了,你不能用它做任何事情,它不存在,你甚至不应该看它。

如果您随后打开另一个句柄,那么Windows可能会重用该句柄值。


5
投票

理论上是的。实际上 - 这种可能性(与经常重用的进程和线程 ID 相比)几乎为零。

在当前实现中,

HWND
的低16位用作窗口句柄表中的索引 - 因此当前最多可以创建64K窗口。接下来的 16 位用作重用索引。当一个小区第一次被使用时,该索引为1。当该小区被重新使用时,该索引增加1。以此类推。因此,要在窗口上获得相同的
HWND
,需要如何创建和销毁最少 64k 的窗口。但这只是在所有这些窗口都将使用同一个单元格的情况下。但我们有 64k 个单元。所以实际的最低值要高得多。不完全是 2^32 但足够大。

即使实施会发生变化,我认为新的实施不会使

HWND
不如当前的独特。


3
投票

是的,窗口句柄被重复使用。

IsWindow
函数的文档说:

线程不应将

IsWindow
用于它未创建的窗口,因为调用此函数后该窗口可能会被销毁。此外,因为窗口句柄是回收的,所以句柄甚至可以指向不同的窗口。


2
投票
鸽子洞原理

,是的,它们不可能是唯一的。 由于与 32 位进程 (WoW64) 的兼容性,即使在 64 位操作系统上,句柄也无法使用整个 64 位 - 想象一下 64 位进程将句柄传递给 32 位子进程,或者获取32 位进程打开的窗口句柄。这使得它们的真实空间非常小,因此很可能重复使用。


1
投票

您不必为了所有实际目的而考虑具体的句柄值。句柄应被视为其他内容的不透明占位符。您可以传递句柄来引用某物(例如窗口),而无需引用真实的事物,但您不必查看句柄

本身

。它是一个数值这一事实应该被视为一个实现细节,即。不重要(除非您可能进行某种低级系统编程)。 话虽如此,我支持@jalf 的回答:句柄值可以被重用。如果我必须对此做出任何假设,我会假设句柄值可以随时重用。

确认这个问题答案的最简单方法之一是编写一个程序并实际测试它。 我写了一个程序,不断创建和销毁窗口,记录使用过的HWND值,最后输出获取重复HWND值所需的次数。


0
投票

总结:

创建和销毁 65534 个窗口后,您将有机会获得重复的 HWND 值
以下是我的测试代码。我将程序编译为32位,因为在64位中,出于未知原因,我有时会得到HWND,其中高位双字不是zreo(例如0xffffffff80230918、0xffffffff80000e68、0xffffffff802d0918)


#include <Windows.h> #include <iostream> #include <vector> LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_DESTROY: PostQuitMessage(0); return 0; default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } } int main() { WNDCLASSW wc{ NULL, WindowProc, 0, 0, NULL, NULL, NULL, NULL, NULL, L"MessageWindowClass" }; RegisterClassW(&wc); std::vector<bool> hwndused(0x7FFFFFFF); std::vector<bool> hwndused2(0x7FFFFFFF); for (long long count = 1;; ++count) { HWND hwnd = CreateWindowW( L"MessageWindowClass", L"WindowName", NULL, NULL, NULL, NULL, NULL, HWND_MESSAGE, NULL, NULL, NULL ); if (hwnd == NULL) { std::cerr << "CreateWindow failed!"; return -1; } if ((size_t)hwnd > 0x7FFFFFFF) { if (hwndused2[(size_t)hwnd - 0x7FFFFFFF]) { std::cout << count << '\t' << hwnd; return 0; } else { hwndused2[(size_t)hwnd - 0x7FFFFFFF] = true; } } else { if (hwndused[(size_t)hwnd]) { std::cout << count << '\t' << hwnd; return 0; } else { hwndused[(size_t)hwnd] = true; } } PostMessage(hwnd, WM_CLOSE, NULL, NULL); MSG msg = {}; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } } }

© www.soinside.com 2019 - 2024. All rights reserved.