編寫一個完整的Win32 控臺應用程序,首先應該掌握的是Windows程序運行的機理,只有清楚Windows程序運行的內層機理,才能真正明白編寫一個Windows時程每一步的具體意義。
簡言之,Windows應用程序是建立在操作系統之上的用戶接口,而操作系統又承擔着應用程序和機器的交互作用。用戶對應用程序實現控制,需要的是嚮應用程序發送一系列指令,即消息。所謂消息,目前只需簡單理解爲用戶通過鼠標、鍵盤等IO設備傳到計算機內的各種信號,操作系統將這些信號包裝成消息後依次存放到消息隊列中。當程序啓動之後,操作系統負責不斷的捕獲消息,包裝消息,消息入隊,從隊列提取消息,然後將得到的消息分配給該應用程序。
應用程序爲了能處理,操作系統交給他的消息,也就是完成從操作系統給他的任務,必須對收到的消息給出正確的響應。而這個消息響應的具體過程就是程序員編寫的窗口過程函數。
我們知道之前編寫一個簡單控臺應用函數時,函數中必須有且僅有一個main()函數作爲整個程序的入口,然後才能保證程序的執行。同樣的Windows控臺應用程序,也有自己入口函數WinMain()。
重點一:WinMain:
函數定義:
int WINAPI WinMain(
HINSTANCE hInstance, //handle to current instance
HINSTANCEhPrevInstance, // handle toprevious instance
LPSTR lpCmdLine, //command line
int nCmdShow // show state
);
筆記1、HINSTANCE hInstance:當前應用程序實例句柄,指向當前應用程序。
筆記2、句柄:功能類似C語言指針,某些實例對象的索引,句柄本身只是系統某種資源的一個代號。系統爲了管理內核對象保留着一個資源表,句柄就存放在這個資源表中,句柄只是作爲某個資源的ID。通過這個ID號,既可以找到對應的資源,可見依靠的不是物理地址,而是邏輯映射間接訪問。因此和指針不同。
筆記3、HINSTANCE hPrevInstance:先前實例句柄,默認爲空。
筆記4、LPSTR lpCmdLine:用於允許用戶通過命令行啓動你程序。類似於console程序中的int argc, char *argv[];
筆記5、int nCmdShow:指明窗口如何顯示。(有的程序打開後就不顯示窗口)
重點二:創建窗口的五大步驟:
<1>設計窗口類;
<2>註冊窗口類;
<3>創建窗口;
<4>顯示窗口
<5>更新窗口
<1>設計窗口類——設計一輛新型汽車
要設計一個窗口類首先應該掌握Windows系統規定的標準的窗口類所具有的屬性,窗口類的結構,所謂用戶創建窗口類實際就是按照自己的想法爲窗口類的每個成員賦予合理的參數。
typedef struct _WNDCLASS {
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCTSTR lpszMenuName;
LPCTSTR lpszClassName;
} WNDCLASS, *PWNDCLASS;
筆記7、WNDPROC lpfnWndProc;指向窗口回調函數的指針,即指向程序員編寫的窗口過程函數。
HANDLE hInstance:用以指明所設計的窗口類屬於的應用程序實例號,該實例號是在程序啓動時由操作系統分配給WinMain的HINSTANCE hInstance
LPCTSTR lpszClassName:用戶在完成組建具有自己特色的窗口類之前爲自己的窗口起一個名字留以今後註冊窗口類和創建窗口用。
<2>註冊窗口類——將你設計的汽車註冊到系統去審覈。
ATOM RegisterClass(
CONST WNDCLASS *lpWndClass // class data
);
筆記8、CONST WNDCLASS*lpWndClass :註冊時用到的是窗口類的指針,因此需要加&
<3>創建窗口——汽車投入生產線。
要創建窗口必須掌握的是創建一個窗口需要完成的必要任務,即給窗口確立最基本的屬性,其實還是用戶通過API對窗口的組建。
HWND CreateWindow(
LPCTSTR lpClassName, // registered class name
LPCTSTR lpWindowName, // window name
DWORD dwStyle, // window style
int x, // horizontal position of window
int y, // vertical position of window
int nWidth, // window width
int nHeight, // window height
HWND hWndParent, // handle to parent or owner window
HMENU hMenu, // menu handle or child identifier
HINSTANCE hInstance, // handle to application instance
LPVOID lpParam // window-creation data
);
筆記8、HINSTANCE hInstance :用以指明被創建的窗口所屬於的應用程序實例號,該實例號是在程序啓動時由操作系統分配給WinMain的HINSTANCEhInstance
<4>顯示窗口——一輛新車產品展示。
顯示窗口時,必須給出需要顯示窗口的句柄,和顯示方式。
BOOL ShowWindow(
HWND hWnd, // handle to window
int nCmdShow // show state
);
筆記9、HWND hWnd :窗口的句柄,本身是窗口的屬性之一,即窗口類中都保留了一個默認成員作爲自己的句柄,供系統管理和程序調用。
<5>更新窗口——負責窗口的刷新重繪。
BOOL UpdateWindow(
HWND hWnd // handle to window
);
重點三:消息循環:
消息循環機制是應用程序正常運行的核心驅動。沒有消息循環機制的程序,就像沒有發動機的汽車失去活動的能力。消息循環的主要功能還是由操作系統完成,包括消息的接收、打包、入隊、讀取、分發。應用程序的功能是接受系統交給的消息,然後再調用系統API完成相應的操作。
消息結果體:
typedef struct tagMSG {
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
} MSG, *PMSG;
筆記10、HWND hwnd:指向接受消息的窗口的句柄。
UINT message:消息的具體值。
獲取消息:
BOOL GetMessage(
LPMSG lpMsg, // message information
HWND hWnd, // handle to window
UINT wMsgFilterMin, // first message
UINT wMsgFilterMax // last message
);
筆記11、LPMSG lpMsg, :消息結構體的指針
HWND hWnd,:對所取消息的範圍限制,爲NULL是取所有消息
消息的打包:
BOOL TranslateMessage(
CONST MSG *lpMsg // message information
);
操作系統將消息解析爲應用程序可以識別的消息。
消息的分發:
LRESULT DispatchMessage(
CONST MSG *lpmsg // message information
);
消息的處理:
筆記12、應用程序接收到系統分發過來的消息之後通過窗口類中保存的窗口過程函數的指針找到窗口過程函數,進入窗口過程函數內進行消息的相應。而窗口過程函數本身就是一系列消息處理方法的集合。