VC++學習(1):Windows程序內部運行原理

Windows應用程序,操作系統,計算機硬件之間的相互關係

          

關於API:向下的箭頭表示應用程序可以通知操作系統執行某個具體的動作,如操作系統能夠控制聲卡發出聲音,但它並不知道應該何時發出何種聲音,需要應用程序告訴操作系統該發出什麼樣的聲音。這個關係好比有個機器人能夠完成行走的功能,但是,如果人們不告訴它往哪個方向上走,機器人是不會主動行走的。這裏的機器人就是操作系統,人們就是應用程序。

  那麼,應用程序是如何通知操作系統執行某個功能的呢?有過編程經驗的讀者都應該知道,在應用程序中要完成某個功能,都是以函數調用的形式實現的,同樣,應用程序也是以函數調用的方式來通知操作系統執行相應的功能的。操作系統所能夠完成的每一個特殊功能通常都有一個函數與其對應,也就是說,操作系統把它所能夠完成的功能以函數的形式提供給應用程序使用,應用程序對這些函數的調用就叫做系統調用,這些函數的集合就是Windows操作系統提供給應用程序編程的接口(Application Programming Interface),簡稱Windows API。如CreateWindow就是一個API函數,應用程序中調用這個函數,操作系統就會按照該函數提供的參數信息產生一個相應的窗口。

關於消息和消息隊列:向上的箭頭表示操作系統能夠將輸入設備的變化上傳給應用程序。如用戶在某個程序活動時按了一下鍵盤,操作系統馬上能夠感知到這一事件,並且能夠知道用戶按下的是哪一個鍵,操作系統並不決定對這一事件如何作出反應,而是將這一事件轉交給應用程序,由應用程序決定如何對這一事件作出反應。好比有個蚊子叮了我們一口,我們的神經末梢(相當於操作系統)馬上感知到這一事件,並傳遞給了我們的大腦(相當於應用程序),我們的大腦最終決定如何對這一事件作出反應,如將蚊子趕走,或是將蚊子拍死。對事件作出反應的過程就是消息響應。

  操作系統是怎樣將感知到的事件傳遞給應用程序的呢?這是通過消息機制(Message)來實現的。操作系統將每個事件都包裝成一個稱爲消息的結構體MSG來傳遞給應用程序,參看MSDN

  

MSG結構定義如下:

typedef struct tagMSG {      

      HWND   hwnd;     

      UINT   message;                   //在windows中採用宏定義,以wm_開始(windows message)

      WPARAM wParam;              //附加參數,如鍵盤上字符的ASSCI碼

      LPARAM lParam;     //附加參數

      DWORD  time;                 //消息發生的時間

      POINT  pt;      //消息發生時,光標所在位置

} MSG;


關於句柄:句柄(HANDLE),資源的標識。

  

  操作系統要管理和操作這些資源,都是通過句柄來找到對應的資源。按資源的類型,又可將句柄細分成圖標句柄(HICON),光標句柄(HCURSOR),窗口句柄(HWND),應用程序實例句柄(HINSTANCE)、HDC:device context 的句柄等等各種類型的句柄。操作系統給每一個窗口指定的一個唯一的標識號即窗口句柄。
從變量的類型區分變量的用途

int x,y;

x=30; 

y=30; 

//xy既可以用來表示座標點,也可以用來表示寬度和高度,還可以用來表示身高和體重。

typedef int WIDTH

typedef int HEIGHT

WIDTH x;

HEIGHT y;

//好處:我們從變量的類型上就可以知道xy是用來表示寬度和高度。

WinMain函數Windows程序的入口函數,由系統調用
int WINAPI WinMain(

HINSTANCE hInstance,      // handle to current instance當前實例句柄

HINSTANCE hPrevInstance,  // handle to previous instance先前的相同的實例句柄

LPSTR lpCmdLine,          // command line命令行參數

int nCmdShow              // show state最大化、最小化或者隱藏顯示

);


窗口的創建:創建一個完整的窗口需要經過下面四個操作步驟:

1、設計一個窗口類;WNDCLASS

2、註冊窗口類;

ATOM RegisterClass(
  __in  CONST WNDCLASS *lpWndClass
);

3、創建窗口; 

HWND CreateWindow(
  __in  LPCTSTR lpClassName,       //窗口類名
  __in  LPCTSTR lpWindowName,  //窗口名
  __in  DWORD dwStyle,     //窗口類型,可最小化、最大化等,是一種特徵位
  __in  int x,          //窗口顯示的位置
  __in  int y,
  __in  int nWidth,       //窗口寬度
  __in  int nHeight,
  __in  HWND hWndParent,  
  __in  HMENU hMenu,
  __in  HINSTANCE hInstance,  //應用程序句柄
  __in  LPVOID lpParam     //WM_CREATE消息的附加參數
);

BOOL DestroyWindow(    //會發送WM_DESTROY消息 __in HWND hWnd );
void PostQuitMessage(    //退出應用程序 __in int nExitCode      //WM_QUIT消息的附加信息 );

4、顯示及更新窗口。

BOOL ShowWindow(
  __in  HWND hWnd,             //顯示的窗口句柄
  __in  int nCmdShow    //顯示窗口的狀態(最大化、最小化SW_)
);

BOOL UpdateWindow( __in HWND hWnd );

設計窗口類

  typedef struct _WNDCLASS {

  UINT      style;                     //窗口類型
  WNDPROC  lpfnWndProc;           //過程函數(回調函數)
  int       cbClsExtra;                 //窗口類附加內存,一般爲0
  int       cbWndExtra;    //窗口附加內存,一般0
  HANDLE   hInstance;    //所屬應用程序實例
     HICON     hIcon;     //LoadIcon(NULL,類型),NULL表示使用windows自帶的圖標;類型爲icon的id
     HCURSOR   hCursor;
           HBRUSH    hbrBackground;
      LPCTSTR   lpszMenuName;
     LPCTSTR   lpszClassName;     //窗口類名,註冊和創建窗口時使用
  } WNDCLASS;

窗口類的類型
  在我們的程序中經常要用到一類變量,這個變量裏的每一位(bit)都對應某一種特性。當該變量的某位爲1時,表示有該位對應的那種特性,當該位爲0時,即沒有該位所對應的特性。當變量中的某幾位同時爲1時,就表示同時具有幾種特性的組合。一個變量中的哪一位代表哪種意義,不容易記憶,所以我們經常根據特徵的英文拼寫的大寫去定義一些宏,該宏所對應的數值中僅有與該特徵相對應的那一bit)爲1,其餘的bit都爲0。我們使用goto definition就能發現CS_VREDRAW=0x0001CS_HREDRAW=0x0002CS_DBLCLKS =0x0008CS_NOCLOSE=0x0200。他們的共同點就是隻有一位爲1,其餘位都爲0。如果我們希望某一變量的數值既有CS_VREDRAW特性,又有CS_HREDRAW特性,我們只需使用二進制OR|)操作符將他們進行或運算相組合,如style=CS_VREDRAW | CS_HREDRAW | CS_NOCLOSE。如果我們希望在某一變量原有的幾個特徵上去掉其中一個特徵,用取反(~)之後再進行與(&)運算,就能夠實現,如在剛纔的style的基礎上去掉CS_NOCLOSE特徵,可以用style & ~CS_NOCLOSE實現。
窗口過程函數
  第二個成員變量lpfnWndProc指定了這一類型窗口的過程函數,也稱回調函數。回調函數的原理是這樣的,當應用程序收到給某一窗口的消息時(還記得前面講過的消息通常與窗口相關的嗎?),就應該調用某一函數來處理這條消息。這一調用過程不用應用程序自己來實施,而由操作系統來完成,但是,回調函數本身的代碼必須由應用程序自己完成。對於一條消息,操作系統到底調用應用程序中的哪個函數(回調函數)來處理呢?操作系統調用的就是接受消息的窗口所屬的類型中的lpfnWndProc成員指定的函數。每一種不同類型的窗口都有自己專用的回調函數,該函數就是通過lpfnWndProc成員指定的
  舉例:汽車廠家生產汽車好比應用程序創建窗口,用戶使用汽車好比操作系統管理窗口,某種汽車在銷售前就指定好了修理站(類似回調函數),當用戶的汽車出現故障後(類似窗口收到消息),汽車用戶(類似操作系統)自己直接找到修理站去修理,不用廠家(類似應用程序)親自將車送到修理站去修理,但修理站還得由廠家事先建造好。
消息處理函數
  獲取消息:獲得WM_QUIT消息時返回爲0
BOOL GetMessage(
  __out  LPMSG lpMsg,     //要被填充的消息結構體
  __in   HWND hWnd,       //獲取哪一個窗口的消息,NULL表示獲取應用程序所擁有的消息隊列中的所有消息
  __in   UINT wMsgFilterMin,  //消息的最小值如WM_KEYFIRST,以一條消息
  __in   UINT wMsgFilterMax
);
  轉化消息:例如將WM_KEYDOWN和WM_KEYUP消息轉換爲WM_CHAR消息 
BOOL TranslateMessage(
  __in  const MSG *lpMsg
);
  分發消息:將消息發送給操作系統,再由系統發給窗口分發函數
LRESULT DispatchMessage(
  __in  const MSG *lpmsg
);

  消息盒子:彈出消息框,返回值爲ID_?,如YES等
int MessageBox(
  __in  HWND hWnd,    
  __in  LPCTSTR lpText,    //消息內容
  __in  LPCTSTR lpCaption,  //標題框
  __in  UINT uType      //消息框的類型如MB_OK
);

過程函數:  LRESULT爲Long型
LRESULT CALLBACK WindowProc(
  __in  HWND hwnd,   //窗口句柄
  __in  UINT uMsg,    //message id
  __in  WPARAM wParam,  
  __in  LPARAM lParam
);
LRESULT DefWindowProc( //默認的消息處理過程,必不可少,消息一旦產生之後,必須找到一個歸宿 __in HWND hWnd, __in UINT Msg, __in WPARAM wParam, __in LPARAM lParam );
繪製圖形文字: 
  獲得與釋放窗口的DC(畫布)
HDC GetDC(
  __in  HWND hWnd
);
int ReleaseDC( __in HWND hWnd, __in HDC hDC );
  書寫文字
BOOL TextOut( __in HDC hdc,          __in int nXStart,      //文字的位置 __in int nYStart, __in LPCTSTR lpString,   //書寫的字符串 __in int cbString      //字符串的長度 );  
  重新與結束繪製窗口:  只能用於響應WM_PAINT消息
HDC BeginPaint(
  __in   HWND hwnd,
  __out  LPPAINTSTRUCT lpPaint
);
BOOL EndPaint( __in HWND hWnd, __in const PAINTSTRUCT *lpPaint );
實例代碼

  
複製代碼
 1 #include <windows.h>
2 #include <stdio.h>
3
4 LRESULT CALLBACK WinSunProc(
5 HWND hwnd, // handle to window
6 UINT uMsg, // message identifier
7 WPARAM wParam, // first message parameter
8 LPARAM lParam // second message parameter
9 );
10
11 int WINAPI WinMain(
12 HINSTANCE hInstance, // handle to current instance
13 HINSTANCE hPrevInstance, // handle to previous instance
14 LPSTR lpCmdLine, // command line
15 int nCmdShow // show state
16 )
17 {
18 WNDCLASS wndcls;
19 wndcls.cbClsExtra=0;
20 wndcls.cbWndExtra=0;
21 wndcls.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);
22 wndcls.hCursor=LoadCursor(NULL,IDC_CROSS);
23 wndcls.hIcon=LoadIcon(NULL,IDI_ERROR);
24 wndcls.hInstance=hInstance;
25 wndcls.lpfnWndProc=WinSunProc;
26 wndcls.lpszClassName="Weixin2003";
27 wndcls.lpszMenuName=NULL;
28 wndcls.style=CS_HREDRAW | CS_VREDRAW;
29 RegisterClass(&wndcls);
30
31 HWND hwnd;
32 hwnd=CreateWindow("Weixin2003","北京維新科學技術培訓中心",WS_OVERLAPPEDWINDOW,
33 0,0,600,400,NULL,NULL,hInstance,NULL);
34
35 ShowWindow(hwnd,SW_SHOWNORMAL);
36 UpdateWindow(hwnd);
37
38 MSG msg;
39 while(GetMessage(&msg,NULL,0,0))
40 {
41 TranslateMessage(&msg);
42 DispatchMessage(&msg);
43 }
44 return 0;
45 }
46
47 LRESULT CALLBACK WinSunProc(
48 HWND hwnd, // handle to window
49 UINT uMsg, // message identifier
50 WPARAM wParam, // first message parameter
51 LPARAM lParam // second message parameter
52 )
53 {
54 switch(uMsg)
55 {
56 case WM_CHAR:
57 char szChar[20];
58 sprintf(szChar,"char is %d",wParam);
59 MessageBox(hwnd,szChar,"weixin",0);
60 break;
61 case WM_LBUTTONDOWN:
62 MessageBox(hwnd,"mouse clicked","weixin",0);
63 HDC hdc;
64 hdc=GetDC(hwnd);
65 TextOut(hdc,0,50,"計算機編程語言培訓",strlen("計算機編程語言培訓"));
66 ReleaseDC(hwnd,hdc);
67 break;
68 case WM_PAINT:
69 HDC hDC;
70 PAINTSTRUCT ps;
71 hDC=BeginPaint(hwnd,&ps);
72 TextOut(hDC,0,0,"維新培訓",strlen("維新培訓"));
73 EndPaint(hwnd,&ps);
74 break;
75 case WM_CLOSE:
76 if(IDYES==MessageBox(hwnd,"是否真的結束?","weixin",MB_YESNO))
77 {
78 DestroyWindow(hwnd);
79 }
80 break;
81 case WM_DESTROY:
82 PostQuitMessage(0);
83 break;
84 default:
85 return
DefWindowProc(hwnd,uMsg,wParam,lParam); //一定要加return呀,否則窗口不會顯示
86 }
87 return 0;
88 }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章