关于句柄][收藏]

 理解句柄

什么是句柄?

功能上的理解:
什么是"句柄"(handle),handle的本意是把柄,把手的意思。是你与操作系统打交道的东东。
举个通俗的例子,比如你考上了大学,入学后,学校(操作系统)会给你一个学生证号。
注意,这个号码是学校指定的,你无法自选。
有了这个号码(学生证,假设一证多用)享受学校提供的服务:
如你就可以去图书馆借书,去食堂吃饭,去教室上课等等。

但你不能到食堂里买啤酒,因为学校不允许这种服务。
而在计算机中系统提供的服务就是API调用,你有了HANDLE,就可以理直气壮地向系统提出调用API的服务。
而指针的权力就大多了,有了指针你可以到处去喝酒,打架,学校(操作系统)管不着,
所以句柄和指针的区别在于句柄指针调用系统提供的服务。
而句柄虽然是一个能相互区别的号码,但与我们普通的ID号又有区别,
普通的ID号是可以由程序员自己定义的,而句柄不行,它是对象生成是系统指定的,
是为了区别系统中存在的各个对象,这个句柄不是由程序员符给的。

概念上的理解
1。句柄,是整个windows编程的基础,一个句柄是指使用的一个唯一的整数值,
是指一个四字节长的数值,用于标志应用程序中的不同对象和同类对象中的不同的实例,
诸如,一个窗口,按钮,图标,滚动条,输出设备,控件或者文件等。
应用程序能够通过句柄访问相应的对象的信息。
2。句柄不是一个指针,程序不能利用它句柄来直接阅读文件中的信息。
如果句柄不用在I/O文件中,它是毫无用处的。
3。句柄是windows用来标志应用程序中建立的或是使用的唯一整数,
windows使用了大量的句柄来来标志很多对象。

机制上的理解
前面的分析很经典,但我认为有一点必须指出的。如果不对,请各位指证。
句柄是指针,一点不假,但是这个指针又与C中的指针有不同之处。
因为Windows是一个多任务的系统,其内存是可以移动的,
这样的话如果某一时刻有一个指针指向一块内存,之后的某个时刻却被系统移走了,
如果你再用这个指针的话就会出错。
为了解决这一问题,windows在系统专区开一块内存用于存放句柄,这个句柄的值就是一个地址,
当这一块内存被移走后,windows就修改这个句柄的值,再访问这块内存时,句柄的值总是有效的。
正因为这样当你使用GlobalAlloc分配的内存时,如果你指定这块内存的属性是固定的,
那么它的返回值可以直接给一个指针,如果是可以移动的,
返回值就必须给一个句柄,你就必须先GlobalLock后才能使用。
这是我对句柄理解,不知道对不对?

我的理解
其实,句柄是一个指向指针的指针。即:
在windows程序设计中,句柄仅是一个应用程序用来识别某些事情的数字

如果想更透彻一点地认识句柄,我可以告诉大家,句柄是一种指向指针的指针。
我们知   道,所谓指针是一种内存地址。
应用程序启动后,组成这个程序的各对象是住留在内的   。
如果简单地理解,似乎我们只要获知这个内存的首地址,那么就可以随时用这个地址访问对象。
但是,如果您真的这样认为,那么您就大错特错了。
我们知道,Windows是一个以虚拟内存为基础的操作系统。在这种系统环境下,
Windows内存管理器经常在内存中来回移动对象,依此来满足各种应用程序的内存需要。
对象被移动意味着它的地址变化   了。如果地址总是如此变化,我们该到哪里去找该对象呢?  
为了解决这个问题,Windows操作系统为各应用程序腾出一些内存储地址,
用来专门   登记各应用对象在内存中的地址变化,而这个地址(存储单元的位置)本身是不变的。
Wi   ndows内存管理器在移动对象在内存中的位置后,把对象新的地址告知这个句柄地址来保存。
这样我们只需记住这个句柄地址就可以间接地知道对象具体在内存中的哪个位置。  
这个地址是在对象装载(Load)时由系统分配给的,当系统卸载时(Unload)又释放给系统   。  

句柄地址(稳定)→记载着对象在内存中的地址→对象在内存中的地址(不稳定)   →实际对象  
        但是,必须注意的是程序每次从新启动,系统不能保证分配给这个程序的句柄还是  
原来的那个句柄,而且绝大多数情况的确不一样的。假如我们把进入电影院看电影看成  
是一个应用程序的启动运行,那么系统给应用程序分配的句柄总是不一样,这和每次电  
影院售给我们的门票总是不同的一个座位是一样的道理。

bool与BOOL的区别联系?
bool是C++中的一种变量类型(布尔类型),只可以写
bool       x;
x       =   true;
x       =   false;
在VC++中BOOL是这样说明的:
typedef   int       BOOL;
也就是说BOOL是当int用的。
BOOL       x;
x       =   1;
x       =   0;
当然为了方便,VC++已经定义了
#define         TRUE       0
#define         FALSE     1

获取句柄:

两种方法:
                (1)   SDK函数   SHGetFileInfo   或使用   ExtractIcon获得图标资源的   handle(句柄),
                (2)   SDK函数   SHGetFileInfo获得有关文件的   很多信息,如大小图标,属性,类型等.

                    Example(1):   在程序窗口左上角显示   NotePad图标.
                      void   CSampleView:   OnDraw(CDC   *   pDC)
                          {
                                if(   ::   SHGetFileInfo(_T("c://pwin95//notepad.exe"),0,
                                          &stFileInfo,sizeof(stFileInfo),SHGFI_ICON))
                                      {
                                          pDC   -> DrawIcon(10,10,stFileInfo.hIcon);
                                      }
                            }

                                                                                                                                                     
                  Example(2):同样功能,Use   ExtractIcon   Function
                    void   CSampleView::   OnDraw(CDC   *pDC)
                            {
                                HICON   hIcon=::   ExtractIcon(AfxGetInstanceHandle(),_T
                                  ("NotePad.exe"),0);

                                if   (hIcon   &&hIcon!=(HICON)-1)
                                      pDC-> DrawIcon(10,10,hIcon);
                            }
      【说明】关于如何得到系统文件的正确路径,象win.ini   system32.ini等的路径,各种系统中具体的路径是不一样的。如:
                      获得notepad.exe的路径正规上来说用GetWindowsDirectory   函数得到;
                      如果是调用   win95下的画笔,应该用访问注册表的方法获得其路径;
                      要作成一个比较考究的程序,考虑应该全面点.

      【另】
                                HINSTANCE   AfxGetResourceHandle(   );
                                Return   Value:An   HINSTANCE   handle   where   the   default   resources   of   the   application   are   loaded.  

4.       有关取得桌面句柄   GetDesktopWindow()  

MSDN中的例子:  

//   静态函数CWnd::   GetDesktopWindow   返回桌面窗口的指针。下例说明了MFC
void   CFrameWnd::BeginModalState   ()
{
    //first   count   all   windows   that   need   to   be   disabled
    UINT   nCount=0;
    HWND   hWnd=::   GetWindow   (::   GetDesktopWindow   (),   GW_CHILD);
    while   (hWnd!=NULL)
    {
        if   (::   IsWindowEnabled   (hwnd)   &&
                CWnd::FromHandlePermanent   (hWnd)!=NULL   &&
                AfxIsDescendant   (pParent-> m_hWnd,   hWnd)   &&
                ::   SendMessage   (hWnd,   WM_DISABLEMODAL,   0,   0)   ==   0)
        {
              ++nCount;
        }
        hWnd=::   GetWindow   (hWnd,   GW_HWNDNEXT);
    }
}  

//用户的问题:下面程序取的不是同一程序的句柄,但是GetModuleFileName返回的结果一样请问为什莫  

HWND   ChWnd;//子窗口句柄  
HWND   hwDesktop=::GetDesktopWindow();//取得桌面句柄  
ChWnd=::GetWindow(hwDesktop,GW_CHILD);//取得桌面子句柄  
CString   csTitle,csClass,csTm,mLookstring;  
char   szBuffer[255];  
while(ChWnd!=NULL)//循环取子句柄的同级句柄  
{  
        if(::IsWindowVisible(ChWnd))//判断是否为可显示窗口  
        {  
                  ::GetWindowText(ChWnd,csTitle.GetBuffer(255),254);  
                  ::GetClassName(ChWnd,csClass.GetBuffer(255),254);  
                  csTitle.ReleaseBuffer();//标题  
                  csClass.ReleaseBuffer();//类名  
                  csTm.Format("%08X:",ChWnd);  
                  if(csTitle=="")  
                  {  
                              mLookstring=csTm+csClass;  
                  }else  
                  {  
                              mLookstring=csTm+csTitle;  
                  }  
                  //这里的窗口句柄不是同一个程序吧?(问题所在!)可是为什莫结果一样  
                  HINSTANCE   hInstance   =   (HINSTANCE)::GetWindowLong(ChWnd,DWL_USER);  
                  ::GetModuleFileName(hInstance,   szBuffer,   sizeof(szBuffer));  
                  MessageBox(szBuffer,mLookstring);  
        }  
        ChWnd=::GetWindow(ChWnd,GW_HWNDNEXT);  
}  

回答:  

问题在于Win32下GetWindowLong(ChWnd,DWL_USER)总是返回当前程序运行的hInstance,所以你得到的文件名总是一个。所以你要用枚举所有"进程的程序名"来获得程序名。  
   

===   再谈句柄于指针的区别  

  许多开始学习VC的朋友,最多听说的两个词莫过于指针和句柄了。  
  但是,确经常搞不清他们之间的区别。  
  首先,句柄是一个窗口的标志,也就是所有从CWND类继承下来的,多有句柄这个成员。  
  他能做的,也就是唯一代表一个桌面上的窗口罢了。而指针是一个地址,如果它指向了一个内存中的对象,那么就可以对它进行任意操作了,当然,并不局限于自己的应用程序,你如果能够获得别的应用程序的某个对象的指针,也可以进行操作。然而,如果要获得指针,首先,必须找到那个窗口的句柄,然后用函数FromHandle就可以得到他的指针了。  

===     问题1:  

如何在自定义的消息中发送一个字符串?例如:  
SendMessage(MyWnd,WM_USERDEFINED,   0,0)  
如何将字符串Buffer写入wParam或lParam?  

  你可以把字符串的地址传递过去,因为地址正好是32位。如:  
char   s[256];  
SendMessage(MyWnd,WM_USERDEFINED,   (WPARAM)   s,0)  
接收方只需要将wParam赋给一个char*就可以了。但此方法只能使用于在一个进程内部传递数据。  
   

===     问题2:  
1.在VC应用程序框架中,如何加入自己做的类,如何定义这个类的对象,我想在鼠标点击某个菜单项的时候才生成这个对象,做得到吗?(这个类的构造函数是带参数的)。  
2.消息发送函数:  
    PostMessage(HWND   handle,WM_MYMESSAGE,  
                            WPARAM   wParam,LPARAM   lParam)  
    中:  
第一个参数如何获得?
如果我的消息是在自己的应用程序中生成的,想发给应用程序的窗口让它显示某些数据(用TextOut函数),能做到吗?
(也可以说是这样的问题:用Appwizard生成应用程序框架,在生成的类(如CView)中如何得到窗口的句柄,并放在PostMessage函数中。)  
3.wParam,lParam,在消息响应函数中如何用?vc是怎样保证这两个数传到函数中的?问题比较多,谢谢!  
水平:   刚入门  

回答:  

1、这个问题是肯定的。你可以使用ClassWizard定义类,也可以手工输入。如果类定义已经在某个文件中,只要使用Project ¦Add   files将文件加入工程就可以了。要想定义类的对象,只要在你的菜单项的相应事件中就可以了。如:  
{  
...  
MyClass   myObject("Hello");  
myObject.MyMethod();  
...  
}  
2、在你自己的程序中传递消息当然没有任何问题,只要你知道要调用的窗口类是从CWnd继承来的,你就可以使用GetSafeHwnd函数获得窗口句柄。不过一般在自己的同一个程序中有时不愿意使用自定义消息,因为太麻烦。你完全可以给要调用的类添加一个成员函数,只要想显示数据,直接调用这个成员函数不就可以了?何必使用PostMessage呢?一般只有在程序间调用,才愿意使用自定义消息。这时,你通常可以使用FindWindow获得窗口句柄(QA000251   "如何利用FindWindow()函数查找程序")。  
3、对于MFC已经定义了消息处理函数的消息,MFC会自动把wParam和lParam映射为更容易使用的方式。如OnMouseMove(   UINT   nFlags,   CPoint   point   )。对于MFC不能自动处理的函数,如你使用ON_MESSAGE定义消息函数,则MFC会把wParam和lParam原原本本的传递给你的函数,不做任何处理。  

===     一个未公开的Win32   API函数:GetTaskmanWindow     ()  

        下例中还用到:   GetProcAddress         GetParent(hWnd)
                                        HMODULE   hUser32   =   GetModuleHandle("user32");  

download  

//   getaskmanwnd.cpp   (Windows   NT/2000)
//
//   利用一个未公开的Win32   API函数:GetTaskmanWindow,
//   对Windows的任务栏进行操作(显示/隐藏)。这个函数返回拥有任务栏按钮的窗口句柄。
//
//   This   example   will   show   you   how   you   can   obtain   a   handle   to   the
//   Windows   Taskbar   window.
//
//   (c)1999   Ashot   Oganesyan   K,   SmartLine,   Inc
//   mailto:ashot@aha.ru,   http://www.protect-me.com,   http://www.codepile.com
#include   <windows.h>
#include   <stdio.h>
//   User32!GetTaskmanWindow   (NT   specific!)
//
//   This   function   returns   a   handle   to   the   window   that   ownes   the   taskbar   buttons
//
//   HWND   GetTaskmanWindow()
//
typedef   HWND   (WINAPI   *PROCGETTASKMANWND)(void);
PROCGETTASKMANWND   GetTaskmanWindow;
void   main(int   argc,   char*   argv[])
{
if   (argc <2)
{
printf("Usage:/n/ngetaskmanwnd.exe   S ¦H/n");
return;
}
HMODULE   hUser32   =   GetModuleHandle("user32");
if   (!hUser32)
return;
GetTaskmanWindow   =   (PROCGETTASKMANWND)GetProcAddress(hUser32,"GetTaskmanWindow");
if   (!GetTaskmanWindow)
return;
HWND   hWnd   =   GetTaskmanWindow();
if   (!hWnd)
return;
if   (*argv[1]=='H'   ¦ ¦   *argv[1]=='h')
ShowWindow(GetParent(hWnd),SW_HIDE);
else
ShowWindow(GetParent(hWnd),SW_SHOW); 

  • 0
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值