博主是一个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