1. 程式人生 > >Windows API 程式設計起始——建立一個視窗

Windows API 程式設計起始——建立一個視窗

        最初瞭解Windows api程式設計呢,就是先創建出一個最簡潔的視窗,就如我們學習C/C++時的"Helloword"一樣,這是進入windows程式設計大門的重要一個步,下面就開始吧...

        大家都知道C/C++中,程式的執行是從main()函式開始的,main()是整個程式的入口函式,是不可或缺的。同樣,windows程式設計中,也是有入口函式的,不過這裡不是main,而是WinMain(),Win表示windows視窗,並且所建立的工程型別也是不同的,大家之前寫C/C++,建立的工程可能是win32控制檯應用程式,這裡呢,需要建立的是win32專案,如下:

         建立工程時,點選下一步,選擇空專案,如下圖選擇:

建立好工程之後呢,我們建立一個.c或者.cpp檔案就可以了

工程的建立過程,明確了之後呢,下面就先將所需要用到的步驟和Function給稍微列舉解釋下:

第一步:

       建立一個視窗類WNDCLASS 的物件wndclass,並且為wndclass進行初始化賦值操作,這一步非常重要,後面會詳細說下。

第二步:

      註冊視窗類:RegisterClass(WNDCLASS lpWndClass),通過判斷該函式的返回值是否為0,非0成功。

第三步:

       建立視窗:HWND CreateWindow( DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, DWORD dwStyle, int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam ),這個函式會創建出來一個視窗,但是呢,這裡創建出來的視窗,還處於不可見的狀態,只是在記憶體中已經創建出來了,接下來還需要顯示出來。

第四步:

       顯示視窗:ShowWindow(HWND hwnd, int iCmdShow);

第五步:

       更新視窗:UpdateWindow(HWND hwnd),傳送一些初始訊息,更新GDI等

第六步:

       每個視窗都有一個自己的視窗訊息佇列,裡面存放了需要處理的視窗訊息,接下來就是建立一個視窗的訊息迴圈,在視窗退出之前一直處於工作狀態,不斷的從訊息佇列中獲取訊息,獲取訊息的函式是:

 BOOL GetMessage( LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax );

該函式需要在while()中執行,如while(GetMessage(&msg, NULL, 0, 0)),這是最簡單的寫法,我們這裡就使用這個就可以了。

第七步:

       在GetMessage()獲取到訊息是虛擬鍵訊息,需要進行處理,呼叫TranslateMessage(MSG *lpMsg),這個函式的功能是將虛擬鍵訊息轉換成字元訊息通俗說就是翻譯訊息。

第八步:

      TranslateMessage()之後呢,需要對訊息進行派發,將每個訊息傳送到相應的需要到達的目標視窗或控制元件,派發函式:

LRESULT DispatchMessage(MSG *lpMsg);

至此呢,建立視窗的主要步驟已經完成了,但是我們還需要建立一個視窗的回撥函式,在初始化視窗類的時候,是需要有這個回撥函式的,這個回撥函式將被windows系統進行回撥。回撥函式的格式必須按照如下格式:

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

通常來說在建立視窗類的時候,就應該先把這個函式寫出來,好了,接下來,就上程式碼嘍

#include <windows.h>

//視窗回撥函式宣告
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

/*
    函式名:WinMain:入口函式
    引數:
         hInstance是windows傳遞的視窗控制代碼
         hPrevInstance是這個視窗的前一個視窗的控制代碼,目前沒有用,只是為了相容以前的版本 
         szCmdLine是傳遞進來的命令列命令,這裡沒有使用
         iCmdShow指定的視窗的顯示方式如:顯示,隱藏等。
*/
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
	static TCHAR szAppName[] = TEXT("HelloWin"); //建立視窗的時候需要一個視窗類名
	HWND hwnd;    //建立視窗函式CreateWindow()會返回一個HWND控制代碼,這裡定義下,用來接收這個控制代碼
	MSG msg;      //訊息結構體,在訊息迴圈的時候需要
	WNDCLASS wndclass; //建立視窗類物件


    //對視窗類的各屬性進行初始化
	wndclass.style = CS_HREDRAW | CS_VREDRAW; /*視窗類的風格,CS字首,C表示Class,S表示
                    Style,這裡使用了水平和垂直風格*/
	wndclass.lpfnWndProc = WndProc;  /*這裡將回到函式的名字賦值用以windows後面回撥*/
	wndclass.cbClsExtra = 0;  //附加引數,通常情況下為0
	wndclass.cbWndExtra = 0;  //附加引數,通常情況下為0
	wndclass.hInstance = hInstance;  //視窗控制代碼,這裡將WinMain中的hInstance控制代碼賦值就可
	wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); /*視窗圖示,LoadIcon()是載入圖示,這裡是載入一個系統資源圖示,LoadIcon()的原型是HICON LoadIcon(HINSTANCE, LPCSTR);*/
	wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);  /*載入滑鼠,同上相似*/
	wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);  /*視窗畫刷,這裡是使用的白色畫刷,所以創建出來的視窗的背景顏色則是白色的*/
	wndclass.lpszMenuName = NULL;  //視窗選單名稱,這裡沒有選單,設為NULL
	wndclass.lpszClassName = szAppName;  //視窗類名稱,這個視窗類名稱可作為這個視窗的唯一標識

    /*註冊視窗類*/
	if (!RegisterClass(&wndclass))
	{
        //註冊視窗類失敗時,彈出提示
		MessageBox(NULL, TEXT("This program requires Window NT!"), szAppName, MB_ICONERROR);
		return 0;
	}

    /*建立視窗 
      HWND CreateWindow(
        LPCTSTR lpClassName,  //視窗類名
        LPCTSTR lpWindowName, //視窗標題
        DWORD dwStyle,        //視窗風格,WS開頭
        int x,                //視窗左上角x座標
        int y,                //視窗左上角y座標
        int nWidth,           //視窗寬度
        int nHeight,          //視窗高度
        HWND hWndParent,      //父視窗控制代碼
        HMENU hMenu,          //選單控制代碼
        HANDLE hlnstance,     //視窗控制代碼
        LPVOID lpParam);      //改值會傳遞給視窗WM_CREATE訊息的一個引數
    */    
	hwnd = CreateWindow(szAppName,    //視窗類名
		TEXT("The Hello Program"),    //視窗標題,會在視窗的左上角標題欄顯示
		WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL, //視窗風格
		CW_USEDEFAULT,  //視窗左上角x位置,這裡使用的系統預設值,可自定義
		CW_USEDEFAULT,  //視窗左上角y位置
		CW_USEDEFAULT,  //視窗的寬度
		CW_USEDEFAULT,  //視窗的高度
		NULL, //該視窗的父視窗或所有者視窗的控制代碼,這裡用不到,設為NULL
		NULL, //視窗選單控制代碼,這裡沒有選單,設定為NULL
		hInstance, //視窗控制代碼
		NULL  //傳遞給視窗WM_CREATE訊息的一個引數,這裡不用,設定為NULL
	);

    /*顯示視窗,顯示方式使用WinMain的引數*/
	ShowWindow(hwnd, iCmdShow);
    /*更新視窗*/
	UpdateWindow(hwnd);

    /*訊息迴圈,獲取訊息*/
	while (GetMessage(&msg, hwnd, NULL, 0))
	{
        //翻譯訊息
		TranslateMessage(&msg);
        //派發訊息
		DispatchMessage(&msg);
	}
    //返回訊息的wParam引數給系統
	return msg.wParam;
}


/*視窗回撥函式*/
LRESULT CALLBACK WndProc(HWND hwnd, UINT message/*視窗訊息*/, WPARAM wParam, LPARAM lParam)
{
    //處理訊息
	switch (message)
	{
	case WM_CREATE:
	    /*視窗在建立時,會接收到該訊息,通常在這裡進行初始化操作*/	
		return 0;
	case WM_SIZE:
	    /*視窗被改變大小時,會接收到該訊息,在視窗被建立時也會收到一次*/
		return 0;
	case WM_PAINT:
		/*視窗有繪圖操作更新時,會收到這個訊息*/
		return 0;
	case WM_DESTROY:
        /*關不視窗時,會收到該訊息,PostQuitMessage()像系統表明終止當前執行緒,沒有這個函式的話,視窗不會關閉*/
		PostQuitMessage(0);
		return 0;
	}
    //將不需要處理的訊息傳遞給系統作預設處理
	return DefWindowProc(hwnd, message, wParam, lParam);
}

通過以上程式碼就建立了一個簡單的視窗

視窗類結構設定了視窗的各項屬性,然後將初始化好的視窗類結構註冊到系統中,讓系統知道,我這裡將要建立一個視窗,並且視窗屬性是什麼。

回撥函式是硬性要求的,是必須的,系統會呼叫這個函式,而我們在則這個函式中作需要的操作

關於什麼是回撥函式,如果不太清楚的話,請看下面的連線瞭解下:

https://baike.baidu.com/item/%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0/7545973?fr=aladdin

好了,建立一個視窗就這樣完成了,如果有錯誤或不對的地方,希望大家指正,謝謝。