窗口控件(按钮)
先包含库#include <CommCtrl.h>
以下代码即可在hwnd窗口创建一个按钮“按钮1”:
CreateWindowW(
WC_BUTTON, // 使用已注册的窗口类名
L"按钮1", // 窗口标题文本
WS_CHILD | WS_VISIBLE, // 标准窗口样式,由于是在窗口里面,所以是CHILD属性,VISIBLE表示可见
10, // 初始x位置(使用默认值)
10, // 初始y位置
200, // 窗口宽度(默认)
100, // 窗口高度
hwindow, // 父窗口句柄(无)
NULL, // 菜单句柄(无)
hInstance, // 程序实例句柄
0 // 创建参数(无)
);
如图:

需要注意的是,如果想把该代码放到回调函数里面,由于回调函数传参并不会传递程序实例句柄hInstance,得使用GetModuleHandleW函数来把hInstance传进来,代码如下所示:
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HINSTANCE hInstance = GetModuleHandleW(NULL);
switch (message) // 根据消息类型进行分支处理
{
case WM_CREATE:
// 创建按钮
CreateWindowW(
WC_BUTTON, // 使用已注册的窗口类名
L"按钮1", // 窗口标题文本
WS_CHILD | WS_VISIBLE, // 标准窗口样式(带标题栏、边框等)
10, // 初始x位置(使用默认值)
10, // 初始y位置
200, // 窗口宽度(默认)
100, // 窗口高度
hwnd, // 父窗口句柄(无)
NULL, // 菜单句柄(无)
hInstance, // 程序实例句柄
0 // 创建参数(无)
);
break;
case WM_LBUTTONDOWN: // 鼠标左键点击时触发
MessageBoxW(hwnd, L"鼠标左键点击", L"提示", MB_OK); // 显示关闭提示
SendMessageW(hwnd, WM_USERMSG, 0, 0);
break;
case WM_USERMSG: //收到自定义消息时触发
MessageBoxW(hwnd, L"自定义消息触发", L"提示", MB_OK);
break;
case WM_RBUTTONDOWN: // 鼠标右键点击时触发
MessageBoxW(hwnd, L"鼠标右键点击", L"提示", MB_OK); // 显示关闭提示
SendMessageW((HWND)0x00010B4E, WM_CLOSE, 0, 0);
break;
default: // 其他未处理的消息交给默认处理函数
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0; // 已处理的消息返回0
}
点击按钮之后,向回调函数发送的信息是WM_COMMAND(WM_COMMAND 消息 (Winuser.h) – Win32 apps | Microsoft Learn),下述代码可以实现点击按钮后的反馈:
case WM_COMMAND: // 按钮点击时触发
MessageBoxW(hwnd, L"按钮点击", L"提示", MB_OK); // 显示关闭提示
break;
如图所示:

但是问题来了,如果想区分按钮1和按钮2怎么办?
这里就用到了回调函数中的后两个参数:
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)

给菜单句柄赋不同的值,然后接受wParam参数即可根据值得不同来处理不同的按钮,代码如下:
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HINSTANCE hInstance = GetModuleHandleW(NULL);
switch (message) // 根据消息类型进行分支处理
{
case WM_CREATE:
// 创建按钮
CreateWindowW(
WC_BUTTON, // 使用已注册的窗口类名
L"按钮1", // 窗口标题文本
WS_CHILD | WS_VISIBLE, // 标准窗口样式(带标题栏、边框等)
10, // 初始x位置(使用默认值)
10, // 初始y位置
200, // 窗口宽度(默认)
100, // 窗口高度
hwnd, // 父窗口句柄(无)
(HMENU)0x100, // 菜单句柄(无)
hInstance, // 程序实例句柄
0 // 创建参数(无)
);
CreateWindowW(
WC_BUTTON, // 使用已注册的窗口类名
L"按钮2", // 窗口标题文本
WS_CHILD | WS_VISIBLE, // 标准窗口样式(带标题栏、边框等)
10, // 初始x位置(使用默认值)
200, // 初始y位置
200, // 窗口宽度(默认)
100, // 窗口高度
hwnd, // 父窗口句柄(无)
(HMENU)0x101, // 菜单句柄(无)
hInstance, // 程序实例句柄
0 // 创建参数(无)
);
break;
case WM_LBUTTONDOWN: // 鼠标左键点击时触发
MessageBoxW(hwnd, L"鼠标左键点击", L"提示", MB_OK); // 显示关闭提示
SendMessageW(hwnd, WM_USERMSG, 0, 0);
break;
case WM_USERMSG: //收到自定义消息时触发
MessageBoxW(hwnd, L"自定义消息触发", L"提示", MB_OK);
break;
case WM_RBUTTONDOWN: // 鼠标右键点击时触发
MessageBoxW(hwnd, L"鼠标右键点击", L"提示", MB_OK); // 显示关闭提示
SendMessageW((HWND)0x00010B4E, WM_CLOSE, 0, 0);
break;
case WM_COMMAND: // 按钮点击时触发
{
WORD BUTTONMSG = LOWORD(wParam);
if (BUTTONMSG == 0x100) {
MessageBoxW(hwnd, L"按钮1点击", L"提示", MB_OK); // 显示关闭提示
}
else if (BUTTONMSG == 0x101) {
MessageBoxW(hwnd, L"按钮2点击", L"提示", MB_OK); // 显示关闭提示
}
break;
}
default: // 其他未处理的消息交给默认处理函数
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0; // 已处理的消息返回0
}
以下代码即可实现,一个按钮关闭QQ,一个按钮关闭浏览器:
#include <Windows.h>
#include <CommCtrl.h>
const UINT WM_USERMSG = WM_USER + 1;
// 窗口过程函数 - 处理所有发送到窗口的消息
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HINSTANCE hInstance = GetModuleHandleW(NULL);
switch (message) // 根据消息类型进行分支处理
{
case WM_CREATE:
// 创建按钮
CreateWindowW(
WC_BUTTON, // 使用已注册的窗口类名
L"关闭QQ", // 窗口标题文本
WS_CHILD | WS_VISIBLE, // 标准窗口样式(带标题栏、边框等)
10, // 初始x位置(使用默认值)
10, // 初始y位置
200, // 窗口宽度(默认)
100, // 窗口高度
hwnd, // 父窗口句柄(无)
(HMENU)0x100, // 菜单句柄(无)
hInstance, // 程序实例句柄
0 // 创建参数(无)
);
CreateWindowW(
WC_BUTTON, // 使用已注册的窗口类名
L"关闭浏览器", // 窗口标题文本
WS_CHILD | WS_VISIBLE, // 标准窗口样式(带标题栏、边框等)
10, // 初始x位置(使用默认值)
200, // 初始y位置
200, // 窗口宽度(默认)
100, // 窗口高度
hwnd, // 父窗口句柄(无)
(HMENU)0x101, // 菜单句柄(无)
hInstance, // 程序实例句柄
0 // 创建参数(无)
);
break;
case WM_LBUTTONDOWN: // 鼠标左键点击时触发
MessageBoxW(hwnd, L"鼠标左键点击", L"提示", MB_OK); // 显示关闭提示
SendMessageW(hwnd, WM_USERMSG, 0, 0);
break;
case WM_USERMSG: //收到自定义消息时触发
MessageBoxW(hwnd, L"自定义消息触发", L"提示", MB_OK);
break;
case WM_RBUTTONDOWN: // 鼠标右键点击时触发
MessageBoxW(hwnd, L"鼠标右键点击", L"提示", MB_OK); // 显示关闭提示
SendMessageW((HWND)0x000600C4, WM_CLOSE, 0, 0);
break;
case WM_COMMAND: // 按钮点击时触发
{
WORD BUTTONMSG = LOWORD(wParam);
if (BUTTONMSG == 0x100) {
MessageBoxW(hwnd, L"关闭QQ", L"提示", MB_OK); // 显示关闭提示
SendMessageW((HWND)0x000600C4, WM_CLOSE, 0, 0);
}
else if (BUTTONMSG == 0x101) {
MessageBoxW(hwnd, L"关闭浏览器", L"提示", MB_OK); // 显示关闭提示
SendMessageW((HWND)0x00060718, WM_CLOSE, 0, 0);
}
break;
}
default: // 其他未处理的消息交给默认处理函数
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0; // 已处理的消息返回0
}
// Windows应用程序入口点(不同于控制台程序的main)
int WINAPI WinMain(
HINSTANCE hInstance, // 当前程序实例句柄(由系统分配)
HINSTANCE hPreHinstance, // 前一个实例句柄(已废弃,总是NULL)
LPSTR lpCmdLine, // 命令行参数(ANSI字符串)
int nCmdShow // 窗口初始显示状态(最小化/正常等)
)
{
// 1. 定义并初始化窗口类结构体
WNDCLASSW myclass = { 0 }; // 清零初始化
myclass.lpszClassName = L"n0ps1ed"; // 窗口类名称(唯一标识)
myclass.lpfnWndProc = WndProc; // 设置窗口消息处理函数
// 2. 注册窗口类到操作系统
RegisterClassW(&myclass); // 注册后才能创建该类的窗口
// 3. 创建窗口实例
HWND hwindow = CreateWindowW(
myclass.lpszClassName, // 使用已注册的窗口类名
L"n0ps1ed", // 窗口标题文本
WS_OVERLAPPEDWINDOW, // 标准窗口样式(带标题栏、边框等)
CW_USEDEFAULT, // 初始x位置(使用默认值)
0, // 初始y位置
CW_USEDEFAULT, // 窗口宽度(默认)
0, // 窗口高度
NULL, // 父窗口句柄(无)
NULL, // 菜单句柄(无)
hInstance, // 程序实例句柄
0 // 创建参数(无)
);
// 4. 显示窗口
ShowWindow(hwindow, SW_SHOWNORMAL); // 以普通状态显示窗口
// 5. 消息循环(程序核心)
MSG msg = { 0 };
while (GetMessageW(&msg, hwindow, 0, 0)) // 获取消息
{
DispatchMessageW(&msg); // 将消息分发到窗口过程WndProc
}
return 0; // 程序结束(当GetMessage收到WM_QUIT时退出循环)
}
此外,如果不用Spy++来找qq的句柄,也可以用FindWindowW来寻找:
HWND FindWindowW( [in, optional] LPCWSTR lpClassName, [in, optional] LPCWSTR lpWindowName );

WORD BUTTONMSG = LOWORD(wParam);
if (BUTTONMSG == 0x100) {
HWND qq = FindWindowW(NULL, L"QQ");
MessageBoxW(hwnd, L"关闭QQ", L"提示", MB_OK); // 显示关闭提示
SendMessageW((HWND)qq, WM_CLOSE, 0, 0);
}
操作控件函数
操作控件可以用到以下函数:
