句柄(Handle)是什么--对句柄的简单理解。

本文详细解释了C++中句柄的概念,句柄是Windows编程的基础,用于标识不同对象及其实例,如窗口、按钮等。句柄作为标识符,其值在程序运行期间保持不变,但指向的对象地址可能发生变化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    开始学习C++,不了解句柄,无从下手,今天在网上找了找,并查阅MSDN,算是明白了不少。现汇总如下:

    简单说来,句柄(Handle)就是对象的一个标识,它就像是人的身份证号码一样具有唯一性。它是Windows用来标识被应用程序所建立或使用的对象的唯一整数(LONG类型的整数,4个字节)。
    句柄是整个Windows编程的基础。用于标识应用程序中不同的对象和同类对象中不同的实例,诸如一个窗口,按钮,图标,滚动条,输出设备,控件或者文件等,都有各自不同的句柄。
    句柄是一些表的索引,也就是指向指针的指针。间接的引用对象,Windows可以修改对象的"物理"地址和描述器的值,但是句柄的值是不变的。
    使用句柄有利于Windows在进程内存地址空间移动分配的内存块,以防止进程的内存空间被撕的四分五裂而存在过多的碎片。

 

    句柄是一个标识符,是拿来标识对象或者项目的,从数据类型上来看它只是一个16位的无符号整数。应用程序几乎总是通过调用一个Windows函数来获得一个句柄,之后其他的Windows函数就可以使用该句柄,以引用相应的对象。

    句柄是一种指向指针的指针。所谓指针是一种内存地址。应用程序启动后,组成这个程序的各对象是住留在内存的。如果简单地理解,似乎我们只要获知这个内存的首地址,那么就可以随时用这个地址访问对象了。不过,Windows是一个以虚拟内存为基础的操作系统。在这种系统环境下,Windows内存管理器经常在内存中来回移动对象,依此来满足各种应用程序的内存需要。对象被移动意味着它的地址变化了。如果地址总是如此变化,该到哪里去找该对象呢?

    为了解决这个问题,Windows操作系统为各应用程序腾出一些内存储地址,用来专门登记各应用对象在内存中的地址变化,而这个地址(存储单元的位置)本身是不变的。Windows内存管理器在移动对象(在内存中的位置)后,把对象新的地址告知这个句柄地址来保存。这样只需记住这个句柄地址,就可以间接地知道对象具体在内存中的哪个位置。这个地址是在对象装载(Load)时由系统分配给的,当系统卸载时(Unload)又释放给系统。 
    句柄地址(稳定)→记载着对象在内存中的地址;对象在内存中的地址(不稳定)→实际对象。


    本质:Windows程序中并不是用物理地址来标识一个内存块,文件,任务或动态装入模块的,相反的,Windows API给这些项目分配确定的句柄,并将句柄返回给应用程序,然后通过句柄来进行操作。

    但是必须注意的是程序每次从新启动,系统不能保证分配给这个程序的句柄还是原来的那个句柄,而且绝大多数情况的确不一样的。

 

[From MSDN]

 

TN003: Mapping of Windows Handles to Objects

This note describes the MFC routines that support mapping Windows object handles to C++ objects.

The Problem

Windows objects are normally represented by HANDLEs. The MFC classes wrap Windows object handles with C++ objects. The handle wrapping functions of the MFC class library provide a way to find the C++ object that is wrapping the Windows object with a particular handle. There are times when a Windows object does not have a C++ wrapper object, however, and at these times a temporary object is created to act as the C++ wrapper.

The Windows objects that use handle maps are:

  • HWND (CWnd and CWnd-derived classes)
  • HDC (CDC and CDC-derived classes)
  • HMENU (CMenu)
  • HPEN (CGdiObject)
  • HBRUSH (CGdiObject)
  • HFONT (CGdiObject)
  • HBITMAP (CGdiObject)
  • HPALETTE (CGdiObject)
  • HRGN (CGdiObject)
  • HIMAGELIST (CImageList)
  • SOCKET (CSocket)

Given a handle to any of these objects, you can find the MFC object that wraps the handle by calling the static member function FromHandle. For example, given an HWND called hWnd:

CWnd::FromHandle(hWnd)

will return a pointer to the CWnd that wraps the hWnd. If that hWnd does not have a specific wrapper object, then a temporary CWnd is created to wrap the hWnd. This makes it possible to get a valid C++ object from any handle.

Once you have a wrapper object, you can get to its handle through a public member variable. In the case of an CWnd, m_hWnd contains the HWND for that object.

Attaching Handles to MFC Objects

Given a newly created handle-wrapper object and a handle to a Windows object, you can associate the two by calling Attach. For example:

CWnd myWnd;
myWnd.Attach(hWnd);

This makes an entry in the permanent map associating myWnd and hWnd. Calling CWnd::FromHandle(hWnd) will now return a pointer to myWnd. When myWnd is deleted, the destructor will automatically destroy the hWnd by calling the Windows DestroyWindow function. If this is not desired, the hWnd must be detached from myWnd before the myWnd object is destroyed (normally when leaving the scope at which myWnd was defined). The Detach member function does this.

myWnd.Detach();
### ESP-IDF 中句柄的概念 在 ESP-IDF 编程环境中,句柄handle)是一个非常重要的概念。句柄通常是指向特定对象或资源的引用,在编程过程中用于间接访问这些对象或资源。 #### 定义与作用 句柄本质上是一种数据结构指针,用来唯一标识某个实体实例。这种机制允许开发者创建多个相同类型的对象,并通过不同的句柄来区分它们[^1]。例如,在 Wi-Fi 驱动程序中,可以通过不同句柄管理多个网络接口;而在 GPIO 控制里,则可以用句柄代表各个引脚配置情况。 #### 创建与初始化 当调用某些 API 函数创建新对象时,函数会返回一个句柄给调用者。这个过程类似于申请内存空间并获得指向该空间地址的过程: ```c // 创建事件循环句柄的例子 esp_err_t ret; event_loop_handle_t event_loop_h; ret = esp_event_loop_create_default(&event_loop_h); if (ret != ESP_OK) { // 错误处理... } ``` 上述代码片段展示了如何利用 `esp_event_loop_create_default` 来获取一个新的事件循环句柄 `event_loop_h`[^2]。 #### 使用场景 - **驱动模块**:对于硬件外设的操作往往涉及到句柄的应用,比如 SPI、I2C 总线通信等。 - **系统组件**:像任务调度器(Task Handle),队列(Queue Handle),信号量(Semaphore Handle)等RTOS特性也广泛采用了句柄作为参数传递方式之一。 - **网络协议栈**:TCP/IP 协议栈中的 socket 连接同样依赖于句柄来进行连接管理和数据传输操作。 #### 生命周期管理 需要注意的是,一旦不再需要某一句柄所关联的对象,应当及时释放相应的资源以防止泄露。这一般通过专门提供的销毁/删除API完成: ```c // 删除之前创建的任务句柄 vTaskDelete(task_handle); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值