- 公開視頻 ->?鏈接點擊跳轉公開課程
- 博客首頁 ->?鏈接點擊跳轉博客主頁
目錄
入口函數
窗口注冊
窗口創建
窗口顯示
窗口更新
消息循環
窗口過程
窗口銷毀
調試信息
示例代碼
入口函數
- 在Windows應用程序中,
WinMain
是主函數,作為應用程序的入口點。這與許多其他平臺上的main
函數類似。 - 函數原型
-
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
- 參數解析
HINSTANCE hInstance
:當前實例的句柄(IMAGEBASE)。HINSTANCE hPrevInstance
:在32位Windows應用程序中,這個參數總是為NULL。在早期版本的Windows中,用于標識程序的前一個實例。LPSTR lpCmdLine
:指向一個以null終止的字符串,該字符串包含命令行參數。請注意,它不包含程序的名稱。int nCmdShow
:指定窗口如何顯示。
窗口注冊
- 在Windows應用程序中,每個窗口都需要一個窗口類,這個類包含了窗口的屬性和一個事件處理函數(窗口過程)。要創建窗口,必須先注冊一個窗口類。
- 函數原型
-
ATOM RegisterClassEx(const WNDCLASSEX *lpwcx);
- 參數解析
lpwcx
:指向WNDCLASSEX
結構的指針,該結構包含了窗口類的信息。WNDCLASSEX
結構定義了窗口的特征,包括背景顏色、光標、圖標、菜單名和窗口過程等。- cbSize: 指定了結構體的大小,必須設置為
sizeof(WNDCLASSEX)
。 - style: 類型的風格。可以是任何窗口類風格的組合,比如
CS_HREDRAW
和CS_VREDRAW
。 - lpfnWndProc: 指向窗口過程的指針。這是一個函數指針,指向一個由系統調用以處理窗口消息的函數。
- cbClsExtra: 指定分配給窗口類結構后面的額外字節數。通常這個值設為0。
- cbWndExtra: 指定分配給每個窗口實例的額外字節數。例如,可以使用額外的空間存儲一個指向窗口數據的指針。
- hInstance: 一個句柄,標識了包含窗口過程的應用程序實例。
- hIcon: 一個圖標的句柄,這是與窗口類關聯的圖標。
- hCursor: 一個光標的句柄,這是與窗口類關聯的光標。
- hbrBackground: 設置窗口背景色的畫刷句柄。可以是一個顏色值的句柄,前面加上
COLOR_
的前綴。 - lpszMenuName: 指向一個以 null 結束的字符串,該字符串指定類菜單,為資源名稱。如果使用類菜單,所有由該類創建的窗口都將使用這個菜單。
- lpszClassName: 指向一個以 null 結束的字符串或是一個原子,如果此參數是一個原子,則它必須是一個全局原子。
- hIconSm: 與窗口類關聯的小圖標的句柄。如果這個成員是 NULL,系統會從
hIcon
成員指定的大圖標中提取一個小圖標。
- cbSize: 指定了結構體的大小,必須設置為
窗口創建
- 注冊了窗口類之后,可以用
CreateWindowEx
函數創建窗口。 - 函數原型
-
HWND CreateWindowEx(DWORD dwExStyle,LPCSTR lpClassName,LPCSTR lpWindowName,DWORD dwStyle,int X,int Y,int nWidth,int nHeight,HWND hWndParent,HMENU hMenu,HINSTANCE hInstance,LPVOID lpParam );
- 函數參數
- dwExStyle: 擴展窗口樣式。這些樣式控制各種擴展的窗口特征,例如帶有邊界陰影的窗口或者無邊框的窗口等。
- lpClassName: 注冊的窗口類名。這可以是一個指向以 null 結尾的字符串的指針,或一個由
RegisterClassEx
函數返回的原子。 - lpWindowName: 窗口的標題文字。如果窗口是一個控件,這個參數是一個指向以 null 結尾的字符串的指針,表示控件的文本。
- dwStyle: 窗口的風格。這些風格控制著窗口的一般外觀和行為。
- X: 窗口創建時水平位置的坐標。如果參數是
CW_USEDEFAULT
,系統會選擇窗口的默認位置。 - Y: 窗口創建時垂直位置的坐標。如果參數是
CW_USEDEFAULT
,系統會選擇窗口的默認位置。 - nWidth: 窗口的寬度。如果設置為
CW_USEDEFAULT
,系統會選擇窗口的默認寬度。 - nHeight: 窗口的高度。如果設置為
CW_USEDEFAULT
,系統會選擇窗口的默認高度。 - hWndParent: 父窗口句柄。如果沒有父窗口,此參數應為
NULL
。彈出窗口和消息框將使用此參數指定的窗口作為它們的所有者。 - hMenu: 窗口菜單句柄或子窗口標識符。如果是一個子窗口,此參數是一個菜單的句柄;如果是頂層窗口,此參數指定窗口的菜單;如果是子窗口,此參數是子窗口的標識符。
- hInstance: 擁有窗口過程的應用程序的實例句柄。
- lpParam: 指向一個值的指針,該值將被傳遞給窗口通過
WM_CREATE
消息。如果不需要傳遞值,此參數可以為NULL
。
窗口顯示
ShowWindow
函數設置窗口的顯示狀態。在一個窗口被創建后,它不會自動顯示;必須調用此函數來控制窗口的顯示。- 函數原型
-
BOOL ShowWindow(HWND hWnd,int nCmdShow );
- 函數參數
hWnd
:窗口句柄,標識要設置顯示狀態的窗口。nCmdShow
:指定窗口如何被顯示。常用參數包括:SW_SHOW
:顯示窗口。SW_HIDE
:隱藏窗口,活動狀態給另一個窗口。SW_MINIMIZE
:最小化窗口,活動狀態給另一個窗口。SW_RESTORE
:激活并顯示窗口。如果窗口最小化或最大化,系統會將其恢復到原始尺寸和位置。SW_SHOWMAXIMIZED
:激活窗口并將其最大化。SW_SHOWMINIMIZED
:激活窗口并將其最小化。SW_SHOWMINNOACTIVE
:窗口最小化,類似SW_SHOWMINIMIZED
,但窗口不被激活。
窗口更新
UpdateWindow
函數用于更新客戶區的無效區域,即發送一個WM_PAINT
消息給窗口過程,如果客戶區沒有無效區域,則不發送消息。- 函數原型
-
BOOL UpdateWindow(HWND hWnd );
- 函數參數
hWnd
:窗口句柄,標識要更新的窗口。- 該函數通常在
ShowWindow
后調用,以便立即更新窗口的客戶區而無需等待WM_PAINT
消息的正常排隊。
消息循環
- Windows應用程序是事件驅動的。在
WinMain
中,程序必須不斷檢查和處理消息。這就是所謂的消息循環或消息處理機制。每個GUI應用程序都有一個消息隊列,Windows操作系統使用它來存儲對該應用程序的所有輸入(如鼠標點擊、鍵盤輸入等)。 - 示例代碼
-
while (GetMessage(&msg, NULL, 0, 0)) {TranslateMessage(&msg);DispatchMessage(&msg); }
- 函數解析
GetMessage
從消息隊列檢索消息。如果沒有消息,它會等待,直到有消息為止。如果返回0,意味著接收到WM_QUIT消息,循環會結束。TranslateMessage
將虛擬鍵消息轉換為字符消息。DispatchMessage
將消息發送到窗口程序。
窗口過程
- 窗口過程是一個函數,它處理發送到窗口的消息。每個窗口都有一個與之關聯的窗口過程。當事件發生(比如用戶點擊按鈕),Windows會將相應的消息發送到窗口過程。窗口過程根據消息的類型執行相應的操作,并返回結果。
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
HWND hwnd
: 窗口的句柄。UINT uMsg
: 消息的標識。WPARAM wParam
: 消息特定的附加信息。LPARAM lParam
: 消息特定的附加信息。-
// 實現窗口過程函數 LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {return DefWindowProc(hwnd, uMsg, wParam, lParam); }
窗口銷毀
- 窗口的銷毀 通常通過調用
DestroyWindow
函數來完成。當窗口被銷毀后,Windows會發送WM_DESTROY
消息給窗口過程,窗口過程可以在接收到此消息時執行清理操作。
調試信息
OutputDebugStringA
函數是 Windows API 中的一個函數,它用于將一個字符串輸出到調試器。
#include <windows.h>
#include <stdio.h>int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{char buffer[256];int value1 = 42;int value2 = 100;// 使用 sprintf 格式化字符串sprintf_s(buffer, sizeof(buffer), "Value 1: %d, Value 2: %d\n", value1, value2);// 輸出格式化后的字符串到調試器OutputDebugStringA(buffer);return 0;
}
示例代碼
#include <Windows.h>LRESULT CALLBACK MainWindowProc (HWND, UINT, WPARAM, LPARAM);INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{// 注冊窗口WNDCLASSEX wndclass = { 0 };wndclass.cbSize = sizeof(WNDCLASSEX);wndclass.style = NULL;wndclass.lpfnWndProc = MainWindowProc;wndclass.cbClsExtra = NULL;wndclass.cbWndExtra = NULL;wndclass.hInstance = hInstance;wndclass.hIcon = NULL;wndclass.hCursor = NULL;wndclass.hbrBackground = (HBRUSH)COLOR_WINDOW;wndclass.lpszMenuName = NULL;wndclass.lpszClassName = TEXT("0xCC");wndclass.hIconSm = NULL;if (!RegisterClassEx(&wndclass)){MessageBox(NULL, TEXT("RegisterClassEx Failed"), TEXT("Error"), MB_OK);return 1;}// 創建窗口HWND hwnd = CreateWindowEx(WS_EX_CLIENTEDGE,TEXT("0xCC"),TEXT("CreateWindowEx"),WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,960,540,NULL,NULL,hInstance,NULL);if (hwnd == NULL){MessageBox(NULL, TEXT("CreateWindowEx Failed"), TEXT("Error"), MB_OK);return 1;}// 顯示窗口ShowWindow(hwnd, SW_SHOWDEFAULT);// 更新窗口UpdateWindow(hwnd);// 消息處理MSG msg = { 0 };while (GetMessage(&msg, 0, 0, 0)){TranslateMessage(&msg);DispatchMessage(&msg);}return 0;
}// 窗口過程
LRESULT CALLBACK MainWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{switch (uMsg){case WM_CREATE:{MoveWindow(hwnd, 0, 0, 500, 500, FALSE);CREATESTRUCT* Cs = (CREATESTRUCT*)lParam;break;}case WM_DESTROY:{PostQuitMessage(0);break;}case WM_SIZE:{TCHAR szBuffer[0xFF] = { 0 };wsprintf(szBuffer, TEXT("WM_SIZE -> %d %d\r\n"), HIWORD(lParam), LOWORD(lParam));OutputDebugString(szBuffer);break;}case WM_MOVE:{TCHAR szBuffer[0xFF] = { 0 };wsprintf(szBuffer, TEXT("WM_MOVE -> %d %d\r\n"), HIWORD(lParam), LOWORD(lParam));OutputDebugString(szBuffer);break;}case WM_LBUTTONDOWN:{TCHAR szBuffer[0xFF] = { 0 };wsprintf(szBuffer, TEXT("WM_LBUTTONDOWN -> %d %d\r\n"), HIWORD(lParam), LOWORD(lParam));OutputDebugString(szBuffer);break;}case WM_KEYDOWN:{TCHAR szBuffer[0xFF] = { 0 };wsprintf(szBuffer, TEXT("WM_KEYDOWN -> %d\r\n"), wParam);OutputDebugString(szBuffer);break;}default:return DefWindowProc(hwnd, uMsg, wParam, lParam);}}