Windows應用程式基礎

林堯彬發表於2020-04-04

關於Windows應用程式的基礎,基本內容就是那幾項,以前學MFC的時候看孫鑫的視訊講過一遍,學習DirectX的時候學過一遍。現在回來想做MFC的程式,發現又忘了,這種學了忘忘了學的感覺真煩惱,每次都要從頭學起,每次都是新手。所以我決定一定要自己寫個總結,可能還是會忘記,但是檢視自己的總結感覺踏實一些。

一. WinMain函式

Windows程式的入口函式:

int WINAPI WinMain(

    HINSTANCE hInstance, // handle to current instance
    // 應用程式例項的控制程式碼。同一程式程式碼也有可能有多個例項,因為應用程式例項也是一種資源,所以需要對應用程式例項進行標識。

    HINSTANCE hPrevInstance, // handle to previous instance
    // 先前例項的標識,之前沒有則為空。Win32下總是為空。

    LPSTR lpCmdLine, // command line
    //LP表示長指標,STR表示字串,所以LPSTR表示指向字串的指標。lpCmdLine接受命令列引數。

    int nCmdShow // show state
    // 顯示狀態,指定程式執行的時候應該如何顯示
);

 

WinMain函式由作業系統呼叫,因此WinMain函式的引數都是由作業系統進行賦值。

二.視窗

視窗一般需要進行以下幾個步驟:

1.設計視窗

2.註冊視窗

3.建立視窗

4.顯示及更新視窗

視窗類是一個結構體

typedef struct WNDCLASSEX
 { 
    UINT style; 
    WNDPROC lpfnWndProc; 
    int cbClsExtra; 
    int cbWndExtra; 
    HANDLE hInstance; 
    HICON hIcon; 
    HCURSOR hCursor; 
    HBRUSH hbrBackground; 
    LPCTSTR lpszMenuName; 
    LPCTSTR lpszClassName;
 } WNDCLASS;

1.設計視窗

設計視窗類。

WNDCLASSEX wc;

//視窗類的型別
wc.style = CS_HREDRAW | CS_VREDRAW; //水平或垂直位置變化的時候要求視窗重畫

//視窗過程函式,一個指標,指向一個視窗過程,用來接收一個函式指標,用來指定視窗對應的過程函式/回撥函式
wc.lpfnWndProc = (WNDPROC) WndProc; //函式名可以代表程式碼的首地址

//類的附加記憶體
wc.cbClsExtra = 0; //通常情況下設定為0

//視窗的附加記憶體空間
wc.cbWndExtra = 0;

wc.cbSize = sizeof(WNDCLASSEX);

//應用程式例項號,來自WinMain函式引數
wc.hInstance = hInstance;

//圖示控制程式碼
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
//標準圖示被載入的時候第一個引數必須為NULL

//如果要自定義的圖示的話
//wc.hIcon = LoadIcon(hInstance, //(LPCTSTR)IDI_DIRECTX_ICON);

//游標控制程式碼
wc.hCursor = LoadCursor(NULL, IDC_ARROW);

//畫刷的控制程式碼
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);

//選單的名字
wc.lpszMenuName = 0;

//視窗類的名字
wc.lpszClassName = "Class Name";

2.註冊視窗

視窗設計完之後,需要向作業系統進行註冊,之後才可以建立基於這種視窗型別的視窗。

//函式原型:
//ATOM RegisterClass (CONST WNDCLASS* lpWndClass) ;

//向作業系統註冊視窗
RegisterClassEx(&wc) ) //傳入視窗類結構體的地址
//函式的返回值為布林值,註冊成功則返回真

3.建立視窗

註冊完成之後,就可以建立視窗類例項了。首先需要定義一個控制程式碼,作為一個標識,儲存下來。

HWND CreateWindow(

    LPCTSTR lpszClassName,    //視窗類名

    LPCTSTR lpszTitle,    //視窗標題名

    DWORD dwStyle,    //建立視窗的樣式

    int x,y,    //視窗左上角座標

    int nWidth,nHeight,    //視窗寬度和高度

    HWND hwndParent,//該視窗的父視窗控制程式碼

    HWENU hMenu,    //視窗主選單控制程式碼

    HINSTANCE hInstance,    //建立視窗的應用程式當前控制程式碼

    LPVOID lpParam    //指向一個傳遞給視窗的引數值的指標
);

//建立視窗

HWND hwnd = 0; //控制程式碼,用以儲存新建立的視窗的標識

hwnd = CreateWindow(
    " Class Name ", //註冊的類名,設計視窗的時候指定的名字
    "視窗標題", 
    WS_OVERLAPPEDWINDOW,//層疊的視窗,具有標題欄和邊框
    0, 0, width, height,
    0 /*parent hwnd*/, 
    0 /* menu */, 
    hInstance, 
    0 /*extra*/); 

//第一個引數是註冊的類名,一定要用註冊之後的視窗類名

//第二個引數是視窗的名字,即視窗標題名

//第三個引數是視窗的型別

//之後的四個參數列示視窗的左上角水平座標、垂直座標、寬度、高度

//之後是一個視窗的控制程式碼HWND,父視窗控制程式碼,沒有父視窗可設定為NULL

//之後是選單控制程式碼

//之後是當前應用程式例項的控制程式碼,WinMain形參之一

//之後是一個資料指標,多文件時用,主要作為WM_CREATE訊息的附加引數

4.顯示及更新視窗

//顯示視窗
ShowWindow(hwnd, SW_SHOW);//視窗控制程式碼及顯示狀態

//更新視窗,重新整理一次視窗,可有可無
UpdateWindow(hwnd);

三.訊息及訊息迴圈

1.訊息

作業系統將每個事件(輸入裝置上的變化)都包裝成一個稱為訊息的結構體MSG來傳遞給應用程式,然後由應用程式來決定對此事件做出何種響應,應用程式通過呼叫函式的形式來通知作業系統執行相應的功能。應用程式對這些函式的呼叫就叫做系統呼叫,這些函式的集合就是Windows作業系統提供給應用程式程式設計的介面(Application Programming Interface),簡稱Windows API。

訊息結構體:

typedef struct tagMSG
{ 
    HWND hwnd;     //接受訊息的視窗的控制程式碼;
            //控制程式碼是資源的標識,視窗控制程式碼的型別是HWND
    UINT message;     //訊息識別符號,表示具體的訊息資訊;
    WPARAM wParam; //32位的附加訊息引數。根據訊息的不同而不同。
    LPARAM lParam;     //32位的附加訊息引數,其值與訊息有關;
    DWORD time;     //雙16位,即32位的整數,訊息放入訊息佇列的時間
    POINT pt;     //訊息放入訊息佇列時滑鼠的座標

} MSG, *PMSG;

UINT是一個無符號整數,因為數值一般不好記憶,所以微軟定義了一些巨集來幫助記憶,巨集以WM作為開頭(Window Message),如WM_LBUTTONDOWN,WM_CHAR等。

當按下鍵盤之後,無論按下哪個鍵,收到的都是WM_CHAR訊息,並不知道按下的是哪個字母,可以通過wParam獲取到相對應的字母的ASCII碼。

2.訊息迴圈

訊息佇列是一個先進先出的緩衝區,作業系統為每一個應用程式都會建立一個訊息佇列,應用程式從訊息佇列中取出訊息,進行相應的相應。

訊息迴圈的常見寫法如下:

MSG msg;

while(GetMessage(&msg,NULL,0,0))

{
    TranslateMessage (&msg);

    DispatchMessage (&msg);
}

GetMessage從訊息佇列中獲取訊息。檢索到WM_QUIT訊息時返回零值。

GetMessage(

    lpMSG,//指向MSGMSG結構的指標

    hwnd, //視窗控制程式碼

    nMsgFilteMin, //用於訊息過濾的最小訊息號值

    nMsgFilterMax//用於訊息過濾的最大訊息號值

);

TranslateMessage轉換訊息。比如將鍵盤的WM_KEYDOWN和WM_KEYUP訊息轉換成WM_CHAR訊息,放在訊息佇列當中。

DispatchMessage將收到的訊息傳到視窗的回撥函式(視窗過程函式)中。

3.視窗過程函式(回撥函式)

視窗過程函式用來處理和響應訊息。

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

函式名可以更改,但是引數的型別不能變,引數名可以隨便取。

接收一個訊息,DispatchMessage呼叫的時候,作業系統呼叫這個視窗過程函式,並且將相關的引數傳遞給這個函式。直到視窗過程函式將控制返回給Windows作業系統,DispatchMessage才能返回。

函式內部一般用Switch case語句判斷具體是什麼訊息,然後採取相應的措施。

一個回撥函式的例子如下:

//
// WndProc
//
//視窗過程函式,回撥函式
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 //視窗控制程式碼、訊息標識、訊息的附加引數
{
    //LRESULT是個Long型,返回的結果碼

    switch( msg )
    {

        case WM_DESTROY: 
    //在訊息處理程式段中一般都有對//WM_DESTROY的處理,該訊息是關閉視窗時發出的
            PostQuitMessage(0);
            break;

        case WM_KEYDOWN:
            if( wParam == VK_ESCAPE )
            DestroyWindow(hwnd);
            break;
        default:
        //提供預設處理,讓系統對不感興趣的訊息進行一些預設處理 
            return DefWindowProc(hwnd, msg, wParam, lParam);

    //按鍵: WM_CHAR 
    //滑鼠左鍵: WM_LBUTTONDOWN
    //視窗重繪: WM_PAINT
    //關閉: WM_CLOSE
    //DestroyWindow函式銷燬視窗,併傳送以下訊息
    //WM_DESTROY 然後PostQuitMessage(0) 退出程式,傳送WM_QUIT訊息,訊息迴圈返回值,結束訊息迴圈,退出WinMain函式
    }
  return 0; 
}

轉載於:https://www.cnblogs.com/mengdd/archive/2012/08/09/2630863.html

相關文章