如何用C语言写一个获取窗口句柄和其他信息的小程序.

博主是一个SDK编程的初学者,始终坚持学技术要任务驱动的观念,在学习了有关Windows进程,内核对象,进程管理和控制的知识之后,就迫不及待地想要设计一个内存修改器练练手,然而在获取当前运行的各窗口的句柄这一步就卡住了,经过一番查阅和钻研,终于写出了如下的CUI小程序,解决了获取窗口及子窗口句柄,获取ClassName,获取WindowText的问题。
不知道这个小程序能不能替代SPY++的部分功能……

//CUI:相对于GUI(Graphical User Interface)图形用户界面而言的Command User Interface命令行用户界面。

PS:博主才疏学浅,程序中如有错误,欢迎各位指正!

该程序基于下列四个API实现
EnumWindows()

EnumWindows()
//BOOL EnumWindows(WNDENUMPROC,LPARAM)
//WNDENUMPROC 为回调函数的地址
//LPARAM为你自已定义的参数,将会传递给回调函数.

EnumChildWindows()

函数原型: 

  BOOL EnumChildWindows(HWND hWndParent,WNDENUMPROC lpEnumFunc, LPARAM lParam);
  //HWND hWndParent 父窗口句柄 
  //WNDENUMPROC lpEnumFunc 回调函数的地址 
  //LPARAM lParam 自定义的参数 
  //注意:回调函数的返回值将会影响到这个API函数的行为。如果回调函数返回true,则枚举继续直到枚举完成;如果返回false,则将会中止枚举。 

GetClassName()

GetClassName(hwnd,classname,256);
//GetClassName();hwnd是需要传入的句柄/classname是需要传入的LPTSTR缓冲区,用于接收类名/256是int,指定classname的大小,单位字节.
//获取成功将返回返回值为拷贝到指定缓冲区的字符个数,如果函数失败,返回值为0.

GetWindowText()

//与GetClassName参数完全一致,不再赘述。

//关于它们的参数列表和解释会在下面的代码注释中体现,想要了解以上四个函数的使用方法的话也可以作为参考。

基本思路比较简单,先调用EnumWindows,遍历所有父窗体,在遍历时再调用EnumChildWindows,在每一个父窗体下遍历其子窗体,如果有的话即输出。

以下为源码:

/*
程序名称: 简易Windows窗体查看器
程序功能: 查看当前状态下所有窗体的classname,windowtext,hwnd(窗体句柄).
程序类别: CUI WIN32应用程序 
作者:     北赤道逆流 
联系方式: [email protected] 
注意:     本程序编译环境为 WindowsXP x86 Dev-C++ 5.4.2
                         Windows10 x64 Dev-C++ 5.9.2 
          经测试64位版本与32位版本状态均良好,其余环境未经测试. 
*/

#define Primary false //关闭初级用户模式 //使用者可以在此处选择打开(true)或是关闭初级用户模式
                      //在初级用户模式下,程序将不会显示子窗体的信息,同时也会隐藏没有WindowText的窗体。 

#include
#include
#include 
//EnumWindows()和EnumChildWindows()需要回调函数.
//先写EnumChildWindows()的回调函数enumchildwindows_callback(),因为在enumwindows_callback()里面要用它.
BOOL CALLBACK enumchildwindows_callback(HWND hwnd, LPARAM lParam)
//关于函数参数等的具体解释见下面的enumwindows_callback()!
//因为enumwindows_callback()函数写的比较完整,所以在它里面加了详细注释,就不在这里加了.
//如果阅读该函数有困难,建议先阅读下面的enumwindows_callback(); 
{
    TCHAR classname[256];
    TCHAR windowtext[256];
    int cn = GetClassName(hwnd,classname,256);
    int wt = GetWindowText(hwnd,windowtext,256);
    if(cn==0)
    {
        if(wt==0)
        {
            printf("    Error in EnumChildWindows_CALLBACK\n");
            return FALSE;
        }
        else if(wt!=0)
        {
            printf("    NULL ||| %18s ||| %d\n",windowtext,hwnd);   //%18s表示该字符串最少占用18个个字符空间,printf格式控制符。 
            return TRUE;
        }
    } 
    else if(cn!=0)
    {
        if(wt==0)
        {
                printf("    %-18s ||| NULL ||| %d\n",classname,hwnd);   //-是格式控制字符,表示左对齐。 
                return TRUE;
        }
        else if(wt!=0)
        {
            printf("    %-18s ||| %s ||| %d\n",classname,windowtext,hwnd);
            return TRUE;
        }
    } 
} 
BOOL CALLBACK enumwindows_callback(HWND hwnd, LPARAM lParam)
//hwnd就是系统传递给该回调函数的窗体句柄,lParam是控制参数,将会由调用函数(EnumWindows)传入,以控制回调函数的行为,默认值为0; 
{
    TCHAR classname[256];//此处务必事先指定变量的内存大小!如果使用LPTSTR指针形式,也务必立即使用malloc分配合适的内存,避免野指针.
    TCHAR windowtext[256];
    int cn = GetClassName(hwnd,classname,256);
    //GetClassName();hwnd是需要传入的句柄/classname是需要传入的LPTSTR缓冲区,用于接收类名/256是int,指定classname的大小,单位字节.
    //获取成功将返回返回值为拷贝到指定缓冲区的字符个数,如果函数失败,返回值为0. 
    int wt = GetWindowText(hwnd,windowtext,256);
    //解释同GetClassName();
    if(cn==0)
    {
        if(wt==0)
        {
            printf("Error in EnumWindows_CALLBACK\n");
            return FALSE;   //理论上不会存在既没有类名又没有标题名的窗体 
        }
        else if(wt!=0)
        {
            printf("NULL ||| %18s ||| %d\n",windowtext,hwnd);
            return TRUE;    //这种情况至今没有见到过! 
        }
    } 
    else if(cn!=0)
    {
        if(wt==0)
        {
            if(Primary==true)return TRUE;//隐藏输出,以面向初级用户,而且不显示子窗体信息. 
            else if(Primary==false)
            {
                printf("------------------------------------------------------------\n");//父窗体与父窗体之间的分割线. 
                printf("%-18s ||| NULL ||| %d\n",classname,hwnd);
                int check=EnumChildWindows(hwnd,(WNDENUMPROC)enumchildwindows_callback,0);//在此处调用显示子窗体的EnumChildWindows.
                if(check == 0) printf("    ->NoneChildWindow\n");//如果没有子窗体我们要这样回显. 
                return TRUE;
            }
        }
        else if(wt!=0)
        {
            if(Primary==true)
            {
                printf("%-18s ||| %s ||| %d\n",classname,windowtext,hwnd);
                return TRUE;
            }
            else if(Primary==false)
            {
                printf("------------------------------------------------------------\n");//父窗体与父窗体之间的分割线. 
                printf("%-18s ||| %s ||| %d\n",classname,windowtext,hwnd);
                int check=EnumChildWindows(hwnd,(WNDENUMPROC)enumchildwindows_callback,0);
                if(check == 0) printf("    ->NoneChildWindow\n");
                return TRUE;
            }
        }
    } 
}

int main()
{
    //先创建一个标题栏 
    printf("WINDOWS_EXPLORER\n");
    if(Primary==true)printf("PRIMARY_MODE\n\n");
    else if(Primary==false)printf("ADVANCED_MODE\n\n");
    printf("CLASSNAME----WINDOWTEXT----(int)HWND\n\n");

    int check = EnumWindows((WNDENUMPROC)enumwindows_callback,0);
    //BOOL EnumWindows(WNDENUMPROC,LPARAM)
    //WNDENUMPROC 为回调函数的地址
    //LPARAM为你自已定义的参数,将会传递给回调函数.
    if(check == 0)printf("Error in EnumWindows\n");
    system("pause");
    return 0;
}

最后附上该源代码的Github地址

https://github.com/ZhangJunshuo/WindowsInformationExplorer.git

你可能感兴趣的:(如何用C语言写一个获取窗口句柄和其他信息的小程序.)