Win32 程式開發:建立一個應用程式視窗
阿新 • • 發佈:2018-12-19
1)簡單介紹建立應用程式的步驟
1.設計一個視窗類
2.註冊這個視窗類
3.建立應用程式視窗
4.更新顯示視窗
5.應用程式訊息迴圈
2)下面根據這個步驟進行建立一個應用程式視窗吧
/* 標頭檔案 */ #include <windows.h> /* 全域性變數 */ WCHAR g_lpszClassName[] = L"CLASSNAME"; WCHAR g_lpszWindowName[] = L"哈嘍,新的征程"; /* 函式宣告 */ LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); /* 應用程式主函式 */ INT APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, INT nCmdShow) { /* 1.設計一個視窗類 */ WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.lpfnWndProc = WndProc; wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wcex.lpszMenuName = NULL; wcex.lpszClassName = g_lpszClassName; wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION); /* 2.註冊這個視窗類 */ if (RegisterClassEx(&wcex) == ((ATOM)0)) { MessageBox(NULL, L"註冊視窗類失敗!", L"錯誤", MB_YESNO | MB_ICONERROR); exit(-1); } /* 3.建立視窗 */ HWND hWnd = CreateWindowEx(NULL, g_lpszClassName, g_lpszWindowName, WS_OVERLAPPEDWINDOW, 10, 10, 800, 800, NULL, NULL, hInstance, NULL); if (hWnd == NULL) { MessageBox(NULL, L"建立視窗失敗!", L"錯誤", MB_YESNO | MB_ICONERROR); exit(-1); } /* 4.更新顯示視窗 */ ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); /* 5.應用程式訊息迴圈 */ MSG msg = { 0 }; BOOL bRet; /* GetMessage 發生錯誤會返回-1 */ while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) { if (bRet != -1) { TranslateMessage(&msg); DispatchMessage(&msg); } } return msg.wParam; } /* 應用程式訊息處理回撥函式 */ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; }
下面進行講解上面的程式:
2.註冊這個設計的視窗類呼叫RegisterClassEx函式進行註冊
3.進行建立視窗,呼叫CreateWindowEx函式進行建立
4.更新顯示此視窗,分別呼叫ShowWindow(顯示視窗)和UpdateWindow(更新視窗)
5.應用程式訊息迴圈,通過while迴圈
6.視窗訊息處理過程
1.設計一個視窗類(...)
2.註冊這個設計的視窗類
①RegisterClassEx函式講解(註冊視窗類函式,winuser.h中提供的函式)
函式原型:
ATOM WINAPI RegisterClassExW(_In_ CONST WNDCLASSEXW *);
_In_ CONST WNDCLASSEXW *: 為我們設計的視窗類
返回值(ATOM也就是原子的意思):成功返回註冊的原子,失敗返回0
②示例中的使用
所以我們只需要通過返回值判斷是否為註冊失敗,註冊失敗返回0,0也就是false
if (RegisterClassEx(&wcex) == ((ATOM)0)) { 提示註冊失敗資訊 }
3.進行建立視窗
①CreateWindowEx函式講解(註冊視窗類函式,winuser.h中提供的函式)
函式原型:(用點多,希望認真看完)
HWND WINAPI CreateWindowExW( _In_ DWORD dwExStyle, _In_opt_ LPCWSTR lpClassName, _In_opt_ LPCWSTR lpWindowName, _In_ DWORD dwStyle, _In_ int X, _In_ int Y, _In_ int nWidth, _In_ int nHeight, _In_opt_ HWND hWndParent, _In_opt_ HMENU hMenu, _In_opt_ HINSTANCE hInstance, _In_opt_ LPVOID lpParam);
dwExStyle: 視窗擴充套件風格
lpClassName: 我們註冊的視窗類的名稱
lpWindowName: 視窗的名稱(說白了就是視窗的標題)
dwStyle: 視窗建立的風格(跟dwExStyle不同哦)
X: 視窗左上角的點位於螢幕的橫座標
Y: 視窗左上角的點位於螢幕的縱座標
nWidth: 視窗的寬度
nHeight: 視窗的高度
hWndParent: 視窗所有者的控制代碼
hMenu: 選單控制代碼
hInstance: 所在模組的例項控制代碼
lpParam: 在WM_CREATE中進行傳遞的引數
返回值: 建立成功返回建立的視窗控制代碼,失敗返回NULL
②示例中的使用
HWND hWnd = CreateWindowEx(NULL, g_lpszClassName, g_lpszWindowName, WS_OVERLAPPEDWINDOW,
10, 10, 800, 800, NULL, NULL, hInstance, NULL);
視窗的擴充套件風格為NULL,也就是沒有擴充套件風格
視窗類的名稱是g_lpszClassName("CLASSNAME")
視窗名稱是g_lpszClassName("哈嘍,新的征程")
視窗的風格為WS_OVERLAPPEDWINDOW
視窗的位於螢幕的橫縱座標為(10, 10)
視窗的寬和高為(800, 800)
視窗的所有者為NULL,也就是沒有所有者
視窗的選單控制代碼為NULL,也就是沒有選單
視窗的所在模組的例項控制代碼,為作業系統在WinMain中傳遞過來的示例控制代碼
在WM_CREATE中傳遞的引數為NULL,也就是傳遞一個NULL的引數
最後通過返回值進行判斷是否建立成功:
if (hWnd == NULL) { 建立視窗失敗的提示資訊 }
4.更新顯示此視窗
①ShowWindow函式講解(顯示視窗,winuser.h中提供的函式)
函式原型:
BOOL WINAPI ShowWindow(
_In_ HWND hWnd,
_In_ int nCmdShow);
hWnd:顯示的視窗控制代碼
nCmdShow:視窗顯示的方式(全屏,最大化視窗,最小化視窗,······)
返回值:成功返回非0,失敗返回0
②UpdateWindow函式講解(顯示視窗,winuser.h中提供的函式)
函式原型:
BOOL WINAPI UpdateWindow(
_In_ HWND hWnd);
hWnd:更新的視窗
返回值:成功返回非0,失敗返回0
③示例中的使用
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
hWnd為CreateWindowEx中建立的視窗
nCmdShow為視窗的顯示的方式(在WinMain由作業系統傳入)
5.應用程式訊息迴圈
①GetMessage函式講解(從呼叫執行緒的訊息佇列中取得一個訊息,winuser.h中提供的函式)
函式原型:
BOOL WINAPI GetMessageW(
_Out_ LPMSG lpMsg,
_In_opt_ HWND hWnd,
_In_ UINT wMsgFilterMin,
_In_ UINT wMsgFilterMax);
lpMsg:接收從訊息佇列中獲取的訊息
hWnd:接收訊息的視窗控制代碼
wMsgFilterMin:指定被檢測的最小訊息值
wMsgFilterMax:指定被檢測的最大訊息值
返回值:獲取錯誤返回-1,訊息為WM_QUIT返回0,其他為非0
②TranslateMessage函式講解(將虛擬鍵訊息轉換為字元訊息,winuser.h中提供的函式)
函式原型:
BOOL WINAPI TranslateMessage(
_In_ CONST MSG *lpMsg);
lpMsg:接收的訊息
返回值:成功返回非0,失敗返回0
③DispatchMessage函式講解(將訊息分發到視窗處理,winuser.h中提供的函式)
函式原型:
LRESULT WINAPI DispatchMessageW(
_In_ CONST MSG *lpMsg);
lpMsg:分發的訊息
返回值:視窗處理過程的返回值
④示例中的使用
while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
{
if (bRet != -1)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
while迴圈的結束,當GetMessage獲取到的訊息為WM_QUIT視窗退出,則返回0(false) 當GetMessage的返回值不為-1(獲取訊息失敗)的時候,進行虛擬鍵轉換和分發訊息
6.視窗訊息處理過程
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
引數:
hWnd: 視窗處理過程的視窗控制代碼
message:訊息ID
wParam: 附加訊息
lParam: 附加訊息
①PostQuitMessage(執行緒終止請求,winuser.h中提供的函式)
函式原型:
VOID WINAPI PostQuitMessage(
_In_ int nExitCode);
nExitCode:程式退出程式碼
②DefWindowProc(預設的視窗處理過程,winuser.h中提供的函式)
函式原型:
LRESULT CALLBACK DefWindowProcW(
_In_ HWND hWnd,
_In_ UINT Msg,
_In_ WPARAM wParam,
_In_ LPARAM lParam);
引數和返回值跟我們的視窗處理過程一樣
這個函式的意義就是我們不想處理的訊息就交給他吧
小插曲:
return msg.wParam
其實這個跟main的return是一樣的,但對於初學者會有疑問,為什麼不是return 0
解釋部分:
當GetMessage獲取到的訊息為WM_DESTROY(銷燬視窗)的時候呼叫我們的處理:
case WM_DESTROY:
PostQuitMessage(0);
break;