windows 訊息迴圈
以下是一個簡單的處理按鈕點選的示例:
#include <windows.h>
#define BUTTON_ID 1 // 定義按鈕ID
LRESULT 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
獲取視窗過程