本系列博文幾乎沒有難啃的「專業術語」,儘可能讓讀者可以看明白文章所述內容,是本系列博文的核心宗旨之一。(因爲本人也是因爲項目須要,因此纔來查閱相關資料,文中出現的錯誤歡迎指出,共同進步!謝謝!)windows
讀本系列博文的讀者必須具有如下的知識儲備:api
窗口在 Windows 中指一個矩形區域,通常狀況下這個區域是用戶與應用程序交互的樞紐;上一小節使用 MessageBox 建立的簡單窗口也是與用戶交互的一個窗口,該窗口的功能有限,只可以簡單的展現一些想要表達的信息,想建立一個能表達更多信息的窗口,可使用 CreateWindow 函數建立。數據結構
建立 Windows 桌面應用程序須要 windows.h,在頭部引入 windows.h 頭文件。app
#include <windows.h>
複製代碼
在C語言中,每一個C語言程序都有一個入口函數,在Windows桌面程序中,這個入口函數是 WinMain ,具體聲明以下:函數
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow);
複製代碼
在程序中,緊接着在頭部文件後,咱們使用 WinMain做爲程序的入口函數:佈局
#include <windows.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {}
複製代碼
寫好入口函數後,必需要使用 RegisterClassEx 註冊一個新的窗口類型,再使用 CreateWindow 進行建立。post
在註冊新窗口前,咱們可使用一個 WNDCLASSEX 結構用來描述建立的Windows,這是窗口類;微軟開發中心對WNDCLASSEXA的描述:「Contains window class information. It is used with the RegisterClassEx and GetClassInfoEx functions.」;WNDCLASSEXA 是包含窗口信息的結構。語法以下:學習
typedef struct tagWNDCLASSEXA {
UINT cbSize;
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCSTR lpszMenuName;
LPCSTR lpszClassName;
HICON hIconSm;
} WNDCLASSEXA, *PWNDCLASSEXA, *NPWNDCLASSEXA, *LPWNDCLASSEXA;
複製代碼
結構成員:字體
sizeof(WNDCLASSEX)
CS_HREDRAW | CS_VREDRAW
static TCHAR szWindowClass[] = _T("CSDN @1_bit");
代碼實現以下:ui
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
wcex.hCursor = LoadCursor(NULL, IDC_CROSS);
wcex.hbrBackground = (HBRUSH)(COLOR_ACTIVECAPTION);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(NULL, MAKEINTRESOURCE(IDI_INFORMATION));
複製代碼
——————————————————————————————————
值參考:
——————————————————————————————————LoadCursor 返回類型爲 HCURSOR:的語法以下:
HCURSOR LoadCursorW( HINSTANCE hInstance, LPCWSTR lpCursorName );
複製代碼
參數說明:
在微軟的參考文檔中說明,lpCursorName 的可設置爲如下值:
——————————————————————————————————lpfnWndProc 爲接收窗口處理的指針,使用 WndProc 處理應用程序在發生事件時從 Windows 接收的消息。在微軟的文檔中寫道:「WndProc 是每一個 Windows 桌面應用程序必須的窗口過程功能。 此函數一般命名爲WndProc,但您能夠爲所欲爲地命名它。 例如,若是用戶在應用程序中選擇"肯定"按鈕,Windows 會向您發送消息,您能夠在WndProc函數內編寫代碼,執行任何適當的操做。 這稱爲處理事件。 您只處理與應用程序相關的事件。WndProc 具備如下語法」;以下:。
LRESULT CALLBACK WndProc( _In_ HWND hWnd, _In_ UINT message, _In_ WPARAM wParam, _In_ LPARAM lParam );
複製代碼
那咱們在程序中聲明也如此聲明,那麼定義以下(使用微軟文檔示例):
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
PAINTSTRUCT ps;
HDC hdc;
TCHAR greeting[] = _T("Hello, 我是CSDN 1_bit 博客主頁:https://me.csdn.net/A757291228 ");
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
TextOut(hdc,
5, 5,
greeting, _tcslen(greeting));
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}
複製代碼
在以上 WndProc 的實現中,使用了 switch 語句,在 switch 中判斷了 WM_PAINT 消息;WM_PAINT 消息爲繪製主窗體,在文檔中寫到:
要處理的一條重要信息是WM_PAINT消息。 當必須更新其顯示WM_PAINT窗口的一部分時,應用程序將接收消息。 當用戶在窗口前面移動窗口,而後再次將其移開時,可能會發生此事件。 您的應用程序不知道這些事件什麼時候發生。 只有 Windows 知道,所以它會經過消息WM_PAINT通知你的應用。 首次顯示窗口時,必須更新全部窗口。 要處理 WM_PAINT 消息,首先應調用 BeginPaint,而後處理全部的邏輯以在窗口中佈局文本、按鈕和其餘控件,而後調用 EndPaint。
——————————————————————————————————
BeginPaint 的語法爲:
HDC BeginPaint( HWND hWnd, LPPAINTSTRUCT lpPaint );
複製代碼
參數說明:
——————————————————————————————————
該調用EndPaint函數標記指定窗口畫的結束。每次調用BeginPaint函數都須要此函數,可是僅在繪製完成以後。
語法:
BOOL EndPaint( HWND hWnd, const PAINTSTRUCT *lpPaint );
複製代碼
參數說明:
——————————————————————————————————
向系統指示線程已請求終止(退出)。一般用於響應WM_DESTROY消息。
語法:
void PostQuitMessage( int nExitCode );
複製代碼
參數說明:
——————————————————————————————————
調用默認窗口過程覺得應用程序未處理的任何窗口消息提供默認處理。此功能確保處理全部消息。DefWindowProc用窗口過程接收到的相同參數調用。
語法:
LRESULT LRESULT DefWindowProcA( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam );
複製代碼
參數說明:
——————————————————————————————————
所述的TextOut函數在指定位置寫入的字符串,利用當前選擇的字體,背景顏色和文本顏色。
語法:
BOOL TextOutW( HDC hdc, int x, int y, LPCWSTR lpString, int c );
複製代碼
參數說明:
——————————————————————————————————
引用文檔解釋:
HDC代碼中是設備上下文的句柄,這是 Windows 用於使應用程序與圖形子系統通訊的數據結構。
銷燬窗口時發送。從窗口中刪除窗口後,它將被髮送到銷燬窗口的窗口過程。 此消息首先發送到被銷燬的窗口,而後發送到被銷燬的子窗口(若是有)。在處理消息期間,能夠假定全部子窗口仍然存在。
WM_DESTROY 在 WndProc 函數中使用
——————————————————————————————————
當應用程序經過調用CreateWindowEx或CreateWindow函數請求建立窗口時發送。(在函數返回以前發送消息。)在建立窗口以後,但在該窗口變爲可見以前,新窗口的窗口過程會收到此消息。
——————————————————————————————————
以後註冊該窗口,使用 RegisterClassEx:
RegisterClassEx(&wcex);
複製代碼
註冊後使用 CreateWindow 進行註冊的窗口建立語法以下:
HWND CreateWindow( LPCTSTR lpClassName, LPCTSTR lpWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HANDLE hInstance, PVOID lpParam );
複製代碼
參數說明:
建立窗體:
HWND hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 1000, 1000, NULL, NULL, hInstance, NULL);
複製代碼
應用窗體名爲 szWindowClass:
static TCHAR szWindowClass[] = _T("win32 Demo");
複製代碼
應用窗體名爲 szTitle:
static TCHAR szTitle[] = _T("This Win32");
複製代碼
窗體風格類型爲:WS_OVERLAPPEDWINDOW 初始位置爲:CW_USEDEFAULT,默認左上角出現 尺寸爲:1000, 1000 父級及菜單欄都爲:NULL hInstance爲:當前實例 hInstance lpParam應用程序使用爲:NULL
代碼以下:
#include <windows.h>
#include <tchar.h>
static TCHAR szWindowClass[] = _T("CSDN @1_bit");
static TCHAR szTitle[] = _T("Win32 桌面應用程序");
HINSTANCE hInst;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
wcex.hCursor = LoadCursor(NULL, IDC_CROSS);
wcex.hbrBackground = (HBRUSH)(COLOR_ACTIVECAPTION);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(NULL, MAKEINTRESOURCE(IDI_INFORMATION));
RegisterClassEx(&wcex);
hInst = hInstance;
HWND hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 100, NULL, NULL, hInstance, NULL);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
PAINTSTRUCT ps;
HDC hdc;
TCHAR greeting[] = _T("Hello, 我是CSDN 1_bit 博客主頁:https://me.csdn.net/A757291228 ");
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
TextOut(hdc,
5, 5,
greeting, _tcslen(greeting));
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}
複製代碼
——————————————————————————————————
完成以上代碼後,還需使用 ShowWindow 讓Windows窗體指定如何顯示,代碼以下:
ShowWindow(hWnd, nCmdShow);
複製代碼
語法:
BOOL ShowWindow( HWND hWnd, int nCmdShow );
複製代碼
參數說明:
nCmdShow 參考:
——————————————————————————————————使用 UpdateWindow 發送 WM_PAINT 消息,更新指定窗口。 語法:
BOOL UpdateWindow( HWND hWnd );
複製代碼
參數:
總體代碼以下:
#include <windows.h>
#include <tchar.h>
static TCHAR szWindowClass[] = _T("CSDN @1_bit");
static TCHAR szTitle[] = _T("Win32 桌面應用程序");
HINSTANCE hInst;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
wcex.hCursor = LoadCursor(NULL, IDC_CROSS);
wcex.hbrBackground = (HBRUSH)(COLOR_ACTIVECAPTION);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(NULL, MAKEINTRESOURCE(IDI_INFORMATION));
RegisterClassEx(&wcex);
hInst = hInstance;
HWND hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 100, NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return 0;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
PAINTSTRUCT ps;
HDC hdc;
TCHAR greeting[] = _T("Hello, 我是CSDN 1_bit 博客主頁:https://me.csdn.net/A757291228 ");
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
TextOut(hdc,
5, 5,
greeting, _tcslen(greeting));
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}
複製代碼
運行程序,發現出現了一閃而過的窗口,這個很像剛學習C語言的時候,沒有加上中止;那咱們就循環偵聽 Windows 發送的消息便可:
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
複製代碼
——————————————————————————————————
GetMessage
從調用線程的消息隊列中檢索消息。該函數分派傳入的已發送消息,直到已發佈的消息可供檢索爲止。
語法:
BOOL GetMessage( LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax );
複製代碼
參數說明:
——————————————————————————————————
#include <windows.h>
#include <tchar.h>
static TCHAR szWindowClass[] = _T("CSDN @1_bit");
static TCHAR szTitle[] = _T("Win32 桌面應用程序");
HINSTANCE hInst;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
wcex.hCursor = LoadCursor(NULL, IDC_CROSS);
wcex.hbrBackground = (HBRUSH)(COLOR_ACTIVECAPTION);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(NULL, MAKEINTRESOURCE(IDI_INFORMATION));
RegisterClassEx(&wcex);
hInst = hInstance;
HWND hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 100, NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
PAINTSTRUCT ps;
HDC hdc;
TCHAR greeting[] = _T("Hello, 我是CSDN 1_bit 博客主頁:https://me.csdn.net/A757291228 ");
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
TextOut(hdc,
5, 5,
greeting, _tcslen(greeting));
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}
複製代碼
運行結果以下: