筆記1——Win32基本程序觀念

1.Windows SDK程序開發流程

主要分爲程序代碼和UI資源兩部分。
 
2.以消息未基礎,以事件驅動

    程序不斷的等待外圍的輸入,判斷在處理。操作系統通過捕捉外圍輸入,以消息的形式進入程序中,程序通過獲取的不同消息進行不同的處理。USER模塊掌管外圍的驅動程序。
    程序通過一個循環來獲取消息。
MSG msg;
while (GetMessage(&msg, NULL, NULL, NULL)) {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}
其中MSG是一個結構體如下:
typedef struct tagMSG
{
    HWND hwnd;
    UINT message; // WM_xxx ,例如WM_MOUSEMOVE ,WM_SIZE...
    WPARAM wParam;
    LPARAM lParam;
    DWORD time;
    POINT pt;
} MSG;
    獲取消息後必須將獲取的消息進行處理,這個過程就需要一個窗口處理函數函數,形式如下:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
    case WM_CREATE:
        //....
        break;
    case WM_CLOSE:
        //....
        break;
    case WM_DESTROY:
        //....
        break;
    //...
    default:
        return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}
整個過程如下圖:
 
 
3.Windows程序
  • 程序入口點
main  是一般C程序的進入點:
    int main(int argc, char *argv[]);
{
    ...
}
WinMain  則是Windows程序的進入點:
    int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpCmdLine, int nCmdShow)
{
    ...
}
// 在Win32 中CALLBACK被定義爲__stdcall,是一種函數調用習慣,關係到
// 參數壓入到堆棧的次序,以及處理堆棧的責任歸屬。其它的函數調用習慣還有
// _pascal  和_cdecl
  • 消息循環
        初始化後程序進入消息循環:
        
while (GetMessage(&msg,...)) {
    TranslateMessage(&msg); //  轉換鍵盤消息
    DispatchMessage(&msg); //  分派消息
}
    其中TranslateMessage是爲了將鍵盤消息轉化,DispatchMessage將消息傳給窗口函數去處理,當消息發生之時,OS已根據當時狀態,爲他表明了所屬窗口。而窗口窗口類又已經標明瞭窗口函數(也就是wc. lpfnWndProc所指定的函數),所以DispatchMessage可以將消息發送給窗口處理。
  • 窗口函數
         消息循環中的DispatchMessage通過USER,模塊將消息送到窗口函數,窗口函數通過Switch/case來判斷消息種類,由於窗口函數是右系統所調用,所以這就是一種回調函數,用於Windows系統調用,還不會由我們調用。
        整個流程是消息經過輸入,再經由消息循環的抓取,再傳輸給窗口進而給窗口函數,
LRESULT CALLBACK WndProc(HWND hWnd,
    UINT message,
    WPARAM wParam,
    LPARAM lParam)
        所有消息都要經過處理,所以Switch/case中的default必須調用DefWindwosProc,這個是windows內部預設的消息處理函數。
  • 消息映射(Message Map)的雛形
         首先,定義一個MSGMAP_ENTRY   結構和一個di m   宏:
struct MSGMAP_ENTRY {
    UINT nMessage;
    LONG (*pfn)(HWND, UINT, WPARAM, LPARAM);
};
#define dim(x) (sizeof(x) / sizeof(x[0]))
        其中pfn是一個函數指針,用出指針處理nMessgae消息,接下來定義兩個數組_messageEntries[]和_commandEntries[],將消息和處理方法關聯起來:
// 消息與處理方法之對照
struct MSGMAP_ENTRY _messageEntries[] =
{
    WM_CREATE, OnCreate,
    WM_PAINT, OnPaint,
    WM_SIZE, OnSize,
    WM_COMMAND, OnCommand,
    WM_SETFOCUS, OnSetFocus,
    WM_CLOSE, OnClose,
    WM_DESTROY, OnDestroy,
} ;
//  Command-ID 與處理方法對照
struct MSGMAP_ENTRY _commandEntries =
{
    IDM_ABOUT,      OnAbout,
    IDM_FILEOPEN,   OnFileOpen,
    IDM_SAVEAS,     OnSaveAs,
} ;  
        窗口函數的設計如下:
//----------------------------------------------------------------------
//窗口函數
//----------------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND  hWnd,     UINT  message,
                            WPARAM wParam, LPARAM lParam)
{
    int i;
    for(i=0; i < dim(_messageEntries); i++) {  // 消息對照表
        if (message ==  _messageEntries[i].nMessage)
            return((*_messageEntries[i].pfn)(hWnd,  message, wParam,  lParam));
    }
    return(DefWindowProc(hWnd, message, wParam, lParam));
}
//----------------------------------------------------------------------
// OnCommand --  專門處理WM_COMMAND
//----------------------------------------------------------------------
LONG OnCommand(HWND hWnd, UINT message,
                WPARAM  wParam, LPARAM lParam)
{
    int i;
    for(i=0; i < dim(_commandEntries); i++) {  // 命令對照表
        if (LOWORD(wParam) ==  _commandEntries[i].nMessage)
            return((*_commandEntries[i].pfn)(hWnd, message, wParam, lParam));
    }
    return(DefWindowProc(hWnd, message, wParam, lParam));
}
//----------------------------------------------------------------------
LONG OnCreate(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
{
    ...
}
//----------------------------------------------------------------------
LONG OnAbout(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
{
    ...
}
//----------------------------------------------------------------------
       這樣一來WndProc和OnComand就不用改變了,每有新要處理的消息,只要添加到_messageEntries[]和_commandEntries[]兩個數組中就行了。
  • 對話框的運作
       對話框有兩種:
  1. 模態對話框:當子對話框運行的時候父窗口不能使用
  2. 無模對話框:子對話框和父窗口共同運行
      一張圖說明問題:


4.Windows程序生命週期

  1. 在初始化過程中調用CreateWindow創建窗口,同時CreateWindow發送WM_CREATE消息,用於初始化動作。
  2. 在程序運行過程中不斷的使用GetMessage獲取存儲的消息,如果獲取的消息是WM_QUIT,GetMessage就返回0同時While循環就結束,從而就結束運行。
  3. DispatchMessage通過USER模塊將消息發送到窗口函數。
  4. 不斷重複2和3。
  5. 當點擊關閉按鈕時,窗口發送WM_CLOSE消息,這個消息一般是DefWindwosProc進行處理。
  6. 當DefWindwosProc收到WM_CLOSE後嗲偶哦那個DestoryWindow把窗口清理,DestoryWindow本身會發送WM_DESTORY消息。
  7. 窗口函數對WM_DESTORY消息進行處理,通過調用PostQuitMessage處理。
  8. 通過PostQuitMessage發送WM_QUIT消息,讓GetMessage獲取消息讓2處理。

5.空閒時間處理

      當消息隊列中沒有消息的時候,就存在空閒時間,獲取這個時間可以通過如下代碼:
while (TRUE) {
    if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE) {
        if (msg.message ==  WM_QUIT)
            break;
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    else {
        OnIdle ();
    }
}
PeekMessage   返回   TRUE   的條件是有消息,如果沒有消息返回   FALSE   
GetMessage   返回   TRUE   的條件是有消息且該消息不爲WM_QUIT返回 ,  FALSE  的條件是有消息且該消息  爲   WM_QUIT 
       相同點:

            PeekMessage函數與GetMessage函數都用於查看應用程序消息隊列,有消息時將隊列中的消息派發出去。

       不同點:
            無論應用程序消息隊列是否有消息,PeekMessage函數都立即返回,程序得以繼續執行後面的語句(無消息則執行其它指令,有消息時一般要將消息派發出去,再執行其它指令)。GetMessage函數只有在消息對立中有消息時返回,隊列中無消息就會一直等,直至下一個消息出現時才返回。在等的這段時間,應用程序不能執行任何指令。


6.進程與線程

        進程:執行中的程序。
        線程:在一個程序內部也可以實現多個任務併發執行,其中每個任務稱爲線程,線程是比進程更小的執行單位,它是在一個進程中獨立的控制流,即程序內部的控制流。
  •  內核對象
          內核對象是系統的一種資源,內核對象一經創建,任何應用程序都可以使用。系統通過一個使用計數來管理內核對象,常用的內核對象如下:
內核對象 產生方法
event CreateEvent
mutex CreateMutex
semaphore CreateSemaphore
file CreateFile
file-mapping CreateFileMapping
process CreateProcess
thread CreateThread
         內核對象產生方式不同,但是都會獲得一個handle句柄作爲識別,每被使用一次,使用計數加1,其結束的時候都是調用CloseHandle。其中process對象是一個數據結構,系統通過它來管理進程。
  • 進程的生命週期
          執行一個程序,就會產生一個進程,最直接的就是通過windows的shell執行一個App.exe應用程序,當雙擊就可運行.流程如下:

  • 創建子進程
           通過CreateProcess創建進程:
BOOL WINAPI
CreateProcessW(
    __in_opt    LPCWSTR lpApplicationName,
    __inout_opt LPWSTR lpCommandLine,
    __in_opt    LPSECURITY_ATTRIBUTES lpProcessAttributes,
    __in_opt    LPSECURITY_ATTRIBUTES lpThreadAttributes,
    __in        BOOL bInheritHandles,
    __in        DWORD dwCreationFlags,
    __in_opt    LPVOID lpEnvironment,
    __in_opt    LPCWSTR lpCurrentDirectory,
    __in        LPSTARTUPINFOW lpStartupInfo,
    __out       LPPROCESS_INFORMATION lpProcessInformation
    );



<待續>

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