• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            依舊的博客

            技術(shù)學習

            C++博客 首頁 新隨筆 聯(lián)系 聚合 管理
              17 Posts :: 1 Stories :: 2 Comments :: 0 Trackbacks

            2007年4月15日 #

            關(guān)于Windows程序模型的最重要之處在于,程序是在Windows面向?qū)ο蟮捏w系結(jié)構(gòu)中運行的。

            在WinMain()函數(shù)中,程序所進行的最重要工作是注冊窗口類,從而把自定義的窗口過程提供給Windows。然后程序調(diào)用Windows創(chuàng)建和顯示窗口,由此啟動同用戶的交互過程。在消息循環(huán)中,程序不斷取得消息,但并不進行處理,而是將其發(fā)回Windows,由Windows將消息發(fā)給相應的窗口過程。消息循環(huán)的作用在于控制生命期,如果沒有消息循環(huán),進程將立即結(jié)束。

            在較高層次上來看,一個可擴展的系統(tǒng)會給模塊提供資源和自由,而模塊應當配合系統(tǒng)的整體結(jié)構(gòu)。程序執(zhí)行時,Windows會為其創(chuàng)建進程,分配資源,并調(diào)用WinMain()。WinMain()是進程入口,也是進程出口,在此期間進程可以做任何事情,但是為了使用Windows提供的各種便利,它必須符合Windows程序模型,將自己的運行結(jié)合到Windows環(huán)境中。作為進程出口,WinMain()決定著程序生命期。一個提供窗口過程而等待Windows調(diào)用的程序如何維持和結(jié)束自己的生命期呢,應該由消息來決定。當進程沒有要處理的消息時,它應該等待,所以WinMain()必須知道有沒有消息,Windows發(fā)給窗口過程的消息不能繞過WinMain();當進程收到特定的消息時,它結(jié)束生命期,所以WinMain()還應該了解消息的內(nèi)容。這正是GetMessage()所做的,如果取不到消息就阻塞,如果取到WM_QUIT消息就返回0,結(jié)束消息循環(huán)。那么如果取到普通的消息呢,由WinMain()直接調(diào)用窗口過程不可以嗎?這種做法有悖于程序由Windows調(diào)用的基本思想,而實際上也會出現(xiàn)問題。一個窗口程序可能有很多窗口類,一些窗口類及其窗口過程是程序自定義的,另一些則是在Windows內(nèi)部定義的,程序看不到其窗口過程,比如各種控件窗口。窗口程序運行起來以后,這些窗口類互相配合,它們通信的方式就是消息。由于消息指向的窗口過程可能是自定義的,也可能是Windows內(nèi)部的,只有Windows才能把它們都送到目的地,并保持發(fā)送方式的一致性。所以WinMain()取到消息后,通過DispatchMessage()將其發(fā)回Windows,由Windows為其調(diào)用適當?shù)拇翱谶^程,直到窗口過程調(diào)用后返回Windows,DispatchMessage()才返回。(Windows調(diào)用窗口過程之后控制首先返回Windows,由WinMain()調(diào)用窗口過程之后控制保持在程序中,這種區(qū)別是否也有作用?不過經(jīng)我試驗,在一個Win32 SDK的Hello程序中改由WinMain()調(diào)用窗口過程,沒有發(fā)現(xiàn)什么問題)

             
            參考資料:

            1.《Windows程序設計》/Charles Petzold 著 北京博彥科技發(fā)展有限公司 譯 北大出版社
            posted @ 2007-04-15 13:08 依舊的博客 閱讀(343) | 評論 (0)編輯 收藏

            2007年1月28日 #

            如果在VC中創(chuàng)建一個控制臺的EXE和一個Win32的DLL,從DLL中導出一個函數(shù),該函數(shù)用new分配一塊內(nèi)存,返回其指針,然后在EXE中調(diào)用該函數(shù),獲得返回的指針,用delete釋放這塊內(nèi)存,就會引發(fā)斷言錯誤。

            產(chǎn)生這個問題的原因是:EXE和DLL中分別靜態(tài)鏈接了C運行時庫,從而new和delete運算符來自C運行時庫的不同版本。C運行時庫在管理堆內(nèi)存時,會使用一些全局變量來跟蹤內(nèi)存分配情況,因此程序中鏈接的C運行時庫必須唯一,否則就會引起不一致。

            解決的辦法很簡單:在EXE和DLL中都動態(tài)鏈接C運行時庫,也就是在工程設置的Link面板選擇"忽略所有默認的庫",再加入msvcrt.lib。

            對這個問題有兩種錯誤的觀點需要澄清:一種以為EXE和DLL有不同的堆,實際上DLL總是被映射到加載它的進程的地址空間,它沒有自己的堆;一種以為DLL和EXE相對于不同的起始地址,動態(tài)鏈接的地址映射機制引起了前面的問題,實際上DLL是和OBJ一樣的目標模塊,每個目標模塊都有自己的起始地址,但是鏈接成加載模塊以后就會統(tǒng)一到一個起始地址,一個目標模塊對其它模塊的引用在鏈接前是以符號方式表示的,鏈接后會被修改成地址方式。靜態(tài)鏈接和動態(tài)鏈接都會保證:加載模塊是統(tǒng)一編址的。

            參考資料:
            1. http://topic.csdn.net/t/20020714/19/873683.html
            2. MSDN July 2000/Knowledge Base/Windows Development/Win32 Software Development Kit/HOWTO: Use the C Run-Time
            3. 《操作系統(tǒng)-內(nèi)核與設計原理(第四版)》/William Stallings 著,魏迎梅等譯 電子工業(yè)出版社

            posted @ 2007-01-28 14:02 依舊的博客 閱讀(311) | 評論 (0)編輯 收藏

            2006年10月19日 #

            有兩個比較基本的問題:

            1. 為什么要用異常代替錯誤碼?

            錯誤碼的缺點:

            1) 默認是可以忽略的,因為調(diào)用函數(shù)時可以不處理其返回值,從而錯誤處理要依賴于程序員的主動性,而不是程序機制的要求;

            2) 不能跨作用域傳送,必須逐層向上轉(zhuǎn)發(fā),即使中間沒有對錯誤碼進行重新定義;
            ?

            使用異常可以解決解決這兩個問題:

            1) 異常默認是不可忽略的,拋出的異常必須捕獲,否則就會報錯;

            2) 異常可以跨作用域傳送,從而錯誤的發(fā)現(xiàn)和處理被很好地分離開來;
            ?

            ?

            2. 異常和斷言的區(qū)別:
            ?

            異常被捕獲后可以不作處理,程序從捕獲位置繼續(xù)執(zhí)行。而斷言是完全無法忽略的,程序在斷言失敗處立即終止。因此斷言通常用于調(diào)試版本,用來發(fā)現(xiàn)程序中的邏輯錯誤。雖然異常也能起到這樣的作用,但是不應該用異常代替斷言:
            1) 如果發(fā)現(xiàn)了邏輯錯誤,必須修改程序,而不可能在程序中進行處理和恢復,所以不需要向外傳送,沒有必要使用異常。
            2) 使用斷言的開銷比異常小得多,而且斷言可以從發(fā)布版中完全去除。
            ?

            異常用于處理正確程序中的運行期問題(比如內(nèi)存分配失敗,窗口創(chuàng)建失敗,線程創(chuàng)建失敗,打開文件失敗),以盡可能恢復,而不是終止程序。對于運行異常,使用斷言是非常不合適的,理由很顯然:
            1) 斷言在發(fā)布版不起作用;
            2) 斷言的處理方式不夠友好;
            3) 運行異常不是程序錯誤,沒有必要報告源代碼出錯位置;



            參考資料:

            1.《C++編程規(guī)范-101條規(guī)則、準則與最佳實踐》/Herb Sutter,Andrei Alexandrescu 著 劉基誠 譯 人民郵電出版社
            2.《C++程序設計語言》/Bjarne Stroustrup 著?裘宗燕 譯 機械工業(yè)出版社
            3.《C與C++中的異常處理》/Robert Schmidt 著 無情 譯 http://download.pchome.net/development/reference/11135.html

            posted @ 2006-10-19 21:28 依舊的博客 閱讀(1443) | 評論 (0)編輯 收藏

            2006年9月10日 #

            軟件設計中會碰到這樣的關(guān)系:一個對象依賴于另一個對象,必須根據(jù)后者的狀態(tài)更新自己的狀態(tài),可以把后者稱作目標對象,前者稱作觀察者對象。不但觀察者依賴于目標,當目標的狀態(tài)改變時也要通知觀察者,這就出現(xiàn)了雙向的依賴。兩個對象互相依賴的后果是它們必須一起復用。如果一個目標有多個觀察者,那么目標也依賴所有觀察者,從而目標對象無法獨立復用。如何消除目標和觀察者之間的互相依賴呢?觀察者模式幫助我們解決這個問題。

            觀察者模式把目標對觀察者的依賴進行抽象:使目標只知道自己有若干觀察者,但不知道這些觀察者具體是誰,可能有多少個;當目標狀態(tài)改變時只要給這些觀察者一個通知,不必作更多的事情。這樣目標對觀察者的依賴就達到了抽象和最小,而目標對具體觀察者的依賴被解除了。

            類圖如下:

            Observer.JPG

            Subject對象保存一個Observer引用的列表,當我們讓一個ConcreteObserver對象觀察Subject對象時,調(diào)用后者的Attach()方法,將前者的引用加入該列表中。當Subject對象狀態(tài)改變時,它調(diào)用自身的Notify方法,該方法調(diào)用列表中每一個Observer的Update()方法。一個ConcreteObserver只要重定義Update()就能收到通知,作為對通知的響應,Update()調(diào)用Subject對象的getStatus()獲取數(shù)據(jù),然后更新自身。當不需要繼續(xù)觀察時,ConcreteObserver對象調(diào)用Subject對象的Detach()方法,其引用被從列表中移除。

            解除目標對具體觀察者的依賴以后,很容易增加新的具體觀察者,因為不受依賴的方面就可以自由變化;而目標也可以獨立地復用,因為無所依賴的方面就可以不受影響。

            以上主要考慮了一個目標有多個觀察者的情況,我們設法解除了目標對具體觀察者的依賴,使具體觀察者的種類和數(shù)目容易改變。有時候一個觀察者觀察多個目標也是有意義的,在前面的類圖中,觀察者對具體目標的依賴仍然存在,因此無法適應目標方面的變化。怎樣抽象這種依賴呢?使觀察者只知道若干個目標會向自己發(fā)出通知,而不知道這些目標具體是誰,可能有多少個;在目標向觀察者發(fā)送通知時,將一個自身的引用作為參數(shù),然后觀察者調(diào)用其抽象方法就可以獲得目標狀態(tài)。這就使得觀察者對目標的依賴是抽象的,觀察者對具體目標的依賴被解除了。

            類圖如下:

            Observer2.JPG

            參考資料:

            1.《設計模式-可復用面向?qū)ο筌浖幕A》/Erich Gamma等著,李英軍等譯 機械工業(yè)出版社

            posted @ 2006-09-10 12:53 依舊的博客 閱讀(2286) | 評論 (0)編輯 收藏

            2006年8月8日 #

            Factory Method-創(chuàng)建多種同類產(chǎn)品的工廠:

            為一類產(chǎn)品 ( 一個抽象產(chǎn)品及其所有具體產(chǎn)品 ) 提供一個工廠,該類的每一種具體產(chǎn)品由工廠中的一個方法創(chuàng)建。種種做法的缺點是不易增加新的具體產(chǎn)品,每增加一個具體產(chǎn)品,工廠中就要增加一個方法,這意味著工廠的所有使用者都要重新編譯。可以用參數(shù)化的方法來改進,工廠只提供一個接受參數(shù)的創(chuàng)建函數(shù),參數(shù)的取值標志了某種具體產(chǎn)品,在創(chuàng)建函數(shù)中對參數(shù)進行判斷,根據(jù)不同的參數(shù)值創(chuàng)建不同的具體產(chǎn)品并返回。這就減小了增加具體產(chǎn)品的代價,每增加一種具體產(chǎn)品時只要修改工廠的創(chuàng)建函數(shù)的實現(xiàn)即可。

            原來是用工廠的不同方法創(chuàng)建不同的具體對象,現(xiàn)在是用同一個方法的不同參數(shù)創(chuàng)建不同的具體對象。還可以用抽象工廠的不同派生類來創(chuàng)建不同的具體對象,這種做法比較笨重.

            Abstract Factory-可替換的工廠:

            見參考資料1


            參考資料:

            1.《設計模式-可復用面向?qū)ο筌浖幕A》/Erich Gamma等著,李英軍等譯 機械工業(yè)出版社
            2.《敏捷軟件開發(fā)-原則,模式與實踐》/Robert C.Martin著 鄧輝譯??清華大學出版社

            posted @ 2006-08-08 13:01 依舊的博客 閱讀(300) | 評論 (0)編輯 收藏

            2006年8月6日 #

            MVC(Model-View-Controller)模式的基本思想是數(shù)據(jù),顯示和處理相分離。模型(Model)負責數(shù)據(jù)管理,視圖(View)負責數(shù)據(jù)顯示,控制器(Controller)負責業(yè)務邏輯和響應策略。

            從MVC的形成過程來看,最初只有模型和視圖兩個元素。模型封裝了數(shù)據(jù)并提供操作接口,視圖用來表現(xiàn)數(shù)據(jù)和接收用戶請求。模型是獨立的,而視圖依賴于模型:從模型獲取數(shù)據(jù)進行顯示;向模型發(fā)送用戶請求,并根據(jù)返回結(jié)果刷新自己。

            需要用多個視圖表現(xiàn)同一模型時,情況發(fā)生了變化:一個視圖修改數(shù)據(jù)以后,不但本身要刷新,其他所有視圖也要刷新。如果由該視圖通知其他視圖,它就需要知道其他所有視圖,由于每個視圖都可能發(fā)出修改,每個視圖都要知道其他所有視圖,這種關(guān)聯(lián)過于復雜,不但難以維護,而且不便于增加新的視圖。如果讓模型通知所有視圖更新,可能會影響模型的獨立性。用觀察者(Observer)模式可以解決上述矛盾,從而實現(xiàn):由模型通知視圖,而模型不依賴于具體的視圖,具體視圖之間相互獨立。

            視圖是用戶請求的接收者,但不宜作為請求的處理者。因為界面是易變的,如果業(yè)務代碼和界面代碼放在一起,頻繁的界面修改可能會破壞比較穩(wěn)定的業(yè)務代碼。將業(yè)務邏輯分離出來,由一個控制器負責,就是為了避免這種干擾。

            模型,視圖和控制器的基本協(xié)作關(guān)系如下圖

            MVC模式協(xié)作圖.gif

            模型在狀態(tài)變化的時候,直接通知所有視圖,視圖向模型查詢狀態(tài)數(shù)據(jù),然后刷新自身。當用戶發(fā)出操作時,視圖把消息發(fā)給控制器,控制器按照業(yè)務邏輯進行處理,需要查詢或更新數(shù)據(jù)時,控制器會調(diào)用模型。下面是一個更詳細的示意圖

            MVC模式協(xié)作圖2.gif


            同樣的數(shù)據(jù),可以有不同的顯示和進行各種處理。顯示僅僅是表現(xiàn)數(shù)據(jù),而處理是根據(jù)用戶請求改變數(shù)據(jù)的過程,不但包含業(yè)務邏輯,也要提供響應策略。響應策略由控制器負責,視圖可以使用不同的控制器提供不同的響應方式,這是策略(Strategy)模式的應用。

            此外,MVC還允許視圖嵌套,通過使用組合(Composite)模式,一致地處理組合視圖和普通視圖。

            用多個視圖表現(xiàn)一個模型,在視圖不變的情況下改變響應策略,允許視圖嵌套,這是MVC的三個主要特性。在內(nèi)部結(jié)構(gòu)上,MVC的主要關(guān)系是由觀察者模式,策略模式和組合模式給出的。由觀察者模式確定的模型視圖關(guān)系是其中最為重要的。

            MVC模式有許多變體。前述結(jié)構(gòu)中,由模型通知視圖刷新,稱為主動MVC;如果由控制器更新模型以后通知視圖,稱為被動MVC結(jié)構(gòu)。在許多應用中,沒有明顯的控制器角色,也沒有視圖嵌套。可見根據(jù)實際需要,構(gòu)成MVC的三個模式上都可能出現(xiàn)變化。Web瀏覽器就是被動MVC結(jié)構(gòu)的一個實例。
            “瀏覽器是一個交互程序,從概念上講,它是由一組客戶、一組解釋器與一個管理它們的控制器所組成。控制器形成了瀏覽器的中心部件,它解釋鼠標點擊與鍵盤輸入,并且調(diào)用其他組件來執(zhí)行用戶指定的操作。例如,當用戶鍵入一個URL或者點擊一個超文本引用時,控制器調(diào)用一個客戶從所需文檔所在的遠程服務器上取回該文檔,并且調(diào)用解釋器向用戶顯示該文檔。每個瀏覽器必須包含一個HTML解釋器來顯示文檔,其他解釋器是可選的。HTML解釋器的輸入由符合HTML語法的文檔所組成,輸出由位于用戶顯示器上的格式版本文檔所組成。解釋器通過將HTML規(guī)則轉(zhuǎn)換成適合用戶顯示硬件的命令來處理版面細節(jié)。HTML解釋器一個最重要的功能是包含可選項。解釋器必須存儲關(guān)于顯示器上位置之間關(guān)系的信息和HTML文檔中被瞄定的項。當用戶用鼠標選定了一個項,瀏覽器通過當前的光標位置和存儲的位置信息來決定哪個項被用戶選定。”(參考資料5)


            MFC的文檔/視圖結(jié)構(gòu)(Document/View architecture)是MVC模式的一種變體,下面討論它是怎樣實現(xiàn)的。

            文檔/視圖結(jié)構(gòu)沒有體現(xiàn)業(yè)務邏輯和視圖的分離,但是將響應策略和視圖區(qū)分開來。它主要包含四種對象:

            1. 文檔
            2. 視圖
            3. 視圖框架窗口
            4. 文檔模板

            這里的視圖框架窗口定義了視圖對用戶輸入的響應方式,而文檔模板用來管理前三種對象的組合。文檔,視圖,視圖框架窗口三者是對應的,從而構(gòu)成一個三元組。一個應用程序可能需要多個這樣的三元組,以實現(xiàn)文檔的多視圖,所以引入文檔模板來表示該三元組。因為程序中可能使用多個文檔模板,MFC用一個文檔管理者對象來管理它們。

            在MFC中,應用程序和主框架窗口是用來封裝底層機制的對象,文檔,視圖,視圖框架窗口和文檔模板是用來構(gòu)架文檔/視圖結(jié)構(gòu)的對象。應用程序通過文檔管理者來使用文檔/視圖結(jié)構(gòu)。

            如果要給文檔增加一種視圖,只需要增加一個文檔模板;如果要改變一種視圖的響應策略,只要改變對應文檔模板中的視圖框架窗口。

            <未完待續(xù)>


            參考資料:

            1.《設計模式-可復用面向?qū)ο筌浖幕A》/Erich Gamma等著,李英軍等譯 機械工業(yè)出版社
            2.《Java與模式》/閻宏 電子工業(yè)出版社
            3.  模型-視圖-控制器 ( MSDN > 技術(shù)資源庫 > 體系結(jié)構(gòu) > 使用 Microsoft .NET 的企業(yè)解決方案模式 >第3章 Web 表示模式)
            4. 《Java設計:對象,UML和過程》/Kirk Knoernschild 著,羅英偉等譯 人民郵電出版社
            5. 《計算機網(wǎng)絡與因特網(wǎng)》/D.E.Comer 著 徐良賢等譯 機械工業(yè)出版社
            6.《深入解析MFC》/中國電力出版社
            7.《VC技術(shù)內(nèi)幕》第5版 / 希望電子出版社

            posted @ 2006-08-06 10:05 依舊的博客 閱讀(3046) | 評論 (0)編輯 收藏

            2006年6月1日 #

            1. 一個用例可以有多個參與者,并且可以同時有多個參與者。
            用例和參與者的關(guān)聯(lián)可以是雙向的,參與者和用例都可以發(fā)起通信。

            2. 用例之間的基本關(guān)系有:泛化,包含和擴展。
            用例A到B的泛化關(guān)系表示A和B是具體與抽象的關(guān)系。
            用例A到B的包含關(guān)系表示A使用了B提供的功能。
            用例A到B的擴展關(guān)系表示A向B提供的可用的功能。
            但從A到B的包含關(guān)系和從B到A的擴展關(guān)系是不同的:
            A包含B說明B是從A中分解出來的公共行為;B自身是獨立的,但對于A來說是不可缺少的一部分。
            B擴展A說明B是從A中分解出來的變體行為,必須指定擴展點,也就是在基本用例中執(zhí)行變體行為的具體條件。B僅僅是A的補充,而不是不可缺少的部分,B自身也不是獨立的。A可以單獨執(zhí)行,表示通常的情況,在特定的情況下,用B來補充它。
            抽象用例不能被實例化,不能被實際執(zhí)行,它的作用在于更好地組織用例關(guān)系。




            參考書:
            《UML用戶指南》/Grady Booch,James Rumbaugh,Ivar Jacobson著 邵維忠等譯 機械工業(yè)出版社
            《統(tǒng)一軟件開發(fā)過程》/Ivar Jacobson,Grady Booch,James Rumbaugh著 周伯生等譯 機械工業(yè)出版社

            posted @ 2006-06-01 17:18 依舊的博客 閱讀(469) | 評論 (0)編輯 收藏

            2006年5月18日 #

            我曾經(jīng)在有一個Windows XP的機器上另裝一個Windows 2000,結(jié)果2000裝完后XP不能啟動了。后來上網(wǎng)看了一些資料,又幾經(jīng)試驗,解決了這個問題。這里總結(jié)一下其中的原理,這個現(xiàn)象很容易在重裝低版本系統(tǒng)后出現(xiàn),而且弄清原理以后,我們可以更自由地處理多系統(tǒng)安裝的問題。

            單個操作系統(tǒng)的引導過程是這樣的:首先,主引導記錄(MBR)被加載到內(nèi)存運行,它讀取磁盤分區(qū)表(DPT),查找第一個活動分區(qū)(可引導分區(qū)),該分區(qū)的引導扇區(qū)存放著操作系統(tǒng)的引導記錄。然后,系統(tǒng)引導記錄被加載到內(nèi)存運行,它從系統(tǒng)安裝目錄讀取系統(tǒng)的啟動文件,將其加載執(zhí)行,控制隨后的啟動過程。

            這里面涉及到一些程序和數(shù)據(jù),它們存放在不同的地方,在不同階段運行。第一段程序MBR,它的數(shù)據(jù)是DPT,它們存放在磁盤的主引導扇區(qū)。第二段程序是系統(tǒng)引導記錄,存放在系統(tǒng)所在分區(qū)的引導扇區(qū)。第三段程序是系統(tǒng)啟動文件,存放在系統(tǒng)所在分區(qū)系統(tǒng)安裝目錄中。這三段程序像接力跑一樣,前一段程序的工作就是加載后一段程序,并把控制交給它。 引導記錄和啟動文件隨操作系統(tǒng)而不同, 是在安裝時形成的,每個系統(tǒng)的安裝程序都把其引導記錄寫入安裝分區(qū)的引導扇區(qū),而啟動文件是系統(tǒng)的一部分。

            上面的引導過程有一個基本缺陷,就是只能引導一個系統(tǒng),并且只能引導裝在第一活動分區(qū)的系統(tǒng)。

            如果一個操作系統(tǒng)不在活動分區(qū),那么該系統(tǒng)要被引導有三種辦法,改寫MBR,改寫第一活動分區(qū)引導記錄,或把所在分區(qū)設為第一活動分區(qū)。最后一種做法是不方便的,系統(tǒng)通常會改寫前兩段引導程序,那么它在解決自身引導問題的同時,也不能破壞其他系統(tǒng)的引導,這就引出了多系統(tǒng)地引導問題。常見的做法是系統(tǒng)提供一個啟動管理器接管引導過程。啟動管理器能夠獲得機器上多個系統(tǒng)的引導記錄,從而可以根據(jù)用戶選擇啟動不同的系統(tǒng)。系統(tǒng)在安裝時改寫磁盤第一活動分區(qū)的引導記錄,使啟動管理器被作為第三段程序加載。

            如果啟動管理器能夠知道機器上每個系統(tǒng)所在的分區(qū),就能獲得該系統(tǒng)的引導記錄,從而可以引導該系統(tǒng)。但實際上,啟動管理器所屬系統(tǒng)的引導記錄是不能再次被加載的,必須特殊對待。同一系列的系統(tǒng),也可能有類似的問題。所以啟動管理器可能要了解機器上每個系統(tǒng)具體如何啟動,相應進行引導。這樣只有讓高版本的系統(tǒng)提供啟動管理器,因為低版本的啟動管理器無法啟動高版本系統(tǒng)。
            2000/XP的啟動管理器是OS Loader。它對98和2000/XP的引導就是不同的,對98是加載98引導記錄的鏡像文件,對2000/XP是加載HAL.DLL等文件。OS Loader在引導多系統(tǒng)時,對于windows系列的引導有特殊性,必須向下兼容。

            OS Loader的載體是ntldr文件,它運行時還會讀取一個配置文件boot.ini,兩個文件都存放在磁盤第一活動分區(qū)根目錄。boot.ini記錄了每個系統(tǒng)所在的分區(qū),每個版本的windows在安裝時都會在boot.ini中填寫有關(guān)自身的一項。2000/XP在安裝時都會更新OS Loader和重寫第一活動分區(qū)的引導記錄,后安裝者的兩個程序才會被保留。如果后裝2000,由于前述的OS Loader版本問題,就可能無法引導XP。

            posted @ 2006-05-18 16:27 依舊的博客 閱讀(919) | 評論 (0)編輯 收藏

            2006年5月15日 #

            我們知道MFC的作用在于封裝Windows的編程接口,并提供應用程序框架的開發(fā)模式。為了完成從前者到后者的過渡,MFC實現(xiàn)了幾種基本機制,它們是消息映射,命令傳遞,運行時類信息(RTCI),動態(tài)創(chuàng)建和序列化。

            消息映射和命令傳遞是對SDK程序交互機制的封裝。序列化是應用程序需要的一種基本特性,即把數(shù)據(jù)保存到磁盤和從磁盤打開數(shù)據(jù)。通過RTCI和動態(tài)創(chuàng)建,可以把軟件的對象數(shù)據(jù)保存到磁盤,反過來從這些數(shù)據(jù)識別和恢復對象,從而實現(xiàn)對象的序列化。基于數(shù)據(jù)庫的序列化機制和這種方式不同,應用程序和數(shù)據(jù)庫之間有一個約定,以什么樣的格式保存什么樣的數(shù)據(jù),再以同樣的方式打開,并且如何重建對象數(shù)據(jù)也定下來了,在打開數(shù)據(jù)時,應用程序不需要有適應性,不需要識別數(shù)據(jù)類型,也不需要根據(jù)在運行期才確定的類型名稱創(chuàng)建其對象。

            動態(tài)創(chuàng)建就是創(chuàng)建某種類型的對象,具體類型在運行時確定,編譯時可能不知道。比如運行時用戶輸入一個類型名稱,如果該類型是程序類型體系中的一員,則程序中將能夠創(chuàng)建該類型的對象。下面的代碼是使用MFC動態(tài)創(chuàng)建機制的一個簡化的例子:

            CRuntimeClass* g_pFirstClass;
            void func()
            {
                 char szClassName[64];
                 CRuntimeClass* pClass;
                 CObject* pObject;
                
                 cout << "enter a class name...  ";
                 cin >> szClassName;
                
                 for (pClass = g_pFirstClass; pClass != NULL; pClass = pClass->m_pNextClass)
                 {
                      if (strcmp(szClassName, pClass->m_lpszClassName) == 0)
                          pObject = pClass->CreateObject();
                 }
            }

            實現(xiàn)動態(tài)創(chuàng)建的思路是把動態(tài)的類型名稱與程序類型體系中的每一個進行比較,與某個類型吻合時讓該類型創(chuàng)建自身的對象。這樣,支持動態(tài)創(chuàng)建的類庫中的每一個類都要額外實現(xiàn)一些功能,即判別一個名稱是否與自身相符,以及創(chuàng)建自身的對象。

            判別一個名稱是否與自身相符,這是運行時類識別的內(nèi)容,所以MFC動態(tài)創(chuàng)建是在RTCI基礎上實現(xiàn)的。

            RTCI是一個對象能夠判定自己是否屬于某種類型,該類型的名稱在運行時確定,編譯時可能不知道。從下面的例子很容易理解RTCI,

            void Func()
            {
                 char szClassName[64];
                 CDocument* pDoc = new CDocument;
                
                 cout << "enter a class name...  ";
                 cin >> szClassName;
                
                 cout << pDoc->IsKindOf(szClassName); //是返回1,否返回0
            }

            有一點需要說明的是,因為CDocument派生于CObject,所以IsKindOf對于CObject也要返回1。因為我們是從動態(tài)創(chuàng)建出發(fā)的,所以如果是這樣可能會有一點背離初衷。但是RTCI明顯和動態(tài)創(chuàng)建有密切聯(lián)系,RTCI也可能有單獨的價值,所以先把RTCI實現(xiàn)起來。

            實現(xiàn)RTCI的思路是讓每一個類記錄自身的類型信息,并提供IsKindOf(char*)函數(shù)進行所給類型與自身類型的比較,而且還要能訪問基類的類型信息,進行比較,一直到根類。所以記錄的類型信息要按繼承關(guān)系連起來,每個類的IsKindOf()還要調(diào)用基類的IsKindOf()。MFC把要記錄的類型信息抽取到一個CRuntimeClass結(jié)構(gòu)體中,每個類中加入一個CRuntimeClass成員即可。

            現(xiàn)在回到動態(tài)創(chuàng)建,在RTCI建立的數(shù)據(jù)結(jié)構(gòu)基礎上將可實現(xiàn)它。動態(tài)創(chuàng)建從不同于IsKindOf()的角度使用這一數(shù)據(jù)結(jié)構(gòu),它要遍歷所有類型的CRuntimeClass。那么僅僅有繼承關(guān)系的類的CRuntimeClass相連還不夠,要把所有類的CRuntimeClass連成一個鏈表。其實動態(tài)創(chuàng)建并不關(guān)心類間的繼承關(guān)系,它平等看待每個類。現(xiàn)在以CRuntimeClass為結(jié)點構(gòu)成一個縱橫兩個方向的鏈表,IsKindOf()和動態(tài)創(chuàng)建分別使用它不同的側(cè)面。

            序列化的概念是在文件中存儲對象信息,并能根據(jù)它恢復對象。對于文檔視圖結(jié)構(gòu)的軟件,用戶需要保存所編輯的文檔和打開已編輯的文檔,這正是序列化的應用,所以序列化是非常重要的一種特性。在序列化恢復對象時,就可以用到動態(tài)創(chuàng)建。

            使用MFC序列化的例子如下,

            void CMyDocument::Serialize(CArichive &ar)
            {
                if (ar.IsStoring())
                {
                    ar << m_pMyClass; //CMyClass m_pMyClass;
                }
                else
                {
                    ar >> m_pMyClass;
                }
            }

            一個支持序列化的類提供Serialize(CArchive &)函數(shù),重載<<和>>操作。注意兩者是不同的,在上例中,CMyDocument類的信息并不被序列化,而CMyClass類的信息被序列化。實際上一個序列化類的<<和>>操作,其不涉及類信息的部分是調(diào)用Serialize()完成的,它必須同時實現(xiàn)這兩者。

            按照MFC的要求,需要在支持序列化的類定義中使用DECLARE_SERIAL宏,在類實現(xiàn)中使用IMPLEMENT_SERIAL宏。我們看一下這兩個宏實現(xiàn)了什么,

            #define DECLARE_SERIAL(class_name) \
             _DECLARE_DYNCREATE(class_name) \
             AFX_API friend CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb);

            #define IMPLEMENT_SERIAL(class_name, base_class_name, wSchema) \
             CObject* PASCAL class_name::CreateObject() \
              { return new class_name; } \
             _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, \
              class_name::CreateObject) \
             AFX_CLASSINIT _init_##class_name(RUNTIME_CLASS(class_name)); \
             CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb) \
              { pOb = (class_name*) ar.ReadObject(RUNTIME_CLASS(class_name)); \
               return ar; } \

            主要是加入了對>>的重載,但是沒有重載<<,MFC僅提供了CObject對<<的重載,如下,

            _AFX_INLINE CArchive& AFXAPI operator<<(CArchive& ar, const CObject* pOb)
             { ar.WriteObject(pOb); return ar; }

            這是因為在序列化讀和寫的時候,都需要具體類的CRuntimeClass信息。相應的GetRuntimeClass()是一個虛函數(shù),CObject重載<<,在寫類信息時調(diào)用到該函數(shù),由于虛函數(shù)機制,寫入的是具體類的信息。但是這里隱含著一個條件,就是調(diào)用<<和GetRuntimeClass()時,具體類對象已經(jīng)存在了,而調(diào)用>>和讀入類信息時,該類對象還未被創(chuàng)建,所以無法利用這種機制,只能在每個具體類中都重載一次>>。我覺得《深入解析MFC》對這個問題的解釋不正確。

            這里有一個問題需要明確一下,序列化為什么要寫入類信息?一是它應該保存完整的能夠獨立恢復對象的信息,二是在程序讀入對象時,要把它的類信息和程序中期望的(所能處理的)類信息相比較,進行檢驗。

            看IMPLEMENT_SERIAL宏對重載>>的實現(xiàn),是提供一個期望的CRuntimeClass結(jié)構(gòu)(用于檢驗),委托CArchive進行對象讀取。因為讀對象時首先要跟文件打交道,所以交給CArchive處理,隨后把讀出的數(shù)據(jù)寫入對象時,CArchive再調(diào)用具體類的Serialize(),如此合作是十分恰當?shù)摹T谶@里,CArchive還負責了讀出和檢驗類信息,然后創(chuàng)建對象的過程。因為一方面具體類對象還不存在,另一方面這些操作對所有具體類都沒有分別,應該提出來,在類級別實現(xiàn)或者讓合作者實現(xiàn)。實際上,MFC先把這個過程交給CArchive::ReadClass(),后者又調(diào)用CRuntimeClass::Load()。 

            對于序列化來說,搞清它的概念以后,就是實現(xiàn)Serialzie(),重載<<和>>。對<<和>>的重載涉及很多工作,MFC已經(jīng)幫我們實現(xiàn)了,我們也看見了大概的設計,主要是與CArchive分工合作,其次是CRuntimeClass。

            現(xiàn)在看到CRuntimeClass結(jié)構(gòu)體在MFC對RTCI,動態(tài)創(chuàng)建和序列化的實現(xiàn)中都起著重要的作用,重新認識一下這個數(shù)據(jù)結(jié)構(gòu)很有必要。

            CRuntimeClass包含了關(guān)于類的各種信息和有關(guān)操作。把類及其基類的CRuntimeClass連成一個鏈表,就可以很方便地實現(xiàn)RTCI的IsKindOf();把所有類的CRuntimeClass連成一個鏈表,再加上一個簡單的CreateObject函數(shù),就可以對以任意類名進行動態(tài)創(chuàng)建的企圖做出反應;CRuntimeClass還實現(xiàn)了向文件讀寫類信息的Load(),Store(),配合序列化的實現(xiàn)。

            在分析消息映射和命令傳遞機制之前,需要對Windows程序模型有很好的理解。

            未完待續(xù)...


            參考:

            《深入解析MFC》/中國電力出版社
            《深入淺出MFC》/華中科大出版社
            《Windows程序設計》/北大出版社

            posted @ 2006-05-15 19:33 依舊的博客 閱讀(1151) | 評論 (0)編輯 收藏

            2006年5月12日 #

            欣賞好的思路是一件愉快的事,特別是對我不會做的題目。

            1. 問題:對32位的二進制整數(shù),不用循環(huán),求出其中1的個數(shù)。

            #define?POW(c)?(1<<(c))
            #define?MASK(c)?(((unsigned?long)-1)?/?(POW(POW(c))?+?1))
            #define?ROUND(n,?c)?(((n)?&?MASK(c))?+?((n)?>>?POW(c)?&?MASK(c)))

            int?bit_count(unsigned?int?n)
            {
            ????n?
            =?ROUND(n,?0);
            ????n?
            =?ROUND(n,?1);
            ????n?
            =?ROUND(n,?2);
            ????n?
            =?ROUND(n,?3);
            ????n?
            =?ROUND(n,?4);
            ????
            return?n;
            }

            基本的想法是把所有的1加起來,得到的就是1的個數(shù)。我們需要把這些1分離出來,每個1都是平等的,與其位置無關(guān)。難題在于不能一個一個去取,那就用到了循環(huán),當然遞歸也是不允許的。需要有一種統(tǒng)一的辦法,可是很難想象具體該怎樣。我們逐步地做這件事,假設前16位和后16位分別求得了1的個數(shù),那么加起來就行了。16位二進制中的1仍然是未知的,隨機出現(xiàn)的,問題的性質(zhì)沒有變,但我們可以繼續(xù)分解,這種逐步的做法不一定就意味著遞歸。每個16位分解為兩個8位,...,每個2位分解為兩個1位,把兩個1位上的數(shù)相加就是這兩位上1的個數(shù)。現(xiàn)在需要取出每一位上的數(shù)嗎?如果想到了這個問題,就離最終的思路不遠了。現(xiàn)在32位已經(jīng)分成了16個兩位,很容易將其看作兩個16位,一個是所有奇數(shù)位,一個是所有偶數(shù)位。我們不難把這兩個16位分開,然后移位相加,就求出了每兩位中1的個數(shù)。到了這一步,以后的思路就很自然了。


            參考:

            《計算二進制位'1'的個數(shù)》來自?http://kaikai.cnblogs.com
            posted @ 2006-05-12 23:14 依舊的博客 閱讀(662) | 評論 (2)編輯 收藏

            僅列出標題  下一頁
            无码人妻少妇久久中文字幕蜜桃| 久久久久免费视频| 久久一区二区三区99| 欧美激情精品久久久久久久| 久久久久久久久66精品片| 久久久久无码精品国产| 久久久精品久久久久特色影视| 欧美精品福利视频一区二区三区久久久精品 | 久久播电影网| 亚洲国产成人久久综合区| 亚洲中文字幕久久精品无码APP | 一本色道久久88精品综合 | 日本免费久久久久久久网站| 国产激情久久久久影院老熟女免费| 狠狠人妻久久久久久综合蜜桃| 色诱久久av| 久久精品国产亚洲AV无码偷窥| 色欲综合久久躁天天躁| 亚洲AV成人无码久久精品老人| 国产高清国内精品福利99久久| 中文字幕亚洲综合久久菠萝蜜| 国产成人精品久久免费动漫| 精品99久久aaa一级毛片| 精品久久人妻av中文字幕| 久久久久久免费一区二区三区 | 国产精品一区二区久久不卡 | 久久九九久精品国产免费直播| 亚洲午夜久久久久久噜噜噜| 国产精品99久久不卡| 中文字幕久久精品无码| 久久受www免费人成_看片中文| 久久伊人色| 国产精品免费看久久久香蕉| 久久99精品久久久久子伦| 亚洲日本久久久午夜精品| 一级做a爰片久久毛片毛片| 国产精自产拍久久久久久蜜| 国产成人精品久久亚洲| 爱做久久久久久| 久久九九久精品国产| 久久婷婷五月综合色99啪ak|