30

在 WinAPI 上,HANDLE类型被定义为 a void*,因此在 64 位应用程序上,该HANDLE值的范围可以从018446744073709551615。但在实践中真的如此吗?是否有任何文档指定了这样的整数范围HANDLE

例如,如果有人想将其存储HANDLEint32_t32 位应用程序,那完全没问题,但在 64 位应用程序上,疑虑仍然存在。

4

3 回答 3

31

MSDN 状态:

32 位和 64 位应用程序之间的进程间通信

64 位版本的 Windows 使用 32 位句柄来实现互操作性。在 32 位和 64 位应用程序之间共享句柄时,只有低 32 位有效,因此截断句柄(将其从 64 位传递到 32 位时)或对句柄进行符号扩展(将其从 32 位传递到 64 位时)。可以共享的句柄包括用户对象(如窗口 (HWND))的句柄、GDI 对象(如钢笔和画笔(HBRUSH 和 HPEN))的句柄,以及命名对象(如互斥体、信号量和文件句柄)的句柄。

还值得注意的是该页面上添加的此评论:

跨进程边界共享此类句柄的正确方法是将 32 位句柄零扩展为 64 位,反之亦然,将 64 位句柄截断为 32 位,丢弃最高位。

请注意“符号扩展”句柄与“零扩展”句柄之间的区别。

编辑:从这个问题的已删除答案中看到的讨论来看,我认为符号扩展 32 位句柄以达到 64 位句柄而不是零扩展的意义在于保留对 INVALID_HANDLE_VALUE 的正确处理句柄的值。

于 2015-04-08T22:52:55.427 回答
3

我希望知道它记录在哪里,但我的一位同事坚持认为 64 位 HWND 句柄始终适合 32 位。我从来没有见过这样的案例,它是不真实的,但不能谈论未来或它被记录在哪里。关于其他句柄,例如 HTREEITEM.... 它们是完整的 64 位,我一直认为它们太适合 32 位。

于 2014-10-24T19:38:22.683 回答
0

为了补充前面的正确答案,让我注意到 HWND 也是跨进程的有效句柄。任何其他 void* 句柄(如 HBRUSH、HBITMAP 等)可能是可截断的,因为只有低 32 位是有效的,但它在它自己的进程之外是无效的。

对于 GDI 对象,它可能会起作用,因为这些实际上是索引(请参阅https://docs.microsoft.com/en-us/previous-versions/ms810501(v=msdn.10)

好吧,这里发生的是 GDI 对象的句柄在内部实现为驻留在 Win32 子系统客户端的句柄表的偏移量。(请记住,Win32 客户端是驻留在基于 Win32 的应用程序的地址空间中并由应用程序调用的 DLL。)换句话说,句柄表是按进程保存的,但它们没有进程标记。这意味着属于进程 A 的对象的句柄可能巧合地看起来像进程 B 的上下文中的有效句柄。因此,从 B 调用 SelectObject 可能会成功,但 B 实际上会在其设备上下文中选择一个完全不同的对象——或者更糟的是,选择正确的对象。选择正确的对象可能会更糟,因为这些对象可能巧合相同,所以你认为它有效,但是该应用程序稍后会表现得很奇怪。所以,不要在应用程序之间传递句柄给 GDI 对象;它们在不同的过程中具有完全不同的含义。

HWND 是一个记录在案的例外。

于 2019-05-30T20:56:36.587 回答