64 位应用程序上的 Windows HANDLE 范围是多少?
Posted
技术标签:
【中文标题】64 位应用程序上的 Windows HANDLE 范围是多少?【英文标题】:What is the range of a Windows HANDLE on a 64 bits application? 【发布时间】:2013-08-16 05:50:27 【问题描述】:在 WinAPI 上,HANDLE
类型定义为 void*
,因此在 64 位应用程序上,HANDLE
值的范围可以从 0
到 18446744073709551615
。
但在实践中真的如此吗?是否有任何文档指定此类HANDLE
的整数范围?
例如,如果有人想将此HANDLE
作为int32_t
存储在 32 位应用程序上,这完全没问题,但在 64 位应用程序上,疑虑仍然存在。
【问题讨论】:
为什么您需要将HANDLE
存储在int
中?听起来有问题。考虑std::map<int, HANDLE>
。
@MSalters 这与 POSIX 文件描述符(即int
)有关。我使用的是 C,所以没有 STL,但是是的,我可以创建第二个句柄系统,指向 Windows HANDLE
,但这会比简单的转换要慢,所以我在这里问。
【参考方案1】:
MSDN 声明:
Interprocess Communication Between 32-bit and 64-bit Applications
64 位版本的 Windows 使用 32 位句柄来实现互操作性。 在 32 位和 64 位应用程序之间共享句柄时,只有 低 32 位很重要,因此截断句柄是安全的 (将其从 64 位传递到 32 位时)或对句柄进行符号扩展 (将其从 32 位传递到 64 位时)。可以共享的句柄 包括用户对象的句柄,例如窗口 (HWND)、GDI 的句柄 笔和刷子(HBRUSH 和 HPEN)等物体,以及 命名对象,例如互斥体、信号量和文件句柄。
还值得注意的是该页面上添加的这条评论:
跨进程边界共享此类句柄的正确方法是 通过截断将 32 位句柄零扩展为 64 位,反之亦然 64 位处理到 32 位丢弃最高位。
注意“符号扩展”句柄与“零扩展”句柄之间的区别。
编辑:从对这个问题的已删除答案中看到的讨论来看,我认为符号扩展 32 位句柄以达到 64 位句柄而不是零的意义-扩展它是为了保留对句柄的 INVALID_HANDLE_VALUE 值的正确处理。
【讨论】:
您所依赖的评论权限为零。遵循文档。 另外,您有足够的声誉可以在此页面上看到投票最高的答案(删除是有问题的),其中涵盖了这一点,并且 MSalters 也参加了 cmets。 @BenVoigt 目前我没有这种能力查看已删除的答案(太棒了,不知道) 但它在被删除之前是公认的答案,任何想法的原因?也许在 cmets 上?出于好奇,如果作者愿意,可以取消删除吗? @thelink2012:它显示它已被(现已退休)钻石版主删除,但我看不出有任何原因,并且已标记为其他版主查看。跨度> 【参考方案2】:我希望知道它记录在哪里,但我的一位同事坚持认为 64 位 HWND 句柄始终适合 32 位。我从未见过这样的案例,它是不真实的,但不能谈论未来或它被记录在哪里。关于其他句柄,比如 HTREEITEM.... 它们是完整的 64 位,我一直认为它们太适合 32 位。
【讨论】:
“我的同事”不是可靠的信息来源,特别是考虑到官方文档(见接受的答案)不同意。 @BoundaryImposition,Joe Willcoxson 是正确的。来自 64 位进程的 HTREEITEM 很容易大于 32 位。这在 Microsoft 文档中也有说明,特别是 OS 对象的句柄将是 32 位的,并且要签名扩展,但这不包括其他类型的句柄,例如 HTREEITEM。也许他的同事在微软工作。 +1 他提到了这个非常有用的方面。我现在正盯着一个通过 SendMessage 将句柄的 3 个半字节截断为 64 位进程的进程。 @Joe Willcoxson 32 位和 64 位互操作性 (MSDN):msdn.microsoft.com/en-us/library/windows/desktop/… @Celess 谢谢。那一定是我同事引用的那篇文章。HWND
s 在 64 位 Windows 上总是适合 32 位。这在Interprocess Communication Between 32-bit and 64-bit Applications 下明确记录。【参考方案3】:
要补充前面的正确答案,请注意 HWND 也是跨进程的有效句柄。任何其他 void* 句柄(如 HBRUSH、HBITMAP 等)都可能是可截断的,因为只有低 32 位是有效的,但它在自己的进程之外无效。
对于 GDI 对象,它可能会起作用,因为这些实际上是索引(请参阅 https://docs.microsoft.com/en-us/previous-versions/ms810501(v=msdn.10))
嗯,这里发生的是 GDI 对象的句柄在内部 实现为驻留在客户端上的句柄表中的偏移量 Win32 子系统的一侧。 (记住 Win32 客户端是一个 DLL 它驻留在基于 Win32 的应用程序的地址空间中,并且是 由应用程序调用。)换句话说,句柄表保持在 每个进程的基础,但它们没有进程标记。这意味着 属于进程 A 的对象的句柄可能巧合 在进程 B 的上下文中看起来像一个有效的句柄。因此,调用 B 中的 SelectObject 可能会成功,但 B 实际上会选择一个 完全不同的对象进入它的设备上下文——或者更糟的是,正确的 一。选择正确的对象可能会更糟,因为对象可能 巧合的是一样,所以你认为它有效,但应用程序 以后会表现得很奇怪。所以,不要将句柄传递给 GDI 对象 应用程序之间;它们在 不同的过程。
HWND 是一个记录在案的例外。
【讨论】:
以上是关于64 位应用程序上的 Windows HANDLE 范围是多少?的主要内容,如果未能解决你的问题,请参考以下文章
32 位与 64 位 Windows 版本上的进程大小和行为差异
有没有办法让 Windows 64 位上的应用程序在 64 位和 32 位仿真层下执行代码?
VS2010 在 64 位版本的 Windows 上的 WinForms 应用程序中不显示未处理的异常消息