Windows編程入門程序詳解
1. 程序
/************************************************************************ * 名 稱:Windows_Frist_Code.cpp * 功 能:Windows編程入門 * 描 述:包含WinMain函數、WNDCLASS、消息循環等多種內容 windows窗口程序的流程如下:【WinMain入口】-->創建和設計窗口類 -->注冊窗口類-->創建、顯示和更新窗口-->消息循環-->【窗口過程函數】 * 作 者:JarvisChu * 時 間:2012-10-24 * 修 訂:1. 2012-10-26,Jarvis. 完善代碼和注釋。 ************************************************************************/ #include <windows.h> #include <stdio.h> #include "resource.h" //回調函數 LRESULT CALLBACK WinProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); //入口函數 WinMain int WINAPI WinMain(HINSTANCE hInstance, //當前應用程序的句柄 HINSTANCE hPrevInstance,//先前應用程序的句柄,總是NULL LPSTR lpCmdLine, //不包含程序名的命令行,可通過GetCommandLine獲取 int nShowCmd //窗口顯示方式 ) { //-------------------創建和設計窗口類---------------------------------------------------- WNDCLASS wndclass; wndclass.cbClsExtra =0; wndclass.cbWndExtra =0; wndclass.hbrBackground =(HBRUSH)GetStockObject(GRAY_BRUSH); wndclass.hCursor =LoadCursor(hInstance,MAKEINTRESOURCE(ID_MYCURSOR)); //LoadCursor(NULL,IDC_HELP);// wndclass.hIcon =LoadIcon(hInstance,MAKEINTRESOURCE(ID_MYICON)); //LoadIcon(NULL,IDI_APPLICATION);// wndclass.hInstance =hInstance; wndclass.lpfnWndProc =WinProc; wndclass.lpszClassName ="Jarvis"; wndclass.lpszMenuName =NULL; wndclass.style =CS_HREDRAW | CS_VREDRAW; //-------------------注冊窗口類---------------------------------------------------- RegisterClass(&wndclass); //-------------------創建顯示更新窗口---------------------------------------------------- HWND hwnd; hwnd=CreateWindow("Jarvis","Jarvis",WS_OVERLAPPEDWINDOW|WS_HSCROLL|WS_MAXIMIZE, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,hInstance,NULL); ShowWindow(hwnd,SW_SHOWNORMAL); UpdateWindow(hwnd); //-------------------消息循環---------------------------------------------------- MSG msg; while(GetMessage(&msg,NULL,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return 0; } //窗口過程函數實現 LRESULT CALLBACK WinProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch(uMsg) { case WM_LBUTTONDOWN: MessageBox(hwnd,"LeftButton Clicked!","Prompt",0); break; case WM_CLOSE: if(IDYES==MessageBox(hwnd,"Are you sure to quit?","Prompt",MB_YESNO)) { DestroyWindow(hwnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd,uMsg,wParam,lParam); } return 0; }
2. WinMain函數解析
2.1. WinMain函數原型
int WINAPI WinMain ( HINSTANCE hInstance, //當前應用程序的句柄 HINSTANCE hPrevInstance,//先先前應用程序的句柄,總是NULL LPSTR lpCmdLine, //不含程序名的命令行,通過GetCommandLine獲取 int nShowCmd //窗口顯示方式 );
2.2. WinMain函數功能
WinMain是一個函數,該函數的功能是被系統調用,作為一個32位應用程序的入口點。WinMain函數應初始化應用程序,顯示主窗口,進入一個消息接收-發送循環,這個循環是應用程序執行的其余部分的頂級控制結構。
2.3. 窗口顯示方式
WinMain函數的nShowCmd參數指示了窗口的顯示方式。顯示方式可以是下表中的任何一種。
表格 1 窗口顯示方式
SW_HIDE |
隱藏窗口並且激活另外一個窗口 |
SW_RESTORE |
激活並顯示窗口。如果窗口已經最小化或最大化,系統將以恢復到原來的尺寸和位置顯示窗口(與SW_SHOWNORMAL相同) |
SW_SHOW |
激活一個窗口並以原來的尺寸和位置顯示窗口 |
SW_SHOWMAXIMIZED |
激活窗口並且將其最大化 |
SW_SHOWMINIMIZED |
激活窗口並將其最小化(以圖標顯示) |
SW_SHOWMINNOACTIVE |
將一個窗口顯示為圖標。激活窗口維持活動狀態 |
SW_SHOWNA |
以窗口的當前狀態顯示窗口。激活窗口保持活動狀態 |
SW_SHOWNOACTIVATE: |
以窗口的最近一次的尺寸和位置顯示窗口。激活窗口維持激活狀態 |
SW_SHOWNORMAL |
激活並顯示窗口。如果窗口最大化或最小化,系統將其恢復到原來的尺寸和位置(與SW_RESTORE相同) |
SW_MINIMIZE |
最小化指定的窗口,並且激活在系統表中的頂層窗口 |
3. 創建和設計窗口類
3.1. WNDCLASS結構體定義
typedef struct { UINT style; //窗口類型CS_HREDRAW|CS_VREDRAW WNDPROC lpfnWndProc; //窗口回調函數 int cbClsExtra; //指定緊隨在 WNDCLASS 后分配的字節數,初始化為零 int cbWndExtra; //指定緊隨在窗口實例之后分配的字節數,初始化為零。 HINSTANCE hInstance; //指示該窗口類的回調函數所在實例的句柄,不為NULL HICON hIcon; //窗口圖標句柄,若為NULL,系統提供默認 HCURSOR hCursor; //光標資源句柄 HBRUSH hbrBackground; //背景畫刷句柄 LPCTSTR lpszMenuName; //菜單資源名 LPCTSTR lpszClassName; //窗口對應的窗口類名 } WNDCLASS, *PWNDCLASS; //
3.2. 窗口類型
多種窗口類型可以使用 | 號疊加
表格 2 窗口類型
標識 |
描述 |
CS_BYTEALIGNCLIENT |
在字節邊界上(在x方向上)定位窗口的用戶區域的位置 |
CS_BYTEALIGNWINDOW |
在字節邊界上(在x方向上)定位窗口的位置 |
CS_CLASSDC: |
該窗口類的所有窗口實例都共享一個窗口類DC |
CS_DBLCLKS |
允許向窗口發送雙擊鼠標鍵的消息 |
CS_GLOBALCLASS |
當調用CreateWindow 或 CreateWindowEx 函數來創建窗口時允許它的hInstance參數和注冊窗口類時傳遞給RegisterClass 的 hInstance參數不同。如果不指定該風格,則這兩個 hInstance 必須相同。 |
CS_HREDRAW |
當水平長度改變或移動窗口時,重畫整個窗口 |
CS_NOCLOSE |
禁止系統菜單的關閉選項 |
CS_OWNDC |
給予每個窗口實例它本身的DC。注意,盡管這樣是很方便,但它必須慎重使用,因為每個DC大約要占800個字節的內存。 |
CS_PARENTDC |
將子窗口的裁剪區域設置到父窗口的DC中去,這樣子窗口便可以在父窗口上繪制自身。注意,這是子窗口還是從系統緩存中獲取DC,而不是使用父窗口的DC。使用該風格可以提高系統性能。 |
CS_SAVEBITS |
以位圖形式保存被該窗口遮擋的屏幕部分,這樣當給窗口移動以后,系統便可以用該保存的位圖恢復屏幕移動的相應部分,從而系統不用向被該窗口遮擋的窗口發送 WM_PAINT 消息。該特性對於菜單類型的窗口比較合適,因為它通常是簡短的顯示一下之后便消失。設置該特性將增加顯示該窗口的時間,因為它通常要先分配保存位圖的內存。 |
CS_VREDRAW |
當垂直長度改變或移動窗口時,重畫整個窗口 |
3.3. 窗口圖標
3.3.1. LoadIcon函數
HICON LoadIcon( HINSTANCE Instance, //應用程序的實例句柄 LPCTSTR lpIconName //圖標資源的字符串型ID ) ;
3.3.2. 加載系統預定義圖標
LoadIcon(NULL, IDI_APPLICATION);
表格 3 系統圖標資源
IDI_APPLICATION |
Default application icon. |
IDI_ASTERISK |
Same as IDI_INFORMATION. |
IDI_ERROR |
Hand-shaped icon. |
IDI_EXCLAMATION |
Same as IDI_WARNING. |
IDI_HAND |
Same as IDI_ERROR. |
IDI_INFORMATION |
Asterisk icon. |
IDI_QUESTION |
Question mark icon. |
IDI_WARNING |
Exclamation point icon. |
IDI_WINLOGO |
Windows logo icon. Windows XP: Default application icon. |
IDI_SHIELD |
Security Shield icon. |
3.3.3. 加載自定義圖標
[1] 添加圖標資源
File-->New-->Files-->Icon File (Name it “My_Icon.ico” on the right)-->Draw the Icon
[2] 添加資源文件
File-->New-->Files-->Resource Script (Name it “My_Resource”)
打開resource.h 文件,添加語句“#define ID_MYICON 1024”(1024 可以隨意)
用記事本打開My_Resource.rc文件,添加語句“ID_MYICON ICON My_Icon.ico”
[3] 添加“resource.h”頭文件的引用
在主程序的.cpp文件中,引用頭文件“#include “resource.h””
[4] 使用自定義圖標
LoadIcon(hInstance,MAKEINTRESOURCE(ID_MYICON));
3.4. 光標資源
光標資源的加載類似於圖標資源
3.4.1. LoadCursor函數
HCURSOR LoadCursor ( HINSTANCE Instance, //應用程序的實例句柄 LPCTSTR lpCursorName //光標資源的字符串型ID ) ;
3.4.2. 加載系統預定義光標
LoadCursor(NULL,IDC_CROSS);
IDC_APPSTARTING |
Standard arrow and small hourglass |
IDC_ARROW |
Standard arrow |
IDC_CROSS |
Crosshair |
IDC_HAND |
Windows 98/Me, Windows 2000/XP: Hand |
IDC_HELP |
Arrow and question mark |
IDC_IBEAM |
I-beam |
IDC_ICON |
Obsolete for applications marked version 4.0 or later. |
IDC_NO |
Slashed circle |
IDC_SIZE |
Obsolete for applications marked version 4.0 or later. Use IDC_SIZEALL. |
IDC_SIZEALL |
Four-pointed arrow pointing north, south, east, and west |
IDC_SIZENESW |
Double-pointed arrow pointing northeast and southwest |
IDC_SIZENS |
Double-pointed arrow pointing north and south |
IDC_SIZENWSE |
Double-pointed arrow pointing northwest and southeast |
IDC_SIZEWE |
Double-pointed arrow pointing west and east |
IDC_UPARROW |
Vertical arrow |
IDC_WAIT |
Hourglass |
3.4.3. 加載自定義光標
具體步驟與圖標相同(3.3.3)
[1] resource.h
[2] My_Resource.rc
[3] main.cpp
3.5. 背景畫刷
背景畫刷就是用來設置窗口的背景。
hbrBackground是畫刷的句柄,它必須是用於繪制背景的物理刷子的句柄,或者是一個顏色的值。
如果給出一個顏色的值,它必須是下面列出的標准系統顏色之一(系統將對所選顏色加1)。
3.5.1. 使用標准系統顏色
hbrBackground=(HBRUSH)(COLOR_ACTIVEBORDER+1);表格 4 標准系統顏色
名稱 |
樣式 |
名稱 |
樣式 |
COLOR_ACTIVEBORDER COLOR_ACTIVECAPTION COLOR_CAPTIONTEXT COLOR_WINDOWTEXT |
|
COLOR_BTNTEXT COLOR_MENUTEXT |
|
COLOR_APPWORKSPACE |
|
COLOR_HIGHLIGHTTEXT |
|
COLOR_BACKGROUND COLOR_GRAYTEXT COLOR_HIGHLIGHT COLOR_INACTIVEBORDER |
|
COLOR_INACTIVECAPTION |
|
COLOR_BTNFACE COLOR_SCROLLBAR COLOR_WINDOWFRAME |
|
COLOR_MENU |
|
COLOR_BTNSHADOW COLOR_WINDOW |
|
|
|
3.5.2. 使用系統預定義的畫刷
hbrBackground =(HBRUSH)GetStockObject(BLACK_BRUSH);
BRUSH |
名稱 |
BLACK_BRUSH |
黑色畫刷 |
DKGRAY_BRUSH |
暗灰色畫刷 |
DC_BRUSH |
(Win7中錯誤) |
GRAY_BRUSH |
灰色畫刷 |
HOLLOW_BRUSH |
空心刷(相當於NULL_BRUSH) |
LTGRAY_BRUSH |
淺灰色畫刷 |
NULL_BRUSH |
空心刷(即背景透明) |
WHITE_BRUSH |
白色畫刷 |
3.5.3. GetStockObject()函數
HGDIOBJ GetStockObject(int fnObject);
該函數檢索預定義的備用筆、刷子、字體或者調色板的句柄。
fnObject可以是: BLACK_BRUSH,WHITE_PEN,SYSTEM_FONT, DEFAULT_PALETTE
4. 注冊窗口類
ATOM RegisterClass(CONST WNDCLASS *lpWndClass);
窗口只有在其對應的窗口類注冊之后,才能使用CreateWindow或CreateWindowEx創建。
5. 創建窗口
HWND hwnd; hwnd = CreateWindow("Jarvis","Jarvis",WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, CW_USEDEFAULT,NULL,NULL,hInstance,NULL);
HWND CreateWindow( LPCTSTR lpClassName, // 對應的窗口類的名稱 LPCTSTR lpWindowName, //窗口名稱 DWORD dwStyle, / /窗口類型/ int x, //初始水平位置 int y, //初始垂直位置 int nWidth, //窗口寬度 int nHeight, //窗口高度 HWND hWndParent, //父窗口句柄 HMENU hMenu, //菜單資源句柄 HINSTANCE hInstance, //實例句柄 LPVOID lpParam //傳給WM_CREATE的值 );
Window_Style(可以組合)
表格 5 Window_Style
Style |
說明 |
WS_BORDER |
創建一個單邊框的窗口。 |
WS_CAPTION |
創建一個有標題框的窗口(包括WS_BODER風格)。 |
WS_CHILD |
創建一個子窗口。這個風格不能與WS_POPUP風格合用。 |
WS_CHLDWINDOW |
與WS_CHILD相同。 |
WS_CLIPCHILDREN |
當在父窗口內繪圖時,排除子窗口區域。在創建父窗口時使用這個風格。 |
WS_CLIPSIBLINGS |
排除子窗口之間的相對區域,也就是,當一個特定的窗口接收到WM_PAINT消息時,WS_CLIPSIBLINGS 風格將所有層疊窗口排除在繪圖之外,只重繪指定的子窗口。如果未指定WS_CLIPSIBLINGS風格,並且子窗口是層疊的,則在重繪子窗口的客戶區時,就會重繪鄰近的子窗口。 |
WS_DISABLED |
創建一個初始狀態為禁止的子窗口。一個禁止狀態的窗口不能接受來自用戶的輸入信息。 |
WS_DLGFRAME |
創建一個帶對話框邊框風格的窗口。這種風格的窗口不能帶標題條。 |
WS_GROUP |
指定一組控制的第一個控制。這個控制組由第一個控制和隨后定義的控制組成,自第二個控制開始每個控制,具有WS_GROUP風格,每個組的第一個控制帶有WS_TABSTOP風格,從而使用戶可以在組間移動。用戶隨后可以使用光標在組內的控制間改變鍵盤焦點。 |
WS_HSCROLL |
創建一個有水平滾動條的窗口。 |
WS_ICONIC |
創建一個初始狀態為最小化狀態的窗口。與WS_MINIMIZE風格相同。 |
WS_MAXIMIZE |
創建一個初始狀態為最大化狀態的窗口。 |
WS_MAXIMIZEBOX |
創建一個具有最大化按鈕的窗口。該風格不能與WS_EX_CONTEXTHELP風格同時出現,同時必須指定WS_SYSMENU風格。 |
WS_OVERLAPPED |
產生一個層疊的窗口。一個層疊的窗口有一個標題條和一個邊框。與WS_TILED風格相同。 |
WS_OVERLAPPEDWINDOW |
創建一個具有WS_OVERLAPPED,WS_CAPTION,WS_SYSMENU WS_THICKFRAME,WS_MINIMIZEBOX,WS_MAXIMIZEBOX風格的層疊窗口,與WS_TILEDWINDOW風格相同。 |
WS_POPUP |
創建一個彈出式窗口。該風格不能與WS_CHLD風格同時使用。 |
WS_POPUPWINDOW |
創建一個具有WS_BORDER,WS_POPUP,WS_SYSMENU風格的窗口,WS_CAPTION和WS_POPUPWINDOW必須同時設定才能使窗口某單可見。 |
WS_SIZEBOX |
創建一個可調邊框的窗口,與WS_THICKFRAME風格相同。 |
WS_SYSMENU |
創建一個在標題條上帶有窗口菜單的窗口,必須同時設定WS_CAPTION風格。 |
WS_TABSTOP |
創建一個控制,這個控制在用戶按下Tab鍵時可以獲得鍵盤焦點。按下Tab鍵后使鍵盤焦點轉移到下一具有WS_TABSTOP風格的控制。 |
WS_THICKFRAME |
創建一個具有可調邊框的窗口,與WS_SIZEBOX風格相同。 |
WS_TILED |
產生一個層疊的窗口。一個層疊的窗口有一個標題和一個邊框。與WS_OVERLAPPED風格相同。 |
WS_TILEDWINDOW |
創建一個具有WS_OVERLAPPED,WS_CAPTION,WS_SYSMENU, WS_THICKFRAME,WS_MINIMIZEBOX,WS_MAXMIZEBOX風格的層疊窗口。與WS_OVERLAPPEDWINDOW風格相同。 |
WS_VISIBLE |
創建一個初始狀態為可見的窗口。 |
WS_VSCROLL |
創建一個有垂直滾動條的窗口。 |
6. 顯示窗口
BOOL ShowWindow(HWND hWnd, //窗口句柄 int nCmdShow //顯示方式 );
顯示方式可以是下表中的任何一種。
表格 6 窗口顯示方式
窗口顯示方式 |
說明 |
SW_HIDE |
隱藏窗口並激活其他窗口。 |
SW_MAXIMIZE |
最大化指定的窗口。 |
SW_MINIMIZE |
最小化指定的窗口並且激活在Z序中的下一個頂層窗口。 |
SW_RESTORE |
激活並顯示窗口。如果窗口最小化或最大化,則系統將窗口恢復到原來的尺寸和位置。在恢復最小化窗口時,應用程序應該指定這個標志。 |
SW_SHOW |
在窗口原來的位置以原來的尺寸激活和顯示窗口。 |
SW_SHOWDEFAULT |
依據在STARTUPINFO結構中指定的SW_FLAG標志設定顯示狀態,STARTUPINFO 結構是由啟動應用程序的程序傳遞給CreateProcess函數的。 |
SW_SHOWMAXIMIZED |
激活窗口並將其最大化。 |
SW_SHOWMINIMIZED |
激活窗口並將其最小化。 |
SW_SHOWMINNOACTIVE |
窗口最小化,激活窗口仍然維持激活狀態。 |
SW_SHOWNA |
以窗口原來的狀態顯示窗口。激活窗口仍然維持激活狀態。 |
SW_SHOWNOACTIVATE |
以窗口最近一次的大小和狀態顯示窗口。激活窗口仍然維持激活狀態。 |
SW_SHOWNORMAL |
激活並顯示一個窗口。如果窗口被最小化或最大化,系統將其恢復到原來的尺寸和大小。應用程序在第一次顯示窗口的時候應該指定此標志。 |
7. 更新窗口
如果窗口更新的區域不為空,UpdateWindow函數通過發送一個WM_PAINT消息來更新指定窗口的客戶區。函數繞過應用程序的消息隊列,直接發送WM_PAINT消息給指定窗口的窗口過程,如果更新區域為空,則不發送消息。
8. 消息循環
MSG msg; while (GetMessage(&msg,NULL,0,0)) //從消息隊列中取得一條消息 { TranslateMessage(&msg); //將虛擬鍵消息轉化成字符消息 DispatchMessage(&msg); //將消息發送給相應的窗口過程函數 }//
8.1. MSG 結構體
MSG結構體包含一條WindowMessage的全部信息
typedef struct tagMSG { //msg HWND hwnd; //接受消息循環的窗口句柄 UINT message; //消息類型 WPARAM wParam; //附加信息 LPARAM lParam; //附加信息 DWORD time; //投遞到消息隊列的時間 POINT pt; //鼠標的位置 }MSG; //
8.2. 自定義MSG
9. 窗口過程
窗口過程函數是一個應用程序定義的函數,用來處理發送到窗口的消息。WNDPROC類型定義了一個指向該回調函數的指針。WindowProc是用於應用程序定義函數的占位符,也就是說,程序員自己更改WindowProc這個名稱,但是參數類型不變。
一個Windows 程序可以包含多個窗口過程。一個窗口過程總是與調用RegisterClass注冊的特定窗口類相關聯。程序通常不直接調用窗口過程。窗口過程通常由 Windows 本身調用。通過調用 SendMessage 函數,程序能夠直接調用它自己的窗口過程。
9.1. 函數聲明
LRESULT CALLBACK WindowProc( HWND hwnd, //指向窗口的句柄 UINT uMsg, //指定消息類型 WPARAM wParam, //指定其余的、消息特定的信息 LPARAM lParam //指定其余的、消息特定的信息 );
9.2. 函數功能
該函數主要是用來處理發送給窗口的各類MSG消息。
窗口過程在處理消息時,必須返回0。
窗口過程不予處理的所有消息應該被傳給名為DefWindowProc() 函數。
從 DefWindowProc 返回的值必須由窗口過程返回。
本文部分內容來自MSDN和網絡。
轉載請注明地址: