windows 消息循环
以下是一个简单的处理按钮点击的示例:
#include <windows.h>#define BUTTON_ID 1 // 定义按钮IDLRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{switch (uMsg){case WM_CREATE:{// 创建一个按钮HWND hButton = CreateWindow(L"BUTTON", // 按钮类名L"Click Me", // 按钮标题WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // 样式50, // x 坐标50, // y 坐标100, // 宽度50, // 高度hwnd, // 父窗口句柄(HMENU)BUTTON_ID, // 按钮ID(HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE),NULL); // 参数break;}case WM_COMMAND:if (LOWORD(wParam) == BUTTON_ID && HIWORD(wParam) == BN_CLICKED){MessageBox(hwnd, L"Button clicked!", L"Notification", MB_OK);}break;case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(hwnd, uMsg, wParam, lParam);}return 0;
}int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{const wchar_t CLASS_NAME[] = L"Sample Window Class";WNDCLASS wc = {};wc.lpfnWndProc = WindowProc;wc.hInstance = hInstance;wc.lpszClassName = CLASS_NAME;RegisterClass(&wc);HWND hwnd = CreateWindowEx(0,CLASS_NAME,L"Button Click Example",WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, CW_USEDEFAULT, 300, 200,NULL, NULL, hInstance, NULL);ShowWindow(hwnd, nCmdShow);MSG msg = {};while (GetMessage(&msg, NULL, 0, 0)){TranslateMessage(&msg);DispatchMessage(&msg);}return 0;
}
下面是消息循环的代码
while (GetMessage(&msg, NULL, 0, 0)){TranslateMessage(&msg);DispatchMessage(&msg);}
当消息队列没有操作系统发来的消息时,GetMessage
会阻塞等待,当消息队列有消息时,GetMessage
会将消息赋值到msg
,并且调用DispatchMessage
分发到各个窗口的消息处理函数
下面是消息处理函数注册的代码
WNDCLASS wc = {};wc.lpfnWndProc = WindowProc;wc.hInstance = hInstance;wc.lpszClassName = CLASS_NAME;RegisterClass(&wc);
通过SetWindowLong
可以针对不同窗口设置消息处理函数
SetWindowLongA(hWnd,GWL_WNDPROC,WindowProc);
通过GetWindowLong
可以获取该窗口的消息处理函数
LONG_PTR wndProc = GetWindowLongPtr(hwnd, GWLP_WNDPROC);
SetWindowLong
和GetWindowLong
仅限当前进程使用,其它进程调用是会有权限不足的错误
x64dbg设置消息断点
加载程序后,运行到窗口弹出来,选择句柄
选项卡,右键点击刷新
有很多关键信息,其中最关键的还是窗口过程,这个就是消息处理函数
在某个窗口右键点击消息断点
弹出消息断点窗口
有很多消息类型,下面我列举一下点击事件的常见消息
WM_LBUTTONDOWN //用户按下鼠标左键时发送的消息。
WM_LBUTTONUP //用户释放鼠标左键时发送的消息
WM_COMMAND //当按钮被点击时,最常见的消息类型。消息携带控件 ID 和通知码,通常与按钮交互事件相关。
其中WM_COMMAND
一般用的最多,因为它会携带被点击的控件ID。
x64dbg消息断点的缺陷
x64dbg的句柄窗口只能获取调用RegisterClass
时的窗口过程
,不能获取SetWindowLong
设置的窗口过程
,所以要准确获取正确的窗口过程
,最好函数写个插件使用注入hook技术调用GetWindowLong
获取窗口过程