首先,要感谢小破站阿婆主@林间寒水。
目录
。。。灵感来了。
看过的都知道,窗口置顶工具确实很有用,我复刻了一个,然后就没有然后了……
额……………………………………………………………………………………………
好吧,WinAPI现学现卖,做了一个简单的GUI。
众所周知,GUI实现的第一步就是创建一个窗口 ,那么要如何创建一个窗口呢?
答:Dialog
一、创建窗口
1.入口函数
写过C/C++的都认识这样的:
int main(void)
{
return 0;
}
其中,main函数就是入口函数,但自己写窗体应用就是从零开始造飞机,不能站在巨人的肩膀上用别人写好的控制台窗口。因此,WINPAI的入口函数就变高级了
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
}
WINAPI定义为#define WINPAI _stdcall,另外CALLBACK原型也是_stdcall
参数1:hInstance
该参数为窗体的实例句柄,程序用它来标识某些对象,在窗体应用中一般标识正在运行的.exe文件。
参数2:hPrevInstance
它表示应用程序上一个实例的句柄,在Win16中,一个程序可以通过该参数来查看是否有其他实例在运行,同时可以将一些数据从前一个实例移动到自己的数据区。但在Win32及其以后版本中,它就没用了,始终为NULL。
参数3:lpCmdLine
lpCmdLine指向程序命令行参数字符串的指针。
参数4:nCmdShow
指定应用程序最初如何显示。例如最大化,最小化
2.注册窗口类
在Window下写一个窗体应用程序就像是自己开餐馆,开餐馆第一步是什么呢?答:筹钱。答:注册你的餐馆(打比方)。众所周知,没有营业执照的餐馆就相当于是三无产品。所以写窗体应用程序要先注册窗口类,让Windows能在众多窗口类(每个窗口都有一个自己的类)中找到你的窗口。
那么怎么注册呢?
在WINPAI中有这样一个类:WNDCLASS,还有它的扩展类:WNDCLASSEX(支持的窗口样式比前者多)注意:本文用WNDCLASSEX扩展样式
给出声明:
//WNDCLASSEX
typedef WNDCLASSEXW WNDCLASSEX;
typedef struct tagWNDCLASSEXW {
UINT cbSize;
/* Win 3.x */
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCWSTR lpszMenuName;
LPCWSTR lpszClassName;
/* Win 4.0 */
HICON hIconSm;
} WNDCLASSEXW, *PWNDCLASSEXW, NEAR *NPWNDCLASSEXW, FAR *LPWNDCLASSEXW;
//WNDCLASS
typedef WNDCLASSW WNDCLASS;
typedef struct tagWNDCLASSW {
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCWSTR lpszMenuName;
LPCWSTR lpszClassName;
} WNDCLASSW, *PWNDCLASSW, NEAR *NPWNDCLASSW, FAR *LPWNDCLASSW;
接着声明一个类
WNDCLASSEX wndclass = { 0 };
这样就声明了一个类,接着,要填写类中的各个参数,直接给出
TCHAR lpszClassName[] = { TEXT("WindowTopMostTool") };
TCHAR lpszWindowName[] = { TEXT("窗口置顶工具Win32版") };
wndclass.cbSize = sizeof(WNDCLASSEX); //该结构的大小
wndclass.style = CS_HREDRAW | CS_VREDRAW; //窗口风格
//CS_HRREDRAW,CS_VREDRAW表示当窗口大小发生改变时,从水平方向和垂直方向对窗口进行重绘
wndclass.lpfnWndProc = WindowProc; //窗口的回调函数,用于处理各种窗口消息(需要自己定义)
wndclass.cbClsExtra = 0; //紧跟在WNDCLASSEX后的附加数据字节数,用于存放自定义数据
wndclass.cbWndExtra = 0; //紧跟在窗口实例后面的附加数据字节数,用于存放自定义数据
wndclass.hInstance = hInstance; //窗口的实例句柄
wndclass.hIcon = LoadIcon(hInstance, IDI_APPLICATION); //图标资源句柄
wndclass.hCursor = LoadCursor(hInstance, IDC_ARROW); //光标资源句柄
wndclass.hbrBackground = CreateSolidBrush(0xFFFFFF); //窗口背景画刷句柄
wndclass.lpszMenuName = NULL; //窗口菜单资源名称
wndclass.lpszClassName = lpszClassName; //窗口类名
函数解析:
LoadIcon(窗口实例句柄,IDI图标资源名称)//载入所用图标
*注意:载入自定义图标请使用如下格式:LoadIcon(窗口句柄,MAKEINTERESOURCE(图标ID));
LoadCursor(窗口句柄,IDC光标资源名称)//载入所用光标
*载入自定义光标格式同上
CreateSolidBrush(RGB(r, g, b))或CreateSolidBrush(颜色对应的十六进制)//创建一个画刷
3.创建窗口
用到CreateWindowEx
给出原型:
#define CreateWindowEx CreateWindowExW
WINUSERAPI
HWND
WINAPI
CreateWindowExW(
_In_ DWORD dwExStyle, //窗口扩展样式,一般填0,本程序使用WM_EX_TOPMOST窗口置顶样式
_In_opt_ LPCWSTR lpClassName, //窗口类名
_In_opt_ LPCWSTR lpWindowName, //窗口名称
_In_ DWORD dwStyle, //窗口风格
_In_ int X, //窗口的X坐标
_In_ int Y, //窗口的Y坐标
_In_ int nWidth, //窗口宽度
_In_ int nHeight, //窗口高度
_In_opt_ HWND hWndParent, //窗口的父窗口
_In_opt_ HMENU hMenu, //窗口菜单(如果是子窗口那么它也是子窗口的ID)
_In_opt_ HINSTANCE hInstance, //实例句柄
_In_opt_ LPVOID lpParam); //解释不清,填NULL就完事儿了
给出创建代码:
HWND hwnd
hwnd = CreateWindowEx(WS_EX_TOPMOST, lpszClassName, lpszWindowName,
WS_POPUPWINDOW | WS_CAPTION | WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, WIDTH, HIGHT,NULL, NULL, hInstance, NULL);
解释一下:WS_POPUPWINDOW表示该窗口是一个弹窗,它包含WS_POPUP,WS_BORDER, WS_SYSMENU。其中WS_SYSMENU表示标题栏上的系统菜单,WS_POPUP表示窗口是一个弹窗。WS_BORDER表示窗口具有一条细线边框,WS_CAPTION表示窗口具有标题栏。注意:WS_POPUPWINDOW要搭配WS_CAPTION才能使标题栏可见,WS_SYSMENU要搭配WS_CAPTION才有效,另外,WS_POPUP不能与WS_CHILD(指定窗口为子窗口)一起使用。
最后,WS_MINIMIZEBOX指定窗口有最小化按钮。
4.显示窗口及更新客户区
很简单,给出声明
ShowWindow(hwnd, SW_SHOW);//显示窗口
UpdateWindow(hwnd); //更新客户区
5.消息循环
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg); //"翻译"窗口消息
DispatchMessage(&msg); //将消息分发给窗口
}
6.返回值
return msg.wParam
至此,创建窗口就完成了
二、处理消息
1.Windows机制
所谓机制,其实就是消息制,系统发送各种消息,窗口收到后处理这些消息并给出回应。
2.回调函数
那么,在程序中,该去哪里处理消息呢?答:回调函数
顾名思义,回调函数就是在窗口接收到消息后调用此函数去处理消息。给出定义:
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
//必要变量
HWND hTopMost, hNoTopMost, hChoose, hClear, hWndTitle;
HDC hdc; //设备DC
PAINTSTRUCT ps; //绘制结构体
LPTSTR lpBuf = NULL; //缓冲区(存放目标窗口标题)
HGDIOBJ hFontOld; //用于设置字体
int nLen; //获取目标窗口标题长度
//存放switch分支
...................
//
reutrn DefWindow(hwnd, uMsg, wParam, lParam);//处理缺省消息
}
其中LRESULT为LONG类型,再直白点就是long。
参数解析:
HWND hwnd:窗口句柄,相当于你的身份证ID
UINT uMsg:窗口接收到的各种消息
WPARAM wParam,PLARAM lParam:(以下内容出于百度(解释不清……))
曾经有那么一段时间,Windows还是一个16位的操作系统。
每一个Windows消息会携带两个参数,它们分别被叫做WPARAM和LPARAM。第一个参数是一个16位的数据(Word),所以它被称之为W。
第二个参数是一个32位的数据(Long),所有它被称之为L。
你可以使用W参数来传递诸如句柄和整数这一类的数据,对于指针数据来说,你可以使用L参数来传递它。当Windows被转换为32位版本之后,WPARAM也从原来的16位迁移到了32位,所以,虽然WPARAM中的W代表Word,但是它已经不再是一个16位的数据了。(甚至在64位操作系统中,这两个参数长度被进一步地扩展到了64位。)
了解这其中的历史故事还是有点用的。如果你仔细地观察一下Windows消息的设计,你会发现,如果消息中携带了某个指针信息,则这个指针通常会保存在消息的LPARAM参数中,如果携带的是一个句柄或者一个整数,则通常会使用WPARAM参数来保存。
接下来开始处理需要用到的消息
3.处理消息
1.WM_DESTROY
这是一个窗口销毁消息,用于退出窗口进程,其前面还有一个WM_CLOSE消息,用于关闭窗口,并同时产生WM_DESTORY(一般可以不写WM_CLOSE)给出消息处理方法
//放在回调函数中
switch (uMsg)
{
//前面还有...
case WM_DESTROY:
KillTimer(hwnd, IDT_TIMER_SHOW); //前面创建的计时器,用于定时获取目标窗口标题
PostQuitMessage(0);
return 0;
}
2.WM_CREATE
该消息在窗口创建时产生,用于初始化窗口,一般用来设置窗口、创建子窗口控件
*由于CreateWindow参数过长,因此我另外写了一个函数用于创建子窗口控件,给出定义:
HWND CreateButton(HWND hParent, int btnX, int btnY, int btnWidth, int btnHight, LONG btnStyle, LPCTSTR btnClass, LPCTSTR btnText, int nID)
{
return CreateWindow(btnClass, btnText, WS_CHILD | WS_VISIBLE | btnStyle,
btnX, btnY, btnWidth, btnHight,
hParent, (HMENU)nID, (HINSTANCE)GetWindowLong(hParent, GWLP_HINSTANCE), NULL);
}
*hParent为父窗口句柄,btnX,BtnY为控件坐标,btnWidth,btnHight为控件长宽 ,btnStyle为控件风格,btnClass为控件类名(有固定名称),nID为控件ID。
给出该消息处理方法
//放在回调函数中
switch (uMsg)
{
case WM_CREATE:
hChoose = CreateButton(hwnd, 10, 130, 100, 40, BS_PUSHBUTTON | WS_BORDER, TEXT("Button"), TEXT("选择目标窗口"), IDC_BTN_CHOOSE); //选择窗口按钮
hClear = CreateButton(hwnd, 115, 130, 100, 40, BS_PUSHBUTTON | WS_DISABLED | WS_BORDER, TEXT("Button"), TEXT("清除窗口句柄"), IDC_BTN_CLEAR); //清除句柄按钮
hTopMost = CreateButton(hwnd, 10, 175, 100, 40, BS_PUSHBUTTON | WS_DISABLED | WS_BORDER, TEXT("Button"), TEXT("设置窗口置顶"), IDC_BTN_TOPMOST);//设置窗口置顶按钮
hNoTopMost = CreateButton(hwnd, 115, 175, 100, 40, BS_PUSHBUTTON | WS_DISABLED | WS_BORDER, TEXT("Button"), TEXT("取消窗口置顶"), IDC_BTN_NOTOPMOST);//取消窗口置顶按钮
hWndTitle = CreateButton(hwnd, 0, 225, 325, 25, ES_READONLY | WS_DISABLED, TEXT("Edit"), TEXT("未选择窗口"), IDC_EDIT_TARGETWND); //编辑控件,用于显示目标窗口标题
break;
//这里还有...
case WM_DESTROY:
……
}
3.WM_PAINT
该消息在窗口重绘时产生(产生条件:窗口创建时,客户区无效时(窗口大小改变,InvalidateRect函数……))给出消息处理方法
//放在回调函数中
switch (uMsg)
{
case WM_CREATE:
……
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
SetBkMode(hdc, TRANSPARENT);
hFontOld = SelectObject(hdc, GetStockObject(OEM_FIXED_FONT));//设置字体
ShowText(hdc);
SelectObject(hdc, hFontOld);
EndPaint(hwnd, &ps);
break;
//这里还有...
case WM_DESTROY:
……
}
其中ShowText为自定义函数,用于显示文字说明,给出定义
VOID ShowText(HDC hdc)
{
TextOut(hdc, 10, 10, TEXT("点击[选择目标窗口]按钮后,"), _tcslen(L"点击[选择目标窗口]按钮后,"));
TextOut(hdc, 10, 30, TEXT("将鼠标移动到目标窗口上并单击,"), _tcslen(L"将鼠标移动到目标窗口上并单击,"));
TextOut(hdc, 10, 50, TEXT("完成后根据需要点击[设置窗口置顶]或"), _tcslen(L"完成后根据需要点击[设置窗口置顶]或"));
TextOut(hdc, 10, 70, TEXT("[取消窗口置顶]按钮即可."), _tcslen(L"[取消窗口置顶]按钮即可."));
TextOut(hdc, 10, 90, TEXT("注意:如果在2秒内未选择窗口,程序将自动"), _tcslen(L"注意:如果未在2秒内选择窗口,程序将自动"));
TextOut(hdc, 10, 110, TEXT("把最前端的窗口设为目标窗口."), _tcslen(L"把最前端的窗口设为目标窗口."));
}
GetStockObject函数用于获取系统资源包括画刷、字体等。给出系统字体列表
值 | 含义 |
ANSI_FIXED_FONT | 等宽系统字体 |
ANSI_VAR_FONT | 变宽系统字体 |
DEVICE_DEFAULT_FONT | 设备默认字体 |
OEM_FIXED_FONT | OEM(原始设备制造商)等宽字体 |
SYSTEM_FONT | 系统字体,默认情况下使用系统字体绘制菜单,对话框和文本 |
SYSTEM_FIXED_FONT | 等宽系统字体 |
4.WM_COMMAND
处理父窗口与子窗口控件之间的通信,给出处理方法
//放在回调函数中
switch (uMsg)
{
case WM_CREATE:
……
case WM_PAINT:
……
case WM_COMMAND:
switch (wParam)
{
case IDC_BTN_CHOOSE: //如果按下选择按钮
ShowWindow(hwnd, SW_HIDE); //影藏窗口
SetTimer(hwnd, IDT_TIMER_SHOW, 60, NULL); //设置计时器
Sleep(2000);
hTarget = GetForegroundWindow();//获取处于最上方窗口句柄
ShowWindow(hwnd, SW_SHOW);//显示窗口
SetEnableWindow(hwnd, FALSE, TRUE, TRUE, TRUE);//垃圾自定义函数(不要这么写)
break;
case IDC_BTN_CLEAR: //如果按下清除句柄按钮
hTarget = NULL;
KillTimer(hwnd, IDT_TIMER_SHOW); //销毁计时器(节约资源)
SetDlgItemText(hwnd, IDC_EDIT_TARGETWND, L"未选择窗口");//设置编辑控件中的内容
SetEnableWindow(hwnd, TRUE, FALSE, FALSE, FALSE);//垃圾自定义函数(不要这么写)
break;
case IDC_BTN_TOPMOST: //如果按下设置窗口置顶按钮
SetWindowPos(hTarget, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);//设置目标窗口置顶
MessageBox(hwnd, TEXT("操作完成"), TEXT("操作完成"), MB_OK | MB_TOPMOST | MB_ICONINFORMATION);
break;
case IDC_BTN_NOTOPMOST://如果按下取消窗口置顶按钮
SetWindowPos(hTarget, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);//取消窗口置顶
MessageBox(hwnd, TEXT("操作完成"), TEXT("操作完成"), MB_OK | MB_TOPMOST | MB_ICONINFORMATION);
break;
}
break;
//这里还有...
case WM_DESTROY:
……
}
给出垃圾函数的定义(不到万不得已不要这么写):
VOID SetEnableWindow(HWND hwnd, BOOL b1, BOOL b2, BOOL b3, BOOL b4)
{
EnableWindow(GetDlgItem(hwnd, IDC_BTN_CHOOSE), b1);
EnableWindow(GetDlgItem(hwnd, IDC_BTN_TOPMOST), b2);
EnableWindow(GetDlgItem(hwnd, IDC_BTN_NOTOPMOST), b3);
EnableWindow(GetDlgItem(hwnd, IDC_BTN_CLEAR), b4);
}
函数解析:
SetTimer(窗口句柄,计时器ID,时间(毫秒),回调函数(一般写NULL));//创建计时器
KillTimer(窗口句柄,计时器ID);//销毁计时器
EnableWindow(窗口句柄,是否启用(TRUE/FALSE));//启用/禁用窗口
GetDlgItem(父窗口句柄,控件ID);//获取控件句柄
5.WM_TIMER
计时器消息,给出处理方法
//放在回调函数中
switch (uMsg)
{
case WM_CREATE:
……
case WM_PAINT:
……
case WM_COMMAND:
……
case WM_TIMER:
nLen = SendMessage(hTarget, WM_GETTEXTLENGTH, 0, 0); //获取目标窗口标题长度
if (nLen > 0)
{
lpBuf = new TCHAR[nLen + 1]; //创建一个用于存放窗口标题的缓冲区,大小为nLen+1(防止溢出)
SendMessage(hTarget, WM_GETTEXT, (nLen + 1), (LPARAM)lpBuf);//向目标窗口发送WM_GETTEXT消息,获取标题,并将标题存放于(nLen+1)大小的缓冲区lpBuf中
SendMessage(GetDlgItem(hwnd, IDC_EDIT_TARGETWND), WM_SETTEXT, 0, (LPARAM)lpBuf);//向编辑控件发送WM_SETTEXT消息,设置文本内容为缓冲区lpBuf中的内容
delete[] lpBuf;//清空缓冲区
}
else
{
SendMessage(GetDlgItem(hwnd, IDC_EDIT_TARGETWND), WM_SETTEXT, 0, (LPARAM)TEXT("未选择窗口"));
KillTimer(hwnd, IDT_TIMER_SHOW);
hTarget = NULL;
SetEnableWindow(hwnd, TRUE, FALSE, FALSE, FALSE);
MessageBox(hwnd, L"无法获取窗口标题\n原因:窗口标题为空或窗口已丢失", L"无法获取窗口标题", MB_OK | MB_TOPMOST | MB_ICONERROR);
}
break;
case WM_DESTROY:
……
}
好了,消息都处理完了。
三、完整代码
#include <Windows.h>
#include "resource.h" //资源头文件,包含自定义图标ID
#include <tchar.h>
#define WIDTH 325 //窗口宽度
#define HIGHT 290 //窗口高度
#define IDC_BTN_CHOOSE 1001 //选择窗口按钮
#define IDC_BTN_CLEAR 1002 //清除句柄按钮
#define IDC_BTN_TOPMOST 1003 //设置置顶按钮
#define IDC_BTN_NOTOPMOST 1004 //取消置顶按钮
#define IDC_EDIT_TARGETWND 1005 //窗口标题显示栏
#define IDT_TIMER_SHOW 1006 //计时器
HWND hTarget;
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
HWND CreateButton(HWND hParent, int btnX, int btnY, int btnWidth, int btnHight, LONG btnStyle, LPCTSTR btnClass, LPCTSTR btnText, int nID);
VOID SetEnableWindow(HWND hwnd, BOOL b1, BOOL b2, BOOL b3, BOOL b4);
VOID ShowText(HDC hdc);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wndclass = { 0 };
HWND hwnd;
MSG msg;
TCHAR lpszClassName[] = { TEXT("WindowTopMostTool") };
TCHAR lpszWindowName[] = { TEXT("窗口置顶工具Win32版") };
wndclass.cbSize = sizeof(WNDCLASSEX);
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WindowProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));//导入自定义图标
wndclass.hCursor = LoadCursor(hInstance, IDC_ARROW);
wndclass.hbrBackground = CreateSolidBrush(0xFFFFFF);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = lpszClassName;
RegisterClassEx(&wndclass);
hwnd = CreateWindowEx(WS_EX_TOPMOST, lpszClassName, lpszWindowName,
WS_POPUPWINDOW | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, WIDTH, HIGHT,
NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HWND hTopMost, hNoTopMost, hChoose, hClear, hWndTitle, hStatusbar;
HDC hdc;
PAINTSTRUCT ps;
LPTSTR lpBuf = NULL;
HGDIOBJ hFontOld;
int nLen;
switch (uMsg)
{
case WM_CREATE:
hChoose = CreateButton(hwnd, 10, 130, 100, 40, BS_PUSHBUTTON | WS_BORDER, TEXT("Button"), TEXT("选择目标窗口"), IDC_BTN_CHOOSE);
hClear = CreateButton(hwnd, 115, 130, 100, 40, BS_PUSHBUTTON | WS_DISABLED | WS_BORDER, TEXT("Button"), TEXT("清除窗口句柄"), IDC_BTN_CLEAR);
hTopMost = CreateButton(hwnd, 10, 175, 100, 40, BS_PUSHBUTTON | WS_DISABLED | WS_BORDER, TEXT("Button"), TEXT("设置窗口置顶"), IDC_BTN_TOPMOST);
hNoTopMost = CreateButton(hwnd, 115, 175, 100, 40, BS_PUSHBUTTON | WS_DISABLED | WS_BORDER, TEXT("Button"), TEXT("取消窗口置顶"), IDC_BTN_NOTOPMOST);
hWndTitle = CreateButton(hwnd, 0, 225, 325, 25, ES_READONLY | WS_DISABLED, TEXT("Edit"), TEXT("未选择窗口"), IDC_EDIT_TARGETWND);
break;
case WM_CTLCOLORSTATIC:
return (LRESULT)CreateSolidBrush(RGB(200, 200, 200));
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
SetBkMode(hdc, TRANSPARENT);
hFontOld = SelectObject(hdc, GetStockObject(OEM_FIXED_FONT));
ShowText(hdc);
SelectObject(hdc, hFontOld);
EndPaint(hwnd, &ps);
break;
case WM_COMMAND:
switch (wParam)
{
case IDC_BTN_CHOOSE:
ShowWindow(hwnd, SW_HIDE);
SetTimer(hwnd, IDT_TIMER_SHOW, 60, NULL);
Sleep(2000);
hTarget = GetForegroundWindow();
ShowWindow(hwnd, SW_SHOW);
SetEnableWindow(hwnd, FALSE, TRUE, TRUE, TRUE);
break;
case IDC_BTN_CLEAR:
hTarget = NULL;
KillTimer(hwnd, IDT_TIMER_SHOW);
SetDlgItemText(hwnd, IDC_EDIT_TARGETWND, L"未选择窗口");
SetEnableWindow(hwnd, TRUE, FALSE, FALSE, FALSE);
break;
case IDC_BTN_TOPMOST:
SetWindowPos(hTarget, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
MessageBox(hwnd, TEXT("操作完成"), TEXT("操作完成"), MB_OK | MB_TOPMOST | MB_ICONINFORMATION);
break;
case IDC_BTN_NOTOPMOST:
SetWindowPos(hTarget, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
MessageBox(hwnd, TEXT("操作完成"), TEXT("操作完成"), MB_OK | MB_TOPMOST | MB_ICONINFORMATION);
break;
}
break;
case WM_TIMER:
nLen = SendMessage(hTarget, WM_GETTEXTLENGTH, 0, 0);
if (nLen > 0)
{
lpBuf = new TCHAR[nLen + 1];
SendMessage(hTarget, WM_GETTEXT, (nLen + 1), (LPARAM)lpBuf);
SendMessage(GetDlgItem(hwnd, IDC_EDIT_TARGETWND), WM_SETTEXT, 0, (LPARAM)lpBuf);
delete[] lpBuf;
}
else
{
SendMessage(GetDlgItem(hwnd, IDC_EDIT_TARGETWND), WM_SETTEXT, 0, (LPARAM)TEXT("未选择窗口"));
KillTimer(hwnd, IDT_TIMER_SHOW);
hTarget = NULL;
SetEnableWindow(hwnd, TRUE, FALSE, FALSE, FALSE);
MessageBox(hwnd, L"无法获取窗口标题\n原因:窗口标题为空或窗口已丢失", L"无法获取窗口标题", MB_OK | MB_TOPMOST | MB_ICONERROR);
}
break;
case WM_DESTROY:
KillTimer(hwnd, IDT_TIMER_SHOW);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
HWND CreateButton(HWND hParent, int btnX, int btnY, int btnWidth, int btnHight, LONG btnStyle, LPCTSTR btnClass, LPCTSTR btnText, int nID)
{
return CreateWindow(btnClass, btnText, WS_CHILD | WS_VISIBLE | btnStyle,
btnX, btnY, btnWidth, btnHight,
hParent, (HMENU)nID, (HINSTANCE)GetWindowLong(hParent, GWLP_HINSTANCE), NULL);
}
VOID SetEnableWindow(HWND hwnd, BOOL b1, BOOL b2, BOOL b3, BOOL b4)
{
EnableWindow(GetDlgItem(hwnd, IDC_BTN_CHOOSE), b1);
EnableWindow(GetDlgItem(hwnd, IDC_BTN_TOPMOST), b2);
EnableWindow(GetDlgItem(hwnd, IDC_BTN_NOTOPMOST), b3);
EnableWindow(GetDlgItem(hwnd, IDC_BTN_CLEAR), b4);
}
VOID ShowText(HDC hdc)
{
TextOut(hdc, 10, 10, TEXT("点击[选择目标窗口]按钮后,"), _tcslen(L"点击[选择目标窗口]按钮后,"));
TextOut(hdc, 10, 30, TEXT("将鼠标移动到目标窗口上并单击,"), _tcslen(L"将鼠标移动到目标窗口上并单击,"));
TextOut(hdc, 10, 50, TEXT("完成后根据需要点击[设置窗口置顶]或"), _tcslen(L"完成后根据需要点击[设置窗口置顶]或"));
TextOut(hdc, 10, 70, TEXT("[取消窗口置顶]按钮即可."), _tcslen(L"[取消窗口置顶]按钮即可."));
TextOut(hdc, 10, 90, TEXT("注意:如果在2秒内未选择窗口,程序将自动"), _tcslen(L"注意:如果未在2秒内选择窗口,程序将自动"));
TextOut(hdc, 10, 110, TEXT("把最前端的窗口设为目标窗口."), _tcslen(L"把最前端的窗口设为目标窗口."));
}
效果图
效果图