Windows 2000系统编程 (1)
?????第1章縱覽Windows 2000
毫不隱瞞地說,我是一個科幻迷。但是,我認為現實中的科幻描述很荒謬可笑。雖然我能
接受存在生物圈和星系帝國的事實,甚至可以接受超光速的星際飛行器,但是我不能接受的是
那么容易地與外星人進行交流。當然,在Star Tr e k中,所有外星人都講英語。事實上,極少數的
科幻故事涉及到第一次接觸外星文化會如何。通常都是外星人通過收音機和電視學英語,要么
它們依靠一臺功能強大的翻譯機。不管哪種方法都在人們看不見的地方進行,因而不會妨礙故
事的進展。
考慮人們之間的交流。不論與誰交流,不論要討論什么話題,兩人的交流大部分都是不言
而喻的,并不需要表達出來,舉個什么例子呢?看下面古怪卻正確的句子:
“I saw the Grand canyon while flying to New Yo r k .”(在飛往紐約時,我見到了Grand
Canyon。)
你我都知道,說話者那時正飛往紐約,并看見了Grand Canyon (大峽谷)。但從語法上理解,
這句話意指, Grand Canyon大峽谷正飛往紐約, 且我看見了它!當然是廢話,因為大家都知道
Grand Canyon大峽谷是不會飛的。而外星人(或電腦,就此而言)并不知道Grand Canyon是什么。
之所以人們能理解這句話,是因為有每個人了解一些常識。
當你穿越世界上的文化界線時,問題則更糟。多年前,英國報紙上刊載在頭條的真實新聞
如下:
“British Left Wa ffles on Falklands”(British Left議論F a l k l a n d群島的局勢。)
通常,美國人會感到驚訝,英國人忘記吃早餐為什么值得報道(他們認為英國人在F a l k l a n d s
忘記吃華夫餅干)。然而,如果你了解在英國發生的事件,就會明白British Left是一個政治黨派。
頭條新聞在說,他們不能接受F a l k l a n d群島的局勢。
英國的報紙編輯是不是瘋了?當然不是。他們簡單地認為,讀者已經有了這些方面的知識,
而多數美國人卻沒有。
同樣的概念在任何復雜的程序設計中也是正確的。當你與其他人討論編程問題時,你也應
設想他們了解這些問題。若在大街上攔住一個人,就問為什么P r i n t f連接到代碼時會失敗。除非
你碰巧遇到C 或C + +程序員,不然對方絕對不知所云。
1.1 新的語言
假定此刻你是C + +程序員。你與其他C + +程序員一樣知道某些基礎知識。如果老板指派你解
決C o b o l語言中的2 0 0 0年問題,沒人指望你能順利地開始這項工作。C o b o l語言的程序員具有和
C + +程序員不同的知識基礎。C o b o l程序員和C + +程序員的交流通常十分困難,每個人都認為如
此。
然而,由于某些原因,操作系統并不能共享這種奢侈。老板們似乎期望你輕易地、不繞彎
路地在U N I X、V M S、M V S、M S - D O S和Wi n d o w s間轉換。如果你擅長Wi n d o w s的某個版本,這
格外正確。但事實上,這些任務大相徑庭。如果你學習過Windows 3.0下的程序設計,那你就可
以慢慢掌握Windows NT或Windows 2000,但這也是努力的結果。
如果你從其他操作系統轉而使用Windows 2000,那情形會相當痛苦。作為一個U N I X的老手,
我目睹了許多朋友從U N I X轉向Wi n d o w s的經歷。他們通常抱怨Wi n d o w s怎么如此糟糕。
事實上, 3 2位版本的Windows 和U N I X并不是完全不同。但確有差異。丟棄原有的基礎知
識并重新開始,確實非常困難。如果有人要求“創建一個新進程”,那么U N I X的權威,就會考
慮fork 而不是C r e a t e P r o c e s s。當然,你能在幫助中查到C r e a t P r o c e s s,但就像出國旅行并使用一
本愚蠢的外語常用手冊,這會有幾分效果,但不舒服也不方便。所以你需要一些基礎知識。
本章的目的是要使每個人從相同的起點開始。這里將給大家展示應該了解的(或許已經知
道的)有關Wi n d o w s的一些內容。這樣,你就增加了需要了解的書中其余部分的基本信息。
1.2 Wi n d o w s簡史
如果我們回去創建公司并開辟Wi n d o w s操作系統市場,不久之后,我們也許會另謀職業。
Wi n d o w s剛面世時,是有爭議的。只有M i c r o s o f t這樣的公司才能支撐Wi n d o w s,直到開發出實用
的東西。
Wi n d o w s的問題不全是M i c r o s o f t的過失。不要忘記,那時的計算機只有緩慢的處理器、帶
寬窄的總線及容量小得可憐的存儲器。Wi n d o w s能運行就很幸運了。只是時機尚未成熟。
I n t e l 3 8 6是第一個P C兼容的處理器,它能處理真正像Wi n d o w s這樣的系統。M i c r o s o f t悄悄地
推出命名為Wi n d o w s / 3 8 6的產品,且顯示出它的優點。這就是Wi n d o w s的第一個版本,運行良好,
深受大多數人的喜愛。
Wi n d o w s / 3 8 6之后不久, M i c r o s o f t推出Windows 3.0。這是第一個Windows 的商業化版本。
該版本并不是沒有共享問題,而是問題沒有足以影響到人們購買該產品。由于潛在購買者眾多,
軟件公司急急忙忙進行Wi n d o w s的程序設計(通常,稱作應用程序)。
而后不久,Microsoft 又發布Windows 3.1。這個版本不僅修補了Windows 3.0中的許多程序
錯誤,而且還引入了許多重要的新特性。許多編程人員首先學習了基于Windows 3.0 或3 . 1的
Wi n d o w s編程。
盡管用戶們非常喜歡Wi n d o w s的這些版本,但多數編程人員都不喜歡它們。Wi n d o w s的這
些版本還保留了以前的版本遺留的許多包袱。如內存管理是有缺陷的、分段式存儲模式常常令
人生厭、多任務處理還很粗糙并需要涉及到的所有程序協同合作完成。如果任一個程序不合作,
整個系統便會崩潰。1 6位系統的根使其對來自U N I X或其他3 2位操作系統的端口代碼相當困
難。
另外,市場壓力要求Wi n d o w s的應用程序,即編程人員提供的應用程序。不論好壞,這就是
大多數程序員的起點。
M i c r o s o f t也曾發布過不同版本的Windows 3.1,包括Windows for Workgroups 3.1和3 . 11、
Windows 3.11。從開發角度講,這些并不重要。
1.2.1 Windows NT
然而,真正的舉動是M i c r o s o f t決定何時開發Windows NT。因為M i c r o s o f t深信,如果不是受
以前處理器的限制,Wi n d o w s會更加出色。同時也知道,在連網和分布處理時, Wi n d o w s無法與
U N I X這樣的操作系統競爭。
那時,使M i c r o s o f感到焦慮的事情是:其他操作系統或微處理器結構的問世會擠垮Wi n d o w s
和I n t e l硬件平臺。M i c r o s o f t確信只有借助N T的靈活性,使其仿效其他操作系統運行于不同硬件
平臺,才不致受到影響。
N T的發布可以說毫無生氣。它對硬件的需求,遠遠超過當時人們所具有的硬件環境。在
1 6 M B內存的情況下(而那時很少有內存超過8 M B),僅僅得到最小的性能。同時,還要有C D -
R O M去安裝N T,而那時極少數人有光驅(事實上,我買光驅完全是出于安裝NT 的需要)。
即使已經具有N T運行所需要的硬件環境,這里仍存在兩個主要的問題:缺少設備支持和缺
少應用程序。因此,當時世界上只有少數P C機運行N T,而多數仍運行Wi n d o w s 3 . 1。硬件和軟件
的開發商缺少支持N T的動力。當然, N T還可運行多數Windows 3.1的程序,而不是所有的程序
都可以運行。為什么要買N T,難道只是為了運行Windows 3.1的程序嗎?尤其, N T需要更多的
費用,并需要昂貴的硬件升級。
然而,M i c r o s o f t仍支撐著N T(就像當初開發Wi n d o w s產品那樣),并默默地在幾個版本上改
進N T。另外,M i c r o s o f t知道必須要吸引第三方開發商來編制N T的應用程序。
1.2.2 Windows 95
解決上述問題的答案是Windows 95。M i c r o s o f t推出新產品Windows 95替代Windows 4.0。
M i c r o s o f t希望將Windows 95看作Windows NT Lite(體會其特性,而不是其替代品)。然而,實
際上Windows 95更像Windows 3.1。
Windows 95的關鍵是其名義上支持如同Windows NT一樣的編程界面。那么,為什么不編寫
運行于Windows 95和N T的程序代碼呢?這樣會使能運行于N T上的軟件大量出現,不是嗎?為達
到這個目的,M i c r o s o f t所要做的是使Windows 3.1的每個用戶立即購買Windows 95。這形成一些
設計選擇,它們在其他方面是難于調整的。
這不僅是一個運作得非常好的戰略性工作, 3 2位應用程序的數量激增。那么,已經有了N T
產品的經銷商們會如何呢?這不正是為N T打開Windows 3.1市場的大好時機嗎?然而事實并非如
此。Windows 95應用程序接口(Application Programming Intertace, API)只是Windows NT應用
程序接口的一個子集,如果了解了這一點,就能編寫在兩個平臺都能運行的代碼,但是除非從
開始就有打算,否則編寫的代碼是靠不住的。在技術上, Windows 3.1 API稱作Wi n 1 6的A P I,而
其他版本則使用Wi n 3 2的A P I。不過,在Windows 95下的Wi n 3 2與在Windows NT下的Wi n 3 2并不
完全是一回事。
然而,從Windows 3.1程序轉到新的Windows 95/NT API顯得突然。許多程序員都趨之若騖。
對于那些仍執迷于Windows 3.1的用戶,M i c r o s o f t為開發者開發了稱作Wi n 3 2 S的產品。如果在程
序中使用了Wi n 3 2 S的庫,則會形成一個很小的Windows NT命令子集。Wi n 3 2 S庫會自動地將其轉換成Windows 3.1式的命令。理論上,代碼的一部分可以運行在Windows 3.1、Windows 95和Windows NT上。事實上,Wi n 3 2 S失敗了。部分原因是其運行不穩定,另外的原因是實際上構成的命令子集
非常小,并對開發者的限制太多。雖然仍有少數開發者在改善Wi n 3 2 S,最終M i c r o s o f t還是放棄
了它。
總而言之,M i c r o s o f t的戰略是非常成功的。也能運行于N T的Windows 95的應用程序在各地
發展起來。突然發現,人們可以在Windows NT上運行真正的3 2位程序了。
1.2.3 其他方面
與此同時,硬件方面的技術發展的也相當快。奔騰( P e n t i u m)級的處理器已成為標準,內
存的價格迅速下跌。高性能視頻卡和打印機也已具有8 M B的隨機存儲器(Random Access
M e m o r y, RAM),許多人的P C機裝上6 4 M B或更大的R A M。這些P C機足以滿足運行N T的要求,
因此許多人開始轉而使用NT 3.5或NT 3.51。多處理器的主板價格的下跌,更刺激人們轉向使
用N T。(在多處理器系統上,運行Windows 95是一種浪費,因為Wi n 9 5任何時候都只使用一個處
理器)
I n t e r n e t的蓬勃發展更激發了人們使用N T的興趣。N T是一個相當不錯的網絡服務器平臺,最
重要的是M i c r o s o f t在N T服務器軟件包中包含了I n t e r n e t工具。
Windows NT 3.51的唯一問題是,從用戶角度看,它的外觀和運作太象Windows 3.1了。許
多用戶更喜歡Windows 95 的界面風格、即插即用、及僅適用于Windows 95 的其他特點。
Windows NT 4.0的發布,則帶給N T用戶更多這方面的東西(和一些新功能)。
對于Windows 2000,M i c r o s o f t帶來更多的用戶所希望的Wi n d o w s特性(如支持多臺監視器),
并為編程人員新增了不少新工具。時至今日,大多數(并不是所有)的家庭用戶使用Wi n d o w s
9 5或Windows 98。大多數公司用戶,開發者和超級用戶(也不是所有的)在運行Windows NT,
并可能轉而使用Windows 2000。
1.3 Wi n d o w s版本
Wi n d o w s的每個版本都有不同的風格。多數情況,編程人員并不在意他們使用哪個版本。不
同風格間的主要區別是M i c r o s o f t在磁盤上放置的額外軟件和許可證號(像協作用戶所允許的號
碼)。
單桌面用戶的首選是專業版( Professional Edition )。它包含作為個人操作系統而使用
Wi n d o w s所需的全部功能。甚至可以用專業版構成一個小型的網絡。
如果要使Wi n d o w s運行在網絡或We b服務器上,則應選擇服務器版( Server Edition)。根據
需要,服務器產品有幾個版本(例如, Site Server提供M i c r o s o f t個人化系統和用于大容量We b站
點的工具)。
最后,Windows Advanceed Server和Datacenter Server使程序潛在地尋址更大的虛擬空間。
Wi n d o w s的這些特殊版本都提供了先進的聯網特性和支持附加的多進程處理。
然而,作為編程人員,這些版本的Wi n d o w s之間沒有真正的差別。可以用同樣的方法,使用
同樣的工具,做相同的調用。如果依靠額外的組件(或3 G B虛擬內存的限制),則也許需要特殊
的版本,但通常情況,不必在意程序必須運行于哪一種Wi n 3 2的平臺上。
1.4 Wi n d o w s體系結構
從編程人員的觀點, Windows 2000提供了相當簡單的環境。每個程序都有一個地址范圍從
0到2G B的平面(非分段式的存儲結構)存儲空間。當然,大部分程序并沒有全部使用此空間,
的確,今天并不是所有系統都有那么充裕的硬盤空間和物理存儲空間。但這不是問題,因為
Wi n d o w s只有在程序使用時才分配其真正的存儲空間。
地址是從0到4 G B的3 2位整數值(盡管只有0到2GB有效)。你不必擔心使用老版本的
Wi n d o w s的分段結構,跟蹤內存或其他古怪的事情。
順便指出, P e n t i u m處理器允許尋址到4 G B的空間。然而,操作系統保留了2 G B的最高限
制。操作系統真能用到那么大的空間嗎?不,能夠運行Wi n d o w s的處理器有2 G B的用戶程序空
間和2G B的操作系統監控程序空間。因此這種模式與微處理器匹配得非常好。
Windows API是系統的標準接口。我們可以構成針對操作系統的調用命令,而操作系統實際
上寄存于系統動態鏈接庫( Dynamic Link Libraries, DLL)。如果使用其他操作系統,這些命令
則與之不同,但是功能相同。這些功能包括分配存儲空間、打開文件等等。這些特性主要被人
們用來編寫程序設計語言(像C + +)。你將經常使用程序語言中的結構去實現上述功能。例如,
你大概不會調用Windows API中的C r e a t e F i l e,而會調用C + +庫中的f o p e n。另一方面,C r e a t e F i l e
可以實現f o p e n不能處理的某些功能。
如果你有先驗的Wi n d o w s編程經驗,就會發現這些函數的命令有幾分相似。許多函數與
Windows 3.1及更早的版本中的調用函數相同。而另一些有些細微的差別。有時, M i c r o s o f t稍微
改變命令的名字,以表示其參數或返回值存在不同。對名字的常見改動是在其尾部加上E x。這
樣,在Windows 3.1 中使用G e t C u r r e n t P o s i t i o n,而在Windows 2000 (或N T)中則使用
G e t C u r r e n t P o s i t i o n E x 。它們有什么不同呢?當兩個1 6位字表示的3 2位字返回值時,
G e t C u r r e n t P o s i t i o n返回當前描述的位置。而G e t C u r r e n t P o s i t i o n E x則返回作為變元傳送的指針結
構中的兩個3 2位字。這些函數有相同的目的,而Wi n 3 2變量則以3 2位運作。
另外的改變發生在接收字符串的任一函數中。N T和Wi n 2 0 0 0內部不使用A N S I字符串。取而
代之,它們使用稱作U N I C O D E的1 6位的字符(且后者使用的更多)。然而,大多數程序使用
A N S I(或考慮8位的A S C I I字符)。所以接收字符串每個函數有兩種情況:其一給出A N S I字符串
(并將其轉換為U N I C O D E),另一種則直接接收U N I C O D E字符串。
例如,考慮Windows 3.1的函數M e s s a g e B o x。大家知道,這個函數彈出帶文本字符串的對話
框,Wi n 3 2沒有此函數。但它有M e s s a g e B o x A給出A N S I變元及M e s s a g e B o x W處理U N I C O D E。
然而,文檔也引用M e s s a g e B o x。這是因為C + +編譯器和許多其他工具根據涉及U N I C O D E的優
先權,來選擇正確的結果。在C + +程序中,當引用M e s s a g e B o x時,根據對編譯器的指令,使用
的擴展為M e s s a g e B o x A和M e s s a g e B o x W宏。當然,這意味著編譯器的錯誤信息涉及到哪個函數
會被拒絕,例如M e s s a g e B o x A。
1.4.1 實際情況
上節討論Wi n d o w s體系結構,本節內容卻很少。事實上,這些顯示屬于Wi n d o w s的程序是虛
假的。Windows 2000 (和Windows NT)實際上并不用Win32 API運作。而使用A P I s特殊集,其中
包含執行程序(E x e c u t i v e)。M i c r o s o f t并沒有公開執行程序的文檔,但確是基本集, M i c r o s o f t及
其授權用戶能夠用來構建操作系統的A P I。這些執行程序執行所有運作。
然而,用戶不直接調用執行程序,而是調用一個子系統。該子系統提供個性化的程序。例
如,Wi n 3 2子系統執行如G e t C u r r e n t P o s i t i o n E x和M e s s a g e B o x A函數,并調用使其工作的執行程
序。還有其他子系統(比如,提出貧乏P O S I X的子系統)。
NT 4以前,Wi n 3 2子系統就像其他子系統一樣是一個單獨的模塊。然而,當NT 4和Wi n d o w s
2 0 0 0面世時,Microsoft 意識到幾乎所有程序實際上都要用Wi n 3 2子系統。因此,現在的N T版本
中,Wi n 3 2子系統實際上是執行程序的一部分。對應用程序編程人員來說,這沒什么差別,只是
其速度更快些。
執行程序之下是硬件分離層( Hardware Abstraction Layer, HAL)程序。這段軟件甚至被普
通編程人員進一步移除。這段代碼知道如何執行Wi n d o w s所需的所有機器特定的任務。所以如
果你想將Wi n d o w s輸送到其他類型的計算機中,你只需編譯Wi n d o w s代碼和編寫客戶的H A L。當
然,為了獲得所有代碼和文檔,就必須得到M i c r o s o f t的同意,因為M i c r o s o f t不公開支持H A L
(或Wi n d o w s源代碼)。對于單處理器或多處理器,存在不同的H A L。對于不同的機器體系結構,
如在Power PC中也會找到H A L。
1.4.2 Wi n 9 5與Wi n 9 8
Windows 95和Windows 98(合起來,稱Windows 9x)如何適于本形象描述呢?如前所述,
Windows 9x更象Windows 3.1而不象Windows NT Lite 。盡管在Windows 95中提供了大部分
Win32 API命令,但它們中的大多數并沒有比Wi n 1 6副本功能強多少。通常,也有例外,如果在
Wi n 1 6中都做不到,那在Windows 95或9 8中也無法實現。
起初,這看起來不可思議。為什么新技術業已成熟時( Windows NT 已研發成功),
M i c r o s o f t仍然發布基于舊技術新產品呢?答案就是市場。Windows 95的一個關鍵目標是鞭策開
發3 2位的程序。由此,幾乎所有Windows 3.1 的用戶不得不轉而使用Windows 95 。否則,
Windows 95會成為另一個Windows NT一樣的犧牲品—沒有應用軟件的強大系統。
M i c r o s o f t編寫Wi n d o w s - O n - Windows (WOW)模塊,以使Windows NT運行Windows 3.1的程
序,并令人驚喜。許多重要問題利用Win16 API出現的缺陷和未公布的特性。這些程序在W O W
情況下運行時會失敗, W O W是根據文檔運轉的。
使W O W真正成為Win16 API是棘手的,所以M i c r o s o f t的回答是保留W O W以使它們做應該
做的事。如果程序無法運行,就是存在缺陷。這意味著一些Windows 3.1程序無法運行在N T上。
對Windows 95來說,沒人準備采用W O W。家庭用戶不大可能更新他們的機器,即使他們也
懷疑一些程序后來無法運行。于是M i c r o s o f t需要把Wi n 1 6子系統復制到Windows 95中。
Microsoft 采用顯而易見的解決辦法:采用現有的Wi n 1 6子系統。這保證所有現存的Wi n d o w s
3 . 1軟件實際上運行在Windows 95下,還能使老的Windows 3.1驅動程序能工作。M i c r o s o f t重寫了
完全使用3 2位代碼的程序部分,但僅僅是一小部分(特別是字體翻譯和內存管理)。
那么,Windows 9x作為3 2位系統會怎么樣?由于它包含Win32 API,它將Wi n 3 2命令轉換成
Wi n 1 6命令(更象走厄運的Wi n 3 2 S產品)。由于這種措施,使許多N T特性不存在于Windows 9x。
其他特性在Windows 95和N T中也不同。為了適應Wi n 1 6程序,內存設置也有所不同。
該書不是講述Windows 95 (或延伸到Windows 98 )的。然而,它有助于理解如何適合
Wi n d o w s 2 0 0 0。不要在意有關Windows 95/98的內容,但要了解來自N T家族的顯著差別。
1.5 Wi n d o w s的特性與差別
如果用慣了早期版本的Wi n d o w s,或不同類的操作系統,就會發現有關Wi n d o w s 2 0 0 0的奇怪
特性。你也不必為此驚嘆不已,而需要逐漸習慣之。當然,我們沒有預先安排,只是闡述
Windows 2000是如何工作的。
1.5.1 多任務處理與線程處理
如果使用過U N I X,再使用Windows 2000的多任務處理,也許會有失敗感。理由是U N I X
(或其他操作系統)雖有處理多任務的不同方式,但其許多術語是相同的。
在Windows 2000下運行程序時,可以創建進程,這并不奇怪。令人驚奇的是操作系統沒有
運行進程的進度表。進程擁有打開文件、內存或其他資源,同時還擁有一個線程。
什么是線程呢?線程( t h r e a d)就是一組處理器寄存器的記錄。它了解執行到代碼的什么地
方,局部變量放在什么地方。Wi n d o w s安排線程的進度,就好象兩次交談。安排線程進度與安
排進程進度有什么區別呢?那就是每個進程只有一個線程。
然而,設想主線程又創建另一個線程會如何呢?而該線程也許又創建更多的線程。重要的
是Wi n d o w s安排線程進度,而不是安排進程進度。連同來自其他進程的線程,每個線程輪流運
行。
那么,線程和進程有什么差別呢?很簡單屬于一個進程的所有線程容易進行通信,因為它
們共享內存和其他資源,而屬于不同進程的線程不易共享數據或通信。的確,它們可以通信,
但需要進程間通信的方法。
1. 派生
對于以前的U N I X編程人員,另外的困難是缺少派生( f o r k)構造。在U N I X中,派生命令復
制當前進程。兩個進程相同,每一個都有一個程序數據的私有拷貝。通常,派生之后,就調用
執行( e x e c )。這將一個新文件裝載到一個新進程中,去除原進程的拷貝。對Wi n 3 2 的
C r e a t e P r o c e s s函數來說,作為單個命令,派生與執行是相同的。
但是如果想要復制進程及保存兩個復制品時,又會如何? Wi n d o w s不易實現這些。這為什么
是重要的?假設你有一個程序,試圖優化塑料球生產進度。這是個實例,因為以特殊順序生產
塑料球會更經濟。換句話說,假設必須生產A、B、C三種塑料制品,以滿足訂單。如果以從A到
B再到C的順序生產,將浪費兩噸塑料。為什么呢?因為每次都要改變生產的塑料制品,在生產
進程中存在化學混合物殘渣,將造成一些浪費。但是當B類制品與A類制品更相似,A類制品與C
類制品沒有太大的化學性質上的差別時,情況又怎樣呢?那么,當先生產B制品,然后生產A制
品,再生產C制品時,也許只浪費5 0 0磅。
對于這個假設的程序,第一步是閱讀所有的順序及當前產品清單,并使之相互匹配。其余
的事就是必須自己加工。現在,你的程序想要嘗試幾種優化的策略。每次嘗試一個策略,與之
不同U N I X程序可以派生多次,為每個優化方法創建新進程。每個新進程得到一個在第一次運行
時搜集到的數據的私有拷貝。最后,主進程將檢驗結果,并決定哪種方法最好。
在Windows 2000 中,這將很難做到。你可以使用C r e a t e P r o c e s s開始一個新進程,但是默認
情況下將沒有和老程序共有的數據。的確,可以使用共享的存儲區域,甚至一個文件,但這樣
也不那么簡單。
使用線程會怎樣呢?這也是一種可能。然而,如果優化方式改變了數據,就不可行了,因
為所有線程共享相同的變量。以派生為例,每一步運行都自動地擁有一個私有數據拷貝。在不
影響相關進程的情況下,每個進程都將改變變量。
有趣的是,由于對于P O S I X子系統是可以做到的執行程序有進行派生的能力。然而沒有辦
法訪問Wi n 3 2的派生處理。請注意:朗訊技術公司的David Korn 已有支持Win32 ( U/Win ) 的
P O S I X庫(見w w w. r e s e a r c h . a t t . c o m / s w / t o o l s / u w i n /),其余的就是執行派生。據悉,該庫運用
C r e a t e P r o c e s s聯合特殊的啟動代碼,它復制使用進程間通信方法的所有數據。聽起來也許有許多
工作,但實際上運行得相當不錯。
2. Windows NT與Windows 2000 對Windows 3.1
即使熟悉Windows 3.1,也必須要重新考慮多任務處理。當然, Windows 3.1中沒有線程,所
運行的每個程序都是一個進程。由于進程都共享內存和Windows 3.1下的其他資源,它們其實更
像Wi n d o w s線程。
另外的問題是程序如何放棄處理器的控制。在Windows 3.1下,程序執行到它們調用少數系
統函數(GetMessage , PeekMessage或Yi e l d)之一為止。此時,Wi n d o w s會選擇中止該程序并恢
復執行另一個。這種相互協作的多任務處理的技術簡單地執行和釋放程序,而編程人員不必擔
心死鎖或資源競爭。只要不調用任何特殊函數,就不必擔心其他程序搶占正在使用的資源。
這種方案的缺點是,如果程序不調用這些特殊函數,系統就死鎖。這就是為什么Wi n d o w s
3 . 1中沒有S l e e p命令的原因。如果程序沒有進程消息而暫停的話,系統的其他部分就會掛起。
Wi n d o w s使用搶先的多任務處理。還可能通過執行某些命令,使自己睡眠。然而,如果不執
行這些命令,Wi n d o w s最終總置于睡眠狀態。
這是好事,對不對?大多數情況下是如此。它防止由于運行錯誤程序而死機。也使系統對
用戶做出更快的響應。但對編程人員來說,這增加了額外的負擔。假設有幾個程序共享一個錯
誤登錄文件。在Wi n d o w s下,可以打開該文件,改寫數據并關閉它。只要沒有調用任何特殊的
系統命令,就會知道沒有其他程序打開該文件(由于沒有其他程序能運行)。
Windows 2000就沒有這么簡單。你可以打開文件,然后放棄(不知不覺地)對另外線程的
控制。如果有線程試圖打開相同的文件,會發生什么呢?每個線程都不能打開文件,或以共享
方式打開文件(這不是所希望的)。即便Wi n d o w s沒有搶先,也可能有另外的線程執行其他進程,
而引起相同問題。
對于許多操作系統(如U N I X)來說,這是個老問題,其解決方法并不復雜。Wi n d o w s提供
同步對象(見第4章),它能協助解決這類問題。你需要明白,這類問題總會發生。
1.5.2 UNICODE
默認情況下, Windows 2000 不使用A N S I字符,而所有內部字符串都是U N I C O D E。
U N I C O D E是一個1 6位的字符序列(不象A N S I使用8位)。在額外的空間下, U N I C O D E可以容納
不同的符號和非英語字符。
當然,大多數編程人員(至少在美國)仍使用A N S I。如果你愿意, Wi n d o w s也允許使用
A N S I(至少,多數情況如此)。其技巧是每個接收或返回字符串A P I函數實際上是兩個函數:一
個配合U N I C O D E,另一個配合A N S I。當你設置方案時,開發工具(如Visual C++)通常允許你
選擇使用哪一個函數。
假定在C + +程序中用到命令M e s s a g e B o x。其編譯器根據是否用U N I C O D E模式,定義符號。
頭文件為M e s s a g e B o x定義一個宏,并將其擴展為A N S I編譯的M e s s a g e B o x A及U N I C O D E編譯的
M e s s a g e B o x W。當錯誤信息和調試輸出引用M e s s a g e B o x A時,這將導致混亂。
若要將字符串從A N S I 轉換成U N I C O D E ,可以使用Wi d e C h a r To M u l t i B y t e 和
M u l t i B y t e To Wi d e C h a r函數。當然, U N I C O D E字符串并不能完全無誤地轉換為A N S I字符串,且
Wi n d o w s可能替代一些A N S I不能表示的一些字符。
1.5.3 文件系統問題
Windows 2000利用可安裝的文件系統技術。這意味著在同一臺機器上,也許會涉及到不同
的文件系統。可能同時在一個硬盤驅動器上使用V FAT(Windows 95的兼容系統),而在另一個
硬盤驅動器上使用N T F S(Wi n d o w s文件系統所選擇的)。
通常,只要不設定文件的名字,這些問題就不會困擾你。例如,設定文件的名字包含1個到
8個字符、1個句點、及1個到3個字符,大概會出錯。如果將文件的名字視作神秘的、不可知的
字符串,也許就不存在任何問題。
在NT 4以前,可以安裝H P F S(O S / 2方式)的文件系統。NT 4撤消了對H P F S正式支持,雖
然在I n t e r n e t上的報告指明,如果需要的話,也可以從NT 3.15安裝盤安裝之。
值得注意的是, N T F S并不能在軟磁盤上運行。NT 3意味著在軟磁盤上不能有長文件名。
NT 4和Wi n 2 0 0 0支持V FAT( Windows 95文件系統),它支持長文件名,因此可以在軟磁盤上使
用V FAT。然而,仍沒有得到N T F S所提供的其他額外特性。
這些特性是什么呢? N T F S是安全的基礎。在FAT和V FAT磁盤上不能保護文件的安全。到底
為什么還要FAT和V FAT呢?因為軟磁盤很重要,且不能格式化一個N T F S軟磁盤(這是不公開的,
如果你真想這樣做的話,請見w w w. n t s e c r e t s . c o m)。還有,許多用戶會在同一臺機器上安裝
Windows 95、Windows NT和Windows 2000。如果沒有FAT和V FAT,將不能在兩個安裝程序間
共享硬盤(還有,不公開地, w w w. n t s e c r e t s . c o m具有針對Windows 95的只讀N T F S驅動程序)。
你要在N T F S下運行Wi n d o w s,則所有情況都一樣。然而,你不能指望它。一些用戶正在使
用V FAT或甚至使用H P F S。即然沒有臨時的本地硬盤,就別指望能從網上發現什么。關鍵是假
定你對文件名象什么知道的不多。
1.5.4 DLL
動態鏈接庫(Dynamic Link Libraries, DLL)是Wi n d o w s的構架。每次調用系統命令,都將
調用M i c r o s o f t提供的D L L。這使你能夠使用代碼庫,而實際上在鏈接時程序中并不包含它們。
這有三個優點:使程序更小、不同的程序能共享相同的庫、庫的更新不需要與程序重新鏈
接。當然,也可以創建自己的D L L并使用它們。
Windows 3.1 的D L L有許多Win2000 DLL 不能共享的特性。不同于Windows 3.1,Wi n 2 0 0 0
調用D L L中函數,以提示進程何時裝載D L L及何時釋放D L L。使用D L L為每個進程分配資源是
十分簡單的。
當多于一個進程使用一個D L L時,D L L能夠專為每個進程設置某個變量,或在進程之間共
享共同的變量。這考慮到共享存儲器的未加工的形式,且如果需要在進程間進行通信,是相當
有用的。
當Wi n d o w s試圖將D L L裝載到程序進程空間時,首先檢測是否為其他進程裝載了相同的D L L。
若有,Wi n d o w s將簡單地嘗試將D L L所在相同的內存映射到兩個進程中(當然,除去私有的數據
內存)。只有當第二個進程有空閑內存,而在同一地址,第一個進程在使用D L L的情況下,這樣
才有效。
如果第二個進程正在使用一些所需要的內存,會怎么樣呢?這時, Wi n d o w s必須重新裝載
D L L(除非共享內存頁)。這意味著兩個使用相同D L L的進程,也許對D L L的地址的意見不一致。
這不是個一般問題,如果在共享內存中使用D L L,就會有問題。最后一行:不要將指針指向共
享內存。相反,考慮使用從共享內存首地址起的偏移量。我們將在第6章學習到有關該題目更多
的內容。
1.6 開發工具
Wi n d o w s當然沒有開發工具方面的不足。當然, Wi n d o w s的多數開發者的材料都有C + +編程
人員的功勞,這本書也不例外。即使你不打算使用C + +,但幾乎所有M i c r o s o f t文檔都是用C + +寫
的(至少在用其他語言前,都是用C + +),因此,你要逐漸熟悉它。
然而,當然也有許多可行的Wi n d o w s開發平臺。例如, J a v a目前很流行。B o r l a n d公司有
Delphi, 可視化的Pascal (及C++ Builder, 它以同樣的方式使用C + + )。經常被忽略的語言是Vi s u a l
Basic (VB)。V B顯示出真正的編譯器,強大的A c t i v e X支持,可以毫不費力地調用A P I。
然而還有不少其他的開發工具,而C + +、J a v a和V B當然是主要的開發工具,可能用來在底
層開發Wi n d o w s。本書中的示例幾乎都是用C + +編寫的,但本章中的直接解答部分將展示如何從
這三種語言中調用A P I的方法。
結束語
本章展示了寓于Wi n d o w s的一些概念,以及與所熟悉的其他操作系統之間的差別。當你想要
建立知識的基準時,請記住,Wi n d o w s不同于你所熟悉的操作系統,不要拒絕它。
在以下各章中,你會閱讀到Wi n d o w s的更多內容,包括本章中主題內容的展開。讀完本書,
你自然會接受Wi n 2 0 0 0,信不信由你!
1.7 直接解答
1.7.1 開發工具的選擇
當閱讀本書有關Wi n d o w s詳細內容時,大概會比其他事情更多地涉及到C + +。另一方面,許
多編程人員已經轉而使用J a v a,對于大多數設計項目來說,它也是可取的選擇。然而,本書中的
大多數示例都是帶有類庫( M F C)的C + +程序,因為現在看來大多數C + +編程人員總是使用
M F C。你應當可以讀懂這些示例(包括程序清單和附錄),盡管有些小困難。圖形化的用戶界面
是不重要的,在那里,可以看到許多寫成控制臺應用程序的例子。控制臺應用程序允許用戶編
寫C或C + +的代碼,它們都帶有m a i n函數和標準I / O函數。
另一個令人感興趣的語言的選擇是B o r l a n d公司的Delphi ( 或相關的C++ Builder)。這個編程
環境是高度圖形化的,并且完全能夠編寫底層代碼和調用Pascal (Delphi)或C + +(C++ Builder)
語言中的A P I。
盡管Visual Basic很長時間被系統編程人員輕視,但VB6 也是個不錯的選擇。如果需要使用
A c t i v e X,選擇V B 6尤其正確,因為V B 6在構成A c t i v e X方面做了大量的工作。V B 6還提供本地機
的代碼編譯,并消除了以前V B版本性能上的許多缺陷。你可以容易地調用多數A P I。其主要缺
點是V B程序需要相當大的運行時間庫。這也是M F C程序的缺點,但這并不能阻止人們使用
M F C。
不論選擇何種語言,都需要能懂構成Wi n d o w s標記的原理。那是本書所討論內容的真正目的,
盡管多數示例是用C + +語言描述的。
1.7.2 Windows 的體系結構
對應用程序編程人員來說,Wi n d o w s為每個程序提供2 G B的平面虛擬地址空間(有些版本是
3 G B)。通常使用規定的3 2位指針,它可以從0尋址到2 G B。
面向操作系統的命令都保存在動態鏈接庫中( D L L)。這些命令將你的需求傳送給Wi n 3 2子
系統,該子系統轉而控制Wi n d o w s執行程序,這些執行程序( E x e c u t i v e)則完成實際工作。通
過該點,執行程序則在硬件抽象層( H A L)進一步調用處理操作的機器規定部分。
1.7.3 理解進程
很重要的一點是,不要混淆Wi n d o w s進程和其他操作系統的進程概念。在Wi n 2 0 0 0中,一個
進程就相當于一個容器。那容器又包含什么呢?存儲空間、打開文件、資源和線程。線程實際
就是個執行單元,Wi n 2 0 0 0安排線程進度,但不安排進程進度。
一個進程開始于一個線程,該線程能夠創建更多的線程(且這些線程又可以創建更多的線
程)。一個進程里的線程共享該進程中的所有東西。它們具有的唯一性是程序中的執行點,以及
在進程地址空間中局部變量的位置。
存在于不同進程中的線程不共享什么資源,除非通過使用規定的進程間通信技術,使它們
共享資源。
1.7.4 從C + +中調用A P I
從多數C + +環境(包括Visual C++),調用A P I相當簡單。只要確信包含適當的頭文件(通常
是W I N D O W S . H)及有正確的庫(通過在線幫助,就可以找到所需要的庫)即可。于是就實現
調用。A P I都被設計成符合C / C + +環境。
由于所應用的環境已經設置好一切,使我們可以輕松地調用A P I,所以通常我們無需考慮那
么多。如果你在使用如M F C一樣的庫,就需要包含如W I N D O W S . H(或其他文件)的庫頭文件。
要記住,根據在使用A N S I還是在使用U N I C O D E,編譯器會在后臺改變許多A P I的名字,以
及它們如何做相應的改變。例如, M e s s a g e B o x命令改變為針對A N S I編譯的M e s s a g e B o x A及針對
U N I C O D E的M e s s a g e B o x W。當查看映象文件、調試信息、或編譯器錯誤信息時,就可以見到這
些名字。
順便說一下,從D e l p h i中調用A P I同樣很容易。只要包括正確的單元,及用相應的庫鏈接即
可。還有,這些總是設置好的。
1.7.5 從V B中調用A P I
盡管V B通常不調用A P I,但可以利用一些手段來實現V B中調用A P I。訣竅是V B幾乎可以調
用D L L中的任何一個函數。由于Wi n d o w s的A P I就是D L L的集合,所以V B能夠構成A P I命令。
因為A P I很大,每次運行任何程序的時候,為了了解每個A P I命令,都會降低V B的編程速度。
然而,多數程序僅僅使用少數命令。M i c r o s o f t提供了A P I文本閱讀器( API Text Vi e w e r )。使用該
閱讀器,可以選取感興趣的命令,并且該瀏覽器將它們作為說明( D e c l a r e)報告輸送到所選擇
的文件中去。這些說明報告使調用A P I成為可能。
這很方便,但也存在一些問題。閱讀器并不了解它們之間依賴關系。根據創建輸出文件過
程,當試圖運行程序時,可能會出錯。例如,在下面的語句中,會得到一個錯誤:
Public Const KEY_EXECUTE = (KEY_READ)
檢查文件,就會發現K E Y _ R E A D是在文件的后面部分定義的。因此,你必須手動地將
K E Y _ R E A D的定義向前移動,以使它處于K E Y _ E X E C U T E之前。
另一個問題很類似。僅僅為了找出基于所需要輸出的內容,你可以輸出一個函數或標識符
(如上述示例中的K E Y _ R E A D)。一旦確定,就有可能發現還需要增加其他項。這樣繼續下去,
直到挖掘出所有的依賴關系。
1.7.6 從Visual J++中調用A P I
從Visual J++中調用A P I很有挑戰性,因為你必須使用J a v e的本機程序界面,它也很棘手。
12 Windows 2000系統編程
然而,M i c r o s o f t的J / D i r e c t卻使其變得相當容易。
J / D i r e c t包括兩個部分。第一部分可使你調用D L L s中的任意函數而不會有麻煩,第二部分是
調用通用Win32 API的簡化方法。
利用第一部分,使用如下J a v a代碼的特殊的注釋和程序行,能夠定義A N S I的M e s s a g e B o x函
數:
/** @d11.import ( "U S E R 3 2") */
private static native int MessageBox ( int w,String msg,String title,int flags );
還能夠調用U N I C O D E版本,如:
/** @d11.import ( "U S E R 3 2",unicode) */
private static native int MessageBox ( int w ,String msg,String title,int flags );
當然,不想對整個A P I編寫這些語句,所以M i c r o s o f t應用幾個類來包裝整個A P I。你也許會
如下面語句,來調用M e s s a g e B o x:
com.ms.win32.User32.MessageBox ( 0 ,"H i","Java Message Box ",0 );
這沒什么麻煩,U s e r 3 2類照顧所有數據類型的轉換和D L L的輸入。
1.7.7 Internet資源
這里,給出查閱資料的U R L:
w w w. a l - w i l l i a m s . c o m—作者的站點,每月都會有各種M F C的提示及關于本書的更新內容。
w w w. s y s i n t e r n a l s . c o m—是尋找N T和Windows 2000系統應用程序的網址。
w w w. z d n e t . c o m / p c c o m p / f e a t u r e s / f e a 0 7 9 7 / n t / w e l c o m e . h t m l—來自PC Computing雜志,題目
為“NT Lies”的有趣文章。
(文章整理中待續......)
總結
以上是生活随笔為你收集整理的Windows 2000系统编程 (1)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 新词添加功能:错别字检查接口 API
- 下一篇: 【中信卡】数据挖掘分析笔试+面经