【20090709-01】句柄的本质

转自:http://www.programfan.com/article/2841.html

一、书上定义:

<<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);


三、理解:
    HANDLE就是PVOID,也就是无类型指针,
    上面这些资源的句柄Handles都不过是指向struct的指针,至于这个struct的用处,连M$都说unused了,现在解释下M$这么做的意义,这就是所谓数据封装,你可以在你的程序中把M$的内部结构指针传来传去,可是你却不知道它到底指向的内容是什么。

    句柄与指针确实是完全不同的两个概念。句柄仅仅是一个32位整数,WIN32中用于标记某个系统或进程的对象,可以理解为对象索引(由于M$未完全公开相关技术,在一定程度上只能如此理解),这个索引更像是一种映射关系(从句柄到对象指针的映射),而不是纯粹意义上的“数组下标”。


     句柄可以理解为用于指向或标识内存的一块“资源”,这些资源如:文件(file)、内存块(block of memory)、菜单(menu)等等。操作系统通过句柄来定位核心对象和系统资源。
    指针即为指向内存的“数据或指令”某一单元。

    说的确切一点,句柄实际上是一种指向某种资源的指针,但与指针又有所不同:指针对应着一个数据在内存中的地址,得到了指针就可以自由地修改该数据。Windows并不希望一般程序修改其内部数据结构,因为这样太不安全。所以Windows给每个使用GlobalAlloc等函数声明的内存区域指定一个句柄(本质上仍是一个指针,但不要直接操作它),平时你只是在调用API函数时利用这个句柄来说明要操作哪段内存。

    
四、引喻:
   牧童遥指杏花村
   牧童的手为指针,杏花村的牌子为句柄,杏花村酒店为对象的实例.


附注:获得窗口句柄三种方法

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)

 

 

C#获取进程的主窗口句柄 http://www.cnblogs.com/qiuyi21/articles/1302732.html

通过调用Win32 API实现。

 

public class User32API
{
    
private static Hashtable processWnd = null;

    
public delegate bool WNDENUMPROC(IntPtr hwnd, uint lParam);

    
static User32API()
    
{
        
if (processWnd == null)
        
{
            processWnd 
= new Hashtable();
        }

    }


    [DllImport(
"user32.dll", EntryPoint = "EnumWindows", SetLastError = true)]
    
public static extern bool EnumWindows(WNDENUMPROC lpEnumFunc, uint lParam);

    [DllImport(
"user32.dll", EntryPoint = "GetParent", SetLastError = true)]
    
public static extern IntPtr GetParent(IntPtr hWnd);

    [DllImport(
"user32.dll", EntryPoint = "GetWindowThreadProcessId")]
    
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, ref uint lpdwProcessId);

    [DllImport(
"user32.dll", EntryPoint = "IsWindow")]
    
public static extern bool IsWindow(IntPtr hWnd);

    [DllImport(
"kernel32.dll", EntryPoint = "SetLastError")]
    
public static extern void SetLastError(uint dwErrCode);

    
public static IntPtr GetCurrentWindowHandle()
    
{
        IntPtr ptrWnd 
= IntPtr.Zero;
        
uint uiPid = (uint)Process.GetCurrentProcess().Id;  // 当前进程 ID
        object objWnd = processWnd[uiPid];

        
if (objWnd != null)
        
{
            ptrWnd 
= (IntPtr)objWnd;
            
if (ptrWnd != IntPtr.Zero && IsWindow(ptrWnd))  // 从缓存中获取句柄
            {
                
return ptrWnd;
            }

            
else
            
{
                ptrWnd 
= IntPtr.Zero;
            }

        }


        
bool bResult = EnumWindows(new WNDENUMPROC(EnumWindowsProc), uiPid);
        
// 枚举窗口返回 false 并且没有错误号时表明获取成功
        if (!bResult && Marshal.GetLastWin32Error() == 0)
        
{
            objWnd 
= processWnd[uiPid];
            
if (objWnd != null)
            
{
                ptrWnd 
= (IntPtr)objWnd;
            }

        }


        
return ptrWnd;
    }


    
private static bool EnumWindowsProc(IntPtr hwnd, uint lParam)
    
{
        
uint uiPid = 0;

        
if (GetParent(hwnd) == IntPtr.Zero)
        
{
            GetWindowThreadProcessId(hwnd, 
ref uiPid);
            
if (uiPid == lParam)    // 找到进程对应的主窗口句柄
            {
                processWnd[uiPid] 
= hwnd;   // 把句柄缓存起来
                SetLastError(0);    // 设置无错误
                return false;   // 返回 false 以终止枚举窗口
            }

        }


        
return true;
    }

}

 

调用User32API.GetCurrentWindowHandle()即可返回当前进程的主窗口句柄,如果获取失败则返回IntPtr.Zero。

 

 

2008年10月7日补充微软实现的获取进程主窗口句柄代码

 


public class MyProcess
{
    
private bool haveMainWindow = false;
    
private IntPtr mainWindowHandle = IntPtr.Zero;
    
private int processId = 0;

    
private delegate bool EnumThreadWindowsCallback(IntPtr hWnd, IntPtr lParam);

    
public IntPtr GetMainWindowHandle(int processId)
    
{
        
if (!this.haveMainWindow)
        
{
            
this.mainWindowHandle = IntPtr.Zero;
            
this.processId = processId;
            EnumThreadWindowsCallback callback 
= new EnumThreadWindowsCallback(this.EnumWindowsCallback);
            EnumWindows(callback, IntPtr.Zero);
            GC.KeepAlive(callback);

            
this.haveMainWindow = true;
        }

        
return this.mainWindowHandle;
    }


    
private bool EnumWindowsCallback(IntPtr handle, IntPtr extraParameter)
    
{
        
int num;
        GetWindowThreadProcessId(
new HandleRef(this, handle), out num);
        
if ((num == this.processId) && this.IsMainWindow(handle))
        
{
            
this.mainWindowHandle = handle;
            
return false;
        }

        
return true;
    }


    
private bool IsMainWindow(IntPtr handle)
    
{
        
return (!(GetWindow(new HandleRef(this, handle), 4!= IntPtr.Zero) && IsWindowVisible(new HandleRef(this, handle)));
    }


    [DllImport(
"user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    
public static extern bool EnumWindows(EnumThreadWindowsCallback callback, IntPtr extraData);

    [DllImport(
"user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    
public static extern int GetWindowThreadProcessId(HandleRef handle, out int processId);

    [DllImport(
"user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
    
public static extern IntPtr GetWindow(HandleRef hWnd, int uCmd);

    [DllImport(
"user32.dll", CharSet = CharSet.Auto)]
    
public static extern bool IsWindowVisible(HandleRef hWnd);
}

 

--EOF--

 

 

/////////////////////////////

 

C#中获取窗口句柄的方法

发布时间:2008-6-6
C#可调用API接口来获取窗口句柄,代码如下

using  System;
using  System.Runtime.InteropServices;
namespace  tstfindwindow
{
///  <summary>
///  Class1  的摘要说明。
///  </summary>
class  Class1
{
    [DllImport( "User32.dll ")]
    public  static  extern  System.IntPtr  FindWindowEx(  System.IntPtr  parent  ,  System.IntPtr  childe  ,      string  strclass  ,string  strname  );
    ///  <summary>
    ///  应用程序的主入口点。
    ///  </summary>
    [STAThread]
    static  void  Main(string[]  args)
    {
    //
    //  TODO:  在此处添加代码以启动应用程序
    //
    IntPtr p=FindWindowEx(System.IntPtr.Zero,System.IntPtr.Zero,null,"窗口标题"); 
    }
}

 

 

posted @ 2009-07-09 11:37  WillWayer  阅读(435)  评论(0编辑  收藏  举报