天天看點

WINDOWS程式設計基礎-最簡單的windows程式

流程

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;
}      

繼續閱讀