亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

Windows編程基礎 - 概述

2019-11-17 05:18:31
字體:
來源:轉載
供稿:網友
1.1、Windows的介紹
  Windows是一種基于圖形界面的多任務操作系統。為這個環境開發的程序有著相同的外觀和命令結構。對用戶 來說,這使得學習使用Windows應用程序變得輕易了。為了幫助開發Windows應用程序,Windows提供了大量的內建 函數以方便地使用彈出菜單、滾動條、對話框、圖標和其他一些友好的用戶界面應該具有的特性。
  Windows運行應用程序以硬件無關的方式來處理視頻顯示、鍵盤、鼠標、打印機、串行口以及系統時鐘。最值 得注重的Windows特性就是其標準化的圖形用戶界面。統一的界面使用圖片或圖標來代表磁盤驅動器、文件、子目 錄以及其它操作系統的命令和動作。統一的用戶界面也為程序員帶來了好處。例如,你可以很方便地使用常見菜單和對話框的內建函數。所有的菜單都具有相同風格的鍵盤和鼠標接口,因為是Windows而不是程序員在實現它。
  Windows的多任務環境答應用戶在同一時刻運行多個應用程序或同一個應用程序的多個實例。一個應用程序可 能處于激活狀態。激活的應用程序是指它正接收用戶的輸入。因為每一個瞬間僅有一個程序能夠被處理,因此同一時間也只能有一個應用程序處于激活狀態。但是,可以有任意個數的并行運行的任務。

1.2、Windows的簡要歷史
  Windows最初由Microsoft公司在1983年11月公布,1985年11月推出了第一公開發行版本,即1.01版。此后兩年,1.01版進行了幾次修改以滿足國際市場的需求,并增減了一些顯示器和打印機的驅動程序。1987年11月發行的Windows 2.0版在用戶界面上做了些改進。例如:重疊式窗口的引入,還增強了鍵盤和鼠標接口,非凡是增強了選單和對話框的功能...(略)

1.3、用戶界面的構件

  1.3.1 窗口
  窗口是屏幕上與一個應用程序相關的矩形區域,它是用戶與產生該窗口的應用程序之間的可視界面。對應用程序來說,窗口是應用程序控制下的屏幕上的一個矩形區域,應用程序創建并控制窗口的所有方面。當用戶啟動一個應用程序時,一個窗口就被創建。每當用戶操作窗口中的對象時,程序就有所響應。

  1.3.2 邊框
  絕大多數窗口都有一個環繞著它的邊框,邊框不僅作為窗口的邊界,它也用來指明窗口的狀態,即窗口是否是一個活動窗口。當我們將鼠標指針放在邊框上按下鼠標鍵并移動鼠標時,就可以改變窗口的大小。

  1.3.3 標題欄
  標題欄位于窗口的頂部,其中顯示的文本信息用于標注程序,一般是應用程序的名字,這便于用戶知道哪個應用程序正在運行。標題欄的顏色反映一個窗口是否是一個活動窗口。

  1.3.4 控制框
  控制框是每個窗口左上方的小圖片,每個應用程序都使用它。在控制圖標上單擊鼠標鍵會使Windows顯示系統菜單。系統菜單它提供了諸如還原、移動、大小、最小化、最大化以及關閉這樣的標準操作。

  1.3.5 最小化圖標
  每個Windows 98及Windows NT應用程序都在窗口的右上角顯示三個圖標。最左邊的圖標是一段短下劃線,這就是最小化圖標。它可以使用程序被最小化。

  1.3.6 最大化圖標
  最大化圖標是三個圖標中中間的那一個,看起來象兩個小窗口。使用最大化圖標可以使用應用程序占滿整個屏幕。假如選擇了這個圖標,其它應用程序窗口都會被蓋住。

  1.3.7 垂直滾動條
  假如有必要,應用程序可以顯示一個垂直滾動條。垂直流動條顯示在應用程序窗口的右邊,在兩端有兩個方向相反的箭頭。它還有一個著色的棒和一個透明的窗口塊。后者被用于顯示當前顯示內容與整個文檔的關系。你可以用滾動條來選擇顯示哪一頁。一般在任何一個箭頭上單擊一下會使顯示內容移動一行。單擊向上箭頭下方的窗口塊并拖動它會使屏幕輸出快速更新到應用程序屏幕輸出的任意位置。

  1.3.8 水平滾動條
  也可以顯示一個水平滾動條 。水平滾動條顯示在窗口的底部,具有與垂直滾動條類似的功能。你用它來選擇 要顯示哪些列。一般在任何一個箭頭上單擊一個會使顯示內容移動一列。單擊向左箭頭右邊的窗口塊并拖動它會使屏幕輸出快速更新到應用程序屏幕輸出的任意位置。

  1.3.9 選單欄
  一個可選擇的菜單條可以顯示在標題條的下方。通過菜單條來選擇菜單和子菜單。這種選擇可以通過用鼠標單擊,也可以用熱鍵組合來實現。熱鍵組合經常是ALT與命令中帶下劃線的字母的組合,比如File命令中的 “F”。

  1.3.10 用戶區
  通常用戶區占據了窗口最大的部分。這是應用程序的基本輸出區域。應當由應用程序來復雜治理用戶區。另外,應用程序可以輸出到用戶區。

1.4、面向對象的思維方法
  對于程序員來說,面向對象意味著非常熟悉的事物:將世界看成是一組彼此相關并相互通信的實體即對象組成,每個對象有一個名字來標識,這是人們通??创澜绲姆绞健@?,當看見一輛汽車時,所見到的是一輛汽車,而不是一大堆原子。人們可以將汽車分解為車輪、發動機、車門、油箱等,它們都是具體的實體即對象。
  對象之間的通信被稱為發送消息,即一個對象請求另一個對象執行某種方式的操作。例如,交叉路口的紅燈“請求”駕駛員停車,駕駛員在接受到消息之后,他所執行的動作是踏下制動踏板,這有向汽車發送了一條消息,汽車在接受到此消息之后,又將該消息分解之后發送到相關的對象上:制動器作用于車輪上,將動能轉變成為勢能,使車速降下來;尾燈又向它后面的其它車輛的駕駛員發送消息;各種儀表盤向駕駛員反饋出所發送的消息的動作結果。
  從程序員角度而言,對象是內存中一塊有名的存儲單元。我們通常所謂的變量就是一種數據對象,但對象的概念比變量的含義更廣義,通常將對象定義成為包含有數據和代碼的內存區域,數據表征對象的特征,而代碼用于響應消息,使對象進行某些動作。從屏幕上顯示的一個可視的窗口對象為例,我們可以對比分析一下用戶心目中的對象和程序員心目中的對象的關系。窗口對象的特征,例如顏色、長度、其中顯示的信息等,在程序中被表示為數據,用戶對窗口對所做的操作,例如移動窗口、改變窗口的大小等,使得用戶向窗口發送了消息,這些消息引起了計算機(內存中的)對象執行相應的代碼,代碼執行的結果改變了對象中的數據,使對應的可以視對象 的位置和大小發生了變化。
  對象為響應消息所執行的代碼被稱為方法,對象中保存的數據構成對象的屬性,對象的抽象定義就是執行某些動作,否則,沒有其它途徑可以使一個對象動作起來。向一個對象發送消息在程序中表示為:

  functionName(id, arg1, arg2, ...);

  其中,消息是functionName,id是標識對象的一個對象名,或稱其為對象的標識符,Windows使用某種類型的 數據來作為對象的標識符,這個標識符號常被稱為對象的句柄。arg1等為消息所帶的參數。
  雖然發消息類似于標準的函數調用,但消息也有函數調用中沒有的特性,例如,消息始終在執行一選擇機制,其參數與其它消息區別開來,從而告訴該對象完成什么樣的操作。一個函數名始終指向內存中該函數的代碼所位于的確定地址,消息并不指向內存中的某地址,但卻告訴接受消息的對象要引用的內存地址是什么。函數不僅說明操作,而且還要執行如何完成該操作的方法。消息只說明該操作,在對象中定義的方法說明如何完成該操作。當向不同的對象發送相同的消息時,所執行的方法是不同的。
  在面向對象的程序設計中,每個對象由一個類來定義,類是對一組性質相同的對象的程序描述,它是由概括了一組對象共同性質的方法和數據組成。從一組對象中抽象出公共的方法與數據,將它們保存在一個類中是面向對象程序設計的核心。
  在日常生活中,我們也以類這種方式來定義客觀對象。通過對客觀對象進行抽象,我們將性質相同的對象歸為一類,形成概念,例如,人類、蘋果類、食品類等。通過對客觀對象分類,我們也可以更好地熟悉客觀對象,例如,當知道張三是一個人時,不用對張三進行更多的描述,我們已知道張三作為一個人所具有的特征和行為,因為它們已經在“人”類中進行了描述。
  在面向對象的程序中,類被用作樣板來生產具有相同行為方式的對象。類就像是生產對象的一個工廠,在生產對象時,對象具有類中所描述的同樣的數據結構和方法,同時,對象的每個數據在創立之初取得一個初始值,形成對象的初始狀態。對象通過發送消息相互作用,對象的狀態從一種狀態過渡到另一種狀態,當所有的有關對象到達某種特定的狀態時就得程序的運行結果。
  使用類產生對象的過程也稱為生成該類的一個實例。因此,對象也可以定義為對象是類的一個實例。定義類也意味著將該類的對象公用代碼放在內存的公共區域中,而不必對每個對象都將它們的代碼和數據重新進行一次描述,這減輕了程序員的勞動強度。我們可以將一些常用對象定義放在一個公用庫中,而在程序中需要該類的一個對象時,就創建該類的一個實例。Windows已為程序員預定義了許多像按鈕、滾動杠和對話框等對象的類,當程序員需要這些類的對象時,僅需創立該類的實例即可。對于同一個類的不同對象,在建立對象時其初始狀態不同,因而這些對象在屏幕上顯示的位置、大小等屬性也不相同,但同類的對象的操作是相同的(因為它們共用相同的方法)。這也就是為什么不同的Windows應用程序對用戶表現出一致的操作特性的原因之一。


1.5、句柄
  Windows應用程序中存在許多對象,例如選單、窗口、圖標、內存對象、位圖、刷子、設備對象和程序實例等,在Windows中,對象使用句柄進行標識,這樣,通過使用一個句柄,應用程序可以訪問一個對象。
  在Windows軟件開發工具中,句柄被定義為一種新的數據類型。在應用程序中,對句柄的使用一般只有賦值(句柄可以被賦以初始值、被改變為用于標識同類對象中的另一個對象和被用作函數的參數)、與NULL進行相等比較(判定一個句柄是否為一個有效的句柄)和與標識同類對象的另一個句柄進行相等比較(判定兩個句柄是否標識同一個對象),沒有其它的運算。雖然在有的書中介紹說句柄是一個十六位的整數,但實際情況并不這樣簡單,它的長度將會隨著不同的計算機平臺和Windows的發展而有所變化,例如,在32位Windows中,句柄將是一個32位的數據,并且不是整數類型。
  一種通用句柄類型為HANDLE,在Windows 3.1以前的版本中,它可被用于標識所有種類的對象,在Windows 3.1中,部分地保留了這一特點,在本教程的程序中也有所反映。在Windows 3.1中,從HANDLE類型又派生出了一些新的句柄數據類型,每種類型的句柄用于標識一種類型的對象,下面是一些常見的句柄類型:

類型說明HANDLE通用句柄類型HWND標識一個窗口對象HDC標識一個設備對象HMENU標識一個選單對象HICON標識一個圖標對象HCURSOR標識一個光標對象HBRUSH標識一個刷子對象HPEN標識一個筆對象HFONT標識一個字體對象HINSTANCE標識一個應用程序模塊的一個實例HLOCAL標識一個局部內存對象HGLOBAL標識一個全局內存對象
1.6、數據類型及常量
  為便于開發Windows應用程序,Windows的開發者新定義了一些數據類型。這些數據類型或是與C/C++中已有的數據類型同義,或是一些新的結構數據類型。引入這些類型的主要目的是為便于程序員開發Windows應用程序,同時也是為了增強程序的可讀性;另一個目的是為了便于程序將來能被移植到其它種類的計算機平臺上或適應Windows將來的新版本的變化。例如,本教程目前使用16位API(application PRogram Interface),現在Windows的版本使用32位API,只要將HANDLE等句柄類型定義為32位長,然后重新編譯程序,就可以很方便地將一個使用16位API的Windows應用程序改為使用32位API的程序,使其能運行在32位API Windows上。大部分的數據類型在Windows.h中定義,下面是在這個文件中定義的部分類型:

  #define  PASCAL     pascal
  #define  NEAR      near
  #define  FAR       far
  typedef  unsigned char  BYTE
  typedef  unsigned short Word
  typedef  unsigned long  DWORD
  typedef  long      LONG
  typedef  char       *PSTR
  typedef   char NEAR    *NPSTR
  typedef  char FAR    *LPSTR
  typedef  void      VOID
  typedef  int       *LPINT
  typedef  LONG      (PASCAL FAR * FARPROC)();

  在Windows.h中,使用typedef還定義了一些新的結構類型。這些結構類型的名字也使用大寫形式的標識符:

類型說明MSG消息結構WNDCLASS窗口的類的結構PAINTSTRUCT繪圖結構POINT點的坐標的結構RECT矩形結構
  我們在這里以類型MSG為例來說明類型的定義方法,對于其它類型,在以后用到時再作具體地說明。類型MSG是一個消息結構,它的定義方式及其各域的含義如下:

  typedef struct tagMSG {
     HWND     hWnd;  // 窗口對象的標識符,該條消息傳遞到它所標識的窗口上
     UINT    message;  // 消息標識符,標識某個特定的消息
     WPARAM   wParam;  // 隨同消息傳遞的16位參數
     LPARAM   lParam;  // 隨同消息傳遞的32位參數
     DWORD     time;  // 消息產生的時間
     POINT      pt;  // 產生消息時光標在屏幕上的坐標
  } MSG;
  typedef MSG FAR *LPMSG;

  其中的POINT類型的定義是:

  typedef struct tagPOINT {
    int x;     /* X坐標 */
    int y;    /* Y坐標 */
  } POINT;
  typedef POINT FAR *LPPOINT;

  Windows.h在定義大部分類型的同時,還定義了該類型的指針類型。例如,上例中的LPPOINT和LPMSG等,其中字母前綴LP表示遠指針類型;若使用NP作為一個類型的前綴,則表示近指針類型;若使用P作為一個類型的前綴時,則表示一般的指針類型,這時由編譯程序時所使用的內存模塊決定這種指針是遠指針或是近指針。在Windows.h中說明的大部分指針類型都采用這里介紹的方法進行說明,例如,LPRECT,它表示一個RECT類型的遠指針。
  在Windows.h中說明的大部分指針類型使用了C/C++的要害字const,假如一個指針類型的名字前綴為LPC、NPC或PC,則其中的字母C表示這種類型的指針變量所指向的變量不能通過該指針變量來修改,這種指針類型一般采用下述方法進行說明:

  typedef const POINT FAR * LPCPOINT;
  typedef const REC  FAR * LPCRECT;

  一個使用const修飾的指針(稱其為const指針)可以指向沒有使用const修飾的變量,但沒有使用const修飾的指針不能指向const修飾的變量,例如:

  const POINT pt;
  LPCPOINT lpPoint = &pt;   // 正確
  LPPOINT  lpPoint = &pt;   // 錯誤

  當向函數傳遞參數時,必須非凡注重這個問題,例如:

  void fun(LPPOINT lPPT) ;
  ......
  LPCPOINT lpPoint ;
  fun(lpPoint) ;

  編譯器將指示這個函數調用語句是錯誤的。所以,在一個函數不修改一個指針參數所指向的變量的情況下,最好將該參數說明為const指針,使const類型的指針也能用于該函數的參數。Windows.h中說明的大部分函數使用了const指針參數。
  在Windows.h中,大多數語句是用于定義一個常量,例如:

  #denfine WM_QUIT 0X0012

  該語句用標識符WM_QUIT來表示編號為0X0012的消息。每個常量由一個前綴和表示其含義的單詞組成的標識符組成,兩者之間用下畫線隔開。前綴表明這些常量所屬的一般范疇。下面是一些前綴和它們所屬的范疇的說明。

類型說明CS窗口類的風格(Class Style)IDI預定義的圖標對象的標識符(IDentity of Icon)IDC預定義的光標對象的標識符(IDentity of Cursor)WS窗口的風格(Windows Style)CW創建窗口(Create Windows)WM窗口消息(Windows Message)DT繪制文本(Drawing Text)
  在變量名的表示方法方面,Windows推薦使用一種稱為“匈牙利表示法”的方法。每個變量名用小寫字母或描述了變量的數據類型的字母作為前綴,變量的名字緊跟其后,且用大寫字母開始的單詞(一個或多個單詞)表示其含義,這樣每個變量都能附加上其數據類型的助記符。例如:

  WORD wOffset ;  /* w表示WORD類型 */
  DWORD dwValue ;  /* dw表示DWORD類型 */

  下面是Windows中常使用的一些字母前綴和它們所代表的數據類型:

類型說明bBOOL,布爾類型byBYTE類型cchar類型dwDWORD類型fn函數類型i整型lLONG類型lp遠(長)指針(long pointer)n短整型np近(短)指針(near pointer)p指針s字符串sz以'/0'結尾的字符串wWORD類型xshort,用于表示X坐標時yshort,用于表示Y坐標時

  Windows程序員也可以根據上述思想和使用目的,發明一些其他的前綴,但要注重,對這些前綴的使用必須保持前后一致。在Windows中,所有的函數根據其用途來命名,它們一般由2到3個英文單詞組成,每個單詞的第一個字母大寫,例如,函數CreateWindow(),由該函數的名字可以知道它的用途是創建一個窗口。 三層交換技術 交換機與路由器密碼恢復 交換機的選購 路由器設置專題 路由故障處理手冊 數字化校園網解決方案

1.7、應用程序使用的一些術語
  本節介紹Winodws應用程序使用的一些術語及其相關概念,在后面的章節中介紹有關的內容時,再對其中的概念進行具體的討論。

  1.7.1 模塊
  在Windows中,術語“模塊”一般是指任何能被裝入內存中運行的可執行代碼和數據的集合。更明確地講,模塊指的就是一個.EXE文件(又稱為應用程序模塊),或一個動態鏈接庫(DLL — Dynamic Linking Library,又被稱為動態鏈接庫模塊或DLL模塊),或一個設備驅動程序,也可能是一個程序包含的能被另一個程序存取的數據資源。模塊一詞也被用于特指自包含的一段程序。例如,一個可單獨編譯的源文件,或該源文件被編譯器處理之后所生成的目標程序。當制作一個程序時,模塊一詞用于指被連接在一起的許多模塊中的某個模塊。
  Windows本身由幾個相關的模塊組成,Windows API函數就是在Windows啟動時裝入內存中的幾個動態鏈接庫模塊實現的。其中的三個主要模塊是USER.EXE(用于窗口治理等)、KERNEL.EXE(用于內存治理的多任務調度)和GDI.EXE(圖形設備接口,用于圖形輸出等)。

  1.7.2 應用程序
  一個Windows應用程序是被Windows調用或在Windows下運行的一個程序,這個程序可以調用靜態連接庫(也就是C的運行時間庫)中的函數和DLL的函數,它也可以啟動其它的應用程序。一個應用程序在運行時的輸入被Windows捕捉,并以消息的形式傳送到應用程序的活動窗口上。一個應用程序的輸出也是通過Windows進行的,所有的輸出首先被送給Windows。許多MS-DOS應用程序基本上占據整個計算機,并認為所有的計算機資源只屬于該應用程序,應用程序告訴相對被動的MS-DOS應做什么。在一個Windows應用程序中,Windows自身是非常主動的,并且和應用程序協同得非常緊密。Windows治理著計算機的所有資源,并調度這些資源,使它們可為正在Windows上運行的所有應用程序共享。

  1.7.3 任務和實例
  Windows將運行的應用程序實例作為不同的任務。當一個應用程序的多個實例在運行時,它們也被Windows當作不同的任務。Windows為一個模塊的每一個實例都裝入一個缺省數據段,但可執行代碼只能裝入一次。也就是說,同一個模塊的實例共享相同的代碼,但有自己私用的數據段。
  對每一個模塊、任務或實例,Windows分別使用一個句柄來標識它。在窗口對象的私有數據存儲區存儲有一個應用程序的任務句柄、實例句柄和模塊句柄。任務句柄被Windows的任務調度程序用于進行任務調度。通過模塊句柄,Windows可以知道一個模塊當前有多少實例正在運行。同一個模塊的不同實例有相同的模塊句柄,但有不同的任務和實例句柄。當Windows由于內存治理的需要而廢棄了一個實例的代碼段時,通過模塊句柄,Windows可以從模塊中重新裝入這個實例所需的代碼。

  1.7.4 動態鏈接庫
  DLL是一種有別于MS-DOS應用程序所使用的庫模塊(例如 C的運行時間庫)的一種非凡的庫模塊,它含有可能 被其它應用程序調用的函數。一個DLL在運行時被動態地連接到一個應用程序中或另一個DLL中,而不是在制作應用程序時靜態地連接到應用程序中的(這種方法是在制作MS-DOS應用程序中使用的方法,它們在Windows應用程序中仍然可以繼續被使用)。使用DLL的好處在于,當有多個應用程序使用同一個DLL并且同時在Windows中運行時,該DLL在內存中只有一個實例。

  1.7.5 應用程序設計接口
  應用程序設計接口(API)是應用程序用于操作四周環境的一組函數調用接口。Windows API大約有600多個函 數,學習Windows程序設計的許多工作就是學習如何使用這些API。

  1.7.6 Windows下的函數
  在進行Windows應用程序設計中,程序員除了需要知道有關一個函數的常用信息(例如函數的名字,近函數或遠函數,返回類型以及應如何調用)之外,同時還要知道更多的內容:一個回調函數、引出函數或是一個引入函數。
  引出函數:這個術語與一個函數如何在一個模塊中說明而在另一個模塊中被調用有關。引出函數是在一個模塊中定義而在這個模塊之外被調用的一種函數;或是被Windows或是被另一個模塊調用。這些函數必須以一種特定的方式進行說明,并被編譯器作非凡的處理。這樣,當它們被調用時,它們會被正確地束定到合適的數據段上。DLL為其它模塊提供要被調用的函數,因此,每個DLL一般都帶有一個DLL庫,以便應用程序可以合法地調用DLL中的函數。DLL庫由DLL中每個引出函數的入口點組成。整個Windows API就是由構成Windows環境的不同的模塊所引出的函數組成,這些API函數的入口點在一個名為IMPORT.LIB的DLL庫中說明。
  引入函數:在DLL中引出的函數若要能為一個模塊調用,必須在這個模塊中將這個函數說明為引入函數。由此可見引出函數和引入函數表達的是從兩種角度處理同一個函數的術語:引出模塊中的一個函數使得這個函數能被其它模塊調用;調用引出函數的模塊通過引入這個函數才能調用它。在制作Windows應用程序時,連接器自動包含一個名為IMPORT.LIB的庫文件。這個文件答應應用程序調用Windows API中的函數。這個文件被稱為引入庫。引入庫提供了應用程序與一個到多個DLL中可被這個應用程序調用的函數之間的連接。
  回調函數:回調函數是一種非凡的引出函數,是由 Windows環境直接調用的函數。一個應用程序至少要有一個回調函數。當一條消息要交給應用程序處理時,Windows調用這個回調函數。這個函數對應于一個活動窗口,被稱為這個窗口的窗口函數。因為許多應用程序至少建立一個窗口,并且Windows需要向這個窗口發送消息,所以,處理消息的函數必須由Windows調用。在請求Windows枚舉它所維護的對象時,例如字體或窗口,Windows也要調用應用程序中的回調函數。當向Windows提出這樣的請求時,就必須向Windows提供回調函數的地址。
  由于引出函數是在不同的模塊中被調用的,也就是說,調用者的代碼段與被調用的引出函數的代碼段不在同一個段中,因此,在所開發的Windows應用程序中,引出函數都被說明為遠函數。為了程序運行的效率原因,引出函數都使用Pascal調用約定,這種調用約定不同于C調用約定的地方在于:
  • 最左邊的參數先入棧:Pascal調用約定的參數進入棧的順序是函數調用中最左邊的參數先入棧。C的調用約定與此相反,它采用最右邊的參數先入棧。
  • 被調用的函數負責從展中清除參數:Pascal調用約定的函數在返回時負責清除棧中的參數;C調用約定的函數不作這種工作,而由調用者來作;這樣,當程序中調用了大量的使用C調用約定的函數時,為清除棧中的參數,在程序中要額外地增加許多代碼。
  • 全局標識符不保持原來的大小寫(一般被為大寫形式),也不在標識符前面加下劃線。
  為便于程序開發活動,在Windows.h中定義了兩個類型名,用于在程序說明引出函數:

類型說明WINAPI等價于FAR PASCAL,說明該函數是一個引出函數,這個類型名只用于在DLL中說明引出函數,或在應用程序中對DLL中的引出函數進行函數說明時。CALLBACK等價于FAR PASCAL,說明該函數是一個回調函數,它常被用在應用程序模塊中說明一個窗口函數或其它種類的回調函數。

1.8、事件和消息
  在Windows中,用戶或系統中所發生的任何活動被當作事件來處理,例如,用戶按下了鼠標按鈕,就產生一鼠標事件。對于所發生的每一個事件,Windows將其轉換成消息的形式放在一個稱為消息隊列的內存區中,然后由Windows的消息發送程序選擇適合的對象,將消息隊列中的消息發送到欲接受消息的對象上。Windows的消息可分為四種類型:
 ?。?)輸入消息:對鍵盤和鼠標輸入作反應。這類輸入消息首先放在系統消息隊列中,然后Windows將它們送入應用程序的消息隊列,使消息得到處理。
 ?。?)控制消息:用來與Windows的非凡控制對象,例如,對話框、列表框、按鈕等進行雙向通信。這類消息一般不通過應用程序的消息隊列,而是直接發送到控制對象上。
 ?。?)系統消息:對程式化的事件或系統時鐘中斷作出反應。有些系統消息,例如大部分DDE消息(程序間進行動態數據交換時所使用的消息)要通過Windows的系統消息隊列。而有些系統消息,例如窗口的創建及刪除等消息直接送入應用程序的消息隊列。
 ?。?)用戶消息:這些消息是程序員創建的,通常,這些消息只從應用程序的某一部分進入到該應用程序的另一部分而被處理,不會離開應用程序。用戶消息經常用來處理選單操作:一個用戶消息與選單中的一選項相對應,當它在應用程序隊列中出現時被處理。
  Windows應用程序通過執行一段稱為消息循環的代碼來輪詢應用程序的消息隊列,從中檢索出該程序要處理的消息,并立即將檢索到的消息發送到有關的對象上。典型的Windows應用程序的消息循環的形式為:

  MSG  msg;
  while (GetMessage(&msg, NULL, 0, 0L))
  {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }

  函數GetMessage從應用程序隊列中檢索出一條消息,并將它存于具有MSG類型的一個變量中,然后交由函數TranslateMessage對該消息進行翻譯,緊接著,函數DispatchMessage將消息發送到適當的對象上。有關這三個函數的更多的細節在1.10節里介紹

1.9、窗口對象
  對Windows用戶和程序員而言,窗口對象(簡稱窗口)是一類非常重要的對象。尤其對程序員,窗口的定義和創建以及對窗口的處理過程最能直觀地反映出Windows中面向對象的程序設計的四個基本機制(類、對象、方法、和消息)。

  1.9.1 窗口類
  如前所述,在程序中創建對象,必須先定義對象所屬的類。在Windows中,窗口類是在類型為WNDCLASS的結構變量中定義的,在Windows.h中,結構類型WNDCLASS的說明為:

  typedef struct tagWNDCLASS {
     DWORD style;         /* 窗口風格 */
     WNDPROC *lpfnWndProc;    /* 窗口函數 */
     int cbClsExtra;       /* 類變量占用的存儲空間 */
     int cbWndExtra;       /* 實例變量占用的存儲空間 */
     HINSTANCE hinstance;    /* 定義該類的應用程序實例的句柄 */
     HICON hicon;        /* 圖標對象的句柄 */
     HCURSOR hCursor;      /* 光標對象的句柄 */
     HBRUSH hbrBackground;    /* 用于擦除用戶區的刷子對象的句柄 */
     LPCSTR lpszMenuName;    /* 標識選單對象的字符串 */
     LPCSTR lpszClassName;    /* 標識該類的名字的字符串 */
  } WNDCLASS;

  WNDCLASS類型有十個域,它描述了該類的窗口對象所具有的公共特征和方法。在程序中可以定義任意多的窗口類,每個類的窗口對象可以具有不同的特征。lpszClassName是類的名字,在創建窗口對象時用于標識該窗口對象屬于哪個類。lpfnWndProc是指向函數的一個指針,所指向的函數應具有下述的函數原型:

  LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,LPARAM lParam);

  該函數被稱為窗口函數,其中定義了處理發送到該類的窗口對象的消息的方法。窗口函數是一個回調函數,因此在定義窗口函數時要使用CALLLBACK類型進行說明。參數hWnd是一個窗口對象的句柄。通過該句柄,一個窗口函數可以檢測出當前正在處理哪個窗口對象的消息。參數message是消息標識符,參數wParam和lParam是隨同消息一起傳送來的參數,隨著消息的不同,這兩個參數所表示的含義也不大相同,在定義消息時對這兩個參數的含義一同進行定義。
  域hIcon、hCursor和hbrBackground分別定義窗口變成最小時所顯示的圖標對象的句柄,當光標進入該類的窗口對象的顯示區域時所顯示的光標對象的句柄,當需要擦除用戶區域顯示的消息時所使用的刷子對象的句柄(該刷子作用的結果形成窗口用戶區的背景色)。
  域style規定窗口的風格,它可用下列常量經位或運算之后形成:

類型說明CS_HREDRAW假如窗口的水平尺寸被改變,則重畫整個窗口CS_VREDRAW假如窗口的垂直尺寸被改變,則重畫整個窗口CS_BYTEALIGNCLIENT在字節邊界上(在X方向上)定位用戶區域的位置CS_BYTEALIGNWINDOW在字節邊界上(在X方向上)定位窗口的位置CS_DBLCLKS當連續兩次按動鼠標鍵時向窗口發送該事件的消息CS_GLOBALCLASS定義該窗口類是一個全局類。全局類由應用程序或庫建立,并且所有的應用程序均可使用全局類CS_NOCLOSE禁止系統選單中的Close選項
  還有其他一些常量,在后面的章節中介紹有關內容時再進行討論。
  域lpszMenuName指向一個以‘/0’字符(稱為空字符或NULL字符)結尾的字符串,用于標識該窗口類的所有對象所使用的缺省選單對象。假如該域為NULL,則表示沒有缺省選單。
  域hInstance用于標識定義該窗口類的應用程序的實例句柄。每一個窗口類需要一個實例句柄來區分注冊窗口類的應用程序或DLL,該實例句柄用于確定類屬。當注冊窗口類的應用程序或DLL被終止時,窗口類被刪除。
  WNDCLASS類型規定了該類窗口對象的基本數據表示和處理消息的窗口函數,但是,在有些應用程序中,單有這些是不夠的。因此,該類型提供了兩個域cbClsExtra及cbWndExtra,指示系統分配額外的存儲空間用于存儲一些附加數據。其中cbClsExtra定義可以為該類的所有對象共用的數據占用的存儲空間的大小(以字節計);而cbWndExtra用于定義該類的每個對象私用的數據占用的存儲空間的大小(以字節計),一個對象可以在該私有存儲空間中存儲一些數據,但該類的其他對象不能訪問到這個對象所存儲的這些私用數據。而在公用存儲空間中所存的數據可被該類的所有對象訪問到。函數SetClassWord/SetClassLong和GetClassWord/GetClassLong用于訪問公用數據,函數SetWindowWord/SetWindowLong和函數GetWindowWord/GetWindowLong用于訪問特定對象的私用數據,這些函數在“窗口對象”一章討論。
  當程序員設置了WNDCLASS變量的各個域之后,使用函數RegisterClass向Windows注冊這個類,至此,完成了定義一個窗口類的過程。函數RegisterClass的原型為:

  BOOL RegisterClass(LPWNDCLASS lpWndClass);

  該函數唯一的一個參數是指向WNDCLASS類型的變量的指針。函數返回非零,表示注冊成功,否則注冊失敗。不能向Windows注冊具有相同名字(lpszClassName域指向相同的兩個字符串)的兩個類,否則第二次注冊失敗并被忽略。下面是定義和注冊窗口類的程序示例說明:

  WNDCLASS wndclass;
  wndclass.style = CS_HREDRAWCS_VREDRAW;
  wndclass.lpfnWndProc = WndProc;
  wndclass.cbClsExtra = 0;
  wndclass.cbWndExtra = 0;
  wndclass.hInstance = hInstance;
  wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  wndclass.hbrBackground = (HBRUSH )GetStockObject( BLACK_BRUSH);
  wndclass.lpszMenuName = NULL;
  wndclass.lpszClassName = "Window";

  if (!RegisterClass(&wndclass))
    ...  / * 處理類注冊錯誤 * /

  其中,WndProc是一個窗口函數名,變量hInstance存儲著當前程序實例的句柄。Windows預定義了一些圖標、光標和刷子對象,函數LoadIcon返回預定義的應用程序圖標的句柄,該圖標由第二個參數IDI_APPLICATION來定義。函數LoadCursor返回標準箭頭光標(IDC_ARROW)的句柄,函數GetStockObject返回庫存對象中一個白色刷子(WHITE_BRUSH)的句柄。

  1.9.2 創建窗口對象
  在上一節中,我們介紹了窗口類的定義方法,窗口的某些特征(如窗口的顏色等)屬于窗口類中定義的,并由該窗口 類的所有實例共享。在注冊了窗口類之后,程序員使用函數CreateWindow創建窗口,得到窗口類的一個實例(一個窗口對象)的句柄。一個窗口可以是一個重疊式窗口,或是一個彈出式窗口,或是一個隸屬窗口,或是一個子窗口,這在使用CreateWindow函數時指定。每一個子窗口都有一個父窗口,每一個隸屬窗口都有一個擁有者,這個擁有者是另一個窗口對象,彈出式窗口是一種非凡的窗口,這些內容在“窗口對象”一章介紹。

  表1-1 CreateWindow 函數
用 途創建一個重疊窗口、彈出式窗口、隸屬窗口或子窗口原 型HWND CreateWindow(   LPCSTR lpClassName,類名,指定該窗口所屬的類?! PCSTR lpWindowName,窗口的名字,即在標題欄中顯示的文本?! WORD dwStyle,該窗口的風格,在后面具體介紹。  int x,窗口左上角相對于屏幕左上角的初始X坐標?! nt y,窗口左上角相對于屏幕左上角的初始Y坐標?! nt nWidth,窗口的寬度?! nt nHeight,窗口的高度?! WND hWndParent,一個子窗口的父窗口的句柄,或隸屬窗口的擁有者窗口的句柄,若沒有擁有或者父窗口,則為NULL。   HMENU hMenu,選單句柄,假如為NULL,則使用類中定義的選單。假如建立的是一個子窗口,該參數是一個子窗口標識符,使用此標識符來區分多個窗口。   HINSTANCE hInstance,創建窗口對象的應用程序的實例句柄?! OID FAR * lpParam創建窗口時指定的額外參數。); 返回值返回值是標識所創建的窗口對象的句柄,假如返回值為NULL,則窗口沒有被創建。
  函數CreateWindow的第三個參數指定窗口的風格,表1-2是在Windows.h中定義的一些常用到的風格常量,通過將這些常量使用位運算組合在一起,形成所要求的窗口風格。

  表1-2 窗口風格
類型說明WS_BORDER創建一個有邊框的窗口WS_CAPTION創建一個有標題欄的窗口WS_CHILDWINDOW(or WS_CHILD)
創建一個子窗口(不能與WS_POPUP一起使用)WS_CLipCHILDREN當在父窗口內繪制時,把子窗口占據的區域剪切在外,即不在該區域內繪圖 WS_CLIPSIBLINGS裁剪相互有關系的子窗口,不在被其它子窗口覆蓋的區域內繪圖,僅與WS_CHILD一起使用 WS_DISABLED創建一個初始被禁止的窗口WS_DLGFRAME創建一個有雙邊框但無標題的窗口WS_HSCROLL創建一個帶水平滾動杠的窗口WS_VSCROLL創建一個帶垂直滾動杠的窗口WS_ICONIC創建一個初始為圖標的窗口,僅可以與WS_OVERLAPPEDWINDOWS一起使用WS_MAXIMIZE創建一個最大尺寸的窗口WS_MINIMIZE創建一個最小尺寸的窗口(即圖標)WS_MAXIMIZEBOX創建一個帶有極大框的窗口WS_MINIMIZEBOX創建一個帶有極小框的窗口WS_OVERLAPPED創建一個重疊式窗口,重疊式窗口帶有標題和邊框WS_POPUP創建一個彈出式窗口,不能與WS_CHILD一起使用WS_SYSMENU窗口帶有系統選單框,僅用于帶標題欄的窗口WS_THICKFRAME創建一個邊框的窗口,使用戶可以直接縮放窗口WS_VISIBLE創建一個初始可見的窗口

  在Windows.h中,還定義了風格WS_OVERLAPPEDWINDOW和WS_POPUPWINDOW。其中,WS_OVERLAPPEDWINDOW由下面的宏進行定義:

  #define WS_OVERLAPPEDWINDOW(
    WS_OVERLAPPED WS_CAPTION WS_SYSMENU
    WS_THICKFRAME WS_MINIMIZEBOX WS_MAXIMIZEBOX
  )

  WS_POPUPWINDOW定義為:

  #define WS_POPUPWINDOW ( WS_BORDER WS_POPUP WS_SYSMENU )

  但是,在使用WS_POPUPWINDOW時,必須組合WS_CAPTION ,否則不能使系統選單(WS_SYSMENU)在窗口上可見。另外 兩個窗口風格是WS_GROUP和WS_TABSTOP,這兩個窗口風格的意義在介紹對話框時進行介紹,在介紹對話框時,還將介紹其它窗口風格。
  CreateWindow函數的x和y參數是窗口左上角相對于屏幕左上角的坐標。這兩個參數可以使用常量CW_USEDFAULT,用于表示使用缺省位置。缺省時,Windows顯示各個重疊窗口的位置在水平方向的垂直方向上均與屏幕左上角有一個相應的偏移值。nWindth和nHeight參數也可以使用常量CW_USEDEFAULT來指定,這時,Windows使用缺省的窗口尺寸。缺省的窗口尺寸在水平方向延伸到屏幕的右邊界,在垂直方向延伸到屏幕底部顯示圖標區域的上方。
  下面的程序說明在Windows程序中創建一個窗口對象的基本方法,所創建的窗口對象所屬的類為在1.9.1節定義的“Window”窗口類。

  HWND hWnd;

  hWnd = CreateWindow(
    "Windows",
    "Sample Program",
    WS_OVERLAPPEDWINDOW,
    CW_USEDEFAULT,CW_USEDEFAULT,
    CW_USEDEFAULT,CW_USEDEFAULT,
    NULL,   // 沒有父窗口
    NULL,   // 使用類選單
    hInstance, // 變量hInstance中存儲有當前程序實例的句柄
    NULL,   // 沒有額外數據
  };

  其中所使用的符號“//”是C++語言新增加的單行注釋符,它表示從“//”開始到它所在的行的結尾所有內容都是注釋。

  1.9.3 窗口函數
  在前面兩小節中,我們介紹了定義類和創建對象的過程。本節介紹窗口對象如何接收和處理所有影響窗口的事件(如擊鍵或按動鼠標鍵)的消息。一個窗口對象所接受到的消息的響應是由該對象的方法決定的,這些方法被定義在一個稱為窗口函數的函數中。同一類的所有對象共用同一個窗口函數。窗口函數決定著對象如何用內部方法對消息作出響應,例如,如何在屏幕上畫出窗口自身。
  一個最簡單的窗口函數為:

  LRESULT CALLBACK WndProc(HWND hwnd, UNIT message, WPARAM wParam, LPARAM lParam)
  {
    return DefWindowProc (hwnd, message, wParam, lParam);
  }

  該窗口函數通過調用Windows的函數DefWindowProc(缺省窗口函數),讓Windows的缺省窗口函數來處理所有發送到窗口對象上的消息。
  當用戶操作屏幕上的一個窗口對象時(例如用戶改變了屏幕上窗口對象的位置或大小)或發生其它事件時,該事件的消息被存于應用程序的消息隊列中, 消息循環首先從該隊列中檢索出該消息,然后將消息發送到某個對象上。發送過程由Windows來控制,Windows根據消息結構中的hWnd域所指示的消息發送的目標對象,調用該對象所在類的窗口函數完成消息的發送工作。窗口函數根據消息的種類 ,選擇執行一段代碼(方法),對消息進行處理,并通過return語句回送一個處理結果或狀態。消息循環、Windows和窗口函數協同配合,完成一條消息的發送和處理。在處理完一條消息之后,假如應用程序隊列中還有其他消息,繼續進行上述處理過程,否則,應用程序在消息循環處理進行等待。

  1.9.4 處理消息
  窗口對象接收到的每條消息由參數message來標識,隨同該消息一傳遞過來的其它數據由參數wParam和lParam給出。wParam用于十六位的數據,而lParam用于32位的數據。
  在窗口函數中,使用switch語句來判定窗口函數接收到什么消息,通過執行相應的語句對消息進行處理。當處理完一條消息時,窗口函數要返回一個值,表示消息的處理結果,許多消息返回0值,有些要求返回其它的值,這由具體的消息決定。窗口函數不打算處理的消息必須交由DefWindowProc()進行處理,并且函數必須返回DefWindowProc()的返回值。
  窗口函數的基本結構為:

  LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  {
    變量說明語句
    初始化語句
    switch (message)
    {
      case 消息 1:
        處理“消息 1”的語句序列
        return 表達式 1;

      case 消息 2:
        處理“消息 2”的語句序列
        return 表達式 2;

         .......

      case 消息 n:
        處理“消息 n”的語句序列
        return 表達式 n;
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
  }

  Windows為預定義的每種消息都指定了一個以WM(Window Message)為前綴的標識符常量。下面的窗口函數處理一條WM_DESTROY消息。

  LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  {
    switch (message)
    {
      case WM_DESTROY:
        PostQuitMessage(0):
               return 0;
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
  }

  在1.11節,我們結合對Windows程序結構的介紹再具體解釋窗口是如何處理WM_DESTROY消息的。 三層交換技術 交換機與路由器密碼恢復 交換機的選購 路由器設置專題 路由故障處理手冊 數字化校園網解決方案


1.10、Windows應用程序的面向對象熟悉
  面向對象作為一種方法學,要求將程序中的數據和操作(代碼)歸結到某些對象名下,將數據看作對象的屬性,要改變這些屬性,必須通過操作來進行。
  進行面向對象的程序設計最好使用面向對象的語言,如C++,SamllTalk等。面向對象的語言的語言所起的作用,就是給程序員們提供一些進行面向對象的程序設計時必需的約束,使數據和操作的銜接有一種顯式的描述,并進行一些技術性的事務治理。但是,假如我們能理解面向對象程序設計的原理和方法,即使不使用面向對象的語言,也能實現面向對象的程序設計。
  Windows本身并不是一個面向對象的程序設計環境,但Windows的某些部分還是明顯地受到面向對象的軟件的概念的影響。從某種程度上說,在進行Windows程序設計時,程序員是在進行面向對象的程序設計。理解Windows的面向對象的思想和應用程序設計的面向對象方法對設計結構合理的應用程序會有很大的幫助。
  前面已給出了對象的定義:每個對象包含有數據和代碼,代碼描述了對象可執行的一系列預定義的動作,而數據是對象私有的,它們由相關的可執行代碼存取。預定義的動作和私有數據的結合稱為封裝。在C中,我們使用一個函數來封裝一個對象的私有數據和動作,使用switch語句來定義預定義的動作,這些動作只存取為該函數本身所知道的數據。
  Windows和Windows應用程序是怎樣發送消息的呢?在Windows及其應用程序中,消息被表示為一個數據結構,并能在對象之間傳遞。發送消息等價于執行其參數表示消息數據的函數調用,參數之一是一個標識該消息的預定義的消息標識符,當一個對象接受到一條消息時,消息標識符決定該對象執行何種動作。消息傳遞是以函數調用的形式來實現的,這種調用可以發生在程序的任何地方。
  Windows程序員必須清楚用消息引發動作的技術。不同的對象能以不同的動作響應同樣的消息。這樣,一個特定的消息可代表一個通用事件。例如,按鍵操作、移動鼠標或繪制用戶區等;而任何一個特定的消息可以在不同的對象中引發不同的動作,例如,不同的窗口對象以不同的動作處理同樣的WM_KEYDOWN、WM_MOUSEMOVE或WM_PAINT消息。
  一個消息可以有一個對象發送到另一個對象,或由Windows發送到某個對象。例如,WM_KEY_DOWN之類的消息是由Windows產生的。有些消息在對象的窗口函數對其處理完畢后就消失了,而有些消息在處理時有產生新的消息:一個對象通過向其它對象或自己發送一條或多條消息來處理一條消息。這樣,Windows應用程序的控制流程不象MS-DOS應用程序那樣易于跟蹤,程序的調試也比MS-DOS應用程序困難。
  除了個別消息以外,對象接受消息的順序是不可預知的,但對象處理每條消息所采取的動作是顯式定義在窗口函數中的。對象并不顯式地定義所有可能消息的動作,對于不顯示處理的消息,都交由DefWindowProc進行缺省處理。
  消息傳遞的途徑很簡單:從一個對象傳遞到另一對象,但由于DefWindowProc對有些消息提供了缺省處理,因此,程序員在設計程序時必須考慮在一個窗口函數中捕捉某條消息時是否還應交給DefWindowProc函數作進一步的處理。DefWindowProc能處理所有的消息,但對大部消息只是簡單地廢棄之,不作具有實際意義的處理,在窗口函數捕捉這些廢棄消息是安全的;若要捕捉其它消息,則必須了解DefWindowProc是怎樣處理這條消息的,并在窗口函數的處理代碼中能提供類似的處理(或將該消息交由DefWindowProc作進一步的處理)。
  現在我們討論窗口函數對對象的私有數據的處理問題。窗口類也說明了對象的私有數據,當調用CreateWindow創建一個窗口對象時,Windows為創建的窗口對象分配私有數據存儲區,其中存儲有窗口的實例句柄、父窗口句柄、窗口函數的地址和其它Windows用于治理窗口對象的數據。對這些私有數據的的操作只能使用GetWindowWord/GetWindowLong等函數。對于程序中說明的變量,如何在窗口函數中將它們與相關的對象銜接在一起就比較復雜,因為窗口函數為該類的所有對象共享,該類的所有對象在接收到消息時都執行相同的代碼。
  在過去,Windows推薦使用的程序設計語言是C,由于C語言不具備將一個對象的私有數據和操作這些私有數據的代碼銜接在一起的語言成份(面向對象的語言的事務性工作之一就是為程序完成這個工作),這個工作只能由程序員來作。程序員心中必須清楚程序中所說明或分配的變量私有于哪個對象,并采用合適的數據結構來表示它們,以便程序在使用它們時,能根據不同的對象將它們區別開來。
  有幾種方法可用于區分對象的私有數據:
  • 程序員編制額外的代碼來判定一個對象應使用哪些數據。
  • 使用窗口附加字節。
  • 使用屬性表。
  當使用第一種方法時,程序實際是使用對象句柄作索引來檢索與該對象相關的私有數據,Windows也使用這種方法使用句柄來檢索一張表,這個表中存儲著該句柄所標識的對象的私有數據。Windows的許多函數需要一個對象的句柄作為第一參數,其原因就是為區分對象的私有數據,以便使用相同的函數處理不同的對象(的數據)。
  后兩種方法與第一種方法本質是一樣的(我們會將在后面的章節對其進行介紹),只是Windows提供了一些相關的函數來簡化程序的工作。
  由于C沒有繼續這種語言成分,因為,也就不能形成對象的等級結構。繼續是面向對象語言的另一個重要成分。繼續使得程序中的對象形成一個分層次的對象結構,低層次的對象可以將它不處理的消息發送到高層對象上進行缺省處理。由于在C中不能(或說很難)建立對象的這種等級結構,但為了簡化應用程序的設計,又必須要求支持消息的缺省處理(否則應用程序要定義一個窗口對象可能接收到的所有消息的處理代碼),因此只能使用DefWindowProc提供消息的缺省處理。這就要求對一個窗口對象所有消息的處理定義在一個函數中,就帶來了定義窗口函數的返回值和參數類型時使用了一種較難為人理解的方法。因為不同的消息可以帶有不同類型和個數的參數,并且返回數據的類型也不相同,Windows的設計者采用了一個折中的方法:為消息規定一個十六位的參數和一個32位的參數,將返回類型指定為LRESULT,這種類型的長度能容下C中所有預定義類型的數據。
  由于不同類的窗口對象定義有自己的窗口函數,但C語言不具備根據接受消息的對象自動決定調用該對象的窗口函數的能力(在面向對象的語言中,這種能力被稱為多態性)。因此,向不同的窗口對象發送消息時使用函數SendMessage對窗口函數作間接調用,由Windows根據該函數調用中所使用的對象標識符來調用該對象的窗口函數。
  在程序設計中由于窗口函數的限制,需經常進行各種各樣的數據類型轉換。例如:

  SendMessage(hwnd, WM_USER, (WPARAM)5, MAKELPARAM(89, 3267));

  在這個例子中,為了組建一個LPARAM類型的數據,使用了宏MAKEPARAM。它將兩個十六位的數據組裝成一個32位的數據(低位字為MAKEPARAM的第一個參數,高位字為第二個參數)。當需要從一個LPARAM類型的數據中分離出低位字和高位字時,使用宏LOWORD和HIWORD。例如,處理上個例子中所發送的WM_USER消息的窗口函數的代碼可能為:

  WORD wStart = LOWORD(lParam);
  WORD wStart = LOWORD(lParam);

  宏MAKELRESULT與MAKELPARAM類似,它被用于裝配LRESULT類型的數據。宏MAKELONG用于裝配LONG類型的數據,當需要從LRESULT或LONG類型的數據中分離出高位字和低位字時,使用宏HIWORD和LOWORD。
  基于上面的介紹,我們在設計Windows應用程序時,要明確程序中存在哪些對象,對象之間是如何通過消息傳遞程序控制的,哪些數據是對所有對象公有的, 哪些數據是私有于某一個對象的,公有數據和對象的私有數據必須是存儲在靜態生存期的變量中(局部生存期的變量在窗口函數返回后就消失了,不能在下次調用該函數時保存上次的值。換句話說,存儲對象的數據的變量的生存期不應小于對象的生存期)。
  由于Windows應用程序各個模塊之間主要是通過消息傳遞控制,因此,Windows應用程序的邏輯結構就不同于MS-DOS應用程序的邏輯結構,如圖1-1所示。從圖1-1可以看出,Windows應用程序的各個模塊通過消息傳遞被聯系在一起,因此,假如正確地組織程序,程序的模塊性和結構較MS-DOS應用程序要好。

Windows編程基礎 - 概述圖1-1 DOS應用程序與Windows應用程序邏輯結構的比較示意說明

1.11、Windows程序的組織
  將1.9節介紹的程序按照C/C++語言的要求組織起來,就得到一個完整的Windows程序。一個Windows程序必須有一個名為WinMain的主函數。

  // 1-1.c 代碼片段
  #include <windows.h>

  LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

  int PASCAL WinMain(
    HINSTANCE hInstance,   // 應用程序的實例句柄
    HINSTANCE hPrevInstance, // 該應用程序前一個實例的句柄
    LPSTR lpszCmdLine,    // 命令行參數串
    int nCmdShow)       // 程序在初始化時如何顯示窗口
  {
     char szAppName[] = "Window";
    HWND hwnd;
    MSG msg;
    WNDCLASS wndclass;
    if (!hPrevInstance) {
      // 該實例是程序的第一個實例,注冊窗口類
      wndclass.style = CS_VREDRAW CS_HREDRAW;
      wndclass.lpfnWndProc = WndProc;
      wndclass.cbClsExtra = 0;
      wndclass.cbWndExtra = 0;
      wndclass.hInstance = hInstance;
      wndclass.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
      wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
      wndclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
      wndclass.lpszMenuName = NULL;
      wndclass.lpszClassName = szAppName;

      if (!RegisterClass(&wndclass))
        // 假如注冊失敗
        return FALSE;
    }

    // 對每個實例,創建一個窗口對象
    hwnd = CreateWindow(
      szAppName,
      "Sample Program",
      WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, CW_USEDEFAULT,
      CW_USEDEFAULT, CW_USEDEFAULT,
      NULL,
      NULL,
      hInstance,
      NULL);

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    while(GetMessage(&msg, NULL, 0, 0)) {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
    }

    return msg.wParam;
  }

  WinMain函數是Windows應用程序開始執行時的入口點,它的返回類型為int。WinMain函數的作用十分類似于MS-DOS中的C應用程序的main函數。
  WinMain帶有四個參數。參數hInstance和hPrevInstance是程序的實例句柄。在Windows環境下,可以運行同一個程序的多個拷貝,每一個拷貝都是該應用程序的一個句柄,每個實例使用一個實例句柄進行標識。hInstance是標識當前程序的實例的句柄,它的值不會為NULL。假如在此之前Windows中已經運行了該程序的另一個實例,則這個實例的句柄由參數hPrevInstace給出。假如在運行該程序時,Windows環境中不存在該程序的另一個實例,則hPrevInstance為NULL。
  我們曾經說過,對同一個類,不能向Windows注冊一次以上。在這個程序中,通過判別hPrevInstance的值是否為NULL,來決定是否應向Windows注冊窗口類。這樣的程序邏輯保證了只在該程序的第一個實例中注冊窗口類。
  參數lpszCmdLine中包含有運行程序時傳遞給程序的命令行參數。例如,若以這樣的命令運行該程序。Sample.exe Programming Windows。則lpszCmdLine將指向字符串“Programming Windows”。
  最后一個參數nCmdShow是一個int類型的整數,用以說明在程序被裝如內存時,Windows以何種方式顯示這個程序的窗口。根據運行程序的方式不同,該參數被設置為SW_SHOWNORMAL或SW_SHOWMINNOACTIVE,SW的含義是“Show Window”(顯示窗口),這兩個參數的含義在后面介紹。 三層交換技術 交換機與路由器密碼恢復 交換機的選購 路由器設置專題 路由故障處理手冊 數字化校園網解決方案
  在程序Sample.CPP中,有幾個函數我們未曾介紹。表1-3給出了這些函數的說明。

  表1-3-1 ShowWindow 函數
用 途顯示或改變給定的窗口原 型BOOL ShowWindow(    HWND hWnd,指定一個窗口對象?! nt nCmdShow 指定窗口的顯示方式。); 返回值返回該窗口更新前的窗口狀態。對先前可見的窗口,其值為非零。對先前隱藏的窗口,其值為零。
  顯示方式(nCmdShow)可以是下列常量之一:

類型說明SW_HIDE隱藏該窗口(并是另一個窗口激活)SW_MINIMIZE使窗口變成圖標(并激活窗口治理表的頂層窗口)SW_SHOW激活一個窗口,并根據其當前的尺寸和位置顯示該窗口SW_SHOWMAXIMIZED激活并以全屏方式顯示一個窗口SW_SHOWMINIMIZED激活并以圖標方式顯示一個窗口SW_SHOWMINNOACTIVE以圖標方式顯示一個窗口,當前活動的窗口仍保持活動SW_SHOWNA以當前狀態顯示一個窗口,當前活動的窗口仍保持活動SW_SHOWNOACTIVE以最近的大小和位置顯示一個窗口,當前活動的窗口仍保持活動SW_SHOWNORMAL激活并顯示一個窗口,若其為圖標或全屏方式顯示,則恢復為它的原始大小和位置SW_RESTORE同SH_SHOWNORMAL
  表1-3-2 UpdateWindow 函數 用 途若應用程序的消息隊列中存在WM_PAINT消息(繪制用戶區消息),則該函數使Windows立即調用窗口函數,向其傳遞WM_PAINT。否則該函數不作為任何動作。原 型VOID UpdateWindow(    HWND hWnd,標識被刷新的窗口的句柄。); 返回值無
  表1-3-3 GetMessage 函數 用 途從應用程序中的消息隊列中檢索一條消息。原 型BOOL GetMessage(    LPMSG lpMsg,指向MSG類型的變量的遠指針,它包含有從應用程序消息隊列中檢索到的一條消息的數據?! WND hWnd,指定為哪個窗口檢索消息,假如hWnd為NULL,則檢索調用該函數的應用程序的所有的消息(不檢索屬于其它應用程序的消息)?! INT wMin,   UINT wMax以下兩個基本參數指定檢索在wMin和wMax范圍內的消息。假如這兩個參數都為零,該函數檢索所有的可用的消息。); 返回值在檢索出WM_QUIT消息時,返回零值,在其它情況下返回非零值。
  表1-3-4 DispatchMessage 函數 用 途將消息發送到指定的窗口對象上(窗口函數被調用)。原 型LRESULT DispatchMessage(   LPCMSG lpMsg指向MSG類型變量的遠指針,該變量中存儲有來自應用程序消息隊列中的消息。); 返回值若有一個WM_CHAR消息被放到應用程序的消息隊列中,返回非零,否則返回零。該函數不改變lpMsg所指向的變量中存儲的消息數據。
  Windows的主函數都是首先以初始化(注冊類、創建對象等)這一步開始,而且緊跟著就是消息循環運行這一步。這些步驟對所有的Windows應用程序都大同小異。Windows應用程序主要的不同點在窗口函數的定義上,由于一個應用程序所解決的任務不同,它的窗口函數對消息的處理方式也就不相同,因而每個應用程序需要定義不同的窗口函數。

  LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  {
    switch (message)
    {
      case WM_DESTROY:
        PostQuitMessage(0):
               return 0;
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
  }

  這個窗口函數僅處理一條WM_DESTROY消息。這條消息是在用戶關閉了屏幕上的窗口時,Windows發送給窗口對象的。該函數對這條消息的處理只是簡單地調用Windows函數PostQuitMessage。表1-4給出了函數PostQuitMessage的說明。當主函數的消息循環中的GetMessage函數檢索出WM_QUIT消息時,函數GetMessage返回零,這樣,消息循環終止,程序也隨之被終止。存儲消息數據的變量msg的wParam域的值是在調用函數PostQuitMessage時所提供的實參的值。假如程序正常結束,調用PostQuitMessage函數時使用零作為該函數的參數,假如需要表示程序由于出現了異常或錯誤而必須終止時,使用非零值(一般使用-1)作為該函數的參數。在調用PostQuitMessage使用的參數值被主函數用語句:

  return msg.wParam;

  返回給Windows,供Windows或其它應用程序使用。因此,我們也稱PostQuitMessage使用的參數為程序的退出碼。

  表1-4 PostQuitMessage 函數 用 途通知Windows,應用程序希望中止。它一般用于響應WM_DESTROY消息。該函數將消息WM_QUIT消息放入應用程序的消息隊列中。原 型PostQuitMessage(   int nExitCode指定應用程序的退出代碼,它用作WM_QUIT消息的wParam參數。); 返回值無
  小結
  本章首先介紹了圖形用戶界面的優點和面向對象的程序設計方法。從某種意義上說,Windows是面向對象的,它主要建立在把窗口作為一個對象的概念上。窗口之間通過消息進行消息傳遞。
  Windows支持直接操作技術。直接操作是對屏幕對象的操作,數據和函數的封裝答應該對象自己響應它們接收到的消息。在用戶界面上發生的任何事件被作為消息發送給窗口對象。程序員在設計程序時,只須關心一個對象要接受哪些消息和怎樣處理這些消息。消息傳遞工作由Windows負責。因而,使用Windows操作環境可以極大地方便程序開發用戶界面的工作,并使程序的結構合理、模塊化程序高。更重要的是,支持直接操作技術的Windows支持用戶進行有創造性的界面設計。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产精品aaaa| 色综合导航网站| 欧美激情久久久久久| 2019中文字幕在线免费观看| 91av免费观看91av精品在线| 欧美精品aaa| 国产精品露脸自拍| 国产精品偷伦一区二区| 中文字幕久久久av一区| 国产成人福利视频| 亚洲成**性毛茸茸| 亚洲一区二区三区乱码aⅴ| 日韩美女中文字幕| 日韩欧美国产网站| 日韩美女视频免费看| 九色91av视频| 亚洲最新在线视频| 欧美黑人性猛交| 久久成年人免费电影| 日韩女优在线播放| 欧美成人免费全部观看天天性色| 最近2019年中文视频免费在线观看| 亚洲人成伊人成综合网久久久| 亚洲欧洲日本专区| 欧美性xxxx极品hd欧美风情| 欧美成人午夜影院| 亚洲色图13p| 久久91精品国产91久久久| 日韩精品亚洲视频| 欧美在线欧美在线| 久久久久久久一区二区三区| 国产精品网站大全| 麻豆乱码国产一区二区三区| 日韩免费av片在线观看| 中日韩美女免费视频网址在线观看| 国产精品久久久久免费a∨大胸| 久久手机精品视频| 国产成人一区二区三区| 亚洲成人久久网| 色综合伊人色综合网站| 国产精品91在线| 色狠狠av一区二区三区香蕉蜜桃| 亚洲一区中文字幕在线观看| 久久天天躁日日躁| 国内精品久久久久久| 中文字幕亚洲第一| 欧美亚洲国产视频| 狠狠操狠狠色综合网| 亚洲www在线观看| 性欧美xxxx视频在线观看| 亚洲系列中文字幕| 在线激情影院一区| 国外成人在线视频| 97精品国产aⅴ7777| 91在线视频免费| 亚洲精品网站在线播放gif| 午夜精品久久久久久久久久久久| 久久久久久久久综合| 亚洲91精品在线| 日韩av在线播放资源| 搡老女人一区二区三区视频tv| 欧美精品video| 国产亚洲精品久久久优势| 日韩欧美一区二区在线| 亚洲自拍欧美色图| 亚洲人成人99网站| 亚洲一区二区国产| 久久这里有精品视频| 日韩福利视频在线观看| 91av视频导航| 欧美日韩在线第一页| 亚洲国模精品私拍| 亚洲欧美变态国产另类| 超在线视频97| 亚洲美女黄色片| 国产欧美日韩精品在线观看| 日韩电影在线观看免费| 国产成人精品久久亚洲高清不卡| 亚洲欧美资源在线| 国产日韩在线免费| 亚洲精品www久久久| 中文字幕无线精品亚洲乱码一区| 亚洲第一福利网站| 欧美日韩国产成人在线观看| 中文字幕欧美视频在线| 亚洲娇小xxxx欧美娇小| 欧美刺激性大交免费视频| 在线精品国产欧美| 久久天天躁狠狠躁老女人| 亚洲xxxx18| 欧美俄罗斯性视频| 国产亚洲精品va在线观看| 亚洲国产91精品在线观看| 97精品免费视频| 91久久精品国产| 国产精品偷伦一区二区| 欧美日韩中文字幕在线| 国产精品精品久久久久久| 日韩av高清不卡| 亚洲国产成人久久综合一区| 韩国19禁主播vip福利视频| 国产精品久久97| 亚洲人成网站777色婷婷| 中文字幕在线视频日韩| 欧美激情精品久久久久久大尺度| 日本欧美爱爱爱| 国产噜噜噜噜久久久久久久久| 欧美日韩视频免费播放| 欧美日韩中国免费专区在线看| 精品久久久香蕉免费精品视频| 91美女片黄在线观| 国产精品激情自拍| 久久精视频免费在线久久完整在线看| 97国产真实伦对白精彩视频8| 亚洲人成毛片在线播放| 亚洲精品欧美日韩专区| 亚洲国产精品久久久久秋霞不卡| 久久精品成人动漫| 国产精品国模在线| 亚洲成人久久一区| 欧美最猛性xxxxx免费| www国产91| 一区二区三区视频免费| 欧美综合一区第一页| 日韩精品在线影院| 欧美性猛交丰臀xxxxx网站| 欧美富婆性猛交| 亚洲香蕉伊综合在人在线视看| 日韩精品在线免费播放| 久久91亚洲精品中文字幕| 国产精品毛片a∨一区二区三区|国| 国产极品精品在线观看| 中文字幕欧美在线| 91爱视频在线| 精品五月天久久| 国产精品狼人色视频一区| 日韩午夜在线视频| 黄色成人在线播放| 日韩精品视频在线观看免费| 日韩中文字幕在线免费观看| 成人网在线免费观看| 国产精品久久久久久久天堂| 亚洲国产欧美日韩精品| 日韩电影免费在线观看| 日韩不卡在线观看| 久久久久久一区二区三区| 日韩精品在线免费播放| 国产日韩欧美一二三区| 亚洲区bt下载| 欧美激情高清视频| 色妞色视频一区二区三区四区| 久久免费成人精品视频| 成人精品一区二区三区| 美女福利精品视频| 久久久亚洲影院| 国产精品美女久久| 精品久久久久久久久久国产| 在线亚洲欧美视频| 欧美裸体xxxx极品少妇软件| 日韩av一卡二卡| 精品欧美激情精品一区| 日韩在线视频线视频免费网站| 97久久超碰福利国产精品…| 在线亚洲午夜片av大片|