轉自:https://blog.csdn.net/jxf_ioriyagami/article/details/1486626
1 說在前面
因爲VC6及MFC的特色,咱們許多人從標準C++學習到VC6MFC應用程序的編程學習的過分會有一個很大的誇躍,從而感到很是的吃力。
究其緣由之一:MFC類庫設計雖然精巧,但咱們在使用MFC設計程序時,會發現MFC處處是API函數的影子。MFC並無象Delphi的VCL類庫,VB的控件庫同樣封裝得讓人幾乎徹底不用知道還有Win32API函數及其操做原理,因此要想利用VC6的MFC編程,我認爲就必定要先學習如何直接用Win32API函數來編程。對API編程中的一些關鍵的概念和原理要有必定認識,這樣纔會有一個比較平滑的過渡。以上就是我寫這個系列的初衷。
2 我假設你已有的知識:
這裏我假設你已經掌握了以下的知識,若是你在以下方面知識有點不太清楚,那要去補一補羅,不然你看到相關的內容時會有麻煩的。
下面說是我對你知識的假設:
2.1 Windows系統的文件、文件夾、路徑的概念
2.2 C語言的基本知識(基本以等級考試二級C語言爲準,還要有所擴充)
2.2.1 指針的概念。
2.2.2 函數指針概念。
2.2.3 各類自定義類型(最重要的是struct類型)的概念。
2.2.4 要知道函數的各類參數傳遞形式(值、地址、引用傳遞)。
2.2.5 typedef及其應用。
2.2.6 #include及其應用。
2.2.7 十進制、二進制、十六進制。
2.2.8 按位與、或、非運算的實質。
2.2.9 宏定義概念、使用及意義。
(每一個人老是學完了C或C++語法後纔會開始用VC6進行Windows編程學習的。可是你的基礎又是如何呢?這是一個關鍵。所以我對你的C知識作了具體的假設。)
2.3 會安裝VC6.0並安裝到一臺機上
2.4 VC6編譯界面的各組成部分及基本操做(至少會用VC6寫控制檯程序)。
2.5 VC6調試中至少要會設置斷點哦。
(呵呵!個人要求不過份吧!)
3 還必須預備的知識:
以上知識是你看本系列的前提,不過我還要給你預備一下咱們再這個階段學習中會遇到的新東西。
3.1 你將會接觸到的Win32API函數庫:
之前的DOS下或Windows的控制檯程序下,你要在顯示器上輸出文字,要用printf(),或cout的函數對象來完。但若是你要顯示一個圖形或圖象或爲你的程序設計一個圖形化的操做界面等等的,那可就慘了,一切都要你自已完成。複雜得很了!(唉!誰叫DOS是字符界面的操做系統呢!)
如今好了,在Windows下編程你可就輕鬆得多了。由於Windows操做系統都爲咱們準備好了,它提供給咱們多達數千個函數(啊!我要昏倒了。這麼多的函數要學。),咱們經過這些函數來操做Windows系統提供給咱們的各類功能。好比我要在桌面上建立並顯示一個窗口。就只要調用幾個相關的被稱爲API的函數,讓Windows來幫助咱們完成這些事。咱們是經過這些函數與Windows系統交互的,因此這些函數被稱做Win32應用程序接口函數,簡稱Win32API函數。
請不用懼怕喲!其實,這麼多的函數咱們沒必要都立刻一一學過,只要掌握了很少的具備表明性的函數的使用方法,並知道大致API函數都提供了哪些功能就能夠了。之後要用時再去查。
Window擁有現成的各類各樣的系統功能,供咱們的程序調用。那麼又是經過什麼方式來調用這些系統功能呢?原來,Window還現成提供一個接口,好讓咱們的程序來使用這些系統功能,這個結口就是Win32API函數了(注:API是應用程序接口的英文縮寫)。Win32API函數是咱們的應用程序與Windows系統交互的惟一途徑。
我並不打算這時就介紹任何一個具體的API函數。你如今只要知道你又要接觸一個函數庫了——被稱爲Win32API的函數庫,如同你之前所學的C/C++函數庫。
哈哈,這真是太好了,咱們不用再象DOS同樣,自已來完成程序界面的繪製了。咱們如今又增長一個全新的函數庫,只要調用幾個相關API函數,剩下的一切由Windows來完成就能夠啦!(固然還有不少其它功能。)
3.2 「新」的數據類型:
學完C、C++以後,咱們就能夠開始進入VC6的Windows編程學習了。可是在接下來的學習中咱們會發如今Windows編程中有許多「新」的數據類型。看下面:
BOOL、BYTE、INT、UINT、WORD、DWORD、FLOAT、CHAR、LPSTR、HINSTANCE、HWND、HMENU、HICON等等。
你看這些大寫的數據類型,你之前有見過嗎?還有不少哦!咱們之後的學習過程當中還會見到的。(呵呵!你可要有思想準備了!)
這真是讓咱們初學者迷惑呀!難道VC6中對C/C++的基本數據類型又有重大的擴充了嗎?
其實不用懼怕,只是用新瓶裝舊酒而已了。在VC6的windef.h頭文件中已有這些定義:
typedef int BOOL;
typedef unsigned char BYTE;
typedef int INT;
typedef unsigned int UINT;
typedef unsigned short WORD;
typedef unsigned long DWORD;
typedef float FLOAT;
在winnt.h中有
typedef long LONG;
typedef char CHAR;
typedef CHAR *LPSTR, *PSTR;
你看其中(粗體字)CHAR只不過是char 的別名而已,也就是說它們是等價的。只要你包含了相關的頭文件,而後你就能夠這樣申明一個變量:
INT i; //等同於int i;
CHAR a; //等同於char a;
LPSTR pa; //等同於char *pa;
明白了嗎?
我想你必定會問:爲何要這樣轉義呢?咱們直接用int 、unsighed int、char等等不就好了嗎?我一句兩句也說不清,你只要知道,微軟這樣作必定是要道理的。
哦!還有這些HINSTANCE、HWND、HMENU、HICON我沒說呢!從此你還會見到許多這樣以H爲開頭的數據類型,下面就讓我在下一節的「句柄」概念中說給你聽。
3.3 「句柄」概念
由windows系統建立出來的或加載的對象(如應用程序進程、線程、窗口、菜單、圖標、光標等等的對象),windows系統都會分配給它們一個惟一的標識值,做爲這些對象的標誌,稱之爲句柄。咱們程序中對這些對象的操做其實就是對其句柄的操做。請記住,句柄就是這些對象的「代號」了。
在編程序中,咱們須要用相應的句柄變量來保存這些句柄值,那麼用什麼類型的句柄變量呢?
就是咱們前面提到過的HINSTANCE、HWND。
像其它變量同樣(如:int a;)申明句柄變量,以下:
HINSTANCE hst; //hst變量能夠保存某個應用程序實例(即一個進程)的句柄。
HWND hwFirst; //hwFrist變量能夠保存某個窗體句柄。
HMENU hMenu; //hMenu變量能夠保存某個菜單句柄。
HICON hIcon; //hIcon變量能夠保存某個圖標句柄。
具體的使用讓我之後再慢慢與你道來啦。
那麼這些類型的實質又是什麼?
目前,它們都只是一個int類型(小語:我據說微軟也許之後會改變它的類型)。不過無論怎樣,你如今只要把HINSTANCE、HWND、HMENU、HICON當作是一個獨立的數據類型就能夠了。
3.4 消息標識
Windows系統是一個基於消息的系統。這樣的機制致使咱們的程序與以往DOS下的程序流程會有很大的不一樣。(這但是很考咱們的智慧嘍!)
從軟件使用者角度看一個Win32窗口程序運行的過程:
1) 咱們運行一個應用程序,程序建立並顯示一個咱們想要的程序窗口。
2) 當咱們對窗口進行操做時(如單擊、雙擊、右擊、按下鍵盤、最大化、最小化、關閉窗口等等),程序會完成特定的操做,如:單擊最大化、最小化按鈕時,窗口會最大化、最小化操做;對窗口中菜單項的選取時,會完成該菜單的相應功能。
從程序員的角度看一個Win32窗口程序運行的過程:
1) 咱們運行一個應用程序,程序中咱們經過Win32API函數建立並顯示一個咱們想要的程序窗口。(由咱們的程序來調用函數實現)
2) 當咱們對窗口進行操做時(如單擊、雙擊、右擊、按下鍵盤、最大化、最小化、關閉窗口等等),窗口會自動產生一系列相應的消息(這是由操做系統實現的)。
3) 具體地講:當咱們改變窗口大小時,會產生WM_SIZE消息;單擊關閉按鈕關閉窗口時,會產生WM_CLOSE消息;選取某一菜單項時,會產生WM_COMMAND消息;按下鍵盤時,會產生WM_CHAR、WM_KEYDOWN、WM_KEYUP消息;單擊鼠標左鍵時,會產生WM_LBUTTONUP、WM_LBUTTONDOWN消息等等。啊,不少不少,我也沒必要所有羅列出來了。(我說過了,這些都是由操做系統實現的)
4) windows系統會將這些消息排入咱們窗口所在線程的消息隊列中(你會明白線程是什麼嗎?)(也由Window操做系統實現),這樣咱們的程序纔有機會獲取並處理這些產生的消息。
5) 咱們的程序能夠經過Window操做系統提供的API函數來獲取這些消息及相關的信息。而後經過咱們學過的條件判斷語句來判斷是什麼消息及其相關的操做信息並可編寫相應的程序代碼,從而實現對窗口操做的不一樣反應。(由咱們的程序來實現)
看上述的過程描述,你可能要有點的抽象思惟能力了。你如今只要有對程序流程有如上的大致認知就能夠了。慢慢地我會將上述流程變成確實的程序代碼噢!
(等等,仍是有個問題:這些WM_CLOSE、WM_COMMAND、WM_CHAR、WM_KEYDOWN、WM_KEYUP、WM_LBUTTONUP、WM_LBUTTONDOWN等等的以WM_開頭的消息到底又是什麼東西呢?)
看VC6的頭文件winuser.h中的片斷:
/*
* Window Messages
*/
#define WM_NULL 0x0000
#define WM_CREATE 0x0001
#define WM_DESTROY 0x0002
#define WM_MOVE 0x0003
#define WM_SIZE 0x0005
#define WM_ACTIVATE 0x0006
/*
* WM_ACTIVATE state values
*/
#define WA_INACTIVE 0
#define WA_ACTIVE 1
#define WA_CLICKACTIVE 2
#define WM_SETFOCUS 0x0007
#define WM_KILLFOCUS 0x0008
#define WM_ENABLE 0x000A
#define WM_SETREDRAW 0x000B
#define WM_SETTEXT 0x000C
#define WM_GETTEXT 0x000D
#define WM_GETTEXTLENGTH 0x000E
#define WM_PAINT 0x000F
#define WM_CLOSE 0x0010
#define WM_QUERYENDSESSION 0x0011
#define WM_QUIT 0x0012
#define WM_QUERYOPEN 0x0013
#define WM_ERASEBKGND 0x0014
#define WM_SYSCOLORCHANGE 0x0015
#define WM_ENDSESSION 0x0016
#define WM_SHOWWINDOW 0x0018
#define WM_WININICHANGE 0x001A
#if(WINVER >= 0x0400)
#define WM_SETTINGCHANGE WM_WININICHANGE
#endif /* WINVER >= 0x0400 */
#define WM_DEVMODECHANGE 0x001B
#define WM_ACTIVATEAPP 0x001C
#define WM_FONTCHANGE 0x001D
#define WM_TIMECHANGE 0x001E
#define WM_CANCELMODE 0x001F
#define WM_SETCURSOR 0x0020
#define WM_MOUSEACTIVATE 0x0021
#define WM_CHILDACTIVATE 0x0022
#define WM_QUEUESYNC 0x0023
#define WM_GETMINMAXINFO 0x0024
// end_r_winuser
/*
* Struct pointed to by WM_GETMINMAXINFO lParam
*/
typedef struct tagMINMAXINFO {
POINT ptReserved;
POINT ptMaxSize;
POINT ptMaxPosition;
POINT ptMinTrackSize;
POINT ptMaxTrackSize;
} MINMAXINFO, *PMINMAXINFO, *LPMINMAXINFO;
// begin_r_winuser
#define WM_PAINTICON 0x0026
#define WM_ICONERASEBKGND 0x0027
#define WM_NEXTDLGCTL 0x0028
#define WM_SPOOLERSTATUS 0x002A
#define WM_DRAWITEM 0x002B
#define WM_MEASUREITEM 0x002C
#define WM_DELETEITEM 0x002D
#define WM_VKEYTOITEM 0x002E
#define WM_CHARTOITEM 0x002F
#define WM_SETFONT 0x0030
#define WM_GETFONT 0x0031
#define WM_SETHOTKEY 0x0032
#define WM_GETHOTKEY 0x0033
#define WM_QUERYDRAGICON 0x0037
#define WM_COMPAREITEM 0x0039
#define WM_COMPACTING 0x0041
#define WM_COMMNOTIFY 0x0044 /* no longer suported */
#define WM_WINDOWPOSCHANGING 0x0046
#define WM_WINDOWPOSCHANGED 0x0047
#define WM_POWER 0x0048
/*
* wParam for WM_POWER window message and DRV_POWER driver notification
*/
#define PWR_OK 1
#define PWR_FAIL (-1)
#define PWR_SUSPENDREQUEST 1
#define PWR_SUSPENDRESUME 2
#define PWR_CRITICALRESUME 3
#define WM_COPYDATA 0x004A
#define WM_CANCELJOURNAL 0x004B
// end_r_winuser
/*
* lParam of WM_COPYDATA message points to...
*/
typedef struct tagCOPYDATASTRUCT {
DWORD dwData;
DWORD cbData;
PVOID lpData;
} COPYDATASTRUCT, *PCOPYDATASTRUCT;
// begin_r_winuser
#if(WINVER >= 0x0400)
#define WM_NOTIFY 0x004E
#define WM_INPUTLANGCHANGEREQUEST 0x0050
#define WM_INPUTLANGCHANGE 0x0051
#define WM_TCARD 0x0052
#define WM_HELP 0x0053
#define WM_USERCHANGED 0x0054
#define WM_NOTIFYFORMAT 0x0055
#define NFR_ANSI 1
#define NFR_UNICODE 2
#define NF_QUERY 3
#define NF_REQUERY 4
#define WM_CONTEXTMENU 0x007B
#define WM_STYLECHANGING 0x007C
#define WM_STYLECHANGED 0x007D
#define WM_DISPLAYCHANGE 0x007E
#define WM_GETICON 0x007F
#define WM_SETICON 0x0080
#endif /* WINVER >= 0x0400 */
#define WM_NCCREATE 0x0081
#define WM_NCDESTROY 0x0082
#define WM_NCCALCSIZE 0x0083
#define WM_NCHITTEST 0x0084
#define WM_NCPAINT 0x0085
#define WM_NCACTIVATE 0x0086
#define WM_GETDLGCODE 0x0087
#define WM_NCMOUSEMOVE 0x00A0
#define WM_NCLBUTTONDOWN 0x00A1
#define WM_NCLBUTTONUP 0x00A2
#define WM_NCLBUTTONDBLCLK 0x00A3
#define WM_NCRBUTTONDOWN 0x00A4
#define WM_NCRBUTTONUP 0x00A5
#define WM_NCRBUTTONDBLCLK 0x00A6
#define WM_NCMBUTTONDOWN 0x00A7
#define WM_NCMBUTTONUP 0x00A8
#define WM_NCMBUTTONDBLCLK 0x00A9
#define WM_KEYFIRST 0x0100
#define WM_KEYDOWN 0x0100
#define WM_KEYUP 0x0101
#define WM_CHAR 0x0102
#define WM_DEADCHAR 0x0103
#define WM_SYSKEYDOWN 0x0104
#define WM_SYSKEYUP 0x0105
#define WM_SYSCHAR 0x0106
#define WM_SYSDEADCHAR 0x0107
#define WM_KEYLAST 0x0108
#if(WINVER >= 0x0400)
#define WM_IME_STARTCOMPOSITION 0x010D
#define WM_IME_ENDCOMPOSITION 0x010E
#define WM_IME_COMPOSITION 0x010F
#define WM_IME_KEYLAST 0x010F
#endif /* WINVER >= 0x0400 */
#define WM_INITDIALOG 0x0110
#define WM_COMMAND 0x0111
#define WM_SYSCOMMAND 0x0112
#define WM_TIMER 0x0113
#define WM_HSCROLL 0x0114
#define WM_VSCROLL 0x0115
#define WM_INITMENU 0x0116
#define WM_INITMENUPOPUP 0x0117
#define WM_MENUSELECT 0x011F
#define WM_MENUCHAR 0x0120
#define WM_ENTERIDLE 0x0121
#define WM_CTLCOLORMSGBOX 0x0132
#define WM_CTLCOLOREDIT 0x0133
#define WM_CTLCOLORLISTBOX 0x0134
#define WM_CTLCOLORBTN 0x0135
#define WM_CTLCOLORDLG 0x0136
#define WM_CTLCOLORSCROLLBAR 0x0137
#define WM_CTLCOLORSTATIC 0x0138
#define WM_MOUSEFIRST 0x0200
#define WM_MOUSEMOVE 0x0200
#define WM_LBUTTONDOWN 0x0201
#define WM_LBUTTONUP 0x0202
#define WM_LBUTTONDBLCLK 0x0203
#define WM_RBUTTONDOWN 0x0204
#define WM_RBUTTONUP 0x0205
#define WM_RBUTTONDBLCLK 0x0206
#define WM_MBUTTONDOWN 0x0207
#define WM_MBUTTONUP 0x0208
#define WM_MBUTTONDBLCLK 0x0209
#if(_WIN32_WINNT >= 0x0400)
#define WM_MOUSEWHEEL 0x020A
#endif /* _WIN32_WINNT >= 0x0400 */
#if (_WIN32_WINNT < 0x0400)
#define WM_MOUSELAST 0x0209
#else
#define WM_MOUSELAST 0x020A
#endif /* if (_WIN32_WINNT < 0x0400) */
#if(_WIN32_WINNT >= 0x0400)
#define WHEEL_DELTA 120 /* Value for rolling one detent */
#endif /* _WIN32_WINNT >= 0x0400 */
#if(_WIN32_WINNT >= 0x0400)
#define WHEEL_PAGESCROLL (UINT_MAX) /* Scroll one page */
#endif /* _WIN32_WINNT >= 0x0400 */
#define WM_PARENTNOTIFY 0x0210
#define MENULOOP_WINDOW 0
#define MENULOOP_POPUP 1
#define WM_ENTERMENULOOP 0x0211
#define WM_EXITMENULOOP 0x0212
#if(WINVER >= 0x0400)
#define WM_NEXTMENU 0x0213
// end_r_winuser
typedef struct tagMDINEXTMENU
{
HMENU hmenuIn;
HMENU hmenuNext;
HWND hwndNext;
} MDINEXTMENU, * PMDINEXTMENU, FAR * LPMDINEXTMENU;
// begin_r_winuser
#define WM_SIZING 0x0214
#define WM_CAPTURECHANGED 0x0215
#define WM_MOVING 0x0216
#define WM_POWERBROADCAST 0x0218
#define WM_DEVICECHANGE 0x0219
#define WM_IME_SETCONTEXT 0x0281
#define WM_IME_NOTIFY 0x0282
#define WM_IME_CONTROL 0x0283
#define WM_IME_COMPOSITIONFULL 0x0284
#define WM_IME_SELECT 0x0285
#define WM_IME_CHAR 0x0286
#define WM_IME_KEYDOWN 0x0290
#define WM_IME_KEYUP 0x0291
#endif /* WINVER >= 0x0400 */
#define WM_MDICREATE 0x0220
#define WM_MDIDESTROY 0x0221
#define WM_MDIACTIVATE 0x0222
#define WM_MDIRESTORE 0x0223
#define WM_MDINEXT 0x0224
#define WM_MDIMAXIMIZE 0x0225
#define WM_MDITILE 0x0226
#define WM_MDICASCADE 0x0227
#define WM_MDIICONARRANGE 0x0228
#define WM_MDIGETACTIVE 0x0229
#define WM_MDISETMENU 0x0230
#define WM_ENTERSIZEMOVE 0x0231
#define WM_EXITSIZEMOVE 0x0232
#define WM_DROPFILES 0x0233
#define WM_MDIREFRESHMENU 0x0234
#if(_WIN32_WINNT >= 0x0400)
#define WM_MOUSEHOVER 0x02A1
#define WM_MOUSELEAVE 0x02A3
#endif /* _WIN32_WINNT >= 0x0400 */
#define WM_CUT 0x0300
#define WM_COPY 0x0301
#define WM_PASTE 0x0302
#define WM_CLEAR 0x0303
#define WM_UNDO 0x0304
#define WM_RENDERFORMAT 0x0305
#define WM_RENDERALLFORMATS 0x0306
#define WM_DESTROYCLIPBOARD 0x0307
#define WM_DRAWCLIPBOARD 0x0308
#define WM_PAINTCLIPBOARD 0x0309
#define WM_VSCROLLCLIPBOARD 0x030A
#define WM_SIZECLIPBOARD 0x030B
#define WM_ASKCBFORMATNAME 0x030C
#define WM_CHANGECBCHAIN 0x030D
#define WM_HSCROLLCLIPBOARD 0x030E
#define WM_QUERYNEWPALETTE 0x030F
#define WM_PALETTEISCHANGING 0x0310
#define WM_PALETTECHANGED 0x0311
#define WM_HOTKEY 0x0312
#if(WINVER >= 0x0400)
#define WM_PRINT 0x0317
#define WM_PRINTCLIENT 0x0318
#define WM_HANDHELDFIRST 0x0358
#define WM_HANDHELDLAST 0x035F
#define WM_AFXFIRST 0x0360
#define WM_AFXLAST 0x037F
#endif /* WINVER >= 0x0400 */
#define WM_PENWINFIRST 0x0380
#define WM_PENWINLAST 0x038F
#if(WINVER >= 0x0400)
#define WM_APP 0x8000
#endif /* WINVER >= 0x0400 */
/* * NOTE: All Message Numbers below 0x0400 are RESERVED. * * Private Window Messages Start Here: */ #define WM_USER 0x0400 #if(WINVER >= 0x0400) /* wParam for WM_SIZING message */ #define WMSZ_LEFT 1 #define WMSZ_RIGHT 2 #define WMSZ_TOP 3 #define WMSZ_TOPLEFT 4 #define WMSZ_TOPRIGHT 5 #define WMSZ_BOTTOM 6 #define WMSZ_BOTTOMLEFT 7 #define WMSZ_BOTTOMRIGHT 8 #endif /* WINVER >= 0x0400 */ #ifndef NONCMESSAGES 哦!這些WM_開頭的所謂的消息只不過是一系列16進制整型數值的符號常量而已。每個不一樣的整型數值表明着一個窗口某一操做的標識,所以咱們將這些數值或者說以WM_開頭的符號常量稱之爲消息了。 也就說,咱們在窗口中做各類不一樣的操做,Windows系統會產生各類相應的數值。咱們就是經過條件語句比較這些數值來判斷咱們在窗口中所作的操做的。 3.5 資源標識 (你看我沒完沒了地介紹一個個概念,以爲煩不煩?不用你說,我自已也有點煩了。唉!不過這些彷佛是必要的,因此我不得不堅持下去。不過,還好,剩下的很少了。) 那麼VC6中資源是什麼一種概念呢? 咱們的程序中可能要用到各類圖標(*.ico文件)、各類形狀的鼠標(*.cur文件)、各類圖像(*.bmp/*.gif等等)、各類聲音(*.wav等)、各類菜單……,這些就是咱們這裏所說的資源了。 每個要用到資源,咱們都要給它分配一個編號或名稱,做爲這個資源的標識。以後咱們的程序只是經過這個編號或名稱來訪問這些資源了。因此這些編號或名稱咱們稱之爲資源標識。好了,如今你也只要有了一個大致的映象就能夠了,具體的形式和應用讓我慢慢再與你說了。 (各位能夠提出你的疑問,白雲小飛必定會盡力回覆的。) 啊!終於結束冗長的概念解說了,看到這裏,請先回顧一下咱們前面講的東西。而後嘛——咱們能夠開工啦!。