我在想是否有相同值的句柄?
为了澄清我的问题,假设我打开记事本,输入一些文本,保存它,然后关闭记事本。如果我重复此操作一千次(甚至更多),我是否有机会看到第一次使用的记事本主窗口使用相同的窗口句柄(HWND)值?如果是这样,为什么?
是的。句柄只能表示有限数量的值,因此 Windows 最终必须重用它们。
一旦关闭句柄,它就消失了,你不能用它做任何事情,它不存在,你甚至不应该看它。
如果您随后打开另一个句柄,那么Windows可能会重用该句柄值。
理论上是的。实际上 - 这种可能性(与经常重用的进程和线程 ID 相比)几乎为零。
在当前实现中,
HWND
的低16位用作窗口句柄表中的索引 - 因此当前最多可以创建64K窗口。接下来的 16 位用作重用索引。当一个小区第一次被使用时,该索引为1。当该小区被重新使用时,该索引增加1。以此类推。因此,要在窗口上获得相同的HWND
,需要如何创建和销毁最少 64k 的窗口。但这只是在所有这些窗口都将使用同一个单元格的情况下。但我们有 64k 个单元。所以实际的最低值要高得多。不完全是 2^32 但足够大。
即使实施会发生变化,我认为新的实施不会使
HWND
不如当前的独特。
您不必为了所有实际目的而考虑具体的句柄值。句柄应被视为其他内容的不透明占位符。您可以传递句柄来引用某物(例如窗口),而无需引用真实的事物,但您不必查看句柄
本身。它是一个数值这一事实应该被视为一个实现细节,即。不重要(除非您可能进行某种低级系统编程)。 话虽如此,我支持@jalf 的回答:句柄值可以被重用。如果我必须对此做出任何假设,我会假设句柄值可以随时重用。
确认这个问题答案的最简单方法之一是编写一个程序并实际测试它。 我写了一个程序,不断创建和销毁窗口,记录使用过的HWND值,最后输出获取重复HWND值所需的次数。
总结:
创建和销毁 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);
}
}
}