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和網絡。
轉載請注明地址:









