C++系列 --- Windows消息驅動原理分析

一、消息驅動

創建窗口後,要對窗口的行爲負責。操作系統不斷的嚮應用程序發送消息,通知它發生了什麼事情。

當Widnows向程序發送消息時,它調用程序中的一個函數,這個函數的參數精確地描述了Windows發送的消息。

在程序中稱其爲窗口函數或消息處理函數。它是一個自定義的回調函數。原型如下:

LRESULT CALLBACK WindowProc(HWND hwnd,UINT hMsg,WPARAM wParam,LPARAM lParam);

 

二、顯示一個窗口的具體步驟

1、註冊窗口類RegisterClassEx

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
	LPSTR lpCmdLine, int nCmdShow) 
{
    char szClassName[] = "MainWClass";
    WNDCLASSEX wndclass;

    wndclass.cbSize = sizeof(wndclass);
    wndclass.style = CS_HREDRAW | CS_VREDRAW;
    wndclass.lpfnWndProc = MainWndProc;
    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hInstance = hInstance;
    wndclass.hIcon = ::LoadIcon(NULL, IDI_APPLICATION);
    wndclass.hCursor = ::LoadCursor(NULL, IDC_ARROW);
    wndclass.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH);
    wndclass.lpszMenuName = NULL;
    wndclass.lpszClassName = szClassName;
    wndclass.hIconSm = NULL;

    ::RegisterClassEx(&wndclass);
    
    ......
}

2、創建窗口CreateWindowEx

//創建主窗口
HWND hWnd = ::CreateWindowEx(0,
	szClassName,//類名
	"我的第一個GUI程序",
	WS_OVERLAPPEDWINDOW,
	CW_USEDEFAULT,
	CW_USEDEFAULT,
	CW_USEDEFAULT,
	CW_USEDEFAULT,
	NULL,
	NULL,
	hInstance,
	NULL
);
if (NULL == hWnd) {
	::MessageBox(NULL, "創建窗口失敗", "錯誤", MB_OK);
	return -1;
}

3、在桌面顯示窗口ShowWindow

//顯示窗口
::ShowWindow(hWnd, nCmdShow);

4、更新窗口客戶區UpdateWindow

::UpdateWindow(hWnd);

5、進入消息獲取和處理的循環。

首先是獲取消息GetMessage,如果有消息到達,則將消息分派到回調函數處理DispatchMessage,如果是WM_QUIT,則GetMessage返回FALSE,則整個消息循環結束。消息的具體處理過程在MainWndProc函數中進行。

//從操作系統的消息隊列中不斷的撿取消息
MSG msg;
while (::GetMessage(&msg, NULL, 0, 0)) 
{
        //轉化鍵盤消息 
	::TranslateMessage(&msg);

        // 將消息發送到相應的窗口函數
	::DispatchMessage(&msg);
}

// 當GetMessage返回0時,程序結束
return msg.wParam;

6、回調函數

LRESULT CALLBACK MainWndProc(HWND hWnd, UINT message, WPARAM wparam, LPARAM lparam)
{
	switch (message) 
        {
	case WM_DESTROY: // 正在銷燬窗口

        // 向消息隊列投遞一個WM_QUIT消息,促使GetMessage函數返回0,結束消息循環
		::PostQuitMessage(0);
		return 0;
	}

    // 將我們不處理的消息交給操作系統默認處理。
	return ::DefWindowProc(hWnd, message, wparam, lparam);

}

 三、實例

1、實例

#include <stdio.h>
#include <windows.h>
LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
	LPSTR lpCmdLine, int nCmdShow) {
	char szClassName[] = "MainWClass";
	WNDCLASSEX wndclass;

	wndclass.cbSize = sizeof(wndclass);
	wndclass.style = CS_HREDRAW | CS_VREDRAW;
	wndclass.lpfnWndProc = MainWndProc;
	wndclass.cbClsExtra = 0;
	wndclass.cbWndExtra = 0;
	wndclass.hInstance = hInstance;
	wndclass.hIcon = ::LoadIcon(NULL, IDI_APPLICATION);
	wndclass.hCursor = ::LoadCursor(NULL, IDC_ARROW);
	wndclass.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH);
	wndclass.lpszMenuName = NULL;
	wndclass.lpszClassName = szClassName;
	wndclass.hIconSm = NULL;

	::RegisterClassEx(&wndclass);

	//創建主窗口
	HWND hWnd = ::CreateWindowEx(0,
		szClassName,//類名
		"我的第一個GUI程序",
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		NULL,
		NULL,
		hInstance,
		NULL
	);
	if (NULL == hWnd) {
		::MessageBox(NULL, "創建窗口失敗", "錯誤", MB_OK);
		return -1;
	}

	//顯示窗口
	::ShowWindow(hWnd, nCmdShow);
	::UpdateWindow(hWnd);

	//從操作系統的消息隊列中不斷的撿取消息
	MSG msg;
	while (::GetMessage(&msg, NULL, 0, 0)) {
		::TranslateMessage(&msg);
		::DispatchMessage(&msg);
	}
	return msg.wParam;
}

LRESULT CALLBACK MainWndProc(HWND hWnd, UINT message, WPARAM wparam, LPARAM lparam) {
	switch (message) {
	case WM_DESTROY:
		::PostQuitMessage(0);
		return 0;
	}
	return ::DefWindowProc(hWnd, message, wparam, lparam);

}

2、運行結果

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章