• <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>
            隨筆 - 42  文章 - 3  trackbacks - 0
            <2012年4月>
            25262728293031
            1234567
            891011121314
            15161718192021
            22232425262728
            293012345

            常用鏈接

            留言簿(2)

            隨筆檔案

            文章檔案

            網(wǎng)頁收藏

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

             
              恭喜,你選擇開發(fā)工程師做為自已的職業(yè)
              悲哀,你選擇開發(fā)工程師做為自已的職業(yè)

              本文所指的開發(fā)工程師,僅指程序開發(fā)人員和以數(shù)字電路開發(fā)為主的電子工程師。
              當你選擇計算機或者電子、自控等專業(yè)進入大學時,你本來還是有機會從事其它行業(yè)的,可你畢業(yè)時執(zhí)迷不悟,仍然選擇了開發(fā)做為你的職業(yè),真是自做孽不可活。不過,歡迎你和我一樣加入這個被其它人認為是風光無限的“白領(lǐng)”吧。
              如果你不是特別的與人世隔絕,我想你一定看過金老先生的名著《笑傲江湖》吧,里面有一門十分奇特的武功叫做"辟邪劍法",你看這個小說第一次看到這種功夫的練法時,我想你當時一定笑歪了牙“呵呵,真好玩!”,可是現(xiàn)在我很痛心的告訴你:你選擇的開發(fā)工作就是你人生路上的"辟邪劍法",而你現(xiàn)在已經(jīng)練了,并且無法再回頭。
              相對同時剛出校門同學從事其它行業(yè)而言優(yōu)厚的薪水,以及不斷學習更新的專業(yè)知識不僅僅讓你感到生活的充實,更滿足了你那不讓外人知的虛榮心。在剛出校門的幾年中,你經(jīng)常回頭看看被你落在后面的同學們,在內(nèi)心憐憫他們的同時,你也會對自已天天加班的努力工作感到

            心里平衡:“有付出才會有回報”這句話在那幾年中你說的最多,不管是對自已的朋友們還是自已的愛人。第二句最常說的話是對公司的領(lǐng)導(dǎo):“不行我就走人!”,實際上你也真的走過幾回。對了,在這幾年中,因為你的經(jīng)濟條件不錯,你開始買房、開始談戀愛、結(jié)婚、開始有了自已的小孩。有時候你會對自已說再過兩年就去買車。當然其中可能有許多大件是需要分期付款的,但你對前途充滿了信心,你確信認為這種日子會永遠的持續(xù)下去,即使不是變得更好的話。
              日子總是在這種平淡中一天天的過去,就在那么不經(jīng)意間,你突然發(fā)現(xiàn)自已已經(jīng)快30歲了,或者已經(jīng)30了,莫名的,你心里會漫延著一種說不清楚的不安情緒,你好像覺得前途并非像前幾年那樣變得越來越好,你也忽然發(fā)現(xiàn)你以前所瞧不起的同學里好像已經(jīng)有不少開著車的了,也有幾個人住著比你還大的房子,好像房款還是一次付清的,你突然明白你現(xiàn)在的生活比起你的同學來最多是中游偏上了。工作中最讓你感到心里不舒服的是,你越來越不敢對你的領(lǐng)導(dǎo)說不了,即使比你來的晚的同事升職或提薪,你也只是在私下與朋友們一起喝酒時才敢發(fā)發(fā)牢騷,在頭的面前你的聲間越來越小、笑臉是越來越溫柔。
              你終于開始迷茫“再過幾年我會是在干什么呢?”,這句話常常出現(xiàn)在你的心里。
              計算機開發(fā)工作,是一種以年輕為資本的工作,說句通俗點的話是“吃青春飯的”,嗯,這句話好像在一種特別的行業(yè)也聽到過。

            其標志就是一:工作的時間性非常強,一個開發(fā)項目被定的時限通常是很緊張的,更有甚者,有些號稱開發(fā)管理的書里面還非常卑鄙的號召將一個項目切成多個小片,每個小片都定一個叫“里程碑”的東東來嚴格跟蹤開發(fā)進度,加班加點在其它行業(yè)是需要加班工資的,而在開發(fā)行業(yè),加班工資好像還沒見到幾個公司發(fā)過,是啊,反正有時間限制著,你干不完我再找你算賬.所以開發(fā)工作通常有著其它工作所沒有的精神上的壓力。

            一旦一個人步入而立之年,因為家庭和孩子的負擔,加上精力上面的衰退,加班工作時間變得越來越少,這點讓很多老板們感到:這些人已經(jīng)老了,不好用了。指示人事部門:“以后招開發(fā)人員限制在30歲以下!”,相對而言硬件開發(fā)會年齡方面限制會稍好一點點,但也是五十步笑百步。還有一個很重要的一點就是:計算機這個爛東東實在是進步的太快了,前兩年買的頂級配置電腦,現(xiàn)在怎么看怎么像廢品,這還是小事,更可氣的是好像每天都需要學習新的知識,剛畢業(yè)時只會書本上的PASCAL,學會了用腐蝕的辦法來做電路板,一上班就開始學習TURBOC和TANGER2.0,剛剛學會,還沒來得及高興,馬上開始學Borland C++和Protel3.0,好不容易學會了,卻發(fā)現(xiàn)需要學習VC和Protel98了。單片機也是啊:Z80的指令背的很熟,工作中沒來得及用就要學8031,好好學吧,本來想著這輩子就吃它了,又發(fā)現(xiàn)又出來什么PIC、DSP、CPLD、FPGA、ARM等等....這還不包括中間要學一大堆74系列、4000系列、XX系列...IC卡居然里面還有CPU卡..如果學習的知識里每個字都能變成一分錢,我想所有的開發(fā)工程師都是腰纏萬貫的富翁。
              一眼看去,這種日子好像見不到頭,年輕時樂此不彼,但現(xiàn)在你一定對自已能堅持到什么時候感到懷疑了。我們都玩過像仙劍奇?zhèn)b傳這樣的RPG游戲,剛開始時你只是一個一名不文的少年,隨著你去打怪物、撿寶貝、學秘芨,最后終于有一天你會變成一個大英雄!那么你在實際生活中過得比那些小俠們還辛苦,為什么成不了一個生活中的大俠呢?呵呵,原因在這里:因為開發(fā)工作是邪門功夫,它雖然可以讓你速成的變成小資,但它最大的特點是經(jīng)驗不積累!日新月異的知識更新,讓你總是感到自已在退步,你就像在RPG中的主人公,開始時就給了你一把好劍和好盔甲,而且讓你的級別很高,但讓你的經(jīng)驗不累積,雖然剛開始打小怪物時你覺得自已很爽,但越到后來,你會發(fā)現(xiàn)你會死的很慘!比較一下你與其它非開發(fā)行業(yè)的同學你就可以知道了,例如和你學醫(yī)的同學比起來。套用岳不群他老人家說華山劍宗和氣宗的區(qū)別那段話:前十年你比你那些學醫(yī)的同學收入和地位要好的多,但十年以后你和他基本上各方面都會持平,而二十年以后你的各方面遠遠不能與你學醫(yī)的同學相提并論!嗯,你已經(jīng)開始不笑辟邪劍法了吧。
              “敢問路在何方?路在腳下...”,不過猴兄和八戒兄這么認為是可以的,你呢?
            總結(jié)了許多開發(fā)朋友在30歲以后的生活之路,讓我們一起看看開發(fā)人員“路在何方?”那么開發(fā)人員在30歲以后都干些什么呢?
            其路一:繼續(xù)做你這個很有“前途”的職業(yè)吧!
              偶掰著腳指頭仔細數(shù)了數(shù),發(fā)現(xiàn)還真的有很多朋友在30歲以后還在從事開發(fā)工作,我這里說的從事,是指你還需要天天在電腦邊上編程序和畫電路板,與你手下是否有幾個小兵無關(guān),也與你是否頭上頂著什么項目經(jīng)理、主任工程師的帽子無關(guān),只要你還需要親自開發(fā),你就屬于這一類。其中有個年齡最大的朋友是63年的,從事醫(yī)療儀器的開發(fā)工作,35歲左右還在從事軟硬件開發(fā)工作的仍有一大堆,分析這些仍然從事開發(fā)的朋友,基本上都有以下特點:
            1 癡迷工作或者癡迷電腦,晚上八點到十二點的這段時間,基本上是在電腦桌或工作臺前渡過的。
            2 不喜歡與人交住,朋友很少,常聯(lián)系的人不超過五個。
            3 與朋友交往時談工作多,但一般不主動談錢。
            4 體型偏胖或偏廋,不在正常區(qū)間。
            5 無未來計劃,對五年后自已生活怎么樣、從事什么工作說不清楚。
            6 儉省,從不亂花錢。
            即使你是還不到30歲的開發(fā)人員,你也可以看看自己對以上幾條是否符合,是否會在30歲后還從事開發(fā)職業(yè),四條疑似,五條以上基本確診你也是這類型的人。
              這些朋友們通常報著過一天是一天的態(tài)度生活,到了這個年齡,也不敢再輕易的換工作了,年輕時的銳氣慢慢的也消退了。唯一不變的希望是有一天從天上掉下來一大堆錢把自己砸傷。說實在話因為他們的性格所限,基本上可以確定他們以后不可能在職場上獲得更好的發(fā)展,當個小頭頭,帶幾個人開發(fā)已經(jīng)是他們發(fā)展的頂點。至于以后的人生之路,不僅他們自己迷茫,可能上帝也正在頭痛。
               不過像這類朋友,偶很奇怪的發(fā)現(xiàn):他們的小孩都是兒子!不知是偶然還是有什么其它說法。
            簡單建議:要改變命運,先改變性格:堅持半年晚上不從事工作、游戲及電視,用此時間與人交往,你的人生會有改變。


            其路二:轉(zhuǎn)行從事技術(shù)支持、行政或生產(chǎn)等工作還有一些朋友,從事了幾年的開發(fā)工作,因為自已并非特別的愛好,或者領(lǐng)導(dǎo)上面的強制工作安排,他們轉(zhuǎn)到了技術(shù)支持、服務(wù)或行政等工作,至少當時從表面上看起來,他們的薪水較開發(fā)要少一些,但真正的統(tǒng)計這些人,發(fā)現(xiàn)他們之中有半數(shù)的人獲得了更好的發(fā)展,升職為服務(wù)部經(jīng)理或行政經(jīng)理等職,最歷害的一個朋友已升職為總經(jīng)理助理,進入高層。
              這類朋友當時轉(zhuǎn)行通常并非自已志愿,屬被逼無奈或者其它原因,但顯然,擁有專業(yè)知識技術(shù)的他們顯然在非技術(shù)部門中鶴立雞群,遇到什么事情他們均可從專業(yè)的角度提出建言,久而久之,他們獲得更多的升職和加薪機會也就不足為奇。
              因為不從事開發(fā),所以經(jīng)驗開始積累,這類的職業(yè)通常會給你一個很安定的感覺,你到30多歲后會發(fā)現(xiàn)這類職業(yè)反而比開發(fā)工作更容易獲得新的工作機會。

              簡單建議:你如果確定在開發(fā)部無法獲得很好的發(fā)展機會,不妨轉(zhuǎn)到其它幾個部門試試,換個活法,錢少點就少點吧,機會多。
            其路三:開發(fā)管理
              如果你現(xiàn)在已經(jīng)是總工或開發(fā)部經(jīng)理,或者你眼看就有機會被提升為這類職務(wù),那么恭喜你,你走的是從“弼馬溫”到“斗戰(zhàn)勝佛”這條金光大路,你不僅擁有很高的專業(yè)技能,而且很顯然,你也有著很強的人際交往能力,你這類人根本不需要對未來有著任何的擔心,你在即使一無所有的時候也很容易白手起家。
              你這種人算是練辟邪劍法練成了仙,嗯,我無話可說。
              你是不是這類人也很容易區(qū)別,就像圍棋二十歲不稱國手終身無望一樣,你應(yīng)該在工作三、四年以后,也就是說二十七歲左右就會發(fā)現(xiàn)自已工作中指手劃腳的時間比親自開發(fā)的時間要多了,而且大多數(shù)這類人在這個年齡手下應(yīng)該有“兵”了,相反的,如果你快30歲了還天天埋頭于電腦前編程序和畫板子,或者30多歲了你還沒升到部門經(jīng)理(雖然你總是覺得自已很有希望),基本上可以確定你不是這類人。好了,如果你確定你是這類人,那么你唯一的想法就是盡快爬上中層和高層,因為有時候人生偶然性太大,不占住坑的蘿卜很有可能被人拔出來!

              簡單建議:天天去你的老板家里面拖地和擦桌子!


            其路四:出國或考研
              有兩個搞開發(fā)后出國的朋友,其中一個甚至打工打到了一個小公司總工的位置,數(shù)據(jù)庫和軟件方面水平巨牛,但仍感覺心里不踏實,于是將自己工作多年的錢忍痛掏出來,出國費加上機票大概將自已辛苦所攢的銀子花完,然后又借了一些錢,在02年身上揣著一萬美元跑去了加拿大,在加拿大不停的重復(fù)找工作,換工作,然后再找工作的循環(huán),找的工作基本上與計算機無關(guān),不過工資總是在1500加元左右,呵呵,折成人民幣與他在國內(nèi)打工拿的基本上差不多,不過租個地下室就花了300加元,然后吃吃喝喝,再買個電腦上上網(wǎng)這類的,基本每月平均還要倒貼一點。前段時間給我的郵件里說,現(xiàn)在身上花的差不多只有5、6000美元了,準備開個小公司,看看能不能往國內(nèi)倒騰點東東,做最后一搏。另外一個朋友去澳州,時間稍早一些,先是大概摘了一年多的葡萄,后來總算找了個技術(shù)工作,每天的工作是畫機械圖紙,收入還算不錯

            將近3000澳元,買了個舊車,也算是過上了資本主義生活。不過前年回來一趟,唯一的感嘆就是:在國外拿2000美元的生活,絕對不如在國內(nèi)拿5000人民幣的生活舒服。
              也有兩個考研的朋友,不過其中一個嚴格的說不是做開發(fā)的出身,偏重于市場方面的工作性質(zhì),不過我的朋友里面考研的不多,只好湊兩個人說說,一個考研后在北京找了個工作,每個月5、6000元錢,但還是做開發(fā),生活仍然與沒考研之前沒有任何的改變,前途仍然沒見到什么大亮的光,還是搞不清楚以后再干些什么,標準的過一天算一天了。另外一個考研后在大學里面找了個工作,工資雖然比他原來打工少了不少,但畢竟終身有靠,穩(wěn)定了下來,也算修成了正果,這位哥們心情一放松下來,也開始有時間琢磨著業(yè)余時間自已做點什么,好像現(xiàn)在慢慢的也開始有了點眉目。
              簡單建議:這兩條路,對開發(fā)人員來說都不算是很好,出國十年前是好事,現(xiàn)在難說,考研能成功轉(zhuǎn)行的概率恐怕也不是很大,多半仍然去搞開發(fā),只不過研究生可以多干幾年罷了。


            其路五:轉(zhuǎn)行到市場
              絞盡腦汁的想想,我所知道的人之中只有兩個開發(fā)人員去了市場,這兩個人都不能說是朋友,認識而已。他們都是主動要求去了市場,結(jié)果是這兩個人均在市場都是干到一年左右,然后都自已開公司了。呵呵,很奇怪,極高的轉(zhuǎn)行成功率!不過仔細想想,我對這兩個人的思路佩服的五體投地。能下決心仍掉每月5、6000元的開發(fā)職位,從事一個自已并不熟悉的崗位,每月拿個2000多元+提成,但提成那是說不清楚的事情,這個決定,只能讓人感覺到他們對自已前途清晰的把握和老謀深算的心機。而且他們不去服務(wù)不去生產(chǎn),挖空心思說服領(lǐng)導(dǎo)去市場(市場部門與開發(fā)部門通常是一個公司的核心部門,進入其實并不容易),可以說是有著長遠的考慮的。有技術(shù)了,再與客戶交成朋友,馬上就會產(chǎn)生很大的機遇應(yīng)該是正常的事情。
              有實力,有心機,也有著很強的決心力,這種人恐怕早在大學畢業(yè)時或更早的時候就已經(jīng)決定了自已的人生之路,他們的每一步路在若干年前早就計劃周全,現(xiàn)在看起來:學會技術(shù)->進入市場->尋找商機->開公司,一條多么清楚的人生之路。但就像我們上小學中學時,所有人都知道上大學是我們最清楚的人生路一樣,最后只有少數(shù)人才能真正達到目標(當然,現(xiàn)在擴招的歷害是另外一回事,我是說我們那個時候,也就是:“很久很久以前,當我像你那么大的時候”)。

              簡單建議:你若是這類人,我的建議是:...嗯?....那個你.你,你別走啊,我還有個事想請你贊助一下啊.....


            其路六:開公司自已干

              呵呵,看到這一條,發(fā)現(xiàn)你的眼睛已經(jīng)圓了,你肯定千百次的想過這個事情吧,咳咳,其實我從事開發(fā)的時候也是天天夢想著這種事情。總想著過兩年找個機會就自已干,這個夢想一年又一年的折磨著你也給著你希望。看看吧,開發(fā)后來開公司的還真的不少,里面有成功的也有很多失敗的,通常開公司都是幾個人合伙開始的,有做技術(shù)的,有做市場的,幾個人一拍即合、狼狽為奸,共同策劃了這一個大活動。一般說來能讓這幾個人下決心走出這一步,產(chǎn)品肯定是先進的,甚至是國內(nèi)獨一無二的,市場也是很大的,負責市場的那個哥們通常會拍著胸保證可以賣出去,并悄悄地告訴你他在某主管領(lǐng)導(dǎo)是他小舅子的同學的二叔,肯定沒問題。于是你們幾個人找地點、注冊執(zhí)照、買了幾個破桌子,再攢了兩臺電腦,每個人又湊了幾萬銀子,公司開張了!
              產(chǎn)品很快出來了,市場的哥們也不負重望,有幾個客戶表示要試用了,一切看起來都是如此的正常,“.......你坐在老板桌前,不停的有人來匯報工作或者找你簽字...人進人出中...你又想起公司再窮也不能只有一把椅子的故事.....”你在夢中笑出聲來。
                是如此的順利,你們很快就有單子了,很快的單子讓你們湊的那點錢不夠了,你們很高興的每個人又增加了投入,拿出錢時你眼淚汪汪的數(shù)著錢說:“這就是我那生蛋的母雞啊”。你們的產(chǎn)品確實不錯,市場也經(jīng)營的很好,客戶慢慢的多了起來,單子來的時候一筆接著一筆,你每天都處于興奮之中,唯一美中不足的是好像客戶回款總是會拖一些日子,不過客戶給你保證說:過幾天,過幾天就付給你們,因為回款總是在計劃外,所以你們?yōu)榱速Y金的流暢運行又湊了一些錢,這個時候你有一些心事了,因為你的存款折上面的數(shù)字已經(jīng)快趨向于零了。“沒事,過兩個月等回款了一切都OK了,誰干事業(yè)不吃點苦呢?”你這么安慰著自已又投入到工作中去,資金總是在回款和生產(chǎn)經(jīng)營費用之間走著一個窄窄的小木橋,你的賬上總是沒有太多的錢,擴大了的公司規(guī)模和許多意外情況,使你又一次、二次、三次的與合作者們再次投入了自已的資金,當然,后來的錢你可能已經(jīng)是借的了.....
              終于有一天,你的會計再一次告訴你,老板啊,賬上又沒現(xiàn)金了,吃過多次苦頭的你終于下決心開始重視資金的運行了,你裁掉了一些不必要的人手,減少了開發(fā)的投入,要求市場人員簽單的時候必須予付XX%的款,回扣也必須等收過款后再付,同時也開始對產(chǎn)品的生產(chǎn)成本開始進行控制。
              時間一天一天的過去,因為竟爭對手的產(chǎn)品也對你的產(chǎn)品進行了仿造,你的產(chǎn)品慢慢變得不再先進,市場人員開始埋怨公司的合同資金方面規(guī)定太嚴格,不好簽單,生產(chǎn)成本的下降通常也導(dǎo)至產(chǎn)品毛病的增多,客戶也開始埋怨你的服務(wù)人員不能及時進行服務(wù)。
              終于有一天,你重新走進了人才交流中心,以前你是來招人的,現(xiàn)在你拿著自已的簡歷開始尋找一個工作
            ......
                公司的成功與否,與產(chǎn)品有關(guān),與市場有關(guān),但更重要的是與資金有關(guān),產(chǎn)品與市場都可以通過資金來彌補,而卻沒有任何東西可以代替

            資金,凡是倒下的公司,99%與資金鏈的斷裂有關(guān)。在你決定要開公司以前,先估計一下你公司支持一年所需要的資金數(shù)額,包括人工費,生產(chǎn),場地,廣告宣傳、市場費用、甚至電、水費等等等等,把你所想到的一切加在一起,得出的值就是..慢..如果你沒有實際的開過公司的經(jīng)驗,你需要將此數(shù)字乘3,然后就是你開公司一年最少需要的費用,呵呵,公司的實際運營所需要的錢是你想像的3倍以上,你要是不信我也沒辦法。

                簡單建議:開公司前最重要的是先確立你后續(xù)的資金來源!也就是說錢不夠了怎么辦?---因為你投入的錢肯定會不夠的。


            其路七:第二職業(yè)
                這類的朋友有不少,他們沒有脫離開發(fā)工作,但是在業(yè)余時間又不停的接項目或者在賣產(chǎn)品,在單位里面他們顯得并不出眾,比起其它人來說他們屬于最不愿意加班的一類.為此他們白天通常工作很勤奮.這類人也許不一定可以掙很多錢,但平均下來他們一年之中通常都可以比同事們多掙個幾萬元.有時候比上班拿得還多.但令人疑惑的是,這類人在生活中更加注重穩(wěn)定,基本上沒見到他們跳過蹧,即使私下里面已經(jīng)開了個小公司,他們通常也不會辭職.
                你的旁邊有沒有這類人呢?分辨他們很容易:
            --電話很多,而且更愿意來電話時離開辦公室找個沒人的旮旯通話.神秘兮兮給人一種"這家伙是不是有二奶啊?"的感覺的人,通常是這類人。這類人是女性最佳的選擇對象:很顧家,不象那些富人容易花心,而比起一般人來說,他們收入相對要高得多。但總結(jié)了一下幾位這類的開發(fā)朋友:也得出了一個令人沮喪的結(jié)論:這種人通常個子不高,體形類似桶狀.....

               簡單建議:這好像是開發(fā)人員最佳的出路了,但比較豐厚的收入通常讓這類人不愿意去冒風險....到現(xiàn)在為止我所認識的這類人還沒有一個真正算是成功的。
               好了,雖然偶的經(jīng)歷遠遠說不上豐富,也沒有什么成功之處可以自滿的,但或許因為比其它朋友癡長了幾歲,見過的人可能會稍多一些,所

            以斗膽寫出了以上的一些文字,讓您掉牙了。
               下面是偶走過開發(fā)這條路上總結(jié)出來的一點心得,你可以不看,但看了就千萬別把嘴咧的太大:
               一、不管是給別人打工還是自已干,都要全心全意的工作,因為你所做的任何一點工作都會讓自已的人生多一點籌碼,這一點最最重要!這樣的例子我至少可以舉出兩起,優(yōu)秀的開發(fā)人員被其它新公司挖走,并給一定的股份,成為新公司的股東的例子。當時與這樣的開發(fā)人員一個部門同時工作或更早工作的有許多人,他們平時經(jīng)常偷點懶,能少干點工作就少干點,有時候還笑話那個平時努力工作的人傻,幾年過去了,究竟誰比誰傻?
               二、多與市場人員交朋友,你接觸他們時可能總會覺得他們知識比你少,甚至素質(zhì)比你低,可能比你還有點黃。但實際上他們比你更懂這個社會!參加到他們這個圈子中去,和他們一起賭賭錢、一起聊聊天、一起洗洗桑拿、一起.....你會通過他們接觸到另外一個世界。
               三、機會遠比錢重要,掙不掙錢在年輕時并不是特別重要!不論是在實際生活中還是在網(wǎng)上或其它地方,如果有機會參與到除本職工作外的一些項目或產(chǎn)品的開發(fā)中(包括你的朋友拉你去做點小生意之類的非開發(fā)性質(zhì)的工作),那怕是幫忙的性質(zhì),也要積極介入,至少你會交到很多的朋友,這樣你的人生會多出很多的機會。

             

            posted @ 2009-11-08 22:37 鷹擊長空 閱讀(832) | 評論 (1)編輯 收藏

            例子是一個mfc的對話框,用vc調(diào)試器查看了一個程序從生成初始化到接受消息的流程。從產(chǎn)生到結(jié)束的基本流程是這樣的:
            KERNEL32->WinMainCRTStartup()->_tWinMain(開始)->AfxWinMain(開始)->AfxGetThread()->AfxWinInit()->InitApplication()->InitInstance()->DoModal()->RunModalLoop()->ExitInstance()->AfxWinMain(結(jié)束)->_tWinMain(結(jié)束)

            1、KERNEL32
            kernel32.dll是Windows9x/Me中非常重要的32位動態(tài)鏈接庫文件,屬于內(nèi)核級文件。它控制著系統(tǒng)的內(nèi)存管理、數(shù)據(jù)的輸入輸出操作和中斷處理,當Windows啟動時,kernel32.dll就駐留在內(nèi)存中特定的寫保護區(qū)域,使別的程序無法占用這個內(nèi)存區(qū)域。

            2、WinMainCRTStartup()函數(shù)
              程序默認的基地址(EXE文件默認為0x400000,DLL默認為x10000000),操作系統(tǒng)裝載一個程序時總是試著先從這個基地址開始。一般Win32的程序,EXE的入口為WinMain,DLL的入口為DllEntryPoint。默認情況下,通過一個C的運行時庫函數(shù)來實現(xiàn):控制臺程序采用mainCRTStartup (或wmainCRTStartup)去調(diào)用程序的main (或wmain)函數(shù);Windows程序采用WinMainCRTStartup (或 wWinMainCRTStartup)調(diào)用程序的WinMain (或 wWinMain,必須采用__stdcall調(diào)用約定);DLL采用_DllMainCRTStartup調(diào)用DllMain函數(shù)(必須采用__stdcall調(diào)用約定)。
            它負責:
              * 檢索指向新進程的完整命令行指針;
              * 檢索指向新進程的環(huán)境變量的指針;
              * 對c/c++運行時的全局變量進行初始化;
              * 對c運行期的內(nèi)存單元分配函數(shù)(比如malloc,calloc)和其他低層I/O例程使用的內(nèi)存棧     進行初始化。
              * 為C++的全局和靜態(tài)類調(diào)用構(gòu)造函數(shù)。
              當這些初始化工作完成后,該啟動函數(shù)就調(diào)用wWinMain函數(shù)進入應(yīng)用程序的執(zhí)行。
            當wWinMain函數(shù)執(zhí)行完畢返回時,wWinMainCRTStartup啟動函數(shù)就調(diào)用c運行期的exit()函
            數(shù),將返回值(nMainRetVal)傳遞給它。
              之后exit()便開始收尾工作:
              * 調(diào)用由_onexit()函數(shù)調(diào)用和注冊的任何函數(shù)。
              * 為C++的全局和靜態(tài)類調(diào)用析構(gòu)函數(shù);
              * 調(diào)用操作系統(tǒng)的ExitProcess函數(shù),將nMainRetVal傳遞給它,這使得操作系統(tǒng)能夠撤銷     進程并設(shè)置它的exit  代碼。
            最小體積的win32程序:(不要編譯缺省庫)
            #pragma comment (linker, "/SUBSYSTEM:WINDOWS")
            #pragma comment (linker, "/NODEFAULTLIB")
            int WinMainCRTStartup()
            {
             return 0;
            }

            3、WinMain()函數(shù)
            _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
             LPTSTR lpCmdLine, int nCmdShow)
            {
             // call shared/exported WinMain
             return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
            }

            4、AfxWinMain()函數(shù)
            int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
             LPTSTR lpCmdLine, int nCmdShow)
            {
             ASSERT(hPrevInstance == NULL);

             int nReturnCode = -1;
             CWinThread* pThread = AfxGetThread();
             CWinApp* pApp = AfxGetApp();

             // AFX internal initialization
             if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))
              goto InitFailure;

             // App global initializations (rare)
             if (pApp != NULL && !pApp->InitApplication())
              goto InitFailure;

             // Perform specific initializations
             if (!pThread->InitInstance())
             {
              if (pThread->m_pMainWnd != NULL)
              {
               TRACE0("Warning: Destroying non-NULL m_pMainWnd\n");
               pThread->m_pMainWnd->DestroyWindow();
              }
              nReturnCode = pThread->ExitInstance();
              goto InitFailure;
             }
             nReturnCode = pThread->Run();

            InitFailure:
            #ifdef _DEBUG
             // Check for missing AfxLockTempMap calls
             if (AfxGetModuleThreadState()->m_nTempMapLock != 0)
             {
              TRACE1("Warning: Temp map lock count non-zero (%ld).\n",
               AfxGetModuleThreadState()->m_nTempMapLock);
             }
             AfxLockTempMaps();
             AfxUnlockTempMaps(-1);
            #endif

             AfxWinTerm();
             return nReturnCode;
            }

            5、AfxGetThread()函數(shù)
            CWinThread* AFXAPI AfxGetThread()
            {
             // check for current thread in module thread state
             AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
             CWinThread* pThread = pState->m_pCurrentWinThread;

             // if no CWinThread for the module, then use the global app
             if (pThread == NULL)
              pThread = AfxGetApp();

             return pThread;
            }

            6、AfxWinInit()函數(shù)
            BOOL AFXAPI AfxWinInit(HINSTANCE hInstance, HINSTANCE hPrevInstance,
             LPTSTR lpCmdLine, int nCmdShow)
            {
             ASSERT(hPrevInstance == NULL);

             // handle critical errors and avoid Windows message boxes
             SetErrorMode(SetErrorMode(0) |
              SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);

             // set resource handles
             AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
             pModuleState->m_hCurrentInstanceHandle = hInstance;
             pModuleState->m_hCurrentResourceHandle = hInstance;

             // fill in the initial state for the application
             CWinApp* pApp = AfxGetApp();
             if (pApp != NULL)
             {
              // Windows specific initialization (not done if no CWinApp)
              pApp->m_hInstance = hInstance;
              pApp->m_hPrevInstance = hPrevInstance;
              pApp->m_lpCmdLine = lpCmdLine;
              pApp->m_nCmdShow = nCmdShow;
              pApp->SetCurrentHandles();
             }

             // initialize thread specific data (for main thread)
             if (!afxContextIsDLL)
              AfxInitThread();

             return TRUE;
            }

            7、InitApplication() 函數(shù)
            BOOL CMy1App::InitApplication()
            {
             // TODO: Add your specialized code here and/or call the base class
             AfxMessageBox("InitApplication");
             return CWinApp::InitApplication();
            }
            BOOL CWinApp::InitApplication()
            {
             if (CDocManager::pStaticDocManager != NULL)
             {
              if (m_pDocManager == NULL)
               m_pDocManager = CDocManager::pStaticDocManager;
              CDocManager::pStaticDocManager = NULL;
             }

             if (m_pDocManager != NULL)
              m_pDocManager->AddDocTemplate(NULL);
             else
              CDocManager::bStaticInit = FALSE;

             return TRUE;
            }

            8、InitInstance()函數(shù)
            AfxWinMain函數(shù)里面的if (!pThread->InitInstance())會調(diào)用程序CMy1App的InitInstance函數(shù):
            BOOL CMy1App::InitInstance()
            {
             AfxEnableControlContainer();
            AfxMessageBox("InitInstance");
             // Standard initialization
             // If you are not using these features and wish to reduce the size
             //  of your final executable, you should remove from the following
             //  the specific initialization routines you do not need.

            #ifdef _AFXDLL
             Enable3dControls();   // Call this when using MFC in a shared DLL
            #else
             Enable3dControlsStatic(); // Call this when linking to MFC statically
            #endif

             CMy1Dlg dlg;//調(diào)用CMy1Dlg的構(gòu)造函數(shù)
             m_pMainWnd = &dlg;
             int nResponse = dlg.DoModal();
             if (nResponse == IDOK)
             {
              // TODO: Place code here to handle when the dialog is
              //  dismissed with OK
             }
             else if (nResponse == IDCANCEL)
             {
              // TODO: Place code here to handle when the dialog is
              //  dismissed with Cancel
             }

             // Since the dialog has been closed, return FALSE so that we exit the
             //  application, rather than start the application's message pump.
             return FALSE;
            }

            9、AfxWinMain()函數(shù)里面的主要的循環(huán)體,在這里:
                    if (!pThread->InitInstance())//主要是模式對話框調(diào)用,對話框關(guān)閉以后InitInstance函數(shù)才會結(jié)束
             {
              if (pThread->m_pMainWnd != NULL)
              {
               TRACE0("Warning: Destroying non-NULL m_pMainWnd\n");
               pThread->m_pMainWnd->DestroyWindow();
              }
              nReturnCode = pThread->ExitInstance();
              goto InitFailure;
             }
             nReturnCode = pThread->Run();//非模式對話框和一般程序調(diào)用這個循環(huán)

            InitInstance函數(shù)調(diào)用了dlg.DoModal()函數(shù),以下是DoModal()函數(shù):
            int CDialog::DoModal()
            {
             // can be constructed with a resource template or InitModalIndirect
             ASSERT(m_lpszTemplateName != NULL || m_hDialogTemplate != NULL ||
              m_lpDialogTemplate != NULL);

             // load resource as necessary
             LPCDLGTEMPLATE lpDialogTemplate = m_lpDialogTemplate;
             HGLOBAL hDialogTemplate = m_hDialogTemplate;
             HINSTANCE hInst = AfxGetResourceHandle();
             if (m_lpszTemplateName != NULL)
             {
              hInst = AfxFindResourceHandle(m_lpszTemplateName, RT_DIALOG);
              HRSRC hResource = ::FindResource(hInst, m_lpszTemplateName, RT_DIALOG);
              hDialogTemplate = LoadResource(hInst, hResource);
             }
             if (hDialogTemplate != NULL)
              lpDialogTemplate = (LPCDLGTEMPLATE)LockResource(hDialogTemplate);

             // return -1 in case of failure to load the dialog template resource
             if (lpDialogTemplate == NULL)
              return -1;

             // disable parent (before creating dialog)
             HWND hWndParent = PreModal();
             AfxUnhookWindowCreate();
             BOOL bEnableParent = FALSE;
             if (hWndParent != NULL && ::IsWindowEnabled(hWndParent))
             {
              ::EnableWindow(hWndParent, FALSE);
              bEnableParent = TRUE;
             }

             TRY
             {
              // create modeless dialog
              AfxHookWindowCreate(this);
              if (CreateDlgIndirect(lpDialogTemplate,
                  CWnd::FromHandle(hWndParent), hInst))//創(chuàng)建對話框的窗口
              {
               if (m_nFlags & WF_CONTINUEMODAL)
               {
                // enter modal loop
                DWORD dwFlags = MLF_SHOWONIDLE;
                if (GetStyle() & DS_NOIDLEMSG)
                 dwFlags |= MLF_NOIDLEMSG;
                VERIFY(RunModalLoop(dwFlags) == m_nModalResult);//這里是真正的循環(huán)RunModalLoop
               }

               // hide the window before enabling the parent, etc.
               if (m_hWnd != NULL)
                SetWindowPos(NULL, 0, 0, 0, 0, SWP_HIDEWINDOW|
                 SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
              }
             }
             CATCH_ALL(e)
             {
              DELETE_EXCEPTION(e);
              m_nModalResult = -1;
             }
             END_CATCH_ALL

             if (bEnableParent)
              ::EnableWindow(hWndParent, TRUE);
             if (hWndParent != NULL && ::GetActiveWindow() == m_hWnd)
              ::SetActiveWindow(hWndParent);

             // destroy modal window
             DestroyWindow();
             PostModal();

             // unlock/free resources as necessary
             if (m_lpszTemplateName != NULL || m_hDialogTemplate != NULL)
              UnlockResource(hDialogTemplate);
             if (m_lpszTemplateName != NULL)
              FreeResource(hDialogTemplate);

             return m_nModalResult;
            }

            模式對話框調(diào)用的循環(huán)函數(shù)RunModalLoop()函數(shù)如下:
            int CWnd::RunModalLoop(DWORD dwFlags)
            {
             ASSERT(::IsWindow(m_hWnd)); // window must be created
             ASSERT(!(m_nFlags & WF_MODALLOOP)); // window must not already be in modal state

             // for tracking the idle time state
             BOOL bIdle = TRUE;
             LONG lIdleCount = 0;
             BOOL bShowIdle = (dwFlags & MLF_SHOWONIDLE) && !(GetStyle() & WS_VISIBLE);
             HWND hWndParent = ::GetParent(m_hWnd);
             m_nFlags |= (WF_MODALLOOP|WF_CONTINUEMODAL);
             MSG* pMsg = &AfxGetThread()->m_msgCur;

             // acquire and dispatch messages until the modal state is done
             for (;;)
             {
              ASSERT(ContinueModal());

              // phase1: check to see if we can do idle work
              while (bIdle &&
               !::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE))
              {
               ASSERT(ContinueModal());

               // show the dialog when the message queue goes idle
               if (bShowIdle)
               {
                ShowWindow(SW_SHOWNORMAL);
                UpdateWindow();
                bShowIdle = FALSE;
               }

               // call OnIdle while in bIdle state
               if (!(dwFlags & MLF_NOIDLEMSG) && hWndParent != NULL && lIdleCount == 0)
               {
                // send WM_ENTERIDLE to the parent
                ::SendMessage(hWndParent, WM_ENTERIDLE, MSGF_DIALOGBOX, (LPARAM)m_hWnd);
               }
               if ((dwFlags & MLF_NOKICKIDLE) ||
                !SendMessage(WM_KICKIDLE, MSGF_DIALOGBOX, lIdleCount++))
               {
                // stop idle processing next time
                bIdle = FALSE;
               }
              }

              // phase2: pump messages while available
              do
              {
               ASSERT(ContinueModal());

               // pump message, but quit on WM_QUIT
               if (!AfxGetThread()->PumpMessage())//主要在這里循環(huán)
               {
                AfxPostQuitMessage(0);
                return -1;
               }

               // show the window when certain special messages rec'd
               if (bShowIdle &&
                (pMsg->message == 0x118 || pMsg->message == WM_SYSKEYDOWN))
               {
                ShowWindow(SW_SHOWNORMAL);
                UpdateWindow();
                bShowIdle = FALSE;
               }

               if (!ContinueModal())
                goto ExitModal;

               // reset "no idle" state after pumping "normal" message
               if (AfxGetThread()->IsIdleMessage(pMsg))
               {
                bIdle = TRUE;
                lIdleCount = 0;
               }

              } while (::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE));
             }

            ExitModal:
             m_nFlags &= ~(WF_MODALLOOP|WF_CONTINUEMODAL);
             return m_nModalResult;
            }

            一般程序調(diào)用的循環(huán)函數(shù)Run函數(shù)如下:
            int CWinThread::Run()
            {
             ASSERT_VALID(this);

             // for tracking the idle time state
             BOOL bIdle = TRUE;
             LONG lIdleCount = 0;

             // acquire and dispatch messages until a WM_QUIT message is received.
             for (;;)
             {
              // phase1: check to see if we can do idle work
              while (bIdle &&
               !::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE))
              {
               // call OnIdle while in bIdle state
               if (!OnIdle(lIdleCount++))
                bIdle = FALSE; // assume "no idle" state
              }

              // phase2: pump messages while available
              do
              {
               // pump message, but quit on WM_QUIT
               if (!PumpMessage())
                return ExitInstance();

               // reset "no idle" state after pumping "normal" message
               if (IsIdleMessage(&m_msgCur))
               {
                bIdle = TRUE;
                lIdleCount = 0;
               }

              } while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));
             }

             ASSERT(FALSE);  // not reachable
            }

            ==========
            我認為是更加完整的應(yīng)該是_DllMainCRTStartup-> WinMainCRTStartup(void)->()->_tWinMain(開始)->AfxWinMain(開始)->AfxGetThread()->AfxWinInit()->InitApplication()->InitInstance()->DoModal()->RunModalLoop()->ExitInstance()->AfxWinMain(結(jié)束)->_tWinMain(結(jié)束)

            參考http://www.shnenglu.com/citywanderer/articles/8716.html
            posted @ 2009-10-01 22:51 鷹擊長空 閱讀(1595) | 評論 (0)編輯 收藏
                    內(nèi)核最高權(quán)限,自古就是兵家必爭之地,魔高一尺道高一丈的爭奪于此亦已變成頗為稀松平常之事。可以說和這些爭奪比起來,SSDT的相關(guān)技術(shù)簡直不值一提。但最初發(fā)作的病毒體總是從ring3開始的——換句話說,任你未來會成長為何等的武林高手,我都可以在你學走路的時候殺掉你——知曉了SSDT的這點優(yōu)勢,所有的病毒咂吧咂吧也就都沒味兒了。所以說,殺毒莫如防毒。

            網(wǎng)上看的這段話,感覺特有氣勢,摘錄在此!
            posted @ 2009-08-31 22:32 鷹擊長空 閱讀(197) | 評論 (0)編輯 收藏

            IOCP(I/O Completion Port,I/O完成端口)是性能最好的一種I/O模型。它是應(yīng)用程序使用線程池處理異步I/O請求的一種機制。在處理多個并發(fā)的異步I/O請求時,以往的模型都是在接收請求是創(chuàng)建一個線程來應(yīng)答請求。這樣就有很多的線程并行地運行在系統(tǒng)中。而這些線程都是可運行的,Windows內(nèi)核花費大量的時間在進行線程的上下文切換,并沒有多少時間花在線程運行上。再加上創(chuàng)建新線程的開銷比較大,所以造成了效率的低下。

            而IOCP模型是事先開好了N個線程,存儲在線程池中,讓他們hold。然后將所有用戶的請求都投遞到一個完成端口上,然后N個工作線程逐一地從完成端口中取得用戶消息并加以處理。這樣就避免了為每個用戶開一個線程。既減少了線程資源,又提高了線程的利用率。

            完成端口模型是怎樣實現(xiàn)的呢?我們先創(chuàng)建一個完成端口(::CreateIoCompletioPort())。然后再創(chuàng)建一個或多個工作線程,并指定他們到這個完成端口上去讀取數(shù)據(jù)。我們再將遠程連接的套接字句柄關(guān)聯(lián)到這個完成端口(還是用::CreateIoCompletionPort())。一切就OK了。

            工作線程都干些什么呢?首先是調(diào)用::GetQueuedCompletionStatus()函數(shù)在關(guān)聯(lián)到這個完成端口上的所有套接字上等待I/O的完成。再判斷完成了什么類型的I/O。一般來說,有三種類型的I/O,OP_ACCEPT,OP_READ和OP_WIRTE。我們到數(shù)據(jù)緩沖區(qū)內(nèi)讀取數(shù)據(jù)后,再投遞一個或是多個同類型的I/O即可(::AcceptEx()、::WSARecv()、::WSASend())。對讀取到的數(shù)據(jù),我們可以按照自己的需要來進行相應(yīng)的處理。

            為此,我們需要一個以O(shè)VERLAPPED(重疊I/O)結(jié)構(gòu)為第一個字段的per-I/O數(shù)據(jù)自定義結(jié)構(gòu)。

            typedef struct _PER_IO_DATA
            {
                     OVERLAPPED ol;      // 重疊I/O結(jié)構(gòu)
                     char buf[BUFFER_SIZE];  // 數(shù)據(jù)緩沖區(qū)
                     int nOperationType;         //I/O操作類型
            #define OP_READ 1
            #define OP_WRITE 2
            #define OP_ACCEPT 3
            } PER_IO_DATA, *PPER_IO_DATA;

            將一個PER_IO_DATA結(jié)構(gòu)強制轉(zhuǎn)化成一個OVERLAPPED結(jié)構(gòu)傳給::GetQueuedCompletionStatus()函數(shù),返回的這個PER_IO_DATA結(jié)構(gòu)的的nOperationType就是I/O操作的類型。當然,這些類型都是在投遞I/O請求時自己設(shè)置的。

            這樣一個IOCP服務(wù)器的框架就出來了。當然,要做一個好的IOCP服務(wù)器,還有考慮很多問題,如內(nèi)存資源管理、接受連接的方法、惡意的客戶連接、包的重排序等等。以上是個人對于IOCP模型的一些理解與看法,還有待完善。另外各Winsock API的用法參見MSDN。

             

            補充IOCP模型的實現(xiàn):

            //創(chuàng)建一個完成端口
            FCompletPort := CreateIoCompletionPort( INVALID_HANDLE_VALUE, 0,0,0 );

            //接受遠程連接,并把這個連接的socket句柄綁定到剛才創(chuàng)建的IOCP上
            AConnect := accept( FListenSock, addr, len);
            CreateIoCompletionPort( AConnect, FCompletPort, nil, 0 );

            //創(chuàng)建CPU數(shù)*2 + 2個線程
            for i:=1 to si.dwNumberOfProcessors*2+2 do
            begin
              AThread := TRecvSendThread.Create( false );
              AThread.CompletPort := FCompletPort;//告訴這個線程,你要去這個IOCP去訪問數(shù)據(jù)
            end;

            OK,就這么簡單,我們要做的就是建立一個IOCP,把遠程連接的socket句柄綁定到剛才創(chuàng)建的IOCP上,最后創(chuàng)建n個線程,并告訴這n個線程到這個IOCP上去訪問數(shù)據(jù)就可以了。

            再看一下TRecvSendThread線程都干些什么:

            procedure TRecvSendThread.Execute;
            var
              ......
            begin
              while (not self.Terminated) do
              begin
                //查詢IOCP狀態(tài)(數(shù)據(jù)讀寫操作是否完成)
                GetQueuedCompletionStatus( CompletPort, BytesTransd, CompletKey, POVERLAPPED(pPerIoDat), TIME_OUT );

                if BytesTransd <> 0  then
                   ....;//數(shù)據(jù)讀寫操作完成

                //再投遞一個讀數(shù)據(jù)請求
                WSARecv( CompletKey, @(pPerIoDat^.BufData), 1, BytesRecv, Flags, @(pPerIoDat^.Overlap), nil );
              end;
            end;

            讀寫線程只是簡單地檢查IOCP是否完成了我們投遞的讀寫操作,如果完成了則再投遞一個新的讀寫請求。
            應(yīng)該注意到,我們創(chuàng)建的所有TRecvSendThread都在訪問同一個IOCP(因為我們只創(chuàng)建了一個IOCP),并且我們沒有使用臨界區(qū)!難道不會產(chǎn)生沖突嗎?不用考慮同步問題嗎?
            呵呵,這正是IOCP的奧妙所在。IOCP不是一個普通的對象,不需要考慮線程安全問題。它會自動調(diào)配訪問它的線程:如果某個socket上有一個線程A正在訪問,那么線程B的訪問請求會被分配到另外一個socket。這一切都是由系統(tǒng)自動調(diào)配的,我們無需過問。

            posted @ 2009-07-29 11:21 鷹擊長空 閱讀(388) | 評論 (0)編輯 收藏
            一個python 編程講座 http://www.swc.scipy.org/lec/figurelist.html
            posted @ 2009-07-15 11:17 鷹擊長空 閱讀(107) | 評論 (0)編輯 收藏

            先來看個例子:

            def foo(*args, **kwargs):
            print 'args = ', args
            print 'kwargs = ', kwargs
            print '---------------------------------------'
            if __name__ == '__main__':
            foo(1,2,3,4)
            foo(a=1,b=2,c=3)
            foo(1,2,3,4, a=1,b=2,c=3)
            foo('a', 1, None, a=1, b='2', c=3)
            輸出結(jié)果如下:

            args =  (1, 2, 3, 4)
            kwargs =  {}
            ---------------------------------------
            args =  ()
            kwargs =  {'a': 1, 'c': 3, 'b': 2}
            ---------------------------------------
            args =  (1, 2, 3, 4)
            kwargs =  {'a': 1, 'c': 3, 'b': 2}
            ---------------------------------------
            args =  ('a', 1, None)
            kwargs =  {'a': 1, 'c': 3, 'b': '2'}
            ---------------------------------------

            可以看到,這兩個是python中的可變參數(shù)。*args表示任何多個無名參數(shù),它是一個tuple;**kwargs表示關(guān)鍵字參數(shù),它是一個dict。并且同時使用*args和**kwargs時,必須*args參數(shù)列要在**kwargs前,像foo(a=1, b='2', c=3, a', 1, None, )這樣調(diào)用的話,會提示語法錯誤“SyntaxError: non-keyword arg after keyword arg”。

            posted @ 2009-07-14 22:45 鷹擊長空 閱讀(213) | 評論 (0)編輯 收藏
                    這個筆記主要是關(guān)于python語言本身的一些概念。
                    在Python中有4種類型的數(shù)——整數(shù)、長整數(shù)、浮點數(shù)和復(fù)數(shù)。如:2是一個整數(shù)的例子。 3.23和52.3E-4是浮點數(shù)的例子。E標記表示10的冪。在這里,52.3E-4表示52.3 * 10-4。 (-5+4j)和(2.3-4.6j)是復(fù)數(shù)的例子。
                   你可以用單引號指示字符串,就如同'Quote me on this'這樣。所有的空白,即空格和制表符都照原樣保留。在雙引號中的字符串與單引號中的字符串的使用完全相同。使用三引號('''或""")可以指示一個多行的字符串。可以在三引號中自由的使用單引號和雙引號。轉(zhuǎn)義符是\,可以用\'來指示單引號—注意這個反斜杠。
                   變量的名字就是標識符。在命名標識符的時候,你要遵循這些規(guī)則:
            ● 標識符的第一個字符必須是字母表中的字母(大寫或小寫)或者一個下劃線(‘ _’)。
            ● 標識符名稱的其他部分可以由字母(大寫或小寫)、下劃線(‘ _ ’)或數(shù)字(0-9)組成。
            ● 標識符名稱是對大小寫敏感的。例如,myname和myName不是一個標識符。注意前者中
            的小寫n和后者中的大寫N。
            ● 有效 標識符名稱的例子有i、__my_name、name_23和a1b2_c3。
            ● 無效 標識符名稱的例子有2things、this is spaced out和my-name。
                     使用變量時只需要給它們賦一個值。不需要聲明或定義數(shù)據(jù)類型。
                     物理行是你在編寫程序時所看見的。邏輯行是Python 看見的單個語句。Python假定每個物理行對應(yīng)一個邏輯行。如果你想要在一個物理行中使用多于一個邏輯行,那么你需要使用分號(;)來特別地標明這種用法。分號表示一個邏輯行/語句的結(jié)束。
                    Python程序中行首的空白稱為縮進,是非常重要的,它用來決定邏輯行的縮進層次,從而用來決定語句的分組。類似于C++中的花括號。同一層次的語句必須有相同的縮進,每一組這樣的語句稱為一個塊(Block)。
                   

            表2.1 運算符與它們的用法

            運算符 名稱 說明 例子
            + 兩個對象相加 3 + 5得到8。'a' + 'b'得到'ab'。
            - 得到負數(shù)或是一個數(shù)減去另一個數(shù) -5.2得到一個負數(shù)。50 - 24得到26。
            * 兩個數(shù)相乘或是返回一個被重復(fù)若干次的字符串 2 * 3得到6。'la' * 3得到'lalala'。
            **

            返回x的y次冪

            3 ** 4得到81(即3 * 3 * 3 * 3)
            / x除以y 4/3得到1(整數(shù)的除法得到整數(shù)結(jié)果)。4.0/3或4/3.0得到1.3333333333333333
            // 取整除 返回商的整數(shù)部分 4 // 3.0得到1.0
            % 取模 返回除法的余數(shù) 8%3得到2。-25.5%2.25得到1.5
            << 左移 把一個數(shù)的比特向左移一定數(shù)目(每個數(shù)在內(nèi)存中都表示為比特或二進制數(shù)字,即0和1) 2 << 2得到8。——2按比特表示為10
            >> 右移 把一個數(shù)的比特向右移一定數(shù)目 11 >> 1得到5。——11按比特表示為1011,向右移動1比特后得到101,即十進制的5。
            & 按位與 數(shù)的按位與 5 & 3得到1。
            | 按位或 數(shù)的按位或 5 | 3得到7。
            ^ 按位異或 數(shù)的按位異或 5 ^ 3得到6
            ~ 按位翻轉(zhuǎn) x的按位翻轉(zhuǎn)是-(x+1) ~5得到6。
            < 小于 返回x是否小于y。所有比較運算符返回1表示真,返回0表示假。這分別與特殊的變量True和False等價。注意,這些變量名的大寫。 5 < 3返回0(即False)而3 < 5返回1(即True)。比較可以被任意連接:3 < 5 < 7返回True。
            > 大于 返回x是否大于y 5 > 3返回True。如果兩個操作數(shù)都是數(shù)字,它們首先被轉(zhuǎn)換為一個共同的類型。否則,它總是返回False。
            <= 小于等于 返回x是否小于等于y x = 3; y = 6; x <= y返回True。
            >= 大于等于 返回x是否大于等于y x = 4; y = 3; x >= y返回True。
            == 等于 比較對象是否相等 x = 2; y = 2; x == y返回True。x = 'str'; y = 'stR'; x == y返回False。x = 'str'; y = 'str'; x == y返回True。
            != 不等于 比較兩個對象是否不相等 x = 2; y = 3; x != y返回True。
            not 布爾“非” 如果x為True,返回False。如果x為False,它返回True。 x = True; not y返回False。
            and 布爾“與” 如果x為False,x and y返回False,否則它返回y的計算值。 x = False; y = True; x and y,由于x是False,返回False。在這里,Python不會計算y,因為它知道這個表達式的值肯定是False(因為x是False)。這個現(xiàn)象稱為短路計算。
            or 布爾“或” 如果x是True,它返回True,否則它返回y的計算值。 x = True; y = False; x or y返回True。短路計算在這里也適用。

            表2.2 運算符優(yōu)先級

            運算符 描述
            lambda Lambda表達式
            or 布爾“或”
            and 布爾“與”
            not x 布爾“非”
            in,not in 成員測試
            is,is not 同一性測試
            <,<=,>,>=,!=,== 比較
            | 按位或
            ^ 按位異或
            & 按位與
            <<,>> 移位
            +,- 加法與減法
            *,/,% 乘法、除法與取余
            +x,-x 正負號
            ~x 按位翻轉(zhuǎn)
            ** 指數(shù)
            x.attribute 屬性參考
            x[index] 下標
            x[index:index] 尋址段
            f(arguments...) 函數(shù)調(diào)用
            (experession,...) 綁定或元組顯示
            [expression,...] 列表顯示
            {key:datum,...} 字典顯示
            'expression,...' 字符串轉(zhuǎn)換

            Format Meaning
            "c" Single character (i.e., string of length 1)
            "B" Unsigned 8-bit integer
            "h" Short (16-bit) integer
            "i" 32-bit integer
            "f" 32-bit float
            "d" Double-precision (64-bit) float
            "2" String of fixed size (see below)
            Table 18.2: Packing Format Specifiers

            在Python中有三種控制流語句——ifforwhile,
            Python中if-elif-else語句類似于C++中的if-elseif-else;

            Python中for i in range(0,5)等價于C/C++中的for (int i = 0; i < 5; i++)。程序中使用內(nèi)建的range函數(shù)生成這個數(shù)的序列。range返回一個序列的數(shù)。這個序列從第一個數(shù)開始到第二個數(shù)為止。例如,range(1,5)給出序列[1, 2, 3, 4]。默認地,range的步長為1。如果我們?yōu)?code>range
            提供第三個數(shù),那么它將成為步長。例如,range(1,5,2)給出[1,3]。記住,range 向上 延伸到第二個數(shù),即它包含第二個數(shù)。

            while語句是循環(huán)語句,while語句有一個可選的else從句。

            break語句是用來 終止 循環(huán)語句的,即哪怕循環(huán)條件沒有稱為False或序列還沒有被完全遞歸,也停止執(zhí)行循環(huán)語句。

            一個重要的注釋是,如果你從forwhile循環(huán)中終止 ,任何對應(yīng)的循環(huán)else塊將執(zhí)行。

            posted @ 2009-07-14 22:36 鷹擊長空 閱讀(291) | 評論 (0)編輯 收藏

            本節(jié)介紹Python的內(nèi)建函數(shù)和異常.許多內(nèi)建函數(shù)的細節(jié)及特性可以在這里找到.

            內(nèi)建函數(shù)

            本節(jié)介紹的函數(shù)在解釋器中總是可用的,他們被包含在 __builtin__ 模塊里.另外每個模塊的 __builtins__ 屬性經(jīng)常指的是這個模塊(除了當在restricted execution環(huán)境下運行時).

            _(下劃線)

            默認情況下,變量 _ 用于在交互模式下表示最近一個表達式的運行結(jié)果.

            參閱 sys.displayhook (118)

            __import__(name [, globals [, locals [, fromlist]]])

            import語句通過調(diào)用這個函數(shù)來導(dǎo)入模塊. name是包含模塊名字的字符串, globals是一個可選的定義全局名稱空間的字典, locals是定義局部名稱空間的字典, fromlist是from語句目標的列表.例如, import spam語句會調(diào)用__import__('spam', globals(), locals(), []) ,而from spam import foo 語句會調(diào)用 __import__('spam', globals(), locals(), ['foo']). 如果模塊名在包名字之后(如foo.bar)而且fromlist為空時,就返回對應(yīng)的模塊對象.如果fromlist不為空,則只會返回最頂級的包.

            這個函數(shù)是一個低等級的模塊載入接口.它并不執(zhí)行import語句的所有步驟(通常情況下局部名稱空間并不會隨模塊中包含對象的名稱引用的改變而改變.這個函數(shù)可以由用戶來重新定義,這樣為import語句加入新的行為.默認的執(zhí)行并不會檢查locals參數(shù),而globals只用于決定包的內(nèi)容(這些參數(shù)可以使 __import__()能夠完整地訪問全局和局部名稱空間)

            abs(x)
            返回x的絕對值

            apply(func [, args [, keywords]])
            對可調(diào)用對象func執(zhí)行函數(shù)調(diào)用. args是一個包含固定位置參數(shù)的元組, keywords是包含關(guān)鍵參數(shù)的字典. apply()函數(shù)也可以寫做func(*args ,**keywords ).

            buffer(sequence [, offset [, size]])
            創(chuàng)建一個新的緩沖器對象.緩沖器通常是一個序列(如字符串)的字節(jié)導(dǎo)向序列.緩沖器和字符串在許多地方是相同的,但是它不支持字符串方法,而且也不能使用string模塊的函數(shù).

            callable(object)
            當object為可調(diào)用對象時返回True,否則返回False

            chr(i)
            將一個0到255的整數(shù)轉(zhuǎn)換為一個字符.

            cmp(x,y)
            比較x和y. x< y返回負數(shù); x== y返回零; x> y返回整數(shù).它可以比較任意兩個對象并返回結(jié)果,即使有時候?qū)ο蟮谋容^豪無意義(例如比較文件對象).在某些環(huán)境下,這樣的比較會引發(fā)異常.

            coerce(x,y)
            將x和y值轉(zhuǎn)換為同一個數(shù)值類型并作為一個元組返回.(第三章,類型和對象)

            compile(string, filename, kind)
            使用exec()或eval()將字符串編譯為代碼對象. filename is a string containing the name of the file in which the string was defined. kind為'exec'時代表一個表達式的序列, 'eval'代表一個表達式, 'single'代表一個運行語句.

            complex(real [, imag])
            創(chuàng)建一個復(fù)數(shù)

            delattr(object, attr)
            刪除對象的一個屬性, attr是一個字符串.與 del object.attr相同

            dir([object])
            返回包含屬性名稱的列表.它們來自對象的 __dict__, __methods__,以及 __members__ 屬性.如果沒有傳遞給它參數(shù),則會返回當前的local symbol table

            divmod(a,b)
            返回一個包含商和余數(shù)的元組.對于整數(shù),將返回(a / b , a % b ),對于浮點數(shù),將返回(math.floor(a / b ), a % b )

            eval(expr [, globals [, locals]])
            計算一個表達式的值. expr是一個字符串或由compile()創(chuàng)建的一個代碼對象. globals和locals為操作定義的全局和局部名稱空間,當省略時,表達式將在調(diào)用時的名稱空間計算.

            execfile(filename [, globals [, locals]])
            運行文件filename中的語句. globals和locals定義了文件運行的全局和局部名稱空間,當省略時,文件將在調(diào)用時的名稱空間運行.這個函數(shù)不能在一個函數(shù)主體里使用,因為它與內(nèi)嵌范圍不相容.

            filter(function, list)
            使用func()函數(shù)來過濾s中的元素.使func返回值為false的元素被丟棄,其它的存入filter函數(shù)返回的列表中.如果function是None,則list中值為False的元素就被刪除.

            float(x)
            將x轉(zhuǎn)換為浮點數(shù)

            getattr(object, name [, default])
            返回一個對象的屬性. name是一個字符串. default是一個可選的值,代表當沒有這個屬性時返回的值. 與 object.name 結(jié)果相同

            globals()
            返回一個與全局名稱空間對應(yīng)的字典

            hasattr(object, name)
            返回object是否有name屬性,布爾值

            hash(object)
            返回一個對象的整數(shù)哈希值(如果可能).兩個相等對象的哈希值是相同的.模塊沒有定義一個哈希值.

            hex(x)
            將一個整數(shù)或長整數(shù)轉(zhuǎn)換為一個十六進制的字符串

            id(object)
            返回一個對象的整數(shù)id

            input([prompt])
            相當于eval(raw_input(prompt ))

            int(x [, base])
            將一個數(shù)字或字符串轉(zhuǎn)換為整數(shù). 可選參數(shù)base代表從字符串轉(zhuǎn)換時的基礎(chǔ)/根據(jù)

            intern(string)
            Checks to see whether string is contained in an internal table of strings. If found, a copy of the internal string is returned. If not, string is added to the internal table and returned. This function is primarily used to get better performance in operations involving dictionary lookups. Interned strings are never garbage-collected. Not applicable to Unicode strings.

            isinstance(object, classobj)
            檢查object是否是classobj的事例或子類.也可用于檢查類型

            issubclass(class1, class2)
            檢查class1是否是class2的子類(派生類)
            注意: issubclass(A , A )返回True

            len(s)
            返回序列s中包含的條目數(shù)目

            list(s)
            返回一個包含序列s中條目的新列表

            locals()
            返回一個與調(diào)用時局部名稱空間相對應(yīng)的字典

            long(x [, base])
            將一個數(shù)字或字符串轉(zhuǎn)換為長整數(shù),可選參數(shù)base代表從字符串轉(zhuǎn)換時的基礎(chǔ)/根據(jù)

            map(function, list, ...)
            將序列l(wèi)ist中的每個元素傳遞給function函數(shù)做參數(shù),函數(shù)的返回值組成列表并返回.如果提供給多個列表,則函數(shù)應(yīng)包含有多個參數(shù),每個參數(shù)從不同的列表獲得.如果函數(shù)為None,則默認為 identity function(?身份函數(shù)).如果None映射到多個列表,則返回一個包含元組的列表,元組的每個元素分別來自各個列表.如果有必要,短的列表將使用None來擴充到與最長列表長度相等. map可以使用list comprehensions 來代替.例如map(function , alist ),可以使用[function (x) for x in alist ]來代替
            參閱 zip (105).

            max(s [, args, ...])
            單個參數(shù)時,返回序列s中的最大值.多個參數(shù)時,返回值最大的參數(shù)

            min(s [, args, ...])
            單個參數(shù)時,返回序列s中的最小值.多個參數(shù)時,返回值最小的參數(shù)

            oct(x)
            將一個整數(shù)或者長整數(shù)轉(zhuǎn)換為八進制字符串

            open(filename [, mode [, bufsize]])
            打開文件filename并返回一個文件對象(第十章,運行環(huán)境). mode代表文件打開的模式. 'r' 表示讀, 'w' 表示寫, 'a' 表示在文件末尾添加內(nèi)容. 還有一種更新模式,你只要在讀寫模式后增加一個'+'就可以使用這種模式,如'r+' 或 'w+'.當一個文件以更新模式打開,你就可以對這個文件進行讀寫操作.只要在任何讀取操作之前刷新所有的輸出緩沖就不會有問題.如果一個文件以 'w+' 模式打開,它的長度就度截為 0.當mode省略時,將會使用'w'模式.bufsize參數(shù)指定了緩沖行為, 0代表無緩沖,1代表行緩沖,其他正數(shù)代表一個大約的字節(jié)緩沖器大小,負數(shù)代表使用系統(tǒng)默認緩沖器大小(也是默認行為)

            ord(c)
            返回單個字符c的整數(shù)順序值.普通字符返回[0,255]中的一個值,Unicode字符返回 [0,65535]中的一個值

            pow(x, y [, z])
            返回x ** y ,如果z存在返回(x ** y ) % z

            range([start,] stop [, step])
            返回一個從start到stop的整數(shù)序列, step代表步進,默認值為1. start默認值為0.負數(shù)的step可以創(chuàng)建一個遞減的整數(shù)序列
            參閱xrange (105)

            raw_input([prompt])
            從標準輸入(sys.stdin)中讀取一行,并把它作為字符串返回.如果提供了prompt,它將首先打印到標準輸出(sys.stdout).當讀取到一個EOF時,就會引發(fā)一個EOFError異常.如果readline模塊被導(dǎo)入,那么這個函數(shù)會使用它來提供更高級的功能

            reduce(func, seq [, initializer])
            函數(shù)從一個序列收集信息,然后只返回一個值(例如求和,最大值,等).它首先以序列的前兩個元素調(diào)用函數(shù),再將返回值和第三個參數(shù)作為參數(shù)調(diào)用函數(shù),依次執(zhí)行下去,返回最終的值. func函數(shù)有且只有兩個參數(shù).在seq為空時,將使用初始值initializer.

            reload(module)
            重新導(dǎo)入一個已經(jīng)導(dǎo)入的模塊. module必須是一個已經(jīng)存在的模塊對象.一般情況下并不鼓勵使用這個函數(shù),除了在調(diào)試的時候.
            當一個模塊重導(dǎo)入時,定義它的全局名稱空間的字典依然存在.Thus, definitions in the old module that aren’t part of the newly reloaded module are retained.模塊可以利用這個來檢查他們是否已經(jīng)被導(dǎo)入.
            重導(dǎo)入一個使用C編寫的模塊通常是不合法的
            If any other modules have imported this module by using the from statement, they’ll continue to use the definitions in the previously imported module. This problem can be avoided by either reissuing the from statement after a module has been reloaded or using fully qualified names such as module.name .
            如果有使用以前模塊中類創(chuàng)建的實例,它們將繼續(xù)使用以前的模塊

            repr(object)
            返回一個對象的標準字符串表示.與向后的引號 `object` 相同.大多數(shù)情況下,返回的字符串可以使用eval()來再次創(chuàng)建這個對象.

            round(x [, n])
            Returns the result of rounding the floating-point number x to the closest multiple of 10 to the power minus n . If n is omitted, it defaults to 0. If two multiples are equally close, rounding is done away from 0 (例如, 0.5 is rounded to 1.0 and -0.5 is rounded to -1.0).

            setattr(object, name, value)
            設(shè)置一個對象的屬性. name是一個字符串. 相當于object.name = value .

            slice([start,] stop [, step])
            返回一個代表指定數(shù)列中一個整數(shù)的切片對象.切片對象也可以有擴展切片操作語句來產(chǎn)生.(第三章,序列和映射方法)

            str(object)
            返回表示對象的可打印形式的字符串.與print語句產(chǎn)生的字符串相同.

            tuple(s)
            從序列s中創(chuàng)建一個元組.如果s已經(jīng)是一個元組,則返回s

            type(object)
            返回object的類型,它是一個types模塊中定義type類型
            參閱isinstance (102)

            unichr(i)
            將一個0到65535的整數(shù)轉(zhuǎn)換為一個Unicode字符

            unicode(string [, encoding [, errors]])
            將string轉(zhuǎn)換為Unicode字符串. encoding指定了string的數(shù)據(jù)編碼,它被省略時,將使用sys.getdefaultencoding(). errors指定編碼錯誤處理方式.('strict', 'ignore', 或 'replace' .參閱第三章和第九章中有關(guān)Unicode內(nèi)容)

            vars([object])
            返回object的 symbol table (通常在object的__dict__屬性).如果沒有給它提供參數(shù),則返回對應(yīng)當前局部名稱空間的字典.

            xrange([start,] stop [, step])
            和range函數(shù)相似,但返回的是一個XRangeType對象.它生成一個迭代器,就是只有用那個數(shù)時才臨時通過計算提供值,而不是全部儲存它們.這樣在處理大的數(shù)列時能節(jié)省大量的內(nèi)存.

            zip(s1 [, s2 [,..]])
            用來將幾個序列組合成一個包含元組的序列,序列中的每個元素t[i ] = (s1[i ], s2[i ], ..., sn[i ]).結(jié)果與最短序列的長度相等.

            posted @ 2009-07-14 22:26 鷹擊長空 閱讀(277) | 評論 (0)編輯 收藏
                    Python是一門面向?qū)ο蟮慕忉屝湍_本語言,類似于Java。Python標準庫很龐大,它可以幫助你處理各種工作,包括正則表達式、文檔生成、單元測試、線程、數(shù)據(jù)庫、網(wǎng)頁瀏覽器、CGI、FTP、電子郵件、XML、XML-RPC、HTML、WAV文件、密碼系統(tǒng)、GUI(圖形用戶界面)、Tk和其他與系統(tǒng)有關(guān)的操作。
            記住,只要安裝了Python,所有這些功能都是可用的。這被稱作Python的“功能齊全”理念。除了標準庫以外,還有許多其他高質(zhì)量的庫,如wxPython、Twisted和Python圖像庫等等。
                   目前,Python的穩(wěn)定版本是2.5,相關(guān)的其他工具也對2.5這個版本支持的最好,所以為避免麻煩,最好用2.5。下載安裝完畢后,需要先正確的設(shè)置PATH變量。對于Windows 2000、XP、2003,點擊控制面板->系統(tǒng)->高級->環(huán)境變量。在“系統(tǒng)變量”表單中點擊叫做PATH的變量,然后編輯這個變量,把;C:\Python25(是Python的安裝路徑,前面有個分號)加到它的結(jié)尾。 在開始->運行 輸入 CMD打開dos,提示符下鍵入python。或者你可以選擇使用IDLE程序。IDLE是集成開發(fā)環(huán)境的縮寫。點擊開始->程序->Python 2.5->IDLE
            (Python GUI)。退出Python提示符,如果你使用的是Linux/BSD shell,那么按Ctrl-d退出提示符。如果是在Windows命令行中,則按Ctrl-z再按Enter。
                    啟動你選擇的編輯器,輸入下面這段程序,把它保存為helloworld.py。
            #!/usr/bin/python
            # Filename : helloworld.py
            print 'Hello World'
            然后啟動DOS,轉(zhuǎn)到helloworld.py所在的路徑,然后鍵入命令python helloworld.py。如果你使用IDLE,請使用菜單Edit->Run Script或者使用鍵盤快捷方式Ctrl-F5。輸出如下所示。
            $ python helloworld.py
            Hello World

            ==========
            Notes:
            1、任何在#符號右面的內(nèi)容都是注釋;
            2、使用DOS命令行運行*.py腳本時,要先cd切換到腳本所在的文件夾路徑,然后運行。
            3、Python中沒有主函數(shù)的說法,沒有必要寫主函數(shù),一個腳本可以全部是語句。


                          
            posted @ 2009-07-14 20:25 鷹擊長空 閱讀(478) | 評論 (0)編輯 收藏

            在圖形圖象處理編程過程中,雙緩沖是一種基本的技術(shù)。我們知道,如果窗體在響應(yīng)WM_PAINT消息的時候要進行復(fù)雜的圖形處理,那么窗體在重繪時由于過頻的刷新而引起閃爍現(xiàn)象。解決這一問題的有效方法就是雙緩沖技術(shù)。
              因為窗體在刷新時,總要有一個擦除原來圖象的過程OnEraseBkgnd,它利用背景色填充窗體繪圖區(qū),然后在調(diào)用新的繪圖代碼進行重繪,這樣一擦一寫造成了圖象顏色的反差。當WM_PAINT的響應(yīng)很頻繁的時候,這種反差也就越發(fā)明顯。于是我們就看到了閃爍現(xiàn)象。

            我們會很自然的想到,避免背景色的填充是最直接的辦法。但是那樣的話,窗體上會變的一團糟。因為每次繪制圖象的時候都沒有將原來的圖象清除,造成了圖象的殘留,于是窗體重繪時,畫面往往會變的亂七八糟。所以單純的禁止背景重繪是不夠的。我們還要進行重新繪圖,但要求速度很快,于是我們想到了使用BitBlt函數(shù)。它可以支持圖形塊的復(fù)制,速度很快。我們可以先在內(nèi)存中作圖,然后用此函數(shù)將做好的圖復(fù)制到前臺,同時禁止背景刷新,這樣就消除了閃爍。以上也就是雙緩沖繪圖的基本的思路。

             

            一、普通方法:

              先按普通做圖的方法進行編程。即在視類的OnDraw函數(shù)中添加繪圖代碼。在此我們繪制若干同心圓,代碼如下:

             CBCDoc* pDoc = GetDocument();

             ASSERT_VALID(pDoc);

             CPoint ptCenter;

             CRect rect,ellipseRect;

             GetClientRect(&rect);

             ptCenter = rect.CenterPoint();

             for(int i=20;i>0;i--)

             {

                  ellipseRect.SetRect(ptCenter,ptCenter);

                  ellipseRect.InflateRect(i*10,i*10);

                  pDC->Ellipse(ellipseRect);

             }

            編譯運行程序,嘗試改變窗口大小,可以發(fā)現(xiàn)閃爍現(xiàn)象。

             

            二、雙緩沖方法:

              在雙緩沖方法中,首先要做的是屏蔽背景刷新。背景刷新其實是在響應(yīng)WM_ERASEBKGND消息。我們在視類中添加對這個消息的響應(yīng),可以看到缺省的代碼如下:

            BOOL CMYView::OnEraseBkgnd(CDC* pDC)

            {

                 return CView::OnEraseBkgnd(pDC);

            }

            是調(diào)用父類的OnEraseBkgnd函數(shù),我們屏蔽此調(diào)用,只須直接return TRUE;即可。

             

              下面是內(nèi)存緩沖作圖的步驟。

             CPoint ptCenter;

             CRect rect,ellipseRect;

             GetClientRect(&rect);

             ptCenter = rect.CenterPoint();

             CDC dcMem;            //用于緩沖作圖的內(nèi)存DC

             CBitmap bmp;          //內(nèi)存中承載臨時圖象的位圖

             dcMem.CreateCompatibleDC(pDC);  //依附窗口DC創(chuàng)建兼容內(nèi)存DC

             bmp.CreateCompatibleBitmap(pDC,rect.Width(),rect.Height());//創(chuàng)建兼容位圖

             dcMem.SelectObject(&bmp);     //將位圖選擇進內(nèi)存DC

            //按原來背景填充客戶區(qū),不然會是黑色

             dcMem.FillSolidRect(rect,pDC->GetBkColor());

            for(int i=20;i>0;i--)  //在內(nèi)存DC上做同樣的同心圓圖象

             {

                  ellipseRect.SetRect(ptCenter,ptCenter);

                  ellipseRect.InflateRect(i*10,i*10);

                  dcMem.Ellipse(ellipseRect);

             }

             pDC->BitBlt(0,0,rect.Width(),rect.Height(),

            &dcMem,0,0,SRCCOPY);//將內(nèi)存DC上的圖象拷貝到前臺

             dcMem.DeleteDC();  //刪除DC

             bm.DeleteObject(); //刪除位圖

            由于復(fù)雜的畫圖操作轉(zhuǎn)入后臺,我們看到的是速度很快的復(fù)制操作,自然也就消除了閃爍現(xiàn)象。

             

            注意:bmp.CreateCompatibleBitmap(pDC,rect.Width(),rect.Height());

            這里面CreateCompatibleBitmap第一個參數(shù)不能用dcMem,這樣的話創(chuàng)建的是黑白位圖。如果你要創(chuàng)建彩色位圖,需要用pDC,它用來創(chuàng)建了內(nèi)存DC. 詳細請見下面的MSDN:

            When a memory device context is created, it initially has a 1-by-1 monochrome bitmap selected into it. If this memory device context is used in CreateCompatibleBitmap, the bitmap that is created is a monochrome bitmap. To create a color bitmap, use the hDC that was used to create the memory device context, as shown in the following code:

                HDC memDC = CreateCompatibleDC ( hDC );

                HBITMAP memBM = CreateCompatibleBitmap ( hDC, nWidth, nHeight );

                SelectObject ( memDC, memBM );

             

            posted @ 2009-07-10 23:07 鷹擊長空 閱讀(287) | 評論 (0)編輯 收藏
            僅列出標題
            共5頁: 1 2 3 4 5 
            久久久久亚洲av无码专区喷水| 伊人久久亚洲综合影院| 国产精品久久网| 久久国产精品免费| 久久久久久久久久久精品尤物 | 一本一道久久精品综合| 久久久久99精品成人片三人毛片 | 伊人久久一区二区三区无码| 日韩久久久久久中文人妻| 色综合合久久天天综合绕视看| 精品国产91久久久久久久| 久久精品aⅴ无码中文字字幕不卡| 久久99精品综合国产首页| 久久久久国产亚洲AV麻豆| 无遮挡粉嫩小泬久久久久久久| 一本一道久久精品综合| 午夜欧美精品久久久久久久| 久久亚洲AV无码西西人体| 国产午夜免费高清久久影院| 久久综合色老色| 91久久香蕉国产熟女线看| 久久综合狠狠综合久久综合88 | 久久人人爽人人人人爽AV| 久久久久九国产精品| 久久99精品国产| 久久99久久99小草精品免视看| 久久香蕉国产线看观看精品yw| 久久人人爽人人人人片av| 久久综合伊人77777| 91久久九九无码成人网站| 91久久精品91久久性色| 奇米影视7777久久精品| 色婷婷综合久久久中文字幕 | 久久综合九色综合97_久久久| 国内高清久久久久久| 亚洲伊人久久综合中文成人网| 久久久精品视频免费观看| 国产精品伊人久久伊人电影| 国产成人精品久久亚洲| 国产精品丝袜久久久久久不卡| 国产亚洲美女精品久久久|