Windows基礎程式設計SDK複習知識點
阿新 • • 發佈:2018-11-20
1. CUI程式與GUI程式
CUI程式:控制檯介面
GUI程式:圖形使用者介面程式
2. windows程式設計標頭檔案
通常我們包含windows.h標頭檔案,它是一個 綜合型標頭檔案。
其次還有一些標頭檔案,例如:tchar.h,通用字串的定義 Commctrl.h控制元件API的定義
3. WinMain函式
C語言中有一個main函式,在windows程式設計中有一個WinMain函式,對於WinMain函式來說,他的形式永遠那麼固定
其他引數略 4. 字元編碼 ASCLL字元佔1個位元組 Unicode佔2個位元組,使用Unicode編碼可以使工程同時支援多種語言,在系統底層開發中,字串都是以Unicode編碼形式進行操作 Tip :當我們定義UNICODE巨集時候,CreateWindowEx是寬位元組版函式,沒有定義UNICODE巨集,CreateWindowEX是多位元組版函式,這裡CreateWindow是一個巨集,我們切記, 在windows程式設計中,根本就沒有CreateWindowEx這個函式 常用字串處理函式:
5. windows資料型別
DWORD 實際是 unsigned long
BOOL 實際是 int
WCHAR 實際是 w_char UINT 實際是 unsigned int 所有windows資料型別都是通過在SDK標頭檔案中定義的,它們都是來源於標準C的資料型別 6. windows控制代碼和物件 控制代碼:用以代表一個物件,然後使用函式操作這個物件的時候,就把控制代碼傳進去,在作用上類似於C++this指標。 常見的控制代碼型別有:HWND 視窗控制代碼 HMODULE模組控制代碼 HDC環境繪圖控制代碼 HMENU選單控制代碼 HANDLE核心物件控制代碼 每一種控制代碼型別都是一種資料型別 7. WINDOWS錯誤處理 我們根據API函式的返回值來判斷函式是否成功,但是我們要進一步知道函式錯誤在哪裡,所有在WINDOWS下每一個執行緒都有一塊區域能夠儲存錯誤碼, 可以使用SetLastError(),這個API設定一個數值,每一個API函式退出之前都會呼叫這個函式,並且給此API設定一個錯誤碼,我們在API呼叫結束之後,可以呼叫GetLaseError()得到錯誤碼,再根據錯誤碼判斷是什麼錯誤 Tip:我們想知道某一個函式的呼叫結果,在函式呼叫完畢的地方,立即使用GetLastError函式,否則錯誤碼可能被其他API覆蓋 檢視錯誤碼的方式:
UINT umessage; //訊息ID
WPARAM wParam; //訊息引數1
LPARAM lParam; //訊息引數2
) 這裡需注意,返回值型別為 LRESULT 因為回撥函式返回值必然是呼叫DefWindowProc函式來處理,所有回撥函式返回值不能為0 LRESULT本質就是 long 長整形 。 DefWindowProc(); 此函式返回值即是上面回撥函式的返回值,本函式作用,它將視窗不處理的訊息預設傳遞給系統做預設處理,此函式在 回撥函式中必不可少 9. 建立視窗 1.先設計一個視窗類 2.在註冊視窗類 3.建立視窗 4.顯示重新整理視窗 5.建立訊息泵,迴圈接受處理訊息(前提要將回調函式寫好) 10. 訊息機制 訊息是windows作業系統發給應用程式的一個通告,他告訴應用程式某個特定的事件發生了 系統傳送給應用程式某個訊息,最終處理訊息的是應用程式的視窗函式,如果程式不負責處理,此訊息就被系統預設處理 (所以在視窗回撥函式返回值不是0,而是我們寫的 return DefWindowProc(hWnd,uMsg,wParam,lParam) ) 訊息本身是作為一個記錄傳遞給應用程式,這個記錄中包含了訊息的型別,以及其他資訊 (這裡也很好理解,因為訊息的所有資訊是被MSG結構體儲存,裡面的不同欄位代表著不同的訊息型別,以及訊息的附加資訊) 這裡再次說明下MSG結構體裡面幾個重要的引數,也是我們常見的引數,例如
Tip:我們常見的WM_COMMAND訊息
Pis:對於按鈕的響應 我們在回撥函式裡面,響應訊息的應該是WM_COMMAND,因為他是通用控制元件
這時候 WORD wHigh = HIWORD(wParam)
WORD wLow = LOWRD (wParam)
這裡 wHigh 取到的是控制元件的視窗控制代碼 wLow 取到的是控制元件ID
訊息識別符號的值 訊息識別符號的取值範圍:在0x0000 到 WM_USER(0x400) 如果我們要自定義訊息,在後面MFC中使用類嚮導去自定義一個訊息,我們需要宣告訊息巨集的時候,範圍要大於WM_USER。通常我們可以 WM_USER+1去定義自定義訊息巨集 訊息的種類 大致分為三種,通用視窗訊息,控制元件訊息,自定義訊息 通用視窗訊息,通常以WM開頭 控制元件訊息,控制元件整體上能夠使用通用視窗訊息,對於不同控制元件還有自己能夠處理的訊息 自定義訊息,就是我們上面所說的我們可以根據用途去規定,wParam和lParam含義 佇列訊息和非佇列訊息 從訊息傳送的途徑來看,訊息可以分為兩種:佇列訊息和非佇列訊息 佇列訊息,最常見的就是滑鼠和鍵盤觸發的訊息 當滑鼠鍵盤事件被觸發,相應的滑鼠和鍵盤驅動程式就會把這些事件轉換成相應的訊息,然後輸送到系統訊息佇列,由Windows系統去進行處理,Windows系統就會把在系統訊息佇列裡面取出一個訊息,儲存到MSG訊息結構體,在將MSG結構體傳送給我們的視窗,下面的事情就由我們執行緒訊息佇列去解決,Window開始自己忙自己的事 非佇列訊息,會繞過系統佇列和訊息佇列,直接將訊息傳送給視窗 訊息的傳送 我們上面說了訊息佇列的概念,下面我們就詳細說說,訊息是如果傳送給我們的視窗的 把一個訊息傳送到視窗有三種方式:傳送,寄送,和廣播 傳送訊息:常見的函式有 SendMessage(非佇列訊息),這個函式的主要作用向一個或者多個視窗傳送一條訊息,一直等訊息被處理了才會返回 寄送訊息:常見的函式是 PostMessage(佇列訊息) 該函式把一條訊息放置建立hWnd視窗的執行緒的訊息佇列中,該函式不等訊息被處理就馬上將控制返回 以上者兩者具有代表性的函式,我們可以分析下發送訊息和寄送訊息,這兩種方式不同: 被髮送的訊息不會被立即處理,函式不會立即返回
被寄送的訊息不會被立即處理,它會被放進一個先進先出的佇列中,一直等到應用程式空線的時候才會被處理,不過函式放置完訊息後立即返回 訊息的接受 訊息接受的函式主要有三個:GetMessage, PeekMessage, WaitMessage GetMessage(LPMSG lpMsg, HWMD hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax) 該函式用來獲取與hWnd引數所指定的視窗相關的wMsgFilterMin和wMsgFilterMax引數所給出訊息值範圍內的訊息,如果hWnd為NULL,則GetMessage獲取屬於該呼叫函式應用程式的任一視窗的訊息,如果wMsgFilterMin和wMsgFilterMax都為0,則GetMessage可以返回所有得到的訊息, 函式獲取訊息之後,就刪除訊息佇列中的除了WM_PAINT訊息之外的其他訊息,至於WM_PAINT則只有被處理後才刪除
對於上面的描述解釋下:GetMessage這個函式第一個引數是訊息MSG結構體的地址,裡面可以得到訊息的各種資訊,通常我們傳參&msg ,至於第二個引數hWnd,我們通常寫0,因為如果寫0,這個GetMessage函式就可以獲得該應用程式的任意視窗訊息,這也是我們想要做到的,我們通常情況下不會希望,哪一個視窗不被髮訊息,不被獲取訊息。第三個引數和第四個引數,從引數原型就可以看出一個是min一個是max,它代表我們獲取訊息的範圍值(通常是0-400),但是如果我們自定義訊息他的預設範圍就會變化,所以我們這裡通常填寫 0 0,它代表GetMessage獲取所有的訊息。
當函式獲取訊息後,系統訊息佇列的傳遞任務就完成了,系統訊息佇列就可以把這些訊息刪除了。但是:WM_PAINT訊息要等其被處理後才能被刪除,它是重繪訊息(特殊)
PeekMessage(LPMSG lpMsg, HWMD hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, wRemoveMsg) PeekMessage與GetMessage區別在於:該函式不會等有訊息進去佇列才返回 WaitMessage() 當一個應用程式無事可做時候, 該函式就將控制權交給另外的應用程式,同時將該程式掛起,知道有一個新的訊息放入應用程式佇列中才返回 11. Window視窗 視窗的風格有三種類型:重疊視窗, 彈出視窗, 子視窗 WS_OVERLAPPED WS_POPUP WS_CHILD 重疊視窗:是頂級視窗,有一個標題欄,邊框,客戶區,它的目的是作為一個應用程式的主視窗,它也可以有一個視窗選單,最大化和最小化的按鈕,滾動條 彈出視窗:是頂級視窗,並且連線到桌面視窗的子視窗列表,彈出視窗多用於對話方塊或者MESSAGBOX,它具有WS_POPUP風格 子視窗: 通常會有WS_CHILD風格, 並且只能夠被分配到父視窗的客戶區域,子視窗必須要有父視窗,父視窗可以是層疊視窗,也可以是彈出視窗,也可以是其他子視窗 也就是說,子視窗不能移出父視窗的客戶區(解釋上面紅色語句) 我們可以使用CreateWindowEx()為 視窗擴充套件風格 視窗層次結構 我們可以從桌面窗口出發,遍歷得到所有視窗具體程式碼:
另一種是通用控制元件,通用控制元件較為複雜
控制元件的建立
我們也是使用CreateWindow函式,只是視窗類不需要我們去註冊,但是我們要指定他們的風格,WS_CHILD與WS_VISIBLE風格
控制元件相關的訊息
分為兩種
一種是用於控制控制元件行為的控制元件控制訊息
一種是用於通知父視窗使用者行為的控制元件通知訊息
簡單的說明下這兩種訊息的含義:
看起來比較繞口,我們只需要明白他們的含義就好,
先來說說第一種控制控制元件行為的控制元件控制訊息,一些控制元件除了會通知視窗訊息之外,還有自己的專屬訊息,
我們只需要向這些控制元件傳送這些訊息來控制他們的行為就行(比如按鈕被點選按下,按鈕被按下只有系統知道,我們看到了圖示改變那是因為圖示被重繪了),我們並不需要知道他們怎麼被處理(按下按鈕觸發什麼事件,我們並不用操心他們會觸發什麼事)
第二種訊息,為控制元件通知訊息,控制元件通知訊息是子控制元件來通知父視窗一些事件,常見的有子控制元件被點選,子控制元件需要重繪,對應了上面所說的去理解其中的含義。 這裡,控制元件通知訊息分為兩大類: WM_COMMAND: 標準控制元件的通知訊息,標準控制元件的通知訊息比較簡單 WM_NOTIFY: 附加通用控制元件通常會用此訊息給父視窗發通知 ( 後面分析為什麼要分為兩大類)
13. Windows中資源 略 14. 對話方塊 引入對話方塊資源這一操作,可以使我們方便去控制視窗的各個控制元件位置,屬性 兩個對話方塊建立函式的API 一個是DiaologBox,一種是CreateDialog DiaologBox是生成一個模態視窗,他不需要自己寫訊息迴圈 CreateDialog生成一個非模態對話方塊,他需要自己寫訊息迴圈 他們的引數都一樣,說明他們又是巨集,他們背後都是在呼叫CreateWindow 上面我們說了模態對話方塊和非模態對話方塊,這裡我們來分析分析這兩個概念以及區別
那麼對話方塊主要處理的訊息有:
WM_INITDIALOG 對話方塊初始化時候操作
WM_COMMAND 響應對話方塊上的控制元件一些處理操作
模態對話方塊的顯示建立
要呼叫DiaologBox,在對話方塊處理函式中(switch語句中)處理WM_INITDIALOG和WM_COMMAND。並且模態對話方塊的關閉要呼叫EndDiaolog關閉對話方塊
訊息框是模態對話方塊的一種特殊形式,也就是我們常見的MessageBox函式生成的訊息框,我們這裡只看他的引數含義
MessageBox(擁有該訊息的視窗控制代碼, 訊息框中顯示的字串, 標題字串, 指定訊息框的內容 )
非模態對話方塊的顯示建立
要呼叫CreateDialog完成建立
不要忘記我們還要自己去寫訊息迴圈,由於非模態對話方塊並不禁止應用程式向其他視窗發訊息,因此,
在WinMain函式的訊息迴圈中必須包含截獲發往非模態對話方塊的訊息
具體程式碼如下 while(GetMessage(&msg,NULL,0,0)) { if (! IsDiaologMessage(hdlg,&msg)) //如果是發往對話方塊的訊息,取反 代表其他不屬於對話方塊的訊息,就進入迴圈,發給其他視窗
{ //這裡也就說明為什麼非模態對話方塊,父視窗可以相應使用者操作 TranslateMessage(&msg); DispatchMessage(&msg); } } 關閉對話方塊函式 DestroyWindow(); 關閉非模態對話方塊,退出訊息迴圈,結束程序,但不等於退出執行 我們總結下關閉視窗或者對話方塊的函式 EndDiaolog(); 關閉模態對話方塊,呼叫函式中關閉對話方塊,關閉後會有一個返回值給父視窗
第二種,如果知道子視窗控制代碼,找父視窗控制代碼方法 GetParent()引數為子視窗控制代碼 控制元件訊息 上面我們在分析訊息的時候,以及提及了控制元件訊息的相關資訊,這裡我們來深入的分析下控制元件訊息 控制元件的本質也是視窗,既然是視窗那麼他也有回撥函式,我們在建立控制元件的時候並沒有指定他的回撥函式,那麼控制元件的訊息誰處理了呢? 他其實是傳送到了父視窗中,所以我們應該在主視窗的回撥函式裡面去處理控制元件的訊息,控制元件訊息主要分為兩種型別WM_COMMAND和WM_NOTIFY,我們上面說過。控制元件分為兩種型別,一種是標準控制元件,一種是通用控制元件,所以訊息的處理也是不同的 我們如果按下一個按鈕,或者滑鼠單擊,那麼WINDOWS將會發送一個WM_COMMAND訊息給父視窗,我們這裡就分析下WM_COMMAND訊息引數
這裡的控制元件通知碼 如果說BN_CLICKED 區分具體是什麼訊息種類 我們在WM_COMMAND 中寫switch語句,其中的case 後面就可寫控制元件通知碼
標準控制元件的分類
<wiz_code_mirror>
Radio Box
它和CheckBox差不多
這裡新增一個函式,ComboBox_GetText(hWnd,szText,64); 獲取選項內容
它和CheckBox的區別就是,一個選其他全不選,所以我們就要為這些按鈕分組
分組的步驟,Ctrl+D,按順序點你的Radio Box,在每一組的第一個按鈕將屬性group至為TRUE
這裡我們通過wParam來區分選單,快捷鍵或者控制元件通知碼,然而我們如果選中了List控制元件的某一行,我們發現我們需要知道我們選中的是哪一行,這下WM_COMMAND就不能滿足我們的要求,於是,WM_NOTIFY就出現了
現在我們將所有的資訊都存放到 NMHDR 結構體中,該結構體指標通過LPARAM通知到父視窗
typedef struct tagNMHDR
{
HWND hwndFrom; // 控制元件控制代碼.
UINT_PTR idFrom; // 控制元件 ID.
UINT code; // NM_ code.
} NMHDR;
但是我們需要知道ListView選中的行和列
通用控制元件的使用
int APIENTRY _tWinMan( _In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance,其中APIENTRY指明瞭函式呼叫方式是stdcall WinMain是一個巨集定義,自適應win32程式的版本是多位元組還是UNICODE版本 (多位元組編碼ASC,寬位元組編碼unicode) hInstance是程式的例項控制代碼,它是程式載入地址_In_ LPTSTR lpCmdLine,_In_ int nCmdShow)
其他引數略 4. 字元編碼 ASCLL字元佔1個位元組 Unicode佔2個位元組,使用Unicode編碼可以使工程同時支援多種語言,在系統底層開發中,字串都是以Unicode編碼形式進行操作 Tip :當我們定義UNICODE巨集時候,CreateWindowEx是寬位元組版函式,沒有定義UNICODE巨集,CreateWindowEX是多位元組版函式,這裡CreateWindow是一個巨集,我們切記, 在windows程式設計中,根本就沒有CreateWindowEx這個函式 常用字串處理函式:
ACS版 | UNICODE | T版 | |
獲取長度 | strlen | wcsnlen | _tcslen |
字串拷貝 | strcpy_s | wcscpy_s | _tcscpy_s |
字串轉數字 | atoi | _wtoi | _tstoi |
sscanf_s | swscanf_s | _stscanf_s | |
數字轉字元 | sprintf_s | swprintf_s | _stprintf_s |
WCHAR 實際是 w_char UINT 實際是 unsigned int 所有windows資料型別都是通過在SDK標頭檔案中定義的,它們都是來源於標準C的資料型別 6. windows控制代碼和物件 控制代碼:用以代表一個物件,然後使用函式操作這個物件的時候,就把控制代碼傳進去,在作用上類似於C++this指標。 常見的控制代碼型別有:HWND 視窗控制代碼 HMODULE模組控制代碼 HDC環境繪圖控制代碼 HMENU選單控制代碼 HANDLE核心物件控制代碼 每一種控制代碼型別都是一種資料型別 7. WINDOWS錯誤處理 我們根據API函式的返回值來判斷函式是否成功,但是我們要進一步知道函式錯誤在哪裡,所有在WINDOWS下每一個執行緒都有一塊區域能夠儲存錯誤碼, 可以使用SetLastError(),這個API設定一個數值,每一個API函式退出之前都會呼叫這個函式,並且給此API設定一個錯誤碼,我們在API呼叫結束之後,可以呼叫GetLaseError()得到錯誤碼,再根據錯誤碼判斷是什麼錯誤 Tip:我們想知道某一個函式的呼叫結果,在函式呼叫完畢的地方,立即使用GetLastError函式,否則錯誤碼可能被其他API覆蓋 檢視錯誤碼的方式:
- 在VS中自帶工具 “錯誤查詢”
- 使用FormatMessage函式,有錯誤碼得到錯誤字串
- 在VS監視欄中輸入 err,hr可以時時檢視API的監控結果 (這個最為方便)
UINT umessage; //訊息ID
WPARAM wParam; //訊息引數1
LPARAM lParam; //訊息引數2
) 這裡需注意,返回值型別為 LRESULT 因為回撥函式返回值必然是呼叫DefWindowProc函式來處理,所有回撥函式返回值不能為0 LRESULT本質就是 long 長整形 。 DefWindowProc(); 此函式返回值即是上面回撥函式的返回值,本函式作用,它將視窗不處理的訊息預設傳遞給系統做預設處理,此函式在 回撥函式中必不可少 9. 建立視窗 1.先設計一個視窗類 2.在註冊視窗類 3.建立視窗 4.顯示重新整理視窗 5.建立訊息泵,迴圈接受處理訊息(前提要將回調函式寫好) 10. 訊息機制 訊息是windows作業系統發給應用程式的一個通告,他告訴應用程式某個特定的事件發生了 系統傳送給應用程式某個訊息,最終處理訊息的是應用程式的視窗函式,如果程式不負責處理,此訊息就被系統預設處理 (所以在視窗回撥函式返回值不是0,而是我們寫的 return DefWindowProc(hWnd,uMsg,wParam,lParam) ) 訊息本身是作為一個記錄傳遞給應用程式,這個記錄中包含了訊息的型別,以及其他資訊 (這裡也很好理解,因為訊息的所有資訊是被MSG結構體儲存,裡面的不同欄位代表著不同的訊息型別,以及訊息的附加資訊) 這裡再次說明下MSG結構體裡面幾個重要的引數,也是我們常見的引數,例如
- HWND hwnd 視窗控制代碼,表示發給哪個視窗,通常在設計視窗類的時候已經指定了是發給哪個視窗
- UINT message 訊息ID,表示傳送的哪個訊息,也就是我們通常說的訊息號,根據號來告訴程式,傳送了什麼訊息型別 比如WM_COMMAND訊息號0X111
- wParam 通常是一個與訊息相關的常量值,它的存在是取決於你是什麼訊息型別,也就是上一條。也可能是視窗或者控制元件的控制代碼
- lParam 通常是一個指向記憶體中資料的指標,由於WParam,lParam都是32位,他們之間都可以轉換
Tip:我們常見的WM_COMMAND訊息
訊息來源 | wParam(高16位) | wParam(低16位) | IParam |
選單 | 0 | 選單ID | 0 |
快捷鍵 | 1 | 快捷鍵ID | 0 |
控制元件 | 控制元件通知碼 | 控制元件ID | 控制元件控制代碼 |
WORD wLow = LOWRD (wParam)
這裡 wHigh 取到的是控制元件的視窗控制代碼 wLow 取到的是控制元件ID
訊息識別符號的值 訊息識別符號的取值範圍:在0x0000 到 WM_USER(0x400) 如果我們要自定義訊息,在後面MFC中使用類嚮導去自定義一個訊息,我們需要宣告訊息巨集的時候,範圍要大於WM_USER。通常我們可以 WM_USER+1去定義自定義訊息巨集 訊息的種類 大致分為三種,通用視窗訊息,控制元件訊息,自定義訊息 通用視窗訊息,通常以WM開頭 控制元件訊息,控制元件整體上能夠使用通用視窗訊息,對於不同控制元件還有自己能夠處理的訊息 自定義訊息,就是我們上面所說的我們可以根據用途去規定,wParam和lParam含義 佇列訊息和非佇列訊息 從訊息傳送的途徑來看,訊息可以分為兩種:佇列訊息和非佇列訊息 佇列訊息,最常見的就是滑鼠和鍵盤觸發的訊息 當滑鼠鍵盤事件被觸發,相應的滑鼠和鍵盤驅動程式就會把這些事件轉換成相應的訊息,然後輸送到系統訊息佇列,由Windows系統去進行處理,Windows系統就會把在系統訊息佇列裡面取出一個訊息,儲存到MSG訊息結構體,在將MSG結構體傳送給我們的視窗,下面的事情就由我們執行緒訊息佇列去解決,Window開始自己忙自己的事 非佇列訊息,會繞過系統佇列和訊息佇列,直接將訊息傳送給視窗 訊息的傳送 我們上面說了訊息佇列的概念,下面我們就詳細說說,訊息是如果傳送給我們的視窗的 把一個訊息傳送到視窗有三種方式:傳送,寄送,和廣播 傳送訊息:常見的函式有 SendMessage(非佇列訊息),這個函式的主要作用向一個或者多個視窗傳送一條訊息,一直等訊息被處理了才會返回 寄送訊息:常見的函式是 PostMessage(佇列訊息) 該函式把一條訊息放置建立hWnd視窗的執行緒的訊息佇列中,該函式不等訊息被處理就馬上將控制返回 以上者兩者具有代表性的函式,我們可以分析下發送訊息和寄送訊息,這兩種方式不同: 被髮送的訊息不會被立即處理,函式不會立即返回
被寄送的訊息不會被立即處理,它會被放進一個先進先出的佇列中,一直等到應用程式空線的時候才會被處理,不過函式放置完訊息後立即返回 訊息的接受 訊息接受的函式主要有三個:GetMessage, PeekMessage, WaitMessage GetMessage(LPMSG lpMsg, HWMD hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax) 該函式用來獲取與hWnd引數所指定的視窗相關的wMsgFilterMin和wMsgFilterMax引數所給出訊息值範圍內的訊息,如果hWnd為NULL,則GetMessage獲取屬於該呼叫函式應用程式的任一視窗的訊息,如果wMsgFilterMin和wMsgFilterMax都為0,則GetMessage可以返回所有得到的訊息, 函式獲取訊息之後,就刪除訊息佇列中的除了WM_PAINT訊息之外的其他訊息,至於WM_PAINT則只有被處理後才刪除
對於上面的描述解釋下:GetMessage這個函式第一個引數是訊息MSG結構體的地址,裡面可以得到訊息的各種資訊,通常我們傳參&msg ,至於第二個引數hWnd,我們通常寫0,因為如果寫0,這個GetMessage函式就可以獲得該應用程式的任意視窗訊息,這也是我們想要做到的,我們通常情況下不會希望,哪一個視窗不被髮訊息,不被獲取訊息。第三個引數和第四個引數,從引數原型就可以看出一個是min一個是max,它代表我們獲取訊息的範圍值(通常是0-400),但是如果我們自定義訊息他的預設範圍就會變化,所以我們這裡通常填寫 0 0,它代表GetMessage獲取所有的訊息。
當函式獲取訊息後,系統訊息佇列的傳遞任務就完成了,系統訊息佇列就可以把這些訊息刪除了。但是:WM_PAINT訊息要等其被處理後才能被刪除,它是重繪訊息(特殊)
PeekMessage(LPMSG lpMsg, HWMD hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, wRemoveMsg) PeekMessage與GetMessage區別在於:該函式不會等有訊息進去佇列才返回 WaitMessage() 當一個應用程式無事可做時候, 該函式就將控制權交給另外的應用程式,同時將該程式掛起,知道有一個新的訊息放入應用程式佇列中才返回 11. Window視窗 視窗的風格有三種類型:重疊視窗, 彈出視窗, 子視窗 WS_OVERLAPPED WS_POPUP WS_CHILD 重疊視窗:是頂級視窗,有一個標題欄,邊框,客戶區,它的目的是作為一個應用程式的主視窗,它也可以有一個視窗選單,最大化和最小化的按鈕,滾動條 彈出視窗:是頂級視窗,並且連線到桌面視窗的子視窗列表,彈出視窗多用於對話方塊或者MESSAGBOX,它具有WS_POPUP風格 子視窗: 通常會有WS_CHILD風格, 並且只能夠被分配到父視窗的客戶區域,子視窗必須要有父視窗,父視窗可以是層疊視窗,也可以是彈出視窗,也可以是其他子視窗 也就是說,子視窗不能移出父視窗的客戶區(解釋上面紅色語句) 我們可以使用CreateWindowEx()為 視窗擴充套件風格 視窗層次結構 我們可以從桌面窗口出發,遍歷得到所有視窗具體程式碼:
int _tmain(int argc, _TCHAR* argv[])
{
//得到桌面視窗控制代碼
HWND hwnd = GetDesktopWindow();
//得到螢幕的第一個子視窗
hwnd = GetWindow(hwnd,GW_CHILD);
char szname[266] = { 0 };
//迴圈遍歷得到所有的子視窗
while (hwnd!=NULL)
{
memset(szname, 0, 266); //每次進入迴圈,清空緩衝區
GetWindowTextA(hwnd, szname, 266); //獲得視窗的視窗名
printf("%s\n", szname);
hwnd = GetNextWindow(hwnd, GW_HWNDNEXT); //賦值給下一個視窗
}
return 0;
}
對於以上函式,解釋下程式碼
GetDesktopWindow() 獲取桌面視窗控制代碼
GetWindow() 返回於
指定視窗有特定關係的視窗控制代碼,這裡,傳入GW_CHILD 獲得相對於螢幕的第一個子視窗控制代碼 (這裡必須是有特定關係)
memset 初始化緩衝區
GetWindowTextA() 獲取指定視窗控制代碼的標題
GetNextWindow 它是一個巨集,他的本質還是GetWindow(),這裡我們傳入的引數變為
GW_HWNDNEXT,這裡我們指定找到他的下一個兄弟視窗,不能傳 GW_CHILD,因為對應了上面的紅字,其他視窗直接是沒有特定關係
12. 控制元件基礎
控制元件是一本分windows系統內建的視窗類,他們
只能是某一個視窗的子視窗,所以建立他們的風格必須都是WS_CHILD風格
我們建立一個控制元件的時候,我們並沒有去註冊一個視窗類,因為系統以及幫我們註冊好了,訊息相應函式也不是我們寫的,都由windows提供,即他們都有自己的視窗回撥函式,(ps:當然我們也可以自己去改變這些空間本身的回撥函式,setwindowlong() )
控制元件具體分為兩種
一種是標準控制元件
視窗類名 | 控制元件 | 英文 |
"button" | 按鈕 | Button |
複選框 | CheckBox | |
單選框 | RadioButton | |
"static" | 靜態文字 | Static Text |
圖片 | Picture Control | |
"combobox" | 複合框 | ComboBox |
"edit" | 編輯 | Edit |
"listbox" | 列表框 | ListBox |
"scrollbar" | 滾動條 | ScrollBar |
視窗類名 | 控制元件 |
WC_LISTVIEW | 列表框控制元件 |
WC_TREEVIEW | 樹控制元件 |
WC_TABCONTROL | Tab控制元件 |
HOTKEY_CLASS | 熱鍵控制元件 |
第二種訊息,為控制元件通知訊息,控制元件通知訊息是子控制元件來通知父視窗一些事件,常見的有子控制元件被點選,子控制元件需要重繪,對應了上面所說的去理解其中的含義。 這裡,控制元件通知訊息分為兩大類: WM_COMMAND: 標準控制元件的通知訊息,標準控制元件的通知訊息比較簡單 WM_NOTIFY: 附加通用控制元件通常會用此訊息給父視窗發通知 ( 後面分析為什麼要分為兩大類)
13. Windows中資源 略 14. 對話方塊 引入對話方塊資源這一操作,可以使我們方便去控制視窗的各個控制元件位置,屬性 兩個對話方塊建立函式的API 一個是DiaologBox,一種是CreateDialog DiaologBox是生成一個模態視窗,他不需要自己寫訊息迴圈 CreateDialog生成一個非模態對話方塊,他需要自己寫訊息迴圈 他們的引數都一樣,說明他們又是巨集,他們背後都是在呼叫CreateWindow 上面我們說了模態對話方塊和非模態對話方塊,這裡我們來分析分析這兩個概念以及區別
- 模態對話方塊建立後一定要在使用者關閉對話方塊後, 才能對父視窗進行使用者操作
- 非模態對話方塊建立之後,不需要等待視窗關閉,也可以對父視窗進行視窗操作
視窗 | 對話方塊 | |
函式返回值 | 返回LRESULT(也就是返回LONG) | 返回BOOL |
訊息處理 | 不處理WM_INITDLALOG | 不處理WM_CREAT,WM_DESTORY,WM_PAINT |
不處理訊息如何處理 | 呼叫DefWindowProc處理程式不處理的訊息 | 直接返回0 (return 0) |
具體程式碼如下 while(GetMessage(&msg,NULL,0,0)) { if (! IsDiaologMessage(hdlg,&msg)) //如果是發往對話方塊的訊息,取反 代表其他不屬於對話方塊的訊息,就進入迴圈,發給其他視窗
{ //這裡也就說明為什麼非模態對話方塊,父視窗可以相應使用者操作 TranslateMessage(&msg); DispatchMessage(&msg); } } 關閉對話方塊函式 DestroyWindow(); 關閉非模態對話方塊,退出訊息迴圈,結束程序,但不等於退出執行 我們總結下關閉視窗或者對話方塊的函式 EndDiaolog(); 關閉模態對話方塊,呼叫函式中關閉對話方塊,關閉後會有一個返回值給父視窗
DestroyWindow(); 關閉非模態對話方塊,退出訊息迴圈,結束程序,但不等於退出執行
PostQuitMessage(); 退出執行,關閉程式15. 控制元件的使用 經過學習可以知道,控制元件的產生可以有兩種方式,第一種是我們使用CreateWindow函式去建立處理 另一種就是用視覺化程式設計創建出來 這裡要說明一點,所有控制元件的ID只有一個,控制代碼是不定的 所以對於控制元件的使用,我們往往是根據ID找控制代碼操作他們,所以我們需要大量使用GetDigItem()函式來操作控制元件 GetDigItem(父視窗控制代碼,控制元件ID) 那麼父視窗的控制代碼如何找到呢?? 第一種: HWND hWnd = FindWindow(NULL, L"當前視窗的名字");
第二種,如果知道子視窗控制代碼,找父視窗控制代碼方法 GetParent()引數為子視窗控制代碼 控制元件訊息 上面我們在分析訊息的時候,以及提及了控制元件訊息的相關資訊,這裡我們來深入的分析下控制元件訊息 控制元件的本質也是視窗,既然是視窗那麼他也有回撥函式,我們在建立控制元件的時候並沒有指定他的回撥函式,那麼控制元件的訊息誰處理了呢? 他其實是傳送到了父視窗中,所以我們應該在主視窗的回撥函式裡面去處理控制元件的訊息,控制元件訊息主要分為兩種型別WM_COMMAND和WM_NOTIFY,我們上面說過。控制元件分為兩種型別,一種是標準控制元件,一種是通用控制元件,所以訊息的處理也是不同的 我們如果按下一個按鈕,或者滑鼠單擊,那麼WINDOWS將會發送一個WM_COMMAND訊息給父視窗,我們這裡就分析下WM_COMMAND訊息引數
訊息來源 | wParam(高16位) | wParam(低16位) | IParam |
選單 | 0 | 選單ID | 0 |
快捷鍵 | 1 | 快捷鍵ID | 0 |
控制元件 | 控制元件通知碼 | 控制元件ID | 控制元件控制代碼 |
- 按鈕類控制元件
<wiz_code_mirror>
case WM_COMMAND:
{//當訊息是WM_COMMAND的時候,wParam的低16位是子控制元件ID
DWORD dwId = LOWORD(wParam);
switch (dwId)
{
case 1000:
MessageBox(0, TEXT("你幹嘛"), TEXT("警告"), 0);
break;
case 1001:
MoveWindow(hWnd, 200, 200, 600, 500, TRUE);
break;
case 1002:
{
WCHAR WindowNamebuf[100] = {};
GetWindowText(hWnd, WindowNamebuf, 100);
wcscat_s(WindowNamebuf, 100, L"hehe");
SetWindowText(hWnd, WindowNamebuf);
}
CheckBox控制元件一般只需要對其控制元件視窗的控制代碼進行發訊息操作就可以設定
這裡說明下,通過控制代碼操作確實可以,但是每次控制代碼都會改變,這裡的控制代碼會是變數,但是控制代碼的獲得是靠ID得來的,用定量去獲得變數,所以這裡傳入控制代碼是可以的使其被選擇上 | SendMessage(控制元件視窗控制代碼,BM_SETCHECK,1,0); |
使其取消選擇 | SendMessage(控制元件視窗控制代碼,BM_SETCHECK,1,0); 再次傳送點選訊息即可 |
獲取其狀態 | SendMessage(控制元件視窗控制代碼,BM_SETCHECK,0,0); |
- 文字框
獲取文字框內容 | GetDlgItemText(hWnd,ID,buf); |
設定文字框內容 | SetDlgItemText(hWnd,ID,buf); |
- ComboBox
向下拉組合框新增一項 | ComboBox_AddString(hwnd,szBuff); |
返回當前選擇的行號 | int dex = ComboBox_GetCursel(hwnd) |
刪除一行 | ComboBox_DeleteString(hwnd_cbb,index); |
根據文字找到第幾行 | int dex=ComboBox_FindString(hwnd,indexstart,szBuff); |
- Picture Control
訊息來源 | wParam(高16位) | wParam(低16位) | IParam |
選單 | 0 | 選單ID | 0 |
快捷鍵 | 1 | 快捷鍵ID | 0 |
控制元件 | 控制元件通知碼 | 控制元件ID | 控制元件控制代碼 |
typedef struct tagNMLISTVIEW { NMHDR hdr; // NMHDR. int iItem; // 行號. int iSubItem; // 列號. UINT uNewState; UINT uOldState; UINT uChanged; POINT ptAction; LPARAM lParam; } NMLISTVIEW, *LPNMLISTVIEW; 它的第一個欄位就是NMHDR所以WM_NOTIFY訊息的附加訊息就如下所示
訊息型別 | WPARAM | LPARAM |
WM_NOTIFY | 發生WM_NOTIFY訊息控制元件的ID | NMHDR指標 |
- 進度條
設定進度 | SendMessage(hPosControl,PBM_SETPOS,數值,0); |
獲取進度 | int nPos=SendMessage(hPosControl,PBM_GETPOS,0,0); |
- 滑塊
- List Control