我是一初学者,正在被windows编程所吸引,但同时也遇到很多让人苦恼的问题,句柄跟指针的区别我想网上的谈论算够多了,但是什么意见都有,有时候看了这个高人的说法觉得有道理,并认为是那样,但是不久以后看了另一个人的提法,觉得他说的也是,所以我现在真的是搞不清了,希望哪位出来帮帮忙!
------------------------------------
以下转载vc知识库
[问题提出]
  如果想对对话框的控件进行控制,那么首先要获得此控件的句柄(指针),然后对其操作.
  [解决方法]
  MFC提供了获取子窗口,指定控件和指定窗口句柄的函数:CWnd::GetDlgItem.
  [实现程序]
  假设你已有了名为My的对话框工程,并且有了一个ID=IDC_EDIT1的Edit控件:
  BOOL CMyDlg::OnInitDialog()
  {
     CDialog::OnInitDialog();
     CEdit *m_Edit=(CEdit *)GetDlgItem(IDC_EDIT1);
     m_Edit->SetWindowText("练习");
     return TRUE;
  }
-----------------------------------
第二:以下是另一种说法:  许多开始学习VC的朋友,最多听说的两个词莫过于指针于句柄了。 
但是,确经常搞不清他们之间的区别。 
首先,句柄是一个窗口的标志,也就是所有从CWND类继承下来的,多有句柄这个成员。 
他能做的,也就是唯一代表一个桌面上的窗口罢了。而指针是一个地址,如果它指向了一个内存中的对象,那么就可以对它进行任意操作了,当然,并不局限于自己的应用程序,你如果能够获得别的应用程序的某个对象的指针,也可以进行操作。然而,如果要获得指针,首先,必须找到那个窗口的句柄,然后用函数FromHandle就可以得到他的指针了。好了,现在,你可以对窗口任意操作了
-------------------------------
第三:
以下另一种说法:
看看C++ 教材中是如何给句柄下定义的:“在Win32里,句柄是指向一个无值型对象(void *)的指针,是一个4字节长的数据”。虽然我对它的本质是什么还是很迷惑,但我知道句柄并不是一个真正意义上的指针。从结构上看,句柄的确是一个指针,尽管它没有指向用于存储某个对象的内存位置(很多书都这么说,这正是我的迷惑所在),而实际上句柄指向的是一个包含了对该对象进行的引用的位置。在编程时,只要抓住了对象的句柄就可以对该对象进行操作了---------------------------------
我想问一下,通过对象的指针和通过对象的句柄来 操作对象到底有什么区别?
为什么有的说法是要先获取句柄以后在获取指针?

解决方案 »

  1.   

    在这里你要区分出两个对象的概念:C++的对象:要用指针来操作而Window系统内部的对象,比如一个窗口(User对象)则是用句柄来操作的。实际句柄在MSDN中的定义就是标识系统资源的一个变量。系统资源有很多比如画刷(Brush)、事件(Event)等等,并不只是窗口一种。在VC中的体现例如:CWnd* 和HWND 的区别,一个是MFC对窗口包装类的指针,一个是窗口的句柄
      

  2.   

    楼主引用的话,并不矛盾,指针指向的是对象在内存中的实际地址,有了它你就可以对对象进行自由的控制。而句柄虽然也可以代表一个具体的对象,但你用它的值并不能直接去控制对象,你只有把它交给操作系统,操作系统通过查表的方式去找该对象在内存中的实际地址,然后才能去控制它。比如用函数FromHandle,就是你把句柄交给操作系统,而操作系统把它的指针传回给你,用函数::SetWindowText(HWND," "),则是你把句柄交给操作系统,让它去对该窗口对象进行操作。
      

  3.   

    首先,句柄是一个窗口的标志,也就是所有从CWND类继承下来的,多有句柄这个成员。 
    他能做的,也就是唯一代表一个桌面上的窗口罢了。而指针是一个地址,如果它指向了一个内存中的对象,那么就可以对它进行任意操作了,当然,并不局限于自己的应用程序,你如果能够获得别的应用程序的某个对象的指针,也可以进行操作。然而,如果要获得指针,首先,必须找到那个窗口的句柄,然后用函数FromHandle就可以得到他的指针了。好了,现在,你可以对窗口任意操作了这里需要明确的是:这里的指针和句柄完全是两个东西,这里的指针指的是MFC封装的窗口类对象的指针,如果这个对象没有跟具体的窗口关联起来,那么这个指针屁用都没有。
    而句柄的确是标识系统资源的一个变量,指向的是一个包含了对该对象进行的引用的位置。标识了具体的窗口或其他如画刷等对象。句柄,HWND,是一个无类型的指针,实际指向的是一个结构,因此他并不指向一个实际的窗口或系统其他资源的对象。如何能通过他找到具体的对象是操作系统的事,对用户透明。所以你可以尽管放心大胆使用他对窗口等对象进行操作。MFC封装的时候把窗口类对象指针同具体窗口关联起来,这样可以用FromHandle通过句柄得到窗口类对象指针,然后利用这个指针对窗口操作,实际在这个类内部还是通过了一个m_hWnd的成员数据(句柄)对窗口在操作。
      

  4.   

    句柄并不是Windows中独有的概念,任何系统中都可以使用句柄这种叫法。
    指针是什么相信大家都明白。
    而句柄,个人认为:
    句柄就是一个对象区分于其他对象的一种标识。这种标识可以使用指向内部结构的
                                        ~~~
    指针来实现,也可以使用任何其他技术实现,比如一个递增的整数,一个Hash值,一个数组的下标,都可以的。其实,我觉得,严格来讲,句柄和指针之间并没有什么必然的联系。
      

  5.   

    句柄只是一个ID,MicroSoft靠它可以隐藏一些东西。
      

  6.   

    在vc中定义一个HANDLE 变量,用光标停在"HANDLE"上会,可能就会提示
    typedef void *HANDLE
    但我想它的意义可能比指针更丰富一些,因为在nt中一些类型还可以有安全权限,但指针好象没有。
      

  7.   

    句柄就是指向mfc特定资源的东西,指针就是指向内存里特定的东西,偏向一些int,long什么的
      

  8.   

    指针里是地址,可以存放对象的地址,句柄是标识,指针就好象你的家地址,句柄是你的名字
    知道你家,在找你,指针存放句柄的地址,*P= NEW CLASS 是系统自动开辟一块内存,P指向
      

  9.   

    没事搞什么Handle?奇怪~~干吗要写*SomeHandle这样的句子呢?直接使用你得到的Handle不就得了~~郁闷~~
      

  10.   

    你如果能够获得别的应用程序的某个对象的指针,也可以进行操作。然而,如果要获得指针,首先,必须找到那个窗口的句柄,然后用函数FromHandle就可以得到他的指针了。这句话我想可以理解,但是如果这么容易的话那不同的应用程序还有什么安全性可言,我想一定有什么保护机制,希望哪位兄弟能说说?
      

  11.   

    我觉得楼上的这种看法是不正确的。
    正因为现在中国的教育制度使很多人失去了对事物的好奇,在这种制度下教出来的学生不想去了解事物的来龙去脉,不去了解系统底层的东西就无法创新。
    此外,小学生想了解相对论绝对是件好事,如果向楼上(codewarrior(会思考的草))那样对待一个想学习相对论的小学生,中国很可能因此失去了一个爱因斯坦。不好意思,跑题了,我觉得hugwind(风之眼)说的已经比较清楚了,句柄虽然定义为一个
    void *,但是你不能直接使用它而是需要让操作系统来帮你间接的使用这个对象。
      

  12.   

    指针就不说了。
    话说windows是一个操作系统,操作系统有资源管理功能。
    如何管理呢,当然要有一个结构来存放当前使用的资源,
    这个结构可以看成用某种数据结构构成的一张表。
    那么,每个资源在这张表中应该有一个ID来标识。
    句柄就是这个ID。
      

  13.   

    不是不要探讨系统底层,而是以初学者的水平不够探讨底层。抱歉没有鄙视各位的意思,因为我也曾经迷茫得一塌糊涂。当初为了搞清回调函数到底是什么东西就差点想破脑袋。结果后来学了汇编,明白了C调用的堆栈特点,一下子就明白了。
    我比较喜欢用英语阅读的方法来对待计算机学习,因为当初刚开始看的时候,真的非常痛苦,一个名词接一个名词,一个术语接着一个术语,如果每个都要追根究底的话,根本没法看下去。我的建议就是,不妨碍理解的,跳过去;妨碍的,就找个类似的比喻,譬如就把句柄当做指针好了,它能唯一标识一个Windows对象,至于系统内部是如何实现的,可以是指针,也可以是一个序号而已。等功夫深了,自然就有能力刨根问底了。
    按现在的水平,停留在细枝末节的地方,很容易只见树木不见森林,初学者还是先见森林,从大局上有个感性认识,有能力了再进行穿越丛林的挑战,那样得到的东西和从别人那里问来的是不一样的,毕竟是自己一步一步trace出来的,别人跟你解释句柄,很可能说了半天你还是一头雾水。
    一点体会,仅供参考。欢迎进行攻击,但不要进行人身攻击:)
      

  14.   

    我的理解是:句柄是个全局的东西,无论哪个进程,得到的句柄都是一样的,但是指针是进程特有的,不同进程对同一个对象的指针可能是不一样的,所以对于一些全局的对象,比方说窗口、文件等等,一般用句柄标识。在dos这样的单任务系统中,句柄和指针应该是一样的
      

  15.   

    我不是很理解,但我能写程序:)句柄的概念,我的理解是由系统来管理的东西,所以你所创建的窗口啊,文件啊,信号量啊都不能够直接指定它们的值。你能够看到的句柄值其实是个地址值,是指向由系统来管理的一段内存区域的某一个内存单元,可能是这样的结构:
    struct tagWND
    {
     int    index;
     int    processid;
     char   szCaption[1024];
     ......
    };
    windows的许多窗口的内存分配正是由这么一段段的结构组成的表,所以就明白了当你调用一个函数,假如:
    BOOL SetWindowText(
      HWND hWnd,         // handle to window or control
      LPCTSTR lpString   // address of string
    );这个函数的执行过程:
    根据hWnd的值从系统的窗口内存分配表中得到相应的窗口数据结构,然后把szCaption改掉,再刷新这个窗口的标题,OK~~
    所以要描述句柄同指针的关系:
     句柄是系统的一个概念,它需要用指针来实现。指针只是个工具而已。不对之处,还望指出。顺便做宣传:
    http://expert.csdn.net/Expert/topic/2284/2284123.xml?temp=.3411981
    不久后会开源码,不过要注册用户:)
      

  16.   

    句柄的类型也有很多呀!你要问哪一种?要是HWND句柄,根进去MFC就是了,他的宏是这样定义的:
    #define DECLARE_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name伤脑筋,如果有时间你自己看吧。
      

  17.   

    看看C++ 教材中是如何给句柄下定义的:“在Win32里,句柄是指向一个无值型对象(void *)的指针,是一个4字节长的数据”。虽然我对它的本质是什么还是很迷惑,但我知道句柄并不是一个真正意义上的指针。从结构上看,句柄的确是一个指针,尽管它没有指向用于存储某个对象的内存位置(很多书都这么说,这正是我的迷惑所在),而实际上句柄指向的是一个包含了对该对象进行的引用的位置。在编程时,只要抓住了对象的句柄就可以对该对象进行操作了.
      

  18.   

    CWnd是MFC封装的对象,windows并不认是他,windows只认识句柄,要想让他知道这个C++对象要经过函数转换。
      

  19.   

    你说的没错,确实可以这样做,CDialog中的成员函数GetDlgItem返回的是CWnd*的指针。CDialog是从CWnd继承下来的,C++中允许把父类强制转换成子类的实例。
    你可能还没有搞清楚,CWnd是如何封装WNDCLASS的,CWnd并不是直接把整个WNDCLASS都包装在内,而仅仅是包装了一个指向窗口的句柄,就是说,使用CWnd的指针,最后还是要转化成句柄对窗口进行操作。
                        CWnd
    CWnd* pWnd-----> ----------
                     | m_hWnd |------>WNDCLASS
                     |  ……  |
                     |其他成员|
                     ----------
    理解了上面你就能理解,为什么创建一个窗口(典型如工具条,状态栏)要经过两次操作,一次是建立C++对象CToolBar,此时CToolBar内的窗口句柄还是空,即不代表任何Window对象,第二次使用Create/CreateEx函数才是真正创建Windows对象,创建完了之后,CToolBar内的窗口句柄就有效了。
      

  20.   

    还有,为什么要使用句柄而不是象在DOS下那样直接提供地址,我想有两个方面的原因,其一,Win32是抢占式多任务操作系统,为了内存保护的目的,不能直接向用户程序提供Window Object的指针,这样的话操作系统对内存的保护能力大大减弱;其二,Win32工作在80386保护模式下,根据保护模式的内存管理方式,Windows也不可能直接提供某个内存地址的指针,因为保护模式下的虚拟地址空间要经过映射才能转化成实际物理地址,Windows内部也经常进行换入换出的操作,各种Window Object也随之在内存中到处移动,如果直接提供物理地址,那么势必就破坏了虚拟内存的基石,因为Windows将无法进行页面换入换出的操作,系统性能将大打折扣。
      

  21.   

    看看保护模式的内存管理,了解386CPU的特点,再假设一下,如果你是Windows的设计者,你会直接向用户提供内存地址吗?
      

  22.   

    支持 codewarrior(会思考的草) 你要仔细研究一点小东西,你这一辈子可能都没见过其他DD。呵呵
      

  23.   

    我们编程中使用的窗口、控件,这些东西,实际上都是一种windows数据结构,但任何结构都是要在内存中运行、实现的,这就是说,窗口、控件这些东西也是在内存中存在的,试想,我们可以随便改变内存中窗口、控件这样的内存中的内容吗?显然不能,如果让你随便改变了,也许窗口、控件就不是现在的这个模样了,也许是改头换面,也许是根本无法显示(因为你改变了它的数据结构,即内存),所以,windows想出来句柄这个东西,知道索引和内容的关系吗?在这里,索引就相当于是句柄,而内容相当于内存地址(或者叫作指针),只要是程序中用到了hWnd等句柄形式,不论是我们使用的,操作系统提供给我们的,或者我们传递给操作系统的,都只是这个索引,先说你得到句柄的情况,当你得到这个索引后,你可以直接访问索引对应的内容吗?也不能,但是,你可以调用操作系统提供给你的函数,去间接的访问索引对应的内容(指针),至于操作系统是如何将索引转化为对应的指针的,这个谁也不知道,但你必须了解它的作用机制,另外,之所以在你的程序中需要自己定义句柄,也只是用于调用操作系统的函数!!记住,要理解它是什么样子的,但不要问句柄的实质,因为实质只有编写操作系统的可以知道,其它的人只可以使用它,理解它,这就足够了,但首先,你要明白它是怎么工作的,以及为什么这样工作。
      

  24.   

    不是很赞成sdcer(独钓雪)的态度。我支持楼主刨根问底的精神,如侯捷所说,用一样东西,但不明白它内部作用机制,实在不高明。但是我觉得凡事应该“先知其然,后知其所以然”,如果连“知其然”都达不到就片面追求“高、深、精”,结果反而是伤了自己学习的兴趣。作为一个初学者,当然可以,也应该做到“只用,而不追究其本质”,但是用得熟练了,自然就应该探求内部的实质,不仅是对自己能力要求的提高,也是科学精神的体现。
      

  25.   

    to ifengfeng(fengfeng):
    支持 codewarrior(会思考的草) 你要仔细研究一点小东西,你这一辈子可能都没见过其他DD。呵呵
    ==================================
    谢谢,不过,你说的DD,啥意思呢?好奇地问。
      

  26.   

    我在上面已经把句柄的作用机制讲了,事实上,如果真能理解它的作用机制(而并见得要非常得明白句柄和指针的对应表的结构,这个表的长度是多少,第一项写的什么,是二进制还是十六进制),可以这么讲,事实上,句柄和指针的对应关系的细节,微软公司根本没有提供给用户,它是保密的,所以,你永远不可能知道它的全貌(但这和明白它的作用机制和使用方法并不矛盾),codewarrior(会思考的草),我想你是误会我的意思了,如果真能理解我和大家上面的发言,无论你用句柄用到多么出神入化的程度,都不会影响你的理解与发挥,关键看你到不到那个火候,是不是真正的理解它的作用机制(理解有的时候需要扒其筋,看其肉,有些时候是做不到的,正如句柄,人家微软都根本就没告诉你它的细节嘛),所以,你要做的是理解它是怎么工作的,而这也同样需要下一番工夫,所以这和(会思考的草)所言的不求甚解根本就是两个概念!
      

  27.   

    CWnd是如何封装WNDCLASS的,CWnd并不是直接把整个WNDCLASS都包装在内,而仅仅是包装了一个指向窗口的句柄,就是说,使用CWnd的指针,最后还是要转化成句柄对窗口进行操作。
                        CWnd
    按这种说法:
     CWnd* pWnd-----> ----------
                     | m_hWnd |------>WNDCLASS
                     |  ……  |
                     |其他成员|
                     ----------
    理解了上面你就能理解,为什么创建一个窗口(典型如工具条,状态栏)要经过两次操作,一次是建立C++对象CToolBar,此时CToolBar内的窗口句柄还是空,即不代表任何Window对象,第二次使用Create/CreateEx函数才是真正创建Windows对象,创建完了之后,CToolBar内的窗口句柄就有效了。我想可以理解!但是我们同样可以通过窗口的句柄获得这个对象的指针,通过对象指针不是同样可以进行任意操作,那安全性还体现在哪里?
      

  28.   

    to ifengfeng(fengfeng):
    是阿,DD是什么意思?会不会是很时髦的话?那你一定得贴出来让大家知道!!呵呵!
      

  29.   

    通过句柄获得指针?好像必须要先创建C++对象然后Attach吧?
    安全性?体现在OS内部。对象的指针最终还是要通过句柄起作用,Windows本身是没有CWnd这个东西的,只有HWND。换句话说,windows只认HWND,不认CWnd*。
      

  30.   

    再次声明!
    C++对象和WNDCLASS没有什么瓜葛!!!
      

  31.   

    窗口就是窗口,和CWnd对象没有与生俱来的必然的联系!!Understand??
    WNDCLASS != CWnd
      

  32.   

    ((CEdit*)GetDlgItem(IDC_EDIT***))->SetWindowText(...)
    上面这个句子大家是否是认为得到了指针呢?其实也不是,它是得到句柄,所以,->以后的必是windows的某个函数,所以,你到底还是用到了如SetWindowText这样的函数,而不是直接对它的指针进行操作。
    但有些函数(如GlobalAlloc()),这些函数虽然得到句柄,但却可以向指针强制转化,这当另当别论,它是为了兼容16位版本,不在大家考虑的通常情况之列。
      

  33.   

    DD就是小弟弟,哈哈`~~每个人的学习方法都不同,每个聪明的人都会认为自己的方法最有效,但是不一定就适合别人。虽然"会思考的草"跟许多人的想法一样,但不见得她(他)跟每个人的理解程度都一样,这也就是为什么C++跟Java都是牛人写出来的,但还是有很多高手在争论它们的优劣,存在即为真理,没什么值得争论的~~~~ (不过我鄙视VB,活活)这段时间在看C++,虽然学了有2年多了,但做考试模拟题还是不及格,汗啊~~~~~
      

  34.   

    听了大家说了这么多,好像这两个概念是只可意会,不可言传的。学习中ing...
      

  35.   

    to  codewarrior(会思考的草)基本理解,我想更深入还是多实践了!谢谢各问.   呵呵.发分了!!
      

  36.   

    系统来管理句柄不是直接体现在安全性,<<操作系统>>的书,内存分配是要算法的,用户想要分配到一块内存首先要看哪些内存正在用,哪些内存没在用,然后从没在用的那部分中再选出符合条件的一段。难道这段算法要用户来指定吗?用户的麻烦事够多了,如果再让他来管理这东一块西一块的内存就难免会出问题,crash~~ 所以啊,安全了~~~~ 厚厚~~~