在WinAPI上,HANDLE
类型定义为void*
,因此在64位应用程序中,HANDLE
值的范围可以从0
到18446744073709551615
。
但这在实践中是真的吗?是否有任何文档指定了HANDLE
的整体范围?
例如,如果有人希望将这个HANDLE
作为int32_t
存储在完全正常的32位应用程序上,但在64位应用程序上则存在疑问。
答案 0 :(得分:23)
MSDN声明:
Interprocess Communication Between 32-bit and 64-bit Applications
64位版本的Windows使用32位句柄来实现互操作性。 在32位和64位应用程序之间共享句柄时,只有 低32位是重要的,因此截断句柄是安全的 (将其从64位传递到32位时)或对句柄进行符号扩展 (当它从32位传递到64位时)。可以共享的句柄 包括用户对象的句柄,例如windows(HWND),GDI句柄 笔和画笔(HBRUSH和HPEN)等对象和句柄 命名对象,如互斥锁,信号量和文件句柄。
还值得注意的是,该页面上添加了此评论:
跨进程边界共享此类句柄的正确方法是 零扩展32位处理为64位,反之亦然 64位处理为32位,丢弃最高位。
注意"符号扩展"之间的区别手柄与"零延伸"手柄。
编辑:从对这个问题的删除答案中看到的讨论判断,我认为签名扩展32位句柄以达到64位句柄而非零的重要性 - 扩展它是为了保持对句柄的INVALID_HANDLE_VALUE值的适当处理。
答案 1 :(得分:3)
我希望知道它在哪里被记录,但是我的一位同事坚持认为64位HWND句柄总是适合32位。我从来没有见过一个不真实的案例,但不能说出未来或者记录在哪里。关于其他句柄,比如说,HTREEITEM ....它们是完整的64位,而且我一直认为它们太适合32位。
答案 2 :(得分:0)
要添加到先前的正确答案,请注意,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是对此的记录例外。