一、前言
获取程序窗口来管理该程序,例如微信、QQ。我想的是首先要能够操作窗口,然后再进行管理,例如预定时间自动发消息,自动回复等等,或者游戏中自动采集资源。然后决定使用window API来实现这些功能。
每个窗口都有一个句柄,操作窗口就需要获取这个句柄(HWND),获取后就可以进行关闭、最小化、打开、移动等操作了。获取句柄需要先获取窗口名称或进程,建议是得到窗口名称然后来获取句柄。
API 头文件:windows.h
二、获取窗口名称
调用EnumWindows()来获取所有窗口的名称,调用时名称将会传入其对应的回调函数EnumWindowsProc()中,所以我们这里先实现回调函数在其中使用一个列表来接收EnumWindows()枚举出的所有窗口名称。实现方法如下:
//.h文件中:
#include <windows.h> //Windows API
//使用一个全局变量来接收窗口名称
extern QStringList windowClassNames;
//EnumWindows 函数枚举所有顶层窗口,并为每个窗口调用 EnumWindowsProc 回调函数
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam);
//.cpp文件中:
QStringList windowClassNames;
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) {
char className[256];
if (GetClassNameA(hwnd, className, sizeof(className))) {
windowClassNames << QString::fromLocal8Bit(className);
}
return TRUE;
}
//调用时,先封装一个函数来更新窗口列表:
QStringList getAllWindowClassNames()
{
windowClassNames.clear(); // 清除之前的内容
EnumWindows(EnumWindowsProc, 0); // 枚举所有顶层窗口
return windowClassNames;
}
QStringList windowClassNamesList = getAllWindowClassNames();
三、获取窗口句柄
使用FindWindowA ()/ FindWindowW()来获取窗口句柄,两个函数功能相同,参数含义也相同,代码如下:
//根据窗口标题查找
HWND hwnd = FindWindowA(NULL, "无标题 - 记事本");
HWND hwnd = FindWindowW(NULL, "无标题 - 记事本");
//根据窗口类名查找
HWND hwnd = FindWindowA("ContactManagerWindow", NULL);
HWND hwnd = FindWindowW("ContactManagerWindow", NULL);
//通过判断返回是否是NULL来确认是否找到
if(!hwnd){
qDebug() << "通讯录管理窗口 未找到!";
}
四、移动窗口位置和调整大小
使用SetWindowPos来设定窗口左上角的坐标,该坐标的值和屏幕分辨率相关。
//函数一共7个参数
//依次为:句柄、显示层级、坐标X、坐标Y、宽、高、状态
//调用示例:
//保证窗口显示
ShowWindow(hWnd, SW_RESTORE);
//HWND_TOP置顶显示,SWP_SHOWWINDOW显示
SetWindowPos(hwnd, HWND_TOP, 0, 0, 1000, 700, SWP_SHOWWINDOW);
五、打开和关闭窗口
打开窗口这里分两种情况
1、程序在后台运行:使用ShowWindow(HWND, SW_RESTORE)或SetWindowPos(HWND, HWND_TOP, X, Y, CX, CY, SWP_SHOWWINDOW)显示。
2、程序没有打开:使用CMD命令行直接运行程序:
//使用CMD命令行直接运行程序
QString command = "start \"\" \"" + programPath + "\"";
std::string commandStr = command.toStdString();
int result = std::system(commandStr.c_str());
关闭窗口可以使用SendMessage()向窗口发送事件;也可以用SetWindowPos()直接关闭,但是有负面影响。代码如下:
//优先发送关闭事件,让程序自动关闭
if (SendMessage(hWnd, WM_CLOSE, 0, 0)) {
qDebug() << "Window close message sent successfully." << getWindowTitle(hWnd) << GetWindowClassName(hWnd);
} else {
qDebug() << "Failed to send window close message. Error:" << GetLastError();
//补救措施,直接关闭
SetWindowPos(hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_HIDEWINDOW);
}
六、已知句柄获取串口标题或类名
如果需要确定该句柄是否是目标窗口,直接输出其标题和类名是一个不错的方法,这里都转为Qt的QString类型输出:
QString getWindowTitle(HWND hWnd)
{
// 获取窗口标题长度
int length = GetWindowTextLengthW(hWnd);
if (length == 0) {
return QString();
}
// 创建一个缓冲区来存储窗口标题
wchar_t *buffer = new wchar_t[length + 1];
GetWindowTextW(hWnd, buffer, length + 1);
// 将缓冲区内容转换为 QString
QString windowTitle = QString::fromWCharArray(buffer);
delete[] buffer;
return windowTitle;
}
QString GetWindowClassName(HWND hWnd)
{
const int bufferSize = 256;
wchar_t className[bufferSize];
// 获取窗口类名
int result = GetClassNameW(hWnd, className, bufferSize);
if (result == 0) {
std::cerr << "Failed to get window class name." << std::endl;
return QString();
}
// 将 wchar_t 转换为 QString
return QString::fromWCharArray(className);
}