流程
1 建立并注冊windows類
2 使用windows類建立視窗
3 實作事件處理,主循環
PeekMessage與GetMessage的對比
相同點:
PeekMessage函數與GetMessage函數都用于檢視應用程式消息隊列,有消息時将隊列中的消息派發出去。
不同點:
無論應用程式消息隊列是否有消息,PeekMessage函數都立即傳回,程式得以繼續執行後面的語句(無消息則執行其它指令,有消息時一般要将消息派發出去,再執行其它指令)。
GetMessage函數隻有在消息對立中有消息時傳回,隊列中無消息就會一直等,直至下一個消息出現時才傳回。在等的這段時間,應用程式不能執行任何指令。
遊戲時一般使用PeekMessage不阻塞,主循環裡除了事件外還要處理繪制邏輯等。
TranslateMessage
将虛拟鍵消息轉換為字元消息。字元消息被送到調用線程的消息隊列中,在下一次線程調用函數GetMessage或PeekMessage時被讀出将虛拟鍵
消息轉換為字元消息。字元消息被送到調用線程的消息隊列中,在下一次線程調用函數GetMessage或PeekMessage時被讀出
DispatchMessage
該函數排程一個消息給視窗程式。通常排程從GetMessage取得的消息。消息被排程到的視窗程式即是MainProc()函數
4 實作事件回調處理WinProc
代碼
#include "stdafx.h"
#include "Win_Base.h"
HINSTANCE hInst; //目前應用的執行個體句柄
HWND hWnd; //視窗句柄
bool exiting = false; //循環開啟标志
bool fullscreen=FALSE; //全屏标志
long windowWidth = 800; //預設視窗寬
long windowHeight = 600;//預設視窗高
long windowBits = 32; //每像素所選的色彩深度
ATOM RegisterWinClass(HINSTANCE hInstance);
BOOL CreateWin(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
//step1 建立并,注冊windows class
RegisterWinClass(hInstance);
//step2 建立(全屏或者非全屏)視窗
if (!CreateWin(hInstance, nCmdShow))
{
return FALSE;
}
//step3 主循環事件處理
while (!exiting)
{
while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
{
if (!GetMessage (&msg, NULL, 0, 0))
{
exiting = true;
break;
}
TranslateMessage (&msg);
DispatchMessage (&msg);
}
}
if (fullscreen)
{
ChangeDisplaySettings(NULL,0); // If So Switch Back To The Desktop
ShowCursor(TRUE); // Show Mouse Pointer
}
return (int) msg.wParam;
}
//建立并,注冊windows class
ATOM RegisterWinClass(HINSTANCE hInstance)
{
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(NULL, IDI_APPLICATION);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = "BaseClass";
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
//建立(全屏或者非全屏)視窗
BOOL CreateWin(HINSTANCE hInstance, int nCmdShow)
{
//設定全屏,建立視窗都要用到
DWORD dwExStyle; //擴充視窗風格
DWORD dwStyle; //視窗風格
RECT windowRect; //取得矩形的左上角和右下角的坐标值
windowRect.left=(long)0;
windowRect.right=(long)windowWidth;
windowRect.top=(long)0;
windowRect.bottom=(long)windowHeight;
hInst = hInstance; //使用全局變量存儲應用執行個體(win32工程預設在這個位置指派)
//設定全屏狀态開始-------------------------------------------------------------
if (fullscreen)
{
DEVMODE dmScreenSettings; //裝置模式
memset(&dmScreenSettings,0,sizeof(dmScreenSettings)); //情況記憶體
dmScreenSettings.dmSize = sizeof(dmScreenSettings); //DEVMODE結構size
dmScreenSettings.dmPelsWidth = windowWidth; //螢幕寬
dmScreenSettings.dmPelsHeight = windowHeight; //螢幕高
dmScreenSettings.dmBitsPerPel = windowBits; //每像素所選的色彩深度
dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
//嘗試設定顯示模式并傳回結果。注: CDS_FULLSCREEN 移去了狀态條。
if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
{
MessageBox(NULL, "Display mode failed", NULL, MB_OK);
fullscreen = FALSE;
}
}
//由于全屏模式可能失敗,使用者可能決定在視窗下運作,我們需要在設定螢幕/視窗之前,再次檢查fullscreen的值是TRUE或FALSE。
//如果我們仍處于全屏模式,設定擴充窗體風格為WS_EX_APPWINDOW,這将強制我們的窗體可見時處于最前面。再将窗體的風格設為WS_POPUP。這個類型的窗體沒有邊框,使我們的全屏模式得以完美顯示。
//最後我們禁用滑鼠指針。當您的程式不是互動式的時候,在全屏模式下禁用滑鼠指針通常是個好主意。
//如果我們使用視窗而不是全屏模式,我們在擴充窗體風格中增加了 WS_EX_WINDOWEDGE,增強窗體的3D感觀。
//窗體風格改用 WS_OVERLAPPEDWINDOW,建立一個帶标題欄、可變大小的邊框、菜單和最大化/最小化按鈕的窗體。
if (fullscreen)
{
dwExStyle=WS_EX_APPWINDOW;
dwStyle=WS_POPUP;
ShowCursor(FALSE);
}
else
{
dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; // Window Extended Style
dwStyle=WS_OVERLAPPEDWINDOW; // Windows Style
}
AdjustWindowRectEx(&windowRect, dwStyle, FALSE, dwExStyle);//調整視窗達到真正要求的大小
//設定全屏狀态結束-------------------------------------------------------------
//建立視窗開始---------------------------------------------------------------------
hWnd = CreateWindowEx(
NULL, // 擴充窗體風格
"BaseClass", // 類名字
"Title", // 視窗标題
dwStyle | // 選擇的窗體屬性
WS_CLIPCHILDREN | // 必須的窗體風格屬性
WS_CLIPSIBLINGS, // 必須的窗體風格屬性
0, 0, // 視窗位置
windowRect.right - windowRect.left, // 計算調整好的視窗寬度
windowRect.bottom - windowRect.top, // 計算調整好的視窗高度
NULL, // 無父視窗
NULL, // 無菜單
hInstance, // 執行個體
NULL); // 不向WM_CREATE傳遞任何參數
if (!hWnd)
{
MessageBox(NULL,"Window Creation Error.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}
//建立視窗結束---------------------------------------------------------------------
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
//繪制代碼
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}