系统相关
首页 > 系统相关> > Windows句柄剖析

Windows句柄剖析

作者:互联网

1 什么是句柄

句柄的概念:     

       在系统中指向某个控件或对象的唯一指针(也可叫句柄),系统可以通过这个句柄与所对应的控件或对象交互(控制它)。控件或对象与句柄的关系就好比电视机与遥控器,通过遥控器来控制电视机一样。

         Windows 环境中有很多对象,诸如窗口、画笔、位图、光标、设备环境、程序实例等,可以通过API函数以不同的形式对这些对象进行操作。为此,必须以某种方法对这些对象进行标识,并把它们以参数的形式传递给函数。Windows用一个32位的整数对各种对象进行标识,这就是“句柄”(Handle)。也就是说句柄是一个对象的标识符。

      句柄----用来标识指定一个窗体的,一个窗体有一个唯一的标识,引用句柄就可以引用窗体”。

比如说:

教室是一台计算机

老师是WINDOWS内核

学生是窗体

句柄的作用:

      老师叫学生最准确的方式是用“学号”,因为学号是唯一的,姓名可能重复;

        WINDOWS操作系统要操纵窗体当然要有个唯一标识号,那就是HANDLE(句柄)

消息机制:

   学生举手->老师选择某个同学,叫出他的学号->学生发言

  窗体请求->操作系统轮循检查到有请求,送消息给窗体->窗体响应消息,发送消息

句柄是什么?

      句柄是其实一个长整型的数字,它是WINDOWS唯一用来分别各个控件的标识。在windows中,句柄是和对象一一对应的32位无符号整数值。对象可以映射到唯一的句柄,句柄也可以映射到唯一的对象。应用程序几乎总是通过调用一个WINDOWS函数来获得一个句柄,之后其他的WINDOWS函数就可以使用该句柄,以引用相应的对象。

句柄是一个标识符,是拿来标识对象或者项目的。

句柄可以表示的项目:

*.模块(module)                         *.任务(task)

*.实例(instance)                        *.文件(file)

*.内存块(block of memory)    *.菜单(menu)

*.控件(control)                          *.字体(font)

*.资源(resource), 包括图标(icon),光标(cursor),字符串(string)等

*.GDI对象(GDI object),包括位图(bitmap),画刷(brush),元文件(metafile),调色板(palette),画笔(pen),区域(region),以及设备描述表(device context)。

在Win32里,句柄是指向一个“无类型对象”(void*)的指针,也就是一个4字节长的数据。

句柄的声明:

typedef void * HANDLE

        从构造上看,句柄是一个指针,尽管它没有指向用于存储某个对象的内存位置。事实上,句柄指向一个包含了对该对象进行的引用的位置。

 2 为什么要使用句柄

       windows需要句柄。windows需要向程序员提供必要地编程接口,在这些接口中,允许程序员访问、创建和销毁对象。

       出于封装的考虑,windows并不想向程序员返回指针。指针包含了太多的信息。

      首先指针给出了对象存储的确切位置;

      其次,要操作一个指针,程序员必须知道指针所指对象的内部结构特征,也即,windows必须向程序员暴露相应的数据结构。

为此,折中处理:

     1.Windows不向用户直接暴露数据;

     2.同时又允许用户按自己的方式直接操作数据;

3 句柄深入剖析

句柄其实是一个指向指针的指针

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

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

注:句柄地址(稳定)→记载着对象在内存中的地址→对象在内存中的地址(不稳定)→实际对象

本质:

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

        句柄是指针的“指针”,使用句柄主要是为了利于windows在进程内存地址空间移动分配的内存块,以防止进程的内存空间被撕的四分五裂而存在过多的碎片。

4 句柄和指针

       句柄和指针其实是两个截然不同的概念。windows 系统用句并标记系统资源,用句柄隐藏系统信息。你只需要知道有这个东西,然后去调用它就行了,它是32bit 的 uint。指针则标记某个物理内存的地址,是不同的概念。

       句柄是指针的“指针” ,使用句柄主要是为了利于 windows 在进程内存地址空间移动分配的内存块,以防止进程的内存空间被撕的四分五裂而存在过多的碎片。

       句柄是一些表的索引也就是指向指针的指针。间接的引用对象,windows 可以修改对象的物理地址和描述器的值,但是句柄的值是不变的。    

指针和句柄的区别:

1.指针

①.指针对应着某个数据在内存空间中的地址,得到了指针就可以自由地修改该数据。

②. 指针也可以指向一个复杂的结构,但通常是由用户自我定义的,所以一些必需的工作都要由用户自己完成,特别是在删除的时候。

2.句柄

①.句柄代表指针的“指针”,也可以将其比作表中数据项的索引值( 表对应某个进程自身的内存空间 )。句柄是间接的引用对象。

②.句柄所指的可以是一个很复杂的结构,并且很有可能与系统有关的,比如上面所说线程的句柄,它指向的就是一个类或者结构,它和系统有很密切的关系。

从窗口指针获取窗口句柄:GetSafeHwnd();

从窗口句柄获取临时窗口指针:FromHandle();

从窗口句柄获取永久窗口指针: FromHandlePermanent()

指针和句柄之间的转换:

a.由指针获得句柄

CWnd * pWnd;

 HWND hwnd;

hwnd = pWnd->GetSafeHWnd(); 

b.由句柄得到指针

CWnd* pWnd=FromeHandle(hMyHandle);

pWnd->SetWindowText("Hello World!");

or CWnd* pWnd; pWnd->Attach(hMyHandle);

5 MFC获得各类指针和句柄的方法

1.获取主窗口句柄:

HWND hwnd = AfxGetMainWnd()->m_hWnd;

2.获得当前窗口的句柄:

GetActiveWindow();

3.获得某个窗口对象指针的句柄:

GetSafeHwnd();

4.获取父窗口句柄:

GetParent();

5.获取控件的句柄:

CWnd *pWnd = GetDlgItem(IDD_***);    //取得控件的指针

HWND hwnd = pWnd->GetSafeHwnd();//取控件的句柄

6.获取静态文本句柄:

//法1:
CPaintDC dc(this);

HDC  hDC;

hDC = dc.m_hDC;

//法2:

CDC  *pDC;

HDC  hDC;

hDC= pDC->GetSafeHdc();

MFC Object  和 Windows Object对比

描述               Windows句柄                     MFC Object

窗口                   HWND                                CWnd

设备上下文        HDC                                     CDC

菜单                   HMENU                                CMenu

画笔                    HPEN                                     CPen

画刷                     HBRUSH                                CBrush

字体                      HFONT                                 CFont

位图                      HBITMAP                             CBitmap

套接字                   SOCKET                                CSocket    

6 窗口ID、句柄和指针之间的转换

1. ID->句柄

 hWnd = ::GetDlgItem(hParentWnd, id);

2. ID->指针

 CWnd::GetDlgItem();

3. 句柄->ID

id = GetWindowLong(hWnd, GWL_ID);

4.句柄->指针

CWnd *pWnd=CWnd::FromHandle(hWnd);

5. 指针->ID

Id = GetWindowLong(pWnd>GetSafeHwnd, GWL_ID);

6. 指针->句柄 

//法1:
(CWnd *pmywnd; )

hWnd= pmywnd.GetSafeHandle()

//法2:

CWnd *pmywnd;  

 hWnd =  pmywnd->m_hWnd;

标签:pWnd,Windows,句柄,剖析,对象,地址,内存,指针
来源: https://blog.csdn.net/zhangchuan7758/article/details/121967154