【C/C++硬核】第一个Win32实用程序

首先,要感谢小破站阿婆主@林间寒水。


目录

首先,要感谢小破站阿婆主@林间寒水。

一、创建窗口

1.入口函数

2.注册窗口类

3.创建窗口

4.显示窗口及更新客户区

5.消息循环

6.返回值

二、处理消息

1.Windows机制

2.回调函数

3.处理消息

1.WM_DESTROY

2.WM_CREATE

3.WM_PAINT

4.WM_COMMAND

5.WM_TIMER

三、完整代码

效果图

 四、

再见


。。。灵感来了。

看过的都知道,窗口置顶工具确实很有用,我复刻了一个,然后就没有然后了……

额……………………………………………………………………………………………

好吧,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);//处理缺省消息
}

其中LRESULTLONG类型,再直白点就是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_FONTOEM(原始设备制造商)等宽字体
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"把最前端的窗口设为目标窗口."));
}

效果图

效果图

 四、

再见

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值