返回列表 发帖

[转帖]关于句柄

<>(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程序中并不是用物理地址来标识一个内存块,文件,任务或动态装入模块的,相反的,WINDOWS API给这些项目分配确定的句柄,并将句柄返回给应用程序,然后通过句柄来进行操作。 在<>(南京大学出版社): 句柄是WONDOWS用来标识被应用程序所建立或使用的对象的唯一整数,WINDOWS使用各种各样的句柄标识诸如应用程序实例,窗口,控制,位图,GDI对象等等。WINDOWS句柄有点象C语言中的文件句柄。 babyman(原文经过翻译): 尽管你会想要深入钻研源代码,但你其实并不会这样做。Windows编程起初都是非常困难的。让我们来快速的看一看Windows下的程序是这样运作的。你编程的关键将是处理和发送消息。那什么是消息呢?简单的说,消息是一个32位值,用来指明一个事件。比如:当你移动鼠标的时候,一个消息(定义为WM_MOUSEMOVE)就被发送给当前的窗口。当你按下键盘上的键,一个消息(定义为WM_KEYDOWN)就被发送给了当前的窗口。当你调整窗口的尺寸,一个消息(定义为WM_SIZE)被发送到当前的窗口。想象出这个过程了么?那么这些消息被发送到哪里去了呢?它们会排进一个队里,窗口最终会将它们拿出来并相应的执行。例如当窗口得到WM_MOVE消息,它将改变窗口坐标并在屏幕上重画窗口。 让我们来看看句柄。Windows在面向对象方面做的很好。你面对着一些window对象(比如桌面,你现在用来阅读的程序,等等...)。一个程序员用非面向对象的方式怎么区分这类东呢? 句柄用来引用不同的windows对象。你可以对窗口、文件使用句柄,也能对分配了的内存、图象使用句柄。可以把句柄理解为与指针类似。你必须通过某种方式来创建句柄;而且在使用完后销毁掉,不然将造成资源泄漏而使你的系统瘫痪。所以要保证它们在某个时候被销毁了。 好了,现在是时候让我们把这两件东西放在一起了。 比方说有一个窗口,你有一个指向它的句柄(称为HWND)。把你的句柄命名为your_HWND。当这个遮盖在这个窗口上面的其他窗口被移去的时候,系统会要求你重画窗口。windows会这样发送消息: PostMessage(your_HWND, WM_PAINT, 0,0); 这个函数发送一个重画的消息给句柄为your_HWND的窗口。最后的两个参数作为该消息的额外信息,现在先不必考虑。这样,你的程序就应该有一个包括很多分支判断的函数来处理不同的消息。比如: void HandleTheMessage(long Message) { switch(Message) { case WM_PAINT DrawWindow(); break; case WM_KEYDOWN break; etc... } } sebsdin (孤灯下) from BBS 水木清华站: 句柄是一种指向指针的指针。我们知 道,所谓指针是一种内存地址。应用程序启动后,组成这 个程序的各对象是住留在内存的。如果简单地理解,似乎我们只要获知这个内存的首地址,那么就可以随时用这个地址 访问对象。但是,如果您真的这样认为,那么您就大错特错了。我们知道,Windows是一 个以虚拟内存为基础的操作系统。在这种系统环境下,Windows内存管理器经常在内存中来回移动对象,依此来满足各种应用程序的内存需要。对象被移动意味着它的地址变化 了。如果地址总是如此变化,我们该到哪里去找该对象呢?为了解决这个问题,Windows操作系统为各应用程序腾出一些内存储地址,用来专门 登记各应用对象在内存中的地址变化,而这个地址(存储单元的位置)本身是不变的。Windows内存管理器在移动对象在内存中的位置后,把对象新的地址告知这个句柄地址来保存。这样我们只需记住这个句柄地址就可以间接地知道对象具体在内存中的哪个位置。这个地址是在对象装载(Load)时由系统分配给的,当系统卸载时(Unload)又释放给系统。句柄地址(稳定)→记载着对象在内存中的地址→对象在内存中的地址(不稳定)→实际对象。但是,必须注意的是程序每次从新启动,系统不能保证分配给这个程序的句柄还是原来的那个句柄,而且绝大多数情况的确不一样的。假如我们把进入电影院看电影看成 是一个应用程序的启动运行,那么系统给应用程序分配的句柄总是不一样,这和每次电 影院售给我们的门票总是不同的一个座位是一样的道理。 feeboby from csdn: 受M$的帮助文档以及很多Windows编程书籍的影响,大家对局柄比较普遍的认识是:句柄 是一个整数,用以标识Windows对象,句柄不是一个指针……而实际上,这些不过是M$进行数据封装的幌子而已,下面我们一起来分析一下HANDLE到底是什么。 请先到Windef.h找绝大多数句柄的定义: DECLARE_HANDLE(HWND); DECLARE_HANDLE(HHOOK); …… DECLARE_HANDLE(HGDIOBJ); DECLARE_HANDLE(HBITMAP); DECLARE_HANDLE(HBRUSH); …… typedef HANDLE HGLOBAL; typedef HANDLE HLOCAL; …… OK, 现在大家跟我一起翻到Winnt.h,看看DECLARE_HANDLE和HANDLE到底是什么: #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 typedef HANDLE *PHANDLE; 哈哈,现在知道了吧,HANDLE就是PVOID,也就是无类型指针, 而DECLARE_HANDLE(HWND);就是: struct HWND__ { int unused;}; typedef struct HWND__ *HWND; 现在实际上都清楚啦,这些Handles都不过是指向struct的指针,至于这个struct的用处 ,连M$都说unused了,^o^ 现在解释下M$这么做的意义,这就是所谓数据封装,你可以在你的程序中把M$的内部结 构指针传来传去,可是你却不知道它到底指向的内容是什么,而且可以编个句柄的瞎话 防止大家的质疑:)。而M$的程序大可以这么写: #include //这个和大家用的一样 #include "windows_in.h" //这个是M$自用的,外人别想看到^o^ HSOMETHINGELSE DoSomething(HSOMETHING hSomething) { struct RealSomething* p = (struct RealSomething*)hSomething; //先强制类型 转换成内部结构指针 ……do something…… return (HSOMETHINGELSE)pRealSomethingElse;//强制类型逆转换 } classfactory from vcroad: 单从概念上讲,句柄指一个对象的标识,而指针是一个对象的首地址。从实际处理的角度讲,即可以把句柄定义为指针,又可以把它定义为同类对象数组的索引,这两种处理方法都有优缺点,至于选用哪种方式,完全应该看实际需要,这可以说是一种程序设计上的技巧。那种单纯认为句柄是指针或索引的想法都是机械的、不确切的。 其实,在Windows中类似的处理是很多的、很灵活的。再具个相似的例子: 我们知道,在Windows中有个函数叫做CallWindowProc。故名思义,它的作用就是向指定的窗口过程传递一个消息。你也许会想,既然我已经有了窗口过程的指针,为什么我不可以直接通过这个指针调用该函数(这是C语言的内建功能)?事实上,在Win16中确实可以这么做,因为GetWindowLong返回的确实是该函数的指针。但在Win32下,GetWindowLong返回的并不是该函数的指针,而是一个包含函数指针的数据结构的指针(MSDN上说返回的是一个窗口函数地址或它的句柄,就是指的这种情况)。该数据结构是可变的,但只要你使用CallWindowProc来调用的话是不会出错的。这里我们又看到使用句柄处理带来的好处。(补充说明一点:微软在这里之所以这么处理,是为了解决16位/32位以及ANSI/UNICODE的转化问题) 神呀,救救那些头脑呆板、一知半解的人吧! 另有一段文字,作者不详: 句柄是一个标识符,是拿来标识对象或者项目的,它就象我们的姓名一样,每个人都会有一个,不同的人的姓名不一样,但是,也可能有一个名字和你一样的人。从数据类型上来看它只是一个16位的无符号整数。应用程序几乎总是通过调用一个WINDOWS函数来获得一个句柄,之后其他的WINDOWS函数就可以使用该句柄,以引用相应的对象。在WINDOWS编程中会用到大量的句柄,比如:HINSTANCE(实例句柄),HBITMAP(位图句柄),HDC(设备描述表句柄),HICON(图标句柄)等等,这当中还有一个通用的句柄,就是HANDLE,比如下面的语句: HINSTANCE hInstance; 可以改成: HANDLE hInstance; 上面的2句语句都是对的。 一个WINDOWS应用程序可以用不同的方法获得一个特定项的句柄。许多API函数,诸如CreateWindow,GlobalAlloc,OpenFile的返回值都是一个句柄值。另外,WINDOWS也能通过应用程序的引出函数将一个句柄作为参数传送给应用程序,应用程序一旦获得了一个确定项的句柄,便可在WINDOWS环境下的任何地方对这个句柄进行操作。其实句柄的大量使用已经影响到了每一个WINDOWS的程序设计。 句柄只有当唯一的确定了一个项目的时候,它才开始有意义。句柄对应着项目表中的一项,而只有WINDOWS本身才能直接存取这个表,应用程序只能通过API函数来处理不同的句柄,举个例子来说吧!比如:我们可以为我们的应用程序申请一块内存块,通过调用API函数GlobalAlloc,来返回一个句柄值: hMem=GlobalAlloc(......); 其实现在hMem的值只是一个索引值,不是物理地址,应用程序还不能直接存取这块内存。这儿还有一个话外题,就是,一般情况下我们在编程的时候,给应用程序分配的内存都是可以移动的或者是可以丢弃的,这样能使有限的内存资源充分利用,所以,在某一个时候我们分配的那块内存的地址是不确定的,因为他是可以移动的,所以得先锁定那块内存块,这儿应用程序需要调用API函数GlobalLock函数来锁定句柄。如下: lpMem=GlobalLock(hMem); 这样应用程序才能存取这块内存 转贴于 华夏黑客同盟

[转帖]关于句柄

收了,路过,给楼主UP一下~~~

TOP

[转帖]关于句柄

加一些句柄的基础知识~~ 句柄一般用来指获取另一个对象的方法——一个广义的假指针。 含糊不清在实际中的某些情况下是有用的。例如,在早期设计时,你可能不准备用句柄来表示。你可能不确定是否将一个简单的指针或者引用或者指向指针的指针或者指向引用的指针或者整型标识符放在一个数组或者字符串(或其它键)以便能够以哈希表(hash-table)(或其他数据结构)或数据库键或者一些其它的技巧来查询。如果你只知道你会需要一些唯一标识的东西来获取对象,那么这些东西就被称为句柄。 因此,如果你的最终目标是要让代码唯一的标识/查询一个Fred类的指定的对象的话,你需要传递一个Fred句柄给这些代码。句柄可以是一个能被作为众所周知的查询表中的键(key)来使用的字符串(比如,在std::map 或 std::map中的键),或者它可以是一个作为数组中的索引的整数(比如,Fred* array = new Fred[maxNumFreds]),或者它可以是一个简单的 Fred*,或者它可以是其它的一些东西。 初学者常常考虑指针,但实际上使用未初始化的指针有底层的风险。例如,如果Fred对象需要移动怎么办?当Fred对象可以被安全删除时我们如何获知?如果Fred对象需要(临时的)连续的从磁盘获得怎么办?等等。这些时候的大多数,我们增加一个间接层来管理位置。例如,句柄可以是Fred**,指向Fred*的指针可以保证不会被移动。当Fred对象需要移动时,你只要更新指向Fred*的指针就可以了。或者让用一个整数作为句柄,然后在表或数组或其他地方查询Fred的对象(或者指向Fred对象的指针)。 重点是当我们不知道要做的事情的细节时,使用句柄。 使用句柄的另一个时机是想要将已经完成的东西含糊化的时候(有时用术语magic cookie也一样,就像这样,“软件传递一个magic cookie来唯一标识并定位适当的Fred对象”)。将已经完成的东西含糊化的原因是使得句柄的特殊细节或表示物改变时所产生的连锁反应最小化。举例来说,当将一个句柄从用来在表中查询的字符串变为在数组中查询的整数时,我们可不想更新大量的代码。 句柄的细节或表示物改变时,维护工作更为简单(或者说阅读和书写代码更容易),因此常常将句柄封装到类中。这样的类常重载operator-> 和 operator*算符(既然句柄的效果象指针,那么它可能看起来也象指针)。 内存句柄与指针的区别 指针对应着一个数据在内存中的地址,得到了指针就可以自由地修改该数据。Windows并不希望一般程序修改其内部数据结构,因为这样太不安全。所以Windows给每个使用GlobalAlloc等函数声明的内存区域指定一个句柄(本质上仍是一个指针,但不要直接操作它),平时你只是在调用API函数时利用这个句柄来说明要操作哪段内存。当你需要对某个内存进行直接操作时,可以使用GlobalLock锁住这段内存并获得指针来直接进行操作。 意见1: 句柄是指针的“指针”,使用句柄主要是为了利于windows在进程内存地址空间移动分配的内存块,以防止进程的内存空间被撕的四分五裂而存在过多的碎片。 意见2: 句柄是一些表的索引也就是指向指针的指针。间接的引用对象,windows可以修改对象的"物理"地址和描述器的值,但是句柄的值是不变的。 意见3: 句柄和指针都是地址,不同在于: 1,句柄所指的可以是一个很复杂的结构,并且很有可以是与系统有关的,比如说上面所说的线程的句柄,它指向的就是一个很类或者结构,他和系统有很密切的关系,当一个线程由于不可预料的原因,而终止时在系统就可以回它所占用的资料,如CPU,内存等等,反过来想可以知道,这个句柄中的某一些项,是与系统进行交互的。由于Windows系统,是一个多任务的系统,它随时都可能要分配内存,回收内存,重组内存。 2,指针它也可以指向一个复杂的结构,但是通常是用户定义的,所以的必需的工作都要用户完成,特别是在删除的时候。 但在VC++6.0中也有一些指针,它们都是处理一些小问题才用的,如最常见的字符的指针,它也是要用户处理的如果你动态分配了内存;但是Cstring就不要用户处理了,它其实是VC++中的一个类,所以的操作都由成员函数完成,产生(分配)由构造函数,删除(回收)由析构函数完成。

TOP

[转帖]关于句柄

单从概念上讲,句柄指一个对象的标识,而指针是一个对象的首地址。从实际处理的角度讲,即可以把句柄定义为指针,又可以把它定义为同类对象数组的索引,这两种处理方法都有优缺点,至于选用哪种方式,完全应该看实际需要,这可以说是一种程序设计上的技巧。那种单纯认为句柄是指针或索引的想法都是机械的、不确切的。

TOP

返回列表 回复 发帖