编写可靠的本机代码
2007-03-22 21:30:41 来源:WEB开发网 闂傚倸鍊搁崐鎼佸磹閹间礁纾归柟闂寸绾惧綊鏌熼梻瀵割槮缁炬儳缍婇弻鐔兼⒒鐎靛壊妲紒鐐劤缂嶅﹪寮婚悢鍏尖拻閻庨潧澹婂Σ顔剧磼閻愵剙鍔ょ紓宥咃躬瀵鎮㈤崗灏栨嫽闁诲酣娼ф竟濠偽i鍓х<闁绘劦鍓欓崝銈囩磽瀹ュ拑韬€殿喖顭烽幃銏ゅ礂鐏忔牗瀚介梺璇查叄濞佳勭珶婵犲伣锝夘敊閸撗咃紲闂佺粯鍔﹂崜娆撳礉閵堝洨纾界€广儱鎷戦煬顒傗偓娈垮枛椤兘骞冮姀銈呯閻忓繑鐗楃€氫粙姊虹拠鏌ュ弰婵炰匠鍕彾濠电姴浼i敐澶樻晩闁告挆鍜冪床闂備胶绮崝锕傚礈濞嗘挸绀夐柕鍫濇川绾剧晫鈧箍鍎遍幏鎴︾叕椤掑倵鍋撳▓鍨灈妞ゎ厾鍏橀獮鍐閵堝懐顦ч柣蹇撶箲閻楁鈧矮绮欏铏规嫚閺屻儱寮板┑鐐板尃閸曨厾褰炬繝鐢靛Т娴硷綁鏁愭径妯绘櫓闂佸憡鎸嗛崪鍐簥闂傚倷鑳剁划顖炲礉閿曞倸绀堟繛鍡樻尭缁€澶愭煏閸繃宸濈痪鍓ф櫕閳ь剙绠嶉崕閬嶅箯閹达妇鍙曟い鎺戝€甸崑鎾斥枔閸喗鐏堝銈庡幘閸忔﹢鐛崘顔碱潊闁靛牆鎳愰ˇ褔鏌h箛鎾剁闁绘顨堥埀顒佺煯缁瑥顫忛搹瑙勫珰闁哄被鍎卞鏉库攽閻愭澘灏冮柛鏇ㄥ幘瑜扮偓绻濋悽闈浶㈠ù纭风秮閺佹劖寰勫Ο缁樻珦闂備礁鎲¢幐鍡涘椽閸愵亜绨ラ梻鍌氬€烽懗鍓佸垝椤栫偛绀夐柨鏇炲€哥粈鍫熺箾閸℃ɑ灏紒鈧径鎰厪闁割偅绻冨婵堢棯閸撗勬珪闁逞屽墮缁犲秹宕曢柆宥呯闁硅揪濡囬崣鏇熴亜閹烘垵鈧敻宕戦幘鏂ユ灁闁割煈鍠楅悘鍫濐渻閵堝骸骞橀柛蹇旓耿閻涱噣宕橀纰辨綂闂侀潧鐗嗛幊鎰八囪閺岋綀绠涢幘鍓侇唹闂佺粯顨嗛〃鍫ュ焵椤掍胶鐓紒顔界懃椤繘鎼圭憴鍕彴闂佸搫琚崕鍗烆嚕閺夊簱鏀介柣鎰緲鐏忓啴鏌涢弴銊ュ箻鐟滄壆鍋撶换婵嬫偨闂堟刀銏犆圭涵椋庣М闁轰焦鍔栧鍕熺紒妯荤彟闂傚倷绀侀幉锟犲箰閸℃稑妞介柛鎰典簻缁ㄣ儵姊婚崒姘偓鐑芥嚄閸撲礁鍨濇い鏍仜缁€澶愭煥閺囩偛鈧摜绮堥崼鐔虹闁糕剝蓱鐏忣厾绱掗埀顒佸緞閹邦厾鍘梺鍓插亝缁诲啫顔忓┑鍫㈡/闁告挆鍕彧闂侀€炲苯澧紒鐘茬Ч瀹曟洟鏌嗗鍛唵闂佺鎻俊鍥矗閺囩喆浜滈柟鐑樺灥閳ь剛鏁诲畷鎴﹀箻閺傘儲鐏侀梺鍓茬厛閸犳鎮橀崼婵愭富闁靛牆楠搁獮姗€鏌涜箛鏃撹€块柣娑卞櫍瀹曟﹢顢欑喊杈ㄧ秱闂備線娼ч悧鍡涘箠閹板叓鍥樄闁哄矉缍€缁犳盯骞橀崜渚囧敼闂備胶绮〃鍡涖€冮崼銉ョ劦妞ゆ帊鑳堕悡顖滅磼椤旂晫鎳冩い顐㈢箻閹煎湱鎲撮崟顐ゅ酱闂備礁鎼悮顐﹀磿閸楃儐鍤曢柡澶婄氨閺€浠嬫煟閹邦厽绶查悘蹇撳暣閺屾盯寮撮妸銉ョ閻熸粍澹嗛崑鎾舵崲濠靛鍋ㄩ梻鍫熷垁閵忕妴鍦兜妞嬪海袦闂佽桨鐒﹂崝鏍ь嚗閸曨倠鐔虹磼濡崵褰熼梻鍌氬€风粈渚€骞夐敓鐘茬闁糕剝绋戝浠嬫煕閹板吀绨荤紒銊e劦濮婂宕掑顑藉亾瀹勬噴褰掑炊椤掑鏅梺鍝勭▉閸樺ジ宕归崒鐐茬婵烇綆鍓欐俊鑲╃磼閳ь剟宕橀鐣屽弳濠电娀娼уΛ娆撍夊⿰鍫熺厽闁挎洖鍊烽幉鐐叏婵犲偆鐓肩€规洘甯掗埢搴ㄥ箳閹存繂鑵愬┑锛勫亼閸婃垿宕硅ぐ鎺撴櫇闁靛牆顦悡婵堚偓骞垮劚椤︻垶宕¢幎鑺ョ厪闊洦娲栧暩濡炪倖鏌ㄩˇ闈涱潖濞差亜绠归柣鎰絻婵爼姊洪崨濠冨鞍闁荤啿鏅犻獮鍐潨閳ь剟鐛惔銊﹀殟闁靛/鍐ㄧ闂傚倷绀侀幉锟犲礉閹达箑绀夐幖娣灪濞呯娀鏌¢崶鈺佇ョ痪鎯с偢閺屽秷顧侀柛鎾跺枎閻e嘲顫滈埀顒勫春閻愭潙绶為柛婵勫劤濞夊潡姊婚崒姘g湅闁稿瀚叅闁靛牆鎮胯ぐ鎺撳€婚柛鎾崇仢濞差參寮崘顔肩劦妞ゆ帒瀚粻鎺撶節閻㈤潧孝闁挎洏鍊濋幃褑绠涘☉娆忎患濠电偛妯婃禍婵嬫偂濞戙垺鍊堕柣鎰邦杺閸ゆ瑥鈹戦垾鐐藉仮闁哄苯绉堕幉鎾礋椤愩倓绱濋柣搴ゎ潐濞叉牕鐣烽鍕厺閹兼番鍊楅悿鈧梺瑙勫劤椤曨厼危濡ゅ啰纾介柛灞捐壘閳ь剚鎮傚畷鎰版倻閼恒儮鎸冮悗骞垮劚椤︻垳绮堟径鎰閺夊牆澧介崚浼存煕閵婏妇绠栭柕鍥у瀵粙顢曢~顓犳崟濠碘剝顨呴幊妯侯潖濞差亜宸濆┑鐘插暙椤︹晠姊洪幖鐐插濠㈢懓妫涢崚鎺撶節濮橆剛顔呴梺鍏间航閸庨亶鍩€椤掑倹鏆柡灞诲妼閳规垿宕卞▎蹇撴瘓缂傚倷闄嶉崝蹇撐涢崟顖涚畳闂備胶绮灙鐎规洜鏁婚幃楣冩倻濡寮挎繝鐢靛Т閸燁垶濡靛┑鍥︾箚妞ゆ劑鍨归弳娆撴煃閽樺妲搁柍璇查叄楠炲洭顢橀悙鈺佷壕闁绘垼濮ら埛鎴︽偣閸ャ劌绲绘い鎺嬪灲閺岋綁顢樿濞呭秶鈧娲╃换婵嬬嵁鎼淬劍鍤嶉柕澶堝劙缁勪繆閻愵亜鈧牕煤瀹ュ纾婚柟鎯х亪閸嬫挾鎲撮崟顒傤槬闂佺粯鐗曢妶鎼佸Υ娴h倽鏃€鎷呴崫銉х嵁闂佽鍑界紞鍡涘磻閸涘瓨鍋熸い鎰ㄦ噰閺€浠嬫煟濡澧柛鐔风箻閺屾盯鏁愭惔锛勪化閻庡灚婢橀敃顏勭暦濠婂棭妲烽梺绋款儐閹稿墽鍒掗鐐╂婵☆垳绮幃娆戠磽娴e搫校闁绘搫绻濆璇测槈閵忕姈銊︺亜閺冨倸甯舵い顐熸櫊濮婃椽鎸婃径濠冩闂佸摜濮甸悧鐘差嚕婵犳碍鏅插璺猴攻椤ユ繈姊洪崷顓€鍦偓娑掓櫊瀹曚即骞囬悧鍫氭嫼闂佺厧顫曢崐鏇㈠几鎼达絿纾界€广儱鎷戦煬顒傗偓娈垮枦椤曆囧煡婢舵劕鐓戦柍瑙勫劤娴滈箖鏌ㄩ弴鐐测偓鍝ョ不閿濆棛绡€闂傚牊绋掑婵喢瑰⿰搴濈凹濞e洤锕幃娆擃敂閸曘劌浜鹃柕鍫濐槸缁€鍫熺箾閸℃ɑ灏伴柛瀣儔閺屾盯鍩勯崘顏佹灁闂侀€炲苯澧俊顐㈠暙閻e嘲顫滈埀顒勩€佸▎鎾冲簥濠㈣鍨板ú銈囩不閸︻厾纾兼い鏃傚帶鐢劑鏌涚€n偅宕岄柟宕囧█椤㈡鍩€椤掑嫬鍚规い鎺戝€荤壕浠嬫煕鐏炴崘澹橀柍褜鍓熼ˉ鎾斥枎閵忋倖鏅搁柣妯垮皺閻涖儱鈹戞幊閸婃洟骞婃惔锝囦笉濞寸厧鐡ㄩ悡娆撴⒒閸屾凹鍤熼柛鏂跨Ч閺屾稓鈧急鍕彋闂佸搫鐭夌紞渚€鐛€n喗鏅查柛鈾€鏅滈ˉ澶岀磽娴i缚妾搁柛妯绘倐瀹曟垿骞樼紒妯锋嫽婵炶揪缍€濞咃絿鏁☉銏$厱闁哄啠鍋撴繛鍙夌矌閸掓帡寮崼鐕佹濠电偟顥愬▍鏇㈡儎椤栨氨鏆︽慨妞诲亾妞ゃ垺鐟╁畷妤呭礂婢惰宀稿缁樼瑹閳ь剟鍩€椤掑倸浠滈柤娲诲灡閺呭爼顢涢悙瀵稿帾闂佹悶鍎滈崘鍙ョ磾婵°倗濮烽崑鐐垫暜閿熺姷宓侀悗锝庝簴閺€浠嬫煙闁缚绨界痪鎯ь煼濮婅櫣鎷犻崣澶婃敪濡炪値鍋勯ˇ鐢哥嵁閹邦収妲归幖杈剧悼閻掑吋绻涢幘鏉戠劰闁稿鎹囬弻娑㈠煛閸愩劋妲愬Δ鐘靛仜椤戝寮崒鐐村癄濠㈣泛顦伴惈蹇涙⒒閸屾瑧顦︽繝鈧潏鈺佸灊妞ゆ牗绮嶉弳婊堟煃閸濆嫬鈧悂顢氶柆宥嗙厓鐟滄粓宕滃☉姘潟闁规儳鐡ㄦ刊鎾煟閻斿憡绶插┑顔哄灲閹嘲饪伴崟顐闂佺ǹ顑囬崰鏍х暦濮樿泛绠抽柟瀛樻⒐閻庡姊虹憴鍕姢闁汇倕娲獮妤呭即閻愨晜鏂€闂佺粯鍔栧ḿ娆撴倶閿曞倹鐓熸い鎾楀啯鐏堥梺瀹狀唺缁瑩銆侀弮鍫濋唶闁绘柨鎼獮宥夋⒑閼姐倕鏋戦柣鐔村劤閳ь剚鍑归崜姘跺箞閵娾晛鐐婇柕濠忕导缁ㄥ姊洪棃娑辨濠碘€虫川缁鎮欑€涙ê寮挎繝鐢靛Т閸燁垶濡靛┑瀣厸閻忕偠濮ら崵鍥煙椤旂晫鎳囬柟宕囧Х閹瑰嫭绗熼娆戠>濠电姷鏁告慨顓㈠箯閸愵喖纾兼慨姗嗗墰閵堫噣姊绘担鍛婃儓闁活剙銈稿畷浼村冀椤撶偟顔愰悷婊呭鐢晠寮崘顔界叆婵犻潧妫欓崳浠嬫煥濞戞瑦宕屾慨濠勭帛閹峰懘鎮烽柇锕€娈濈紓鍌欐祰椤曆呪偓姘緲閻g兘骞嬪┑鍐╊潔闂侀潧绻掓慨鐑藉储閹绢喗鈷戦柣鐔煎亰閸ょ喎鈹戦鍛籍鐎规洘鍨块獮妯肩磼濡粯鐝抽梺鍦帶閻°劑鏁嬫繛瀛樼矌閸嬫捇濡甸崟顖氱閻庣數纭舵慨鍥р攽閻愬弶鍣归柨鏇ㄤ邯瀵鏁嶉崟顏呭媰闂佷紮绲介惈妤呮晲閸℃瑧顔曠紒鐐緲瑜板鏌囬娑辨闁绘劘灏欑粻鍐裁归悪鍛暤闁圭ǹ锕ュ鍕節閸涱厼缂氶梻鍌氬€搁崐鎼佸磹閻戣姤鍊块柨鏇炲€归崕鎴犳喐閻楀牆绗掔痪鎯х秺閺岋繝宕堕妷銉т患缂備胶濮锋繛鈧柡宀€鍠栭弻鍥晝閳ь剟寮搁悢鎼炰簻妞ゆ劧绲剧粈瀣煛瀹€鈧崰鏍嵁閸℃凹妲鹃梺鍦櫕婵挳鍩為幋锔绘晬婵炴垶鐟ラ崬澶愭⒑閸濆嫭婀伴柣鈺婂灦閻涱喖顫滈埀顒€顕i崼鏇炵闁绘ḿ鍋i崑锟犳⒒閸屾瑧顦﹂柟璇х節楠炴劗绮欑捄銊︽濡炪倖甯掔€氀囧焵椤掍焦顥堢€规洘锕㈤、娆撳床婢诡垰娲﹂悡鏇㈡煃閳轰礁鏋ゆ繛鍫熋湁闁绘ǹ娅曢崐鎰叏婵犲啯銇濋柟绛圭節婵″爼宕ㄩ鐣屾И闂傚倷绀侀幖顐﹀箠韫囨稒鍎庢い鏍仜缁犳牕螖閿濆懎鏆為柛濠傤煼閺岋箑螣閻氬绀嗛梺闈浤涢崟顐g€惧┑鐘灱閸╂牠宕濋弴鐘差棜濠电姵纰嶉悡娆撴煕閹炬鎳庣粭锟犳⒑閸濆嫭鍣洪柣鎿勭節閻涱噣寮介銏犵亰闂佽崵鍠愬姗€鍩涙径鎰拺閻犲洩灏欑粻鎵磼婢跺本鍤€妞ゎ偄绻橀幖褰掑捶椤撶媴绱叉繝纰樻閸ㄧ敻顢氳濡嫬顓奸崨顏呮杸闂佺粯鍔栬ぐ鍐棯瑜旈弻銊╁即濡櫣浠炬繛锝呮搐閿曨亪骞冮悾宀€鐭欓悹渚厛濡茶淇婇悙顏勨偓鏍偋濡も偓椤繈濡搁埡鍌氫痪闂侀€炲苯澧存慨濠傤煼瀹曟帒顫濋钘変壕闁归棿鐒﹂崑瀣攽閻樻彃顏柣顓熺懇閺岀喖鏌囬敃鈧弸锕€鈹戦钘夆枙闁哄被鍊曢湁閻庯綆鍋呴悵鏍磼閻愵剙绀冩俊顐㈠濠€渚€姊洪幐搴g畵闁绘锕棢濠㈣埖鍔栭悡鐔兼煙閻愵剚缍戝┑顔肩墦閺岀喐绗熼崹顔碱瀳闁句紮绲跨槐鎺斺偓锝庝簽娴犮垺銇勯鈧鍛村煘閹达箑鐏抽柛鎰皺妤犲洭姊洪崨濠冣拹闁荤啿鏅犻幃浼搭敊閸㈠鍠栧畷妤呮偂鎼达絽閰遍梻鍌欐祰閸嬫劙鍩涢崼銉ョ闁挎洍鍋撻崡鍗灻归悡搴f憼闁抽攱甯掗湁闁挎繂姣ヨぐ鎺戞辈闂侇剙绉甸悡娆戠棯閺夊灝鑸瑰ù婊勫閳ь剝顫夊ú姗€宕濋弽顐e床婵犻潧鏌婇幒鏃傜煓闁圭ǹ楠搁弸鐘绘倵濞堝灝鏋﹂柛鈺傜墵楠炲棝寮崼婵堫啋闁诲孩绋掕摫婵犮垺鍨甸埞鎴︽晬閸曨偂鏉梺绋匡攻閻楁洟锝炶箛鏃傜瘈婵﹩鍎甸妷鈺傚€甸柨婵嗙凹閹查箖鏌涢悢閿嬪殗闁哄本娲樺鍕槈濠婂拋妲瑰┑鐐茬摠缁秶鍒掑澶娢﹂柛鏇ㄥ灠缁犲鎮规ウ鎸庛€冪紒顔挎硾閳规垿鍩勯崘銊хシ濡炪値鍘鹃崗妯侯嚕婵犳碍鏅插璺侯儐濞呮粓姊洪幖鐐插妧闁告劑鍔庨鍝勨攽鎺抽崐妤佹叏閻戣棄纾婚柣鎰仛閺嗘粓鏌ㄩ悢鍝勑ョ€规挷绶氶幃妤呮晲鎼粹剝鐏堢紓渚囧亜缁夊綊寮诲鍫闂佸憡鎸鹃崰鏍嵁閸愩剮鏃€鎷呴搹鍦婵犳鍠楅敃鈺呭储閹间礁绠繛宸簼閻撶喖鏌i弬鎸庢喐闁瑰啿鍟撮幃妤€顫濋悡搴$睄閻庤娲樺ú鏍亙闂佸憡渚楅崰姘跺储閸楃偐鏀介柍钘夋閻忋儵鏌曢崱蹇撲壕闂備胶枪椤戝棝骞戦崶顒€绠栭柕蹇嬪€曠粻鐢告煙閻戞ê鐏╅梻鍐e亾婵犵數濮烽弫鍛婃叏閻戣棄鏋侀柛娑橈攻閸欏繘鏌i幋锝嗩棄闁哄绶氶弻娑樷槈濮楀牊鏁鹃梺鍛婄懃缁绘﹢寮婚敐澶婄闁挎繂妫Λ鍕⒑閸濆嫷鍎庣紒鑸靛哺瀵鈽夊Ο閿嬵潔濠殿喗顨呴悧濠囧极妤e啯鈷戦柛娑橈功閹冲啰绱掔紒妯虹伌濠碉紕鏁诲畷鐔碱敍濮橀硸鍟嬮梻浣告啞椤ㄥ牓宕戦悢鍝ヮ浄闁兼祴鏅濈壕濂告煟閹伴潧澧柛鏂诲€栭妵鍕敇閻樻彃骞嬮悗娈垮枛椤兘骞冮姀銈嗗亗閹艰揪缍嗗Σ鍫曟煟閻斿摜鐭婄紒缁樺浮瀵偊顢欑亸鏍潔闂侀潧楠忕槐鏇㈠储閹剧粯鈷掑ù锝呮憸娴犮垺銇勯幋婵囧殗闁诡喗锕㈤弫鍐磼濞戞艾甯鹃梻浣规偠閸庢粓宕橀崣銉х>濠德板€楁慨鐑藉磻閻愬灚鏆滈柍銉ョ-閺嗭箓鏌涘Δ鍐ㄥ壉婵炴挸顭烽弻鐔碱敍閸℃婀版い銉磿缁辨捇宕掑顑藉亾閹间礁纾归柟闂寸绾剧懓顪冪€n亝鎹i柣顓炴閵嗘帒顫濋敐鍛闂佽姤蓱缁诲牆顫忓ú顏嶆晢闁逞屽墰缁棃骞橀鐓庡殤婵炶揪绲跨涵鍫曞绩娴犲鐓熸俊顖涘閻濐亪鏌i妸锕€鐏╅柍褜鍓濋~澶愬箰妞嬪孩顐芥慨妯挎硾閽冪喐绻涢幋娆忕仼闁绘帗妞介弻娑㈠箛閸忓摜鎸夋繝娈垮枛濞差厼顫忛搹鍦煓闁告牑鈧啿顫犻梻浣呵圭换鎴︽晝閵忕媭鍤曢悹鍥ㄧゴ濡插牊淇婇鐐存暠闁哄倵鍋撻梻鍌欒兌绾爼宕滃┑瀣ㄢ偓鍐疀閺傛鍤ら梺閫炲苯澧ǎ鍥э躬閹瑩顢旈崟銊ヤ壕闁哄诞灞剧稁閻熸粎澧楃敮鎺旂矆婢舵劖鐓涢柛銉e劚閻忊晠鏌i幘杈捐€块柡宀€鍠愬ḿ蹇斻偅閸愨晩鈧秹姊虹粙鍖″伐妞ゎ厾鍏樺璇测槈閵忕姈銊╂煏韫囧﹤澧查柣婵囩墵閺屸€愁吋韫囨洜鐦堝┑顔硷功缁垶骞忛崨鏉戝窛濠电姴鍊瑰▓姗€姊绘担鍛婅础閺嬵亝銇勯鐘插幋妤犵偛鍟撮幃婊堟嚍閵夛附鐝曢梻浣风串缁茶姤寰勯崶顒€缁╅柧蹇e亞缁♀偓闂佹眹鍨藉ḿ褍鐡繝鐢靛仩椤曟粎绮婚幘宕囨殾闁汇垻枪缁€鍐┿亜閺冨倹娅曢柛妯绘崌濮婃椽宕ㄦ繝鍕暤闁诲孩鍑归崜鐔奉嚕閹惰姤鍋勯柛蹇氬亹閸欏棗鈹戦悙鏉戠仸闁荤啙鍥ㄥ剹闁圭儤鎸婚崣蹇撯攽閻樺弶宸濈紒鍙樺嵆閺屾洟宕堕妸銉ヮ潚濡ょ姷鍋炵敮锟犵嵁鐎n亖鍫柛鎰ㄦ櫇閳ь剚濞婂濠氬磼濞嗘埈妲梺纭咁嚋缁绘繈骞冮悜钘壩ㄩ柨鏃傜帛椤旀棃姊鸿ぐ鎺擄紵缂佲偓娓氣偓閹€斥攽鐎n偆鍘甸梺缁樺姦閸撴岸鎮橀柆宥嗙厱妞ゆ劦鍋傞柇顖炴煛鐏炲墽娲存い銏℃礋婵″爼宕ㄩ鍙ョ按闂傚倷绀侀幉陇鎽梺璇″枛閸婂灝顕f繝姘櫜闁割偁鍨婚弶鎼佹⒑閸濆嫭宸濋柛瀣耿楠炲顦版惔锝囷紲缂傚倷闄嶉崹褰掔嵁閺嶎厽鐓熼柡宥庡亜鐢爼鏌i敐鍥у幋妤犵偛顑夐弫鍐焵椤掑倻涓嶅┑鐘崇閸嬶綁鏌涢妷顔荤盎闁汇劍妞介弻锝夊Χ閸屾矮澹曟繝鐢靛Х閺佹悂宕戦悩璇茬妞ゅ繐妫楃欢銈吤归悩宸剰缂佺姷鍠栭弻銊╂偄閸濆嫅銏㈢棯閹规劦娼愰柕鍥у瀵粙顢曢~顓熷媰闂備焦濞婇弨閬嶅垂瑜版帗鍎夋い蹇撶墱閺佸洭鏌i幇顓熺稇婵炲拑绲剧换娑氣偓娑欋缚閻﹦绱撳鍜冭含妤犵偛鍟伴幑鍕偘閳╁喚娼旈梻浣告惈鐠囩偤宕橀妸鎰礋濮婄粯鎷呴搹骞库偓濠囨煛閸屾瑧绐旂€规洘鍨块獮姗€骞囨担鐟扮槣闂備線娼ч悧鍡椢涘Δ鍐當闁圭儤顨嗛悡鏇㈡煟閺囨氨顦﹀ù婊€鍗抽弻鐔碱敍濮橆剚娈柣鎾卞€栭妵鍕疀閹炬潙娅ч梺鍛娒幉锛勬崲濞戞瑦缍囬柛鎾楀啫鐓傛繝鐢靛Л閸嬫捇寮堕崼娑樺婵炲懐濮甸妵鍕疀閹捐泛顤€闂佺粯鎸搁崯鎾箖瀹勬壋鏋庨煫鍥ㄦ惄娴犲ジ姊虹拠鑼闁瑰憡濞婂濠氭偄绾拌鲸鏅╅梺浼欑到閺堫剟宕虫导瀛樺€垫繛鍫濈仢閺嬫盯鏌i弽褋鍋㈤柣娑卞枤閳ь剨缍嗛崰妤呭磻閹版澘绾ч柛顐亞閸樻盯鏌℃担鍛婂枠婵﹤顭峰畷鎺戭潩椤戣棄浜惧瀣捣閻棗霉閿濆浜ら柤鏉挎健瀵爼宕煎☉妯侯瀷婵炲濮靛畝绋款潖缂佹ɑ濯村〒姘煎灡閺侇垱绻濆▓鍨灁闁稿﹥顨婂畷姘跺箳閹炬潙鍔呴梺闈浨归崕鎶剿囬锔解拺闁革富鍘奸崝瀣亜閵娿儲鍣介柣姘劤椤撳吋寰勭€n剙骞堟俊鐐€栭崝鎴﹀磹閺囥垹鍑犻幖绮瑰煑瑜版帗鍋愰柣鎴烇供娴犫晝绱撴担浠嬪摵闁圭ǹ顭烽獮蹇涘川閺夋垹顦梺鍦帛鐢帗绔熷鍡曠箚闁绘劦浜滈埀顒佺墪鐓ゆ俊顖濆吹缁犳儳鈹戦悩鍙夋悙闁哄绶氶弻娑㈠箛闂堟稒鐏堢紒鐐劤閸氬鎹㈠☉銏犵闁绘劘娉涢ˉ婵單旈悩闈涗粶闁绘鎸搁~蹇曠磼濡顎撻梺鍛婄☉閿曘儵宕曢幘鏂ユ斀闁绘劘灏欏﹢鎾煕閵娿劍顥夐柣锝呭槻閳规垿宕卞▎鎰暦闂備礁鎲″ú锕傚礈濞嗘挸鐒垫い鎺嗗亾闁绘牕銈稿濠氭晲閸涘倻鍠栭幊鏍煛娴d警鍋ч梻鍌欒兌缁垶骞愮拠瑁佹椽鎮㈤悡搴ゆ憰闂佺粯鏌ㄩ崥瀣吹鐎n偁浜滈柟鍝勬娴滅偓绻濈喊澶岀?闁告鍥ㄧ畳婵犵數濮撮敃銈団偓姘煎墴瀹曟繈濡舵径瀣帗闁荤喐鐟ョ€氼剟鎮橀幘顔界厸濞达絽鎽滄晥閻庤娲滈崰鏍€侀弴銏犵労闁告劏鏅濈粣鏃堟⒒閸屾艾鈧兘鎳楅懜鐢典粴闂備焦瀵уú蹇涘磿閻㈢ǹ绠栫憸鏃堝箖閳哄懏鍤戞い鎺嶇劍椤旀洘绻濋悽闈涒枅婵炰匠鍥舵晞闁糕剝绋戦悿鐐節闂堟侗鍎愰柣鎾冲暟閹茬ǹ饪伴崼婵堫槶闂佺粯姊婚崢褔鎮橀幎鑺ョ叆闁哄洨鍋涢埀顒佹倐閺屻劑濡堕崱鏇犵畾闂侀潧鐗嗛崐鍛婄妤e啯鈷戠紓浣姑粭鎺楁煟韫囨柨鍝哄┑锛勬暬瀹曠喖顢涘槌栧敽闁诲骸绠嶉崕閬嶆偋閸℃稑鍌ㄩ柨娑樺绾捐棄霉閿濆懏鎯堢€涙繃绻濋埛鈧崒婊呯厯闂佺硶鏂侀崑鎾愁渻閵堝棗鍧婇柛瀣崌閺屾稑螣閼姐倗鐓夐悗瑙勬礃閸ㄥ潡鐛鈧顒勫Ψ閿旇姤婢戦梻鍌欒兌缁垱鐏欐繛瀛樼矤閸撴稓鍒掗敐澶婄睄闁割偆鍠撻崢閬嶆煟鎼搭垳绉甸柛瀣笒閳绘捇寮崼鐔哄帗闁荤喐鐟ョ€氼剟鎮樼€涙ǜ浜滈柕蹇ョ磿閹冲懏绻涢幋鐘虫毈闁诡喗绮撻幃鍓т沪閽樺鍞ㄥ┑鐘垫暩婵兘寮幖浣哥;婵炴垯鍨圭粻顖炴煙鐎电ǹ孝缂佽翰鍊濋弻娑⑩€﹂幋婵囨疇闂佹寧绻傞ˇ顖滅不濞戙垺鐓涘璺哄绾埖銇勯弬鍖¤含婵﹥妞介幃鐑藉级閹稿孩鐦g紓浣稿⒔閾忓酣宕i崘銊ф殾濞村吋娼欑粻濠氭偣閸ヮ亜鐨烘い鏂挎濮婅櫣绱掑Ο鍓佺窗缂備緡鍣崹璺虹暦閻㈢ǹ绠i柨鏃傛櫕閸樺墽绱撴担鍓插創婵炲娲樼粋鎺戔槈濞嗘劕寮块梺鎸庣箓濡鎱ㄥ鍡樺弿濠电姴鍋嗛悡鑲┾偓瑙勬礃鐢帡锝炲┑瀣垫晞闁芥ê顦竟鏇㈡⒑缂佹ê鐏卞┑顔哄€濆畷鐢稿礋椤栨稓鍘鹃梺鍛婄缚閸庢煡寮抽埡浼卞綊鎮╁畷鍥舵殹缂備胶绮换鍫ュ箖娴犲顥堟繛鎴烆殘閹规洘淇婇悙顏勨偓鏍洪敃鍌氱煑闁告劑鍔庨弳锔戒繆閵堝倸浜鹃柧浼欑到閵嗘帒顫濋悡搴d哗濠电偛鐗勯崝宀勨€旈崘顔嘉ч柛鈩冾殔椤洭姊虹粙鍖℃敾闁绘绮撻崺鈧い鎺嶈兌椤e弶鎱ㄥΟ绋垮闁糕斁鍋撳銈嗗笒閸婂綊宕甸埀顒佺節閵忋垺鍤€闁挎洦浜滈悾閿嬪閺夋垵鍞ㄩ悷婊冾樀瀵悂寮崼鐔哄帾婵犵數濮寸换鎰般€呴鍌滅<闁抽敮鍋撻柛瀣崌濮婄粯鎷呴崷顓熻弴闂佹悶鍔忓Λ鍕幓閼愁垼妲奸梺缁橆殔濞撮妲愰幘瀛樺闁告繂瀚竟鏇炩攽閻橆喖鐏畝锝堟硶閸掓帡寮崼鐔蜂画闂備緡鍙忕粻鎴濃枔閵娾晜鈷戦柛婵嗗椤箓鏌涙惔銈勫惈缂侇喖顭烽幃浠嬪川婵犲嫬骞嶉梻浣虹帛閸ㄨ泛鐜荤捄銊т笉婵せ鍋撻柡灞剧洴閹瑩宕归锝嗙槗闂備礁鎼惌澶岀礊娓氣偓楠炲啴鍩¢崨顔尖偓缁樻叏濡も偓濡棃宕Δ鍛拺閻犲洩灏欑粻鎵磼鐠囪尙澧︾€规洘绻傞悾婵嬪礋閸偅娅撻梻濠庡亜濞诧妇绮欓幋婵囨殰闂佽崵鍠愮划宀勊囬棃娑氭殾闁硅揪绠戠粻濠氭煠閹间焦娑ч柡瀣€垮娲川婵犲啫顦╅梺鍛婃尰閻熝囧窗婵犲偆鍚嬮柛娑变簼閺傗偓闂備礁鐤囧Λ鍕涘Δ浣侯洸婵犻潧鐗忕壕濂告偣閸ャ劌绲婚柍褜鍓欏ḿ锟犲极閹扮増鍊烽柛鎾茶兌閺夌ǹ鈹戦悙鏉戠仸闁荤噦绠撳畷鏇㈩敂閸啿鎷洪梻鍌氱墐閺呮盯鎯佸⿰鍫熺厱婵せ鍋撶紒鐘崇墵瀵偄顓奸崨顏勭墯闂佸憡鍔х徊楣冨棘閳ь剟姊绘担鍝ユ瀮婵☆偄瀚灋婵°倕鎳忛崐鍫曟煟濡偐甯涢柣鎾寸懅閻ヮ亪寮堕崹顔垮煘婵炲瓨绮堥崡鎶藉蓟閵娿儮鏀介柛顐g箑缁泛顪冮妶鍡樺碍闁靛牏枪閻g兘宕奸弴鐐靛幐闂佸憡鍔樺▔鏇㈡⒒椤栨稓绡€闁汇垽娼ф禒鈺呮煙濞茶绨界紒杈╁仦缁楃喖鍩€椤掑啯锛傞梻浣筋潐瀹曟﹢顢氳缁牊寰勭仦绋夸壕妤犵偛鐏濋崝姘亜閿斿灝宓嗛柟顔光偓鏂ユ瀻闁瑰濮烽敍婊堟煟鎼搭垳绉靛ù婊呭仦缁傛帡濮€閵堝棛鍘搁梺绯曞墲缁嬫劙骞夋ィ鍐╃厸鐎光偓鐎n剛袦闂佽桨鐒﹂崝娆忕暦閹偊妲诲Δ鐘靛仜椤戝懓鐏冮梺缁橈耿濞佳勭濠婂嫨浜滈柟瀛樼箥濡偓閻庢鍣崑濠傜暦濮椻偓椤㈡瑩鎳栭埡浣感曞┑锛勫亼閸婃牜鏁幒妤€纾圭紓浣贯缚閳绘梻鈧箍鍎遍幊澶愬绩娴犲鐓熸俊顖濇閿涘秵銇勯敐鍡欏弨闁哄本绋撻埀顒婄到婢у海绮旈鈧弻锛勪沪閸撗勫垱婵犵绱曢崗姗€鐛€n亖鏀介柛鈩兩戦宥呪攽鎺抽崐妤佹叏閺夋嚚娲敇閵忕姷鐣哄┑掳鍊曢崯顖炲窗閸℃稒鐓曢柡鍥ュ妼婢ь喚鐥弶璺ㄐょ紒杈ㄦ尰閹峰懘宕滈崣澹囨⒑閻熺増鍟炲┑鐐诧躬瀹曡銈i崘銊х潉闂佸壊鍋呯换鍕囬妸銉富闁靛牆妫欓悡銉︿繆閹绘帞澧fい锕€缍婇弻锛勪沪閸撗勫垱闂佺硶鏅涚€氭澘鐣峰Δ鍛亼闁逞屽墯缁傚秹顢旈崟搴㈢洴瀹曠喖顢曢銏″€梻浣规偠閸庮噣寮插┑瀣櫖婵犻潧娲ㄧ粻楣冨级閸繂鈷旈柛鎺撴緲椤潡鎮风敮顔垮惈閻庤娲樺ú鐔肩嵁閸ヮ剚鍋嬮柛顐犲灩楠炲牓姊绘笟鈧ḿ褎鐏欓梺绋块叄娴滃爼濡撮崒姘辨殾闁搞儮鏅濋敍婊冾渻閵堝棙鈷掗柍宄扮墦瀹曟洝绠涢弬璁崇盎闂佽鍎抽崯鍧楀箖閹寸姭鍋撻崹顐g凡閻庢凹鍣i崺鈧い鎺戯功缁夐潧霉濠婂嫮澧电€规洘鍨块獮妯肩磼濡厧寮抽梺璇插嚱缁插宕濈€n剝濮冲┑鐘崇閳锋垿鏌i悢鍝勵暭闁诡垰鐗忕槐鎺撳緞婵犲嫬鐓熼柦妯荤箞閺屻劑寮崼鐔告闂佺ǹ顑嗛幐鎼佸煝閹捐鍨傛い鏃傛櫕娴滎亪姊绘担绛嬪殭缂佺粯鍨归幑銏ゅ醇閵夈儲妲梺缁樺姇閹碱偆绮婚敐澶嬬叆闁哄洦顨呮禍楣冩⒑缂佹ɑ鎯堢紒缁樼箞瀵鈽夐姀鐘靛姶闂佸憡鍔楅崑鎾绘偩閸忚偐绠鹃悗鐢登归宀勬煕閵娿劍纭炬い顐㈢箰鐓ゆい蹇撳缁愭稒绻濋悽闈浶㈡繛瀵稿厴瀹曟繈宕奸弴鐔叉嫼闂佸憡绋戦敃銉﹀緞閸曨垱鐓曟繛鍡楃箻椤庢鎮¢妶澶嬬厱婵炴垶锕妤冪磼鐠囧弶顥㈤柡灞炬礋瀹曠厧鈹戦崼銏╁敽闂備礁鎲$敮濠囧础閹惰棄钃熸繛鎴欏灪閸嬪棗霉閿濆懏鎲稿ù鐘虫倐閹鎲撮崟顒傤槰闂佸憡姊归悷銉╂偩閻ゎ垬浜归柟鐑樼箖閺呮繈姊洪幐搴g畵闁瑰啿瀛╃€靛吋鎯旈姀銏㈢槇缂佸墽澧楄摫妞ゎ偄锕弻娑㈠Ω閿曗偓閳绘洜鈧娲忛崹濂杆囧畷鍥╃<闁稿本姘ㄦ牎闂侀潧鐗炵紞浣哥暦濮椻偓閸┾剝鎷呴幓鎺嶅闂佸壊鐓堥崑鍛村矗韫囨柧绻嗘い鏍ㄧ矊鐢泛霉濠婂牏鐣洪柟顔筋殔椤繈鎮欓鈧锟�

摘要:通过开发一个显示和实时控制 MFC 直方图的应用程序,来学习 eMbedded Visual C++ 环境的开发过程和功能,同时还将学习 Visual C++ 本机代码和 .NET Framework 精简版的各种强大功能。
下载本文讨论的示例应用程序的源代码。
概述对于 Microsoft(r) Windows(r) CE .NET Embedded 的开发人员来说,有多种开发方法可以选择。本机 Microsoft eMbedded Visual C++(r) 和新的 .NET Framework 精简版提供了两种截然不同的应用程序开发方法。以 eMbedded Visual C++ 4.0 来开发本机代码,仍然是最适合用来开发高速代码的开发环境,而且它开发的代码能够充分利用 Windows CE .NET 平台的实时功能。本次学习通过开发一个显示和实时控制 MFC 直方图的应用程序,来探索 eMbedded Visual C++ 环境的开发过程和功能,还将比较 Visual C++ 本机代码与 .NET Framework 精简版。控制应用程序开发将利用 Microsoft Win32 线程和同步对象、中断接口、共享内存接口技术以及实时优先级策略;MFC 应用程序设计的主题包括显示开发、实时数据接口技术和直方图库集成。两种应用程序的开发都是从头开始的,只利用了很少几个源代码格式的可用库。
本机与 .NET Framework 精简版开发选择本机开发还是选择 .NET Framework 精简版开发是一个非常复杂的问题,需要综合分析应用程序工具、平台要求和开发专家的意见,才能明确选择标准。下一节为这种选择提供了高级指南,引导您进入开发过程。
应用程序开发工具选择对于 Microsoft Windows CE .NET Embedded 开发人员来说,有许多应用程序开发工具可供选择,而在 Windows CE .NET 中集成 .NET Framework 精简版进一步扩大了选择范围。
Platform Builder(平台生成器)是开发操作系统、驱动程序和服务的首选工具。它充当嵌入式平台开发程序时,能够紧密集成操作系统配置、驱动程序开发、内核级调试以及其他许多此处未列举的功能。但 Platform Builder(平台生成器)不适合用来开发大型应用程序。
本机应用程序是直接为特定处理器编译的应用程序。从 Microsoft Visual C++ 的 Build(生成)菜单中选择 Build MyApp.exe(生成 MyApp.exe)时,编译器将创建一个本机应用程序。在引入 Framework 精简版之前,Microsoft eMbedded Visual C++ 和 Microsoft Visual Basic(r) 一直是所有 Windows CE 应用程序开发的基础。在 Visual C++ 中,有两个主要选项可用于应用程序开发。Windows CE .NET 是围绕 Microsoft Win32(r) API 构建的,而 Win32 API 可以在本机应用程序中通过编程方式直接使用。由于存在重复的应用程序开发过程,所以出现了一系列封装了大多数常见任务的类库,这些类库称为 Microsoft 基础类 (MFC) 库。eMbedded Visual C++ 允许嵌入式开发人员利用 MFC 库,为可视应用程序提供图形化开发环境。
随着 Framework 精简版的引入,现在可以在 Visual Studio .NET 环境中开发应用程序,使之同时适用于桌面和 Windows CE .NET 公共语言运行库 (CLR)。从而允许对 Windows CE .NET 进行 Visual Basic .NET 和 C# .NET 开发。
开发 API 选择Window CE .NET 开发人员可以选择本机 Win32、本机 MFC 或 Framework 精简版应用程序开发。下表概要介绍了这些选择:
空间 - 介绍预期的平台要求
优势与劣势 - 列举基本的选择
表 1:空间
空间要求 | Windows CE .NET | Windows XP |
Win32 | - | - |
MFC | 280 KB | 1.25 MB |
.NET Framework | 1.5 MB | 34 MB |
表 2:优势与劣势
API | 优势 | 劣势 |
Microsoft Win32 (C / C++) | 最小和最快的 .exe 文件和 DLL 不需要其他运行时,Windows CE .NET 就是运行时。 最低的内存开销 对于设备驱动程序、控制面板小程序和 shell 扩展是必需的 | 应用程序/驱动程序开发人员负责清理对象,使得此 API 很容易出现内存泄露。 低级 API - 可能难以掌握。 面向过程而不是面向对象的 API。 |
MFC (C++) | 面向对象。继承、封装、多态(也称为功能重载)。 良好的工具支持和向导 容器类支持数组、列表、对象映射,并能简化数据处理。 类型安全。 Embedded Visual 工具附带完整的 MFC 源代码。 | 对象清理是半自动的,因此与 Win32 相比不易于出现内存泄露,但由于 MFC 是对 Win32 的简单包装,所以仍然易受攻击。 运行时大小 ~ 500 KB(MFC 和 OLECE) |
.NET Framework (C# 和 Microsoft Visual Basic .NET) | 精心设计的编程界面。 优秀的工具支持 - Forms Designer(窗体设计器)。 面向对象。继承、封装、多态(也称为功能重载)。 容器类支持数组、列表、散列表、字典和堆栈。 类型安全。 命名空间。 自动进行内存回收,可以消除内存泄露。 便携式计算机指令集 MSIL / CIL,提供二进制可移植的可执行(.exe 和 .dll)文件。 可以便捷地编写 Web 服务客户端。 很好地支持处理 XML | 运行时大小 ~ 1.5 MB。 在托管代码和非托管代码之间的调用开销很高。COM 互操作性不够灵活。要求编写需要调用 COM 接口函数的 Win32 包装程序。 源代码不可用。 要求基于显示器的平台。 |
要在资源有限的平台上开发高速控制应用程序,显然应该选择本机 Win32 进行控制器的开发,选择本机 MFC 进行可视化开发。在许多情况下,开发环境的选择可能很简单,但在另外一些情况下,可能会很复杂。
中断体系结构以下插图是 Windows CE .NET 的中断体系结构的应用程序视图,说明了中断期间的硬件、内核、OAL 和线程的交互操作。

图 1:Windows CE .NET 中断
图中以向右的方向表示时间的推移。最底层是硬件的状态;上一层是 Windows CE OEM 适配层 (OAL),描述板卡支持程序包 (BSP) 的任务;最顶层代表服务和中断所需的应用程序或驱动程序线程交互操作。
活动从图表左侧部分以直线表示的中断开始。首先生成异常,导致内核中断服务例程 (ISR) 矢量被加载到处理器中。内核 ISR 与硬件交互,禁用所有处理器上的所有优先级相等和较低的中断(ARM 和 Strong ARM 体系结构除外)。然后,内核推进到已为该中断注册的 OAL ISR。接着 OAL ISR 检查该硬件以确定其是否导致了中断。这一操作通常是通过检查中断状态寄存器完成的。如果是该硬件导致了中断,ISR 将返回该硬件的 SYSID。
一旦 ISR 完成检查,内核将重新启用处理器上除已标识的中断之外的所有中断。然后,内核通知与 SYSID 值关联的事件。
如果驱动程序或应用程序的中断服务线程 (IST) 是要运行的线程中优先级最高的,则接下来就会运行该线程。IST 将与相关设备通信,并从设备中读取所有必要的数据,完成其中断交互操作。然后,IST 用关联的 SYSID 值来调用 InterruptDone( ),通知其已完成运行。
内核接收到 SYSID 值的 InterruptDone 时,将重新启用指定的中断。这时可以开始接收该设备的另一个中断。
这是对 Windows CE .NET 内部活动的中断序列的一个快速浏览。插图代表了一次中断期间的交互操作,但没有显示 Windows CE .NET 的共享中断功能。有关这项功能的详细信息,请参阅 Interrupt Architecture in Windows CE .NET(英文)。
应用程序中断处理处理应用程序或驱动程序的中断需要两个步骤。首先,中断必须使用关联的事件进行初始化。其次,IST 必须等待响应内核中断的中断事件。
中断初始化以下示例代码将设置 IST 并将 IST 与特定的中断相关联。初始化中断的关键步骤包括:
创建事件
获取 IRO 的系统中断号
创建挂起的中断服务线程 (IST)
调用 InterruptInitialize 以创建 IRQ 与事件的关联
创建未挂起的 IST 可能会导致 InterruptInitialize 失败,因为该事件已经处于等待状态。将线程优先级设置为相应的优先级
恢复 IST
Void SetupInterrupt( void )
{
// 创建事件
//
g_hevInterrupt = CreateEvent(NULL, FALSE, FALSE, NULL);
if (g_hevInterrupt == NULL)
{
RETAILMSG(1, (TEXT("DEMO: Event creation failed!!!
")));
return;
}
// 使 OAL 将 IRQ 转换成系统 IRQ
//
fRetVal = KernelIoControl( IOCTL_HAL_TRANSLATE_IRQ,
&dwIrq,
sizeof( dwIrq ),
&g_dwSysInt,
sizeof( g_dwSysInt ),
NULL );
// 创建等待信号的线程
//
g_fRun = TRUE;
g_htIST = CreateThread(NULL, // 安全性
0, // 没有堆大小
ThreadIST, // 中断线程
NULL, // 没有参数
CREATE_SUSPENDED, // 创建挂起的线程
&dwThreadID // 线程 ID
);
// 设置线程的优先级 - 随意选择了 5
//
m_nISTPriority = 5;
if( !CeSetThreadPriority( g_htIST, m_nISTPriority ))
{
RETAILMSG(1,(TEXT("DEMO: Failed setting Thread Priority.
")));
return;
}
// 初始化中断
//
if ( !InterruptInitialize(g_dwSysInt,g_hevInterrupt,NULL,0) )
{
RETAILMSG (1, (TEXT("DEMO: InterruptInitialize failed!!!
")));
return;
}
// 使线程启动
//
ResumeThread( g_htIST );
}
需要特别注意的是,调用 InterruptInitialize 仅获取 SYSINTR 值和事件。内核不知道或者说也不关心将要等待事件的线程。这样一来,就可以建立多种应用程序和驱动程序体系结构。应用程序的简单主循环可以初始化中断,然后立即等待事件。一个中断只能与一个事件关联,并且调用 WaitForMultipleObjects 的过程中不能使用该事件。我们将会看到一个简单的线程为中断服务。这是大多数实现方案中的标准解决方法。
应用程序中断服务例程:以下是中断服务线程 (IST) 的示例代码。此 IST 中断处理线程的关键组件包括:
等待中断事件
确认有一个来自操作系统的事件
在尽可能短的时间内处理中断
调用 InterruptDone()
在调用 InterruptDone 之前,操作系统不会提供有关此 IRQ 的另一个中断。再次等待中断事件
DWORD WINAPI ThreadIST( LPVOID lpvParam )
{
DWORD dwStatus;
// 始终检查运行标志
//
while( g_fRun )
{
dwStatus = WaitForSingleObject(g_hevInterrupt, INFINITE);
// 确保拥有对象
//
if( dwStatus == WAIT_OBJECT_0 )
{
// 在此处理中断
//
g_dwInterruptCount ++;
// 完成中断
//
InterruptDone( g_dwSysInt );
}
}
return 0;
}
优先级初始化代码中的关键 Win32 API 调用是对 CeSetThreadPriority 的调用。此函数接受两个参数。第一个参数是线程句柄,第二个值介于 0-255 之间,用于描述所需的优先级。选择使用哪个线程优先级非常关键,而能够以图表表现应用程序优先级的使用,也有助于确保适当的性能。优先级从 0 至 247 的线程(0 表示最高优先级)是实时线程优先级,需要调用 CeSetThreadPriority 来访问。一般线程优先级介于 248-255 之间,要使用 SetThreadPriority 进行访问。下表提供了 Windows CE .NET 标准优先级实现的快速指南。
表 3:实时线程优先级:CeSetThreadPriority
优先级 | 组件 |
0-19 | 开放 - 高于驱动程序的实时 |
20 | Permedia 垂直折返 |
21-98 | 开放 - 高于驱动程序的实时 |
99 | 电源管理恢复线程 |
100-108 | USB OHCI UHCI、串行 |
109-129 | Irsir1、NDIS、触摸板 |
130 | KITL |
131 | VMini |
132 | CxPort |
133-144 | 开放 - 设备驱动程序 |
145 | PS2 键盘 |
146-147 | 开放 - 设备驱动程序 |
148 | IRComm |
149 | 开放 - 设备驱动程序 |
150 | TAPI |
151-152 | 开放 - 设备驱动程序 |
153-247 | 开放 - 低于驱动程序的实时 |
表 4:一般线程优先级:SetThreadPriority
优先级 | 组件 |
248 | 电源管理 |
249 | WaveDev、TVIA5000、鼠标、PnP、电源 |
250 | WaveAPI |
251 | 电源管理器电池线程 |
252-255 | 开放 |
一般来说,最先需要决定的是要确定关键线程是否需要驱动程序。如果关键线程需要驱动程序才能正常工作,而将它的优先级设定为高于驱动程序的优先级,则很难获得好的性能。总之,时间关键型应用程序需要放在“高于驱动程序类别的实时”类别中,优先级范围为 0-98。
应用程序体系结构同时使用 DemoControl 和 View 应用程序,可以提供对平台硬件的中断状态的控制和显示功能。在此演示中使用的是来自 NML 的基于 SH4 的平台。演示平台包含一个连接到中断的简单按钮。按钮状态的改变将触发操作系统的中断。每次硬件开关的释放和按下状态变化都会收到中断。收到第一个中断时,DemoControl 应用程序开始每 5 毫秒计数一次,并递增 8 个内存容器之一的计数。每次按下按钮,当前的容器索引都会递增一。如果容器索引达到 8,则重置为 0。DemoView 应用程序的直方图将自动调整大小以显示 8 个容器中每一个的相对计数。直方图最终显示的是每个容器位置所花费的时间量。DemoView 还显示了平均容器计数、总容器计数和当前容器编号。
高速信息的显示是典型的实时接口题。如果实时控制器在绘制过程中更新容器计数,则显示屏显示的容器计数、平均数和总数可能有一部分不正确。对实时应用程序而言,在一个快照中获取所有数据非常关键,这样才能保持各个项的完全一致。这也被称为暂时一致性。为了在一个快照内获取数据(即暂时保持一致),最常用的方法是与实际控制线程同步,以便在需要时发送此快照。
演示策略使用了 Win32 中最常用的两个同步对象:命名事件和内存映射文件。事件提供了一种机制,使一个应用程序能够通知另一个应用程序它已达到某种状态。应用程序在得到通知以前可以一直等待这些事件。因为这些事件已命名,所以可以在应用程序之间引用。内存映射文件(按名称引用)提供了一种方法,使两个独立的应用程序可以查看同一个内存区域。
同步策略以下插图概要描述了同步策略。

图 2:同步策略
同步按以下步骤循环进行:
DemoView 应用程序设置复制事件,请求将新的统计信息复制到演示内存区域,然后等待完成事件。
DemoControl 应用程序检查每个控制系统是否已设置复制事件。如果已设置,则转至步骤 3;否则将不断循环。
DemoControl 更新演示内存区域中的数据。
DemoControl 设置完成事件。
等待完成事件之后,DemoView 将被唤醒,重画屏幕,休眠 100 毫秒,然后返回步骤 1。
最小化控制线程的交互操作和要求具有最高的优先级。控制器在检查复制事件的状态时或者在将数据复制到内存区域时花费的时间很少。您可能会问,是否应该继续执行并在每个控制循环中复制内存。这样做的问题是 DemoView 可能正在将数据复制到其本地内存中,最终导致不一致的快照。
演示控制体系结构为了支持同步和控制器要求,将实现以下的 DemoControl 体系结构:

图 3:演示控制体系结构
DemoControl 应用程序使用两个主要线程:IST 和主要控制线程。
一个简单的中断服务线程 (IST) 将响应按下按钮引起的中断。IST 将确保该中断表示的是按钮释放的状态。然后,IST 将增加容器索引并使 LED 闪烁。
控制线程将循环检查表示关闭的完成标志。如果未设置完成标志,控制线程将增加当前容器索引的容器值,然后计算当前的统计数据。控制线程将检查来自 DemoView 的复制请求事件,如果已设置,则将数据复制到演示内存区域。然后控制线程将设置完成事件,休眠 5 毫秒并重复循环。
中断服务线程必须尽快发挥作用而不应该被控制线程停滞,其优先级应该设置为 50。演示控制线程则不依赖于任何驱动程序,因此优先级为 60。
控制器开发 - DemoControl.exe目录结构建议您创建如下目录结构:
DEMOTop 目录,可在任意位置
DEMODemoControlPlace,用于 DemoControl 项目
DEMODemoViewPlace,用于 DemoView 项目
DEMOLibPre,用于现有的 SharedMemory 和历史记录库
DEMOIncPre,用于现有的 DemoMemory.h 文件
应用程序设置DemoControl.exe 是一个 Win32 应用程序。创建 Win32 应用程序包括两个步骤。先要选择一个新的 WCE 应用程序,然后要选择简单的 Windows CE .NET 应用程序,如下所示。

图 4:新建 WCE 应用程序对话框
要创建应用程序,请选择 WCE Application(WCE 应用程序),然后单击 OK(确定)。

图 5:WCE Application(WCE 应用程序)对话框
一些库和内存定义已经创建。创建内存映射文件的封装类包含在 SharedMemory.cpp 和 SharedMemory.h 文件中。演示内存区域在 DemoMemory.h 中定义。在您的项目中添加这三个文件,即产生以下 DemControl 文件列表。

图 6:DemControl 文件列表
库和包含文件分别位于 Include(包含文件)和 Lib(库)子目录下。将这些项映射到 Project Settings(项目设置)对话框的包含目录搜索路径。

图 7:Project Settings(项目设置)对话框中的库和包含文件
为了访问平台的硬件,请利用 CEDDK 库并将其添加到 Project Settings(项目设置)对话框的 Object Modules(对象模块)列表中。

图 8:添加到 Project Settings(项目设置)对话框的 Object Modules(对象模块)列表
演示内存区域 - DemoMemory.h两个应用程序的全局内存结构已在 DemoMemory.h 中定义。DEMO_MEMORY_STRUCTURE 包含:
nButton Current Button Index from 0 -7
ulButtonCount Array of 8 Bins worth of Tick Counts
ulAverage Average Bin Value
ulTotal Total Tick Counts
ulNumInts Number of Interrupts
fFinished Terminate Controller Flag
// 新建文件 DemoMemory.h
//
// 定义
//
#define DEMO_MEMORY_NAME _T("DEMO_MEMORY")
#define DEMO_COPY_EVENT_NAME _T("DEMO_COPY")
#define DEMO_COPY_FINISHED_EVENT_NAME _T("DEMO_COPY_FINISHED")
#define DEMO_NUM_BINS 8
#define DEMO_IST_PRIORITY 50
#define DEMO_CONTROL_PRIORITY 60
// 全局内存结构
//
typedef struct
{
int nButton;
ULONG ulButtonCount[ DEMO_NUM_BINS ];
ULONG ulAverage;
ULONG ulTotal;
ULONG ulNumInts;
BOOL fFinished;
}DEMO_MEMORY_STRUCT,*DEMO_MEMORY_PTR;
“初始化”和“控制代码”节中的其余代码将取代由 eMbedded Visual C++ 生成的 DemoControl.cpp 默认代码。
初始化// DemoControl.cpp:定义应用程序的入口点。
//
#include "stdafx.h"
#include "SharedMemory.h"
#include "DemoMemory.h"
#include <pkfuncs.h>
#include "celog.h"
#include "ceddk.h"
#include "Platform.h"
// 全局内存
//
CSharedMemory* g_SM;
DEMO_MEMORY_PTR g_pDM;
DEMO_MEMORY_STRUCT g_CM;
HANDLE g_hevInterrupt;
HANDLE g_htIST;
DWORD g_dwSysInt;
HANDLE g_htControl;
HANDLE g_hevCopyRequest;
HANDLE g_hevCopyFinished;
PVBYTE g_pLEDPORT;
PVBYTE g_pButtonPort;
// 定义
//
#define BUTTON_MASK 0x20000000
#define LED_ON 0x0C
#define LED_OFF 0x00
// 原型
//
DWORD SetupMemory ( void );
DWORD SetupInterrupt ( void );
DWORD SetupControl ( void );
DWORD LED ( BYTE ucPort, BOOL fState );
DWORD WINAPI ThreadIST ( LPVOID lpvParam );
DWORD WINAPI ThreadControl ( LPVOID lpvParam );
// 主要
//
int WINAPI WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
DWORD dwRet;
dwRet = SetupMemory();
if( dwRet ) return dwRet;
dwRet = SetupInterrupt();
if( dwRet ) return dwRet;
dwRet = SetupControl();
if( dwRet ) return dwRet;
// 更新局部内存
//
memcpy( (PVOID)&g_CM, (PVOID)g_pDM, sizeof( DEMO_MEMORY_STRUCT ) );
// 使线程开始执行
//
ResumeThread( g_htIST );
ResumeThread( g_htControl );
while( !g_pDM->fFinished )
{
Sleep( 500 );
}
return 0;
}
DWORD SetupMemory( void )
{
// 创建共享内存区域
//
g_SM = new CSharedMemory( sizeof( DEMO_MEMORY_STRUCT ), DEMO_MEMORY_NAME );
if( !g_SM ) return 1;
// 从共享内存中获取内存
//
g_pDM = (DEMO_MEMORY_PTR)g_SM->GetMemory();
if( !g_pDM ) return 2;
// 清除内存
//
g_pDM->fFinished = FALSE;
// 使用 CEDDK 函数来映射 LED 和按钮寄存器
//
LARGE_INTEGER liAddress;
liAddress.LowPart = NET_LED_BASE;
liAddress.HighPart = 0;
g_pLEDPORT = (PVBYTE) MmMapIoSpace ( liAddress, 0x10, FALSE );
if( !g_pLEDPORT ) return 3;
liAddress.LowPart = PCTRA;
liAddress.HighPart = 0;
g_pButtonPort = (PVBYTE) MmMapIoSpace ( liAddress, 0x4, FALSE );
if( !g_pButtonPort ) return 4;
return 0;
}
DWORD SetupInterrupt( void )
g_htIST = CreateThread( NULL, // CE 安全性
0, // 默认大小
ThreadIST, // IST
NULL, // 没有参数
CREATE_SUSPENDED, // 挂起
&dwThreadID // 线程 ID
);
if( !g_htIST )return 12;
// 将线程优先级设置为实时
//
if( !CeSetThreadPriority( g_htIST, DEMO_IST_PRIORITY ))return 13;
// 初始化中断
//
if ( !InterruptInitialize(g_dwSysInt,g_hevInterrupt,NULL,0) )return 14;
return 0;
}
DWORD SetupControl( void )
{
DWORD dwThreadID;
// 创建事件
//
g_hevCopyRequest = CreateEvent(NULL, FALSE, FALSE,
DEMO_COPY_EVENT_NAME );
if(!g_hevCopyRequest) return 20;
g_hevCopyFinished = CreateEvent(NULL, FALSE, FALSE,
DEMO_COPY_FINISHED_EVENT_NAME );
if(!g_hevCopyFinished) return 20;
// 创建高优先级线程
//
g_htControl = CreateThread( NULL,
0,
ThreadControl,
NULL,
CREATE_SUSPENDED,
&dwThreadID );
if( !g_htControl ) return 20;
// 将线程优先级设置为实时
//
if( !CeSetThreadPriority( g_htControl, DEMO_CONTROL_PRIORITY )) return 21;
return 0;
}
DWORD LED( BYTE ucPort, BOOL fState )
{
if( !g_pLEDPORT )return 0;
if( fState ) WRITE_REGISTER_UCHAR( g_pLEDPORT, LED_ON | ucPort ); // 开
else WRITE_REGISTER_UCHAR( g_pLEDPORT, LED_OFF | ucPort ); // 关
return 0;
}
从 WinMain 初始化控制器的关键步骤包括:
调用 SetupMemory:
创建演示内存区域的新内存映射文件。
通过 CEDDK.lib 映射 LED 和按钮的输入/输出 (I/O) 空间。
调用 SetupInterrupt:
创建中断事件和 IST,并且调用 InterruptInitialize 以挂起中断。
将 IST 优先级设置为 50。
调用 SetupControl:
创建或连接到复制请求事件。
创建或连接到复制完成事件。
创建控制线程。
将控制线程的优先级设置为 60。
在演示内存的全局状态下复制。
恢复 IST 和控制线程。
等待设置 fFinished 标志。
控制代码中断线程ThreadIST 遵循上面的简单示例,并添加了针对硬件的代码以处理按钮和按钮索引。
DWORD WINAPI ThreadIST( LPVOID lpvParam )
{
DWORD dwStatus;
BOOL fState = TRUE;
BOOL fFirstTime = TRUE;
while( !g_pDM->fFinished )
{
dwStatus = WaitForSingleObject(g_hevInterrupt, INFINITE);
// 检查是否已经完成
//
if(g_pDM->fFinished ) return 0;
// 确保拥有对象
//
if( dwStatus == WAIT_OBJECT_0 )
{
// 仅检查按钮释放。在释放和按下时获取中断
//
if (!( READ_REGISTER_ULONG(g_pButtonPort) & BUTTON_MASK))
{
// 递增按钮
//
g_CM.ulNumInts++;
if( !fFirstTime )
{
g_CM.nButton ++;
if( g_CM.nButton == DEMO_NUM_BINS )
g_CM.nButton = 0;
}
else
fFirstTime = FALSE;
// 在 CELOG 外存储计数
//
CELOGDATA( TRUE,
CELID_RAW_LONG,
&g_CM.ulNumInts, (WORD) (sizeof(DWORD)),
1, CELZONE_MISC);
// 闪烁 LED
LED( 0, fState );
fState = !fState;
}
// 完成中断
//
InterruptDone( g_dwSysInt );
}
}
return 0;
}
此 IST 的应用程序特有的步骤包括:
收到中断时,IST 检查是否存在按钮释放事件。
增加中断数目并清除第一次的标志。
向 CELOG 报告中断数目。
切换 LED 状态。
报告 InterruptDone。
控制线程下面是主要的控制器线程。
DWORD WINAPI ThreadControl( LPVOID lpvParam )
{
int i;
DWORD result;
while( !g_pDM->fFinished )
{
// 递增当前的容器位置
//
if( g_CM.ulNumInts )
{
g_CM.ulTotal ++;
g_CM.ulButtonCount[ g_CM.nButton ] ++;
g_CM.ulAverage = g_CM.ulTotal / DEMO_NUM_BINS;
}
// 获取要更新的请求
//
result = WaitForSingleObject( g_hevCopyRequest, 0 );
// 检查是否发出了信号
//
if( result == WAIT_OBJECT_0 )
{
g_pDM->ulAverage = g_CM.ulAverage;
g_pDM->ulNumInts = g_CM.ulNumInts;
g_pDM->ulTotal = g_CM.ulTotal;
g_pDM->nButton = g_CM.nButton;
i = 0;
while( i < DEMO_NUM_BINS )
{
g_pDM->ulButtonCount[i] = g_CM.ulButtonCount[i];
i ++;
}
// 已经完成
//
SetEvent( g_hevCopyFinished );
}
Sleep( 5 );
}
return 0;
}
ThreadControl 执行的关键步骤包括:
检查每个循环的完成标志。
根据当前按钮递增指定的容器计数。
计算平均数。
检查是否已设置复制请求事件。如果已设置,则执行以下步骤:
将平均数、中断数、总中断数和按钮索引复制到演示内存区域。
将容器计数复制到演示内存区域。
设置复制完成事件。
休眠 5 毫秒,然后重复上述步骤。
注意:现在可以生成并执行 DemoControl 应用程序。不使用 DemoView,您也可以看到 NMI 平台上的 LED 根据按钮的按下状态进行切换。显示代码 - DemoView.exe应用程序设置DemoView.exe 是一个 MFC 应用程序。创建 MFC 应用程序包括两个步骤。选择 WCE MFC AppWizard (exe)(WCE MFC 应用程序向导 [exe])对话框,然后单击 OK(确定),如下图所示。

图 9:New(新建)对话框
单击 OK(确定)。

图 10:New WCE MFC AppWizard (exe)(新建 WCE MFC 应用程序向导 [exe])对话框
单击 Finish(完成)。
一些库和内存定义已经创建。创建内存映射文件的封装类包含在 SharedMemory.cpp & .h 文件中。演示内存区域在 DemoMemory.h 中定义。直方图类库包含在 HistoryLib.cpp & .h 中。在您的项目中添加这五个文件,即产生以下 DemoView 文件列表。

图 11:DemoView 文件列表
库和包含文件分别位于 Include(包含文件)和 Lib(库)子目录下。将这些项映射到 Project Settings(项目设置)对话框的包含目录搜索路径。

图 12:Project Settings(项目设置)对话框
对话框设置打开 IDD_DEMOVIEW_DIALOG 对话框,放置以下项,使对话框如下图所示。DemoView 对话框的大小应该在 330 x 190 像素范围内。
表 5:对话框设置项
项 | 资源 ID | 属性 |
平均数编辑框 | IDC_AVG_EDIT | 禁用,可视 |
总计数 | IDC_TOTAL_EDIT | 禁用,可视 |
中断数 | IDC_NUM_INTS_EDIT | 禁用,可视 |
“停止”按钮 | IDC_STOP_BUTTON | 说明文字 - 停止 |

图 13:DemoView 对话框
双击对话框中的“停止”按钮,创建 OnStopButton 消息。在 MFC ClassWizard(MFC 类向导)对话框中向类 CdemoViewDlg 添加以下成员变量:

图 14:MFC ClassWizard(MFC 类向导)对话框
在 MFC ClassWizard(MFC 类向导)对话框中,将 WM_TIMER 和 WM_PAINT 消息处理程序添加到对话框。

图 15:添加 WM_TIMER 和 WM_PAINT 消息处理程序
对话框标题 - DemoViewDlg.h将以下粗体定义添加到 DemoViewDlg.h 中受保护的 m_hIcon 定义之下。它们将添加历史记录库、绘图 RECT 和统计信息等成员变量。
// 实现
protected:
HICON m_hIcon;
CHistoryLib m_HistoryLib;
CRect m_PlotRect;
ULONG m_ulLastAverage;
ULONG m_ulLastTotal;
ULONG m_ulLastNumInts;
CString m_Output;
“对话框”、“初始化”和“对话框详细处理程序”各节中的其余代码将取代由 eMbedded Visual C++ 生成的 DemoViewDlg.cpp 默认代码。
对话框初始化以下代码示例演示了对话框的初始化过程:
// DemoViewDlg.cpp:实现文件
//
#include "stdafx.h"
#include "DemoView.h"
#include "DemoViewDlg.h"
#include "HistoryLib.h"
#include "DemoMemory.h"
#include "SharedMemory.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
CSharedMemory* g_SM;
DEMO_MEMORY_PTR g_pDM;
HANDLE g_hevCopyRequest;
HANDLE g_hevCopyFinished;
/////////////////////////////////////////////////////////////////////////////
// CDemoViewDlg 对话框
CDemoViewDlg::CDemoViewDlg(CWnd* pParent /*=NULL*/)
: CDialog(CDemoViewDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CDemoViewDlg)
//}}AFX_DATA_INIT
// 请注意,LoadIcon 不需要 Win32 中后续的 DestroyIcon
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CDemoViewDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CDemoViewDlg)
DDX_Control(pDX, IDC_NUM_INTS_EDIT, m_NumIntsEdit);
DDX_Control(pDX, IDC_TOTAL_EDIT, m_TotalEdit);
DDX_Control(pDX, IDC_AVG_EDIT, m_AvgEdit);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CDemoViewDlg, CDialog)
//{{AFX_MSG_MAP(CDemoViewDlg)
ON_WM_PAINT()
ON_WM_TIMER()
ON_BN_CLICKED(IDC_STOP_BUTTON, OnStopButton)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CDemoViewDlg 消息处理程序
BOOL CDemoViewDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// 设置此对话框的图标。当应用程序的主窗口不是对话框时,
// 框架不会自动完成此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
CenterWindow(GetDesktopWindow()); // 在 hpc 屏幕中居中显示
// 设置直方图
//
GetClientRect( &m_PlotRect );
m_PlotRect = m_PlotRect;
m_PlotRect.right -= 10;
m_PlotRect.bottom -= 70;
m_HistoryLib.Init( HistoryLeft, // 类型
&m_PlotRect, // 区域
_T("Button-Histogram"), // 标题
_T("(Button)" ), // 水平标题
_T("(Counts)" ), // 垂直标题
0.0, // 左
8, // 容器数
1.0 // 容器大小
);
// 设置编辑操作
//
m_ulLastAverage = 0;
m_ulLastTotal = 0;
m_ulLastNumInts = 0;
// 创建共享内存区域
//
g_SM = new CSharedMemory( sizeof( DEMO_MEMORY_STRUCT ), DEMO_MEMORY_NAME );
if( !g_SM ) return FALSE;
// 从共享内存中获取内存
//
g_pDM = (DEMO_MEMORY_PTR)g_SM->GetMemory();
if( !g_pDM ) return FALSE;
// 获取事件
//
// 创建事件
//
g_hevCopyRequest = CreateEvent(NULL, FALSE, FALSE,
DEMO_COPY_EVENT_NAME );
if(!g_hevCopyRequest) return FALSE;
g_hevCopyFinished = CreateEvent(NULL, FALSE, FALSE,
DEMO_COPY_FINISHED_EVENT_NAME );
if(!g_hevCopyFinished) return FALSE;
// 使定时器开始执行
//
SetTimer( 10000, 200, NULL );
return TRUE; // 除非将焦点设置到某个控件上,否则返回 TRUE
}
对话框初始化的关键步骤包含在 OnInitDialog 消息处理程序中:
计算直方图的绘图矩形
初始化 m_HistoryLib 库
创建演示内存区域的新内存映射文件
创建或连接到复制请求事件
创建或连接到复制完成事件
在 200 毫秒时启动计时器以更新显示
对话框消息处理程序以下消息处理程序 OnPaint、OnTimer 和 OnStopButton 将完成全部工作。
void CDemoViewDlg::OnPaint()
{
CPaintDC dc(this); // 绘图设备上下文
m_HistoryLib.PlotBackground( &dc );
// 不要调用 CDialog::OnPaint() 来绘制消息
}
void CDemoViewDlg::OnTimer(UINT nIDEvent)
{
static int i = 0;
// 更新显示
//
CDC* dc;
dc = GetDC();
// 请求控制器信息,并等待其完成
//
SetEvent( g_hevCopyRequest );
WaitForSingleObject( g_hevCopyFinished, 500 );
// 更新直方图
//
m_HistoryLib.SetBinData( DEMO_NUM_BINS, &g_pDM->ulButtonCount[0] );
m_HistoryLib.Update( dc );
// 更新编辑操作
//
if( g_pDM->ulAverage != m_ulLastAverage )
{
m_Output.Format( _T("%ld"), g_pDM->ulAverage );
m_AvgEdit.SetWindowText( m_Output );
m_ulLastAverage = g_pDM->ulAverage;
}
if( g_pDM->ulTotal != m_ulLastTotal )
{
m_Output.Format( _T("%ld"), g_pDM->ulTotal );
m_TotalEdit.SetWindowText( m_Output );
m_ulLastTotal = g_pDM->ulTotal;
}
if( g_pDM->ulNumInts != m_ulLastNumInts )
{
m_Output.Format( _T("%ld"), g_pDM->ulNumInts );
m_NumIntsEdit.SetWindowText( m_Output );
m_ulLastNumInts = g_pDM->ulNumInts;
}
// 返回此 dc!
ReleaseDC( dc );
CDialog::OnTimer(nIDEvent);
}
void CDemoViewDlg::OnStopButton()
{
g_pDM->fFinished = TRUE;
}
消息处理程序的关键步骤包括:
OnPaint
绘制直方图库的背景。
OnTimer
获取当前绘图设备的上下文。
设置复制请求事件。
等待来自控制器的复制完成事件,并在 500 ms 时设为超时以确保其不被锁定。
设置来自演示内存区域的直方图库的容器数据。
使直方图库更新显示。
更新对平均中断数、总中断数和中断数的编辑结果,如果这些数字与上次刷新时不同。
释放当前绘图设备的上下文。
返回。
注意:现在可以生成和执行 DemoView 应用程序。要测试控制器,请按硬件平台上的按钮。直方图容器基本上可以测量每次按钮按下所用的时间。如果有必要,直方图库将自动调整自身的大小。小结Windows CE .NET Embedded 开发人员可以选择多种开发工具。本机应用程序和 .NET Framework 精简版在应用程序开发中都占有一席之地。综合考虑性能、空间以及代码的可移植性等因素可以帮助您确定选择哪个工具。您可以在 eMbedded Visual C++ 中快速开发复杂的应用程序,eMbedded Visual C++ 允许对 Windows CE .NET 本机的各种 Win32 功能进行高性能访问。Windows CE .NET 为各种应用程序体系结构提供了丰富的实时环境。eMbedded Visual C++ 是开发功能强大的应用程序的得力工具。
更多精彩
赞助商链接