红联Linux门户
Linux帮助

Linux中句柄是什么?

发布时间:2016-11-27 09:33:38来源:linux网站作者:不辣红烧肉
句柄:句柄是一个32位的整数,实际上是windows在内存中维护的一个对象(窗口等)内存物理地址列表的整数索引。
指针:指针对应着一个数据在内存中的地址,得到了指针就可以自由地修改该数据。
(在Linux有相应机制,但没有统一的句柄类型,各种类型的系统资源由各自的类型来标识,由各自的接口操作。)
当把硬盘上的资源调入内存以后,将有一个句柄指向它,但是句柄只能指向一个资源。而且句柄知道所指的内存有多大。还有指针,指针指向地址,它不知道分配的内存有多大。 
但是如果你定义一个句柄,然后在VC里面右击鼠标,选择"go to definition of handle”,你会发现它的本质就是一个指针,但是它的作用不同于指针。它和通常意义上的指针是有区别的。句柄借用了指针的思想,有它的逻辑特点,但没 有它的物理功能。句柄是WINDOWS分配给窗口等资源的唯一标识,是一个整数。
 
一、书上定义:
<<Microsoft Windows 3 Developer''s Workshop>>(Microsoft Press,by Richard Wilton)
在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)。 
<<WINDOWS编程短平快>>(南京大学出版社):
句柄是WONDOWS用来标识被应用程序所建立或使用的对象的唯一整数,WINDOWS使用各种各样的句柄标识诸如应用程序实例,窗口,控制,位图,GDI对象等等。WINDOWS句柄有点象C语言中的文件句柄。
 
二、MFC源代码:
#ifdef STRICT
typedef void *HANDLE;
#define DECLARE_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name
#else
typedef PVOID HANDLE;
#define DECLARE_HANDLE(name) typedef HANDLE name
#endif
DECLARE_HANDLE(HMODULE); 
DECLARE_HANDLE(HINSTANCE); 
DECLARE_HANDLE(HLOCAL); 
DECLARE_HANDLE(HGLOBAL); 
DECLARE_HANDLE(HDC); 
DECLARE_HANDLE(HRGN); 
DECLARE_HANDLE(HWND); 
DECLARE_HANDLE(HMENU); 
DECLARE_HANDLE(HACCEL); 
DECLARE_HANDLE(HTASK); 
 
三、理解:
句柄是一个32位的整数,实际上是windows在内存中维护的一个对象(窗口等)内存物理地址列表的整数索引。因为windows的内存管理经常 会将当前空闲对象的内存释放掉,当需要时访问再重新提交到物理存储,所以对象的物理地址是变化的,不允许程序直接通过物理地址来访问对象。程序将想访问的 对象的句柄传递给系统,系统根据句柄检索自己维护的对象列表就能知道程序想访问的对象及其物理地址了。句柄是一种指向指针的指针。我们知道,所谓指针是一 种内存地址。应用程序启动后,组成这个程序的各个对象是驻留在内存的。如果简单地理解,似乎我们只要获知这个内存的首地址,那么就可以随时用这个地址访问对象了。但是,如果真这么认为,那么就大错特错了。我们知道windows是一个虚拟内存为基础的操作系统。在这种情况下,windows内存管理器经常 在内存中来回移动对象,以此来满足各种应用程序的内存需要,对象被移动意味着它的地址变化了。如果地址总是如此的变化,我们应该去那里找对象呢?为了解决 这个问题,windows操作系统为各个应用程序腾出一些内存地址,用来专门登记各个应用对象在内存中的地址变化,而这个地址(存储单元的位置)本身是不变的。windows 内存管理器移动对象在内存中的位置后,把对象新的地址告知这个句柄地址来保存。这样我们只需要记住这个句柄地址就可以间接地知道对象具体在内存中哪个位置了。这个地址是在对象装载(load)时由系统分配的,当系统卸载时又释放给系统。句并地址(稳定)----->记载着对象在内存中的地址 -------->对象在内存中的地址(不稳定)----->实际对象。但是必须注意,程序每次重新启动,系统不保证分配跟这个程序的句柄还 是原来哪个句柄,而绝大多数情况下的确不一样。假如我们把进入电影院看电影看成是一个应用程序的启动运行,那么系统给应用程序分配的句柄总是不一样,这和 每次电影院给我们的门票总是不同的座位是一个道理。
因此,句柄和指针其实是两个截然不同的概念。windows系统用句并标记系统资源,用句并隐藏系统信息。你只需要知道有这个东西,然后去调用它就行了,它是32bit的uint。指针则标记某个物理内存的地址,是不同的概念。
指针对应着一个数据在内存中的地址,得到了指针就可以自由地修改该数据。Windows并不希望一般程序修改其内部数据结构,因为这样太不 安全。所以Windows给每个使用GlobalAlloc等函数声明的内存区域指定一个句柄(本质上仍是一个指针,但不要直接操作它),平时你只是在调 用API函数时利用这个句柄来说明要操作哪段内存。当你需要对某个内存进行直接操作时,可以使用GlobalLock锁住这段内存并获得指针来直接进行操作。
句柄是指针的“指针”,使用句柄主要是为了利于windows在进程内存地址空间移动分配的内存块,以防止进程的内存空间被撕的四分五裂而存在过多的碎片。 
句柄是一些表的索引也就是指向指针的指针。间接的引用对象,windows可以修改对象的"物理"地址和 描述器的值,但是句柄的值是不变的。
句柄可以在获得窗口的时候使用,指针可以进行调用窗口,两个使用的地方不一样.一个括号外,一个括号内.
从窗口指针获取窗口句柄:GetSafeHwnd();
从窗口句柄获取临时窗口指针:FromHandle(); 
从窗口句柄获取永久窗口指针: FromHandlePermanent();
其实两者被没有关系,实际上是MFC在创建窗口的时候用钩子函数沟住HCBT_CREATEWND消息,
然后通过CWnd::Attach()函数把二者捆绑在一起。
以后就可以用GetSafeHwnd(),FromHandle(),FromHandlePermanent()这三个函数可以互相得到了。
MFC之所以要这样做,主要是为了使原来的SDK面向过程的编程遍成面向对象的编程,所有的MFC的窗口都共用一窗口过程函数,在窗口过程函数里, 通过窗口句柄(HWND)找到窗口对象指针(CWnd *)从而把消息分发到窗口对象中,这样以后就可以在窗口类中实行消息响应编程处理了。
 
附注:获得窗口句柄三种方法
1.HWND FindWindow(LPCTSTR lpClassName, LPCTSTR lpWindowName) 
HWND FindWindowEx(HWND hwndParent, HWND hwndChildAfter,LPCTSTR lpClassName, LPCTSTR lpWindowName)
2.HWND WindowFromPoint(POINT& Point)//获得当前鼠标光标位置的窗口HWND
3.BOOL CALLBACK EnumChildProc(HWND hwnd,LPARAM lParam)
BOOL CALLBACK EnumChildWindows(HWND hWndParent, WNDENUMPROC lpEnumFunc,LPARAM lParam)
BOOL CALLBACK EnumWindows(WNDENUMPROC lpEnumFunc, LPARAM lParam)
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
 
在Linux中:
1.句柄就是一个标识符,只要获得对象的句柄,我们就可以对对象进行任意的操作。
2.句柄不是指针,操作系统用句柄可以找到一块内存,这个句柄可能是标识符,map的key,也可能是指针,看操作系统怎么处理的了。
fd算是在某种程度上替代句柄吧;
Linux有相应机制,但没有统一的句柄类型,各种类型的系统资源由各自的类型来标识,由各自的接口操作。
3.在操作系统层面上,文件操作也有类似于FILE的一个概念,在Linux里,这叫做文件描述符(FileDescriptor),而在Windows里,叫做句柄(Handle)(以下在没有歧义的时候统称为句柄)。用户通过某个函数打开文件以获得句柄,此后用户操纵文件皆通过该句柄进行。
设计这么一个句柄的原因在于句柄可以防止用户随意读写操作系统内核的文件对象。无论是Linux还是Windows,文件句柄总是和内核的文件对象相关联的,但如何关联细节用户并不可见。内核可以通过句柄来计算出内核里文件对象的地址,但此能力并不对用户开放。
下面举一个实际的例子,在Linux中,值为0、1、2的fd分别代表标准输入、标准输出和标准错误输出。在程序中打开文件得到的fd从3开始增长。
fd具体是什么呢?在内核中,每一个进程都有一个私有的“打开文件表”,这个表是一个指针数组,每一个元素都指向一个内核的打开文件对象。而fd,就是这个表的下标。当用户打开一个文件时,内核会在内部生成一个打开文件对象,并在这个表里找到一个空项,让这一项指向生成的打开文件对象,并返回这一项的下标作为fd。由于这个表处于内核,并且用户无法访问到,因此用户即使拥有fd,也无法得到打开文件对象的地址,只能够通过系统提供的函数来操作。
在C语言里,操纵文件的渠道则是FILE结构,不难想象,C语言中的FILE结构必定和fd有一对一的关系,每个FILE结构都会记录自己唯一对应的fd。
在程序设计中,句柄是一种特殊的智能指针。当一个应用程序要引用其他系统(如数据库、操作系统 )所管理的内存 块或对象时,就要使用句柄。
句柄与普通指针的区别在于,指针包含的是引用对象的内存地址,而句柄则是由系统所管理的引用标识,该标识可以被系统重新定位到一个内存地址上。这种间接访问对象的模式增强了系统对引用对象的控制。
在上世纪80年代的操作系统(如MacOS 和Windows)的内存管理中,句柄被广泛应用。Unix 系统的文件描述符基本上也属于句柄。和其它桌面环境 一样,WindowsAPI 大量使用句柄来标识系统中的对象,并建立操作系统与用户空间之间的通信渠道。例如,桌面上的一个窗体由一个HWND 类型的句柄来标识。
如今,内存容量的增大和虚拟内存算法使得更简单的指针 愈加受到青睐,而指向另一指针的那类句柄受到冷淡。尽管如此,许多操作系统仍然把指向私有对象的指针以及进程传递给客户端 的内部数组下标称为句柄。
 
本文永久更新地址:http://www.linuxdiyf.com/linux/26358.html