在Office大戰(zhàn)中,國(guó)產(chǎn)軟件的確在一些方面與Microsoft進(jìn)行較量,其實(shí)給人的感覺(jué)很勉強(qiáng),界面上的似是而非,或用戶習(xí)慣方面的接近并不能解決根本的問(wèn)題,一個(gè)好的軟件開發(fā)人員必須是一個(gè)軟件使用的高手,很難想象一個(gè)軟件操作水平很拙劣的開發(fā)人員能開發(fā)出高水平的軟件,我最早使用的軟件之一就是Microsoft Word,當(dāng)時(shí)的版本是2.0,大概是1992年的事情,給我留下深刻印象的是集成于Word中的Word Basic,后來(lái),我接觸到Excel 3.0,不出所料,Excel中集成的是Excel Basic,后來(lái)使用的Access中自然內(nèi)置Access Basic 1.0,在這些軟件集成捆綁成Office之前,我就感覺(jué)這些產(chǎn)品的構(gòu)思十分了不起,很具有Microsoft的風(fēng)格,因?yàn)槟阒溃词故且粋€(gè)DOS,Microsoft都要提供一個(gè)內(nèi)置的QBasic或GW Basic。雖然關(guān)于Microsoft的產(chǎn)品評(píng)論很多,作為一個(gè)技術(shù)人員,我認(rèn)為Microsoft的產(chǎn)品構(gòu)思絕對(duì)是第一流的,從1994年早期的Office系列到1997年形成的Office 4.2,我認(rèn)為,技術(shù)構(gòu)思上均領(lǐng)先于我國(guó)2002年以后的Office產(chǎn)品,你聽說(shuō)過(guò)如下說(shuō)法嗎?"Dos 作為操作系統(tǒng)的時(shí)代,Windows是應(yīng)用軟件;Windows是操作系統(tǒng)時(shí),Office成為Dos時(shí)代的Windows;那么如果按此規(guī)律,Office會(huì)不會(huì)替代Windows而成為操作系統(tǒng)?",現(xiàn)在在開發(fā)領(lǐng)域Visual Studio( .NET)正在成為另一個(gè)Office,你注意到了嗎?控制Visual Studio( .NET)集成開發(fā)環(huán)境的仍然是一個(gè)Basic語(yǔ)言引擎(Visual Basic .NET)。
與許多公司不同的是,在技術(shù)體系上,Microsoft幾乎所有的產(chǎn)品是息息相關(guān)的,Windows、Office、Visual Studio .NET雖然各不相同,但公共的核心即將形成,我們已經(jīng)看到,核心組件方面,Office與Visual Studio .NET日漸趨于一致,例如Microsoft正在將Office 2003的核心組件VBA 6.X逐步用新的Visual Studio Tools for Office替代,而我們依然在一些似是而非的現(xiàn)象上與Microsoft的產(chǎn)品比較差距,國(guó)家采購(gòu)或政府采購(gòu)支持的公司,不去鉆研核心技術(shù),只是急功近利的采用短期行為急于與Microsoft相爭(zhēng),不知是否有蚍蜉撼樹的感覺(jué),個(gè)人的體驗(yàn)是,先學(xué)習(xí)Microsoft,踏踏實(shí)實(shí)的學(xué),了解Microsoft,深入的了解,然后再喊口號(hào)。
四、為什么用MFC?
經(jīng)過(guò)若干年的競(jìng)爭(zhēng),Borland 的OWL幾乎消失了,這個(gè)OWL是個(gè)非常漂亮的C++類庫(kù),在Borland C++ 3.1風(fēng)光無(wú)限的年代,OWL真正的做到了獨(dú)領(lǐng)風(fēng)騷。然而,Borland C++ 4.0錯(cuò)過(guò)了進(jìn)入32位程序的最佳時(shí)機(jī),BC 4.0推出后不久,迎來(lái)了Win95,Borland倉(cāng)促上陣,以一個(gè)小的"Pack"使得BC4可以編譯基于Win4的程序,當(dāng)時(shí)的Visual C++是2.0版,支持Window16的版本為Visual C++1.51,有意思的是Borland可以用同一個(gè)編譯器同時(shí)支持Win16、Win32,而Microsoft卻不得不為Win16、Win32提供不同的編譯器。然而,非正式版本的Visual C++ 2.1與Visual C++ 2.2卻悄悄地支持了Win95的最新特征,即Win95新提供的一組公共控件,在我的印象中,Borland對(duì)Win95新特征的支持不利使得MFC與OWL的距離極大的縮短了。稍后到來(lái)的Borland C++ 4.5沒(méi)有改變這個(gè)狀況,盡管Borland C++ 5.0同時(shí)支持OWL與MFC,可是敗象已經(jīng)顯露,Borland C++非常遺憾的只走到了5.5版。C++ Builder雖然形式上引入了Delphi的VCL庫(kù),可是許多C++程序員并不買賬,因?yàn)樵S多以C++為樂(lè)的人更喜歡以編輯的模式進(jìn)行編碼。Visual C++ 4.0的出現(xiàn),在C++這個(gè)戰(zhàn)場(chǎng)上,Borland開始落敗了。
MFC發(fā)展到今天,已經(jīng)十多年了,盡管褒貶不一,但可以肯定,十幾年的技術(shù)積累已經(jīng)奠定了MFC的生存基礎(chǔ),即使Microsoft的長(zhǎng)角發(fā)布,MFC也不能推出Windows的舞臺(tái),事實(shí)上,長(zhǎng)角(Longhorn)之后的Visual Studio .NET仍將MFC作為一個(gè)重要的組成部分,在今年的Visual Studio .NET 2005中,MFC在C++中的位置依然如故。MFC的未來(lái),應(yīng)該不必?fù)?dān)心,只要你深入考察.NET類庫(kù),你會(huì)發(fā)現(xiàn),MFC的許多思想機(jī)制正悄然進(jìn)入.NET,與此同時(shí),Microsoft的第三方盟友十多年來(lái)已為MFC開發(fā)了大量的擴(kuò)展庫(kù),如果Microsoft是船,第三方盟友就是載舟之水。許多人認(rèn)為MFC不發(fā)展了,其實(shí)是一種錯(cuò)覺(jué),Visual C++ 6的界面十分經(jīng)典,特別是其中的Docking控制條機(jī)制,其實(shí)Visual C++ 6的IDE完全就是MFC寫的,可是MFC類庫(kù)中控制條相關(guān)的類功能很弱,為什么?你會(huì)看到許多與Microsoft友好的公司,他們很快的在MFC基礎(chǔ)上實(shí)現(xiàn)了Visual C++ 6 的Docking機(jī)制,這就是Microsoft的高明之處,Microsoft很會(huì)給盟友提供機(jī)會(huì),其一貫的做法就是在自己的商品化產(chǎn)品中預(yù)先提供一些有趣的特征,使得其他一些公司進(jìn)行模仿以帶動(dòng)用戶群體。Borland不具備這樣的儲(chǔ)備。MFC第三方市場(chǎng)的繁榮,得益于Microsoft的策略與明智。MFC可否跨平臺(tái)?理論上完全可以,Microsoft不做,也是策略,但是有許多重要的產(chǎn)品Microsoft卻默許MFC移植到其他平臺(tái),事實(shí)上,Microsoft的合作伙伴之一Mainsoft公司(Windows源碼就是從這家公司流失的),幾年來(lái)就是負(fù)責(zé)移植MFC程序移植到UINIX、Linux、AIX等操作系統(tǒng)之上。
新版的Visual C++中MFC已經(jīng)支持.NET開發(fā)了,MFC與ATL的協(xié)作更好了。根據(jù)我的經(jīng)驗(yàn),MFC、ATL與.NET庫(kù)三者完全可以融合在一起綜合應(yīng)用到實(shí)際的開發(fā)工作中去,如果你是MFC行家,我希望ATL與.NET庫(kù)能成為你的忠實(shí)的左右手。那么有沒(méi)有同時(shí)支持MFC、ATL與.NET庫(kù)的程序?當(dāng)然有,Visual Studio .NET IDE就是!而且Visual Studio .NET IDE還支持用ATL與.NET庫(kù)擴(kuò)展的Addin,如果你希望用MFC管理ATL與.NET庫(kù),請(qǐng)繼續(xù)支持我!
五、認(rèn)識(shí)Application對(duì)象
如果你熟悉Microsoft Office,你應(yīng)該進(jìn)一步的剖析這個(gè)大型軟件,Microsoft Office中幾乎每個(gè)程序都是可二次開發(fā)的,這一點(diǎn)得益于Microsoft Office內(nèi)置的二次開發(fā)機(jī)制,一個(gè)是基于COM機(jī)制的VBA模型,另一個(gè)是基于.NET框架的托管模型:Visual Studio Tools for Office。作為一名程序員,你應(yīng)當(dāng)在技術(shù)角度解析Office的技術(shù)結(jié)構(gòu)。Microsoft的大多數(shù)軟件的對(duì)象結(jié)構(gòu)可以通過(guò)Visual Studio提供的工具OLE/COM Object Viewer考察其類型庫(kù)得到,通過(guò)引用類型庫(kù),你甚至可以得到描述對(duì)象信息的C++頭文件。這樣做真是好處多多。一個(gè)典型的Office通常都有一個(gè)Application對(duì)象(或其他一個(gè)與之相當(dāng)?shù)膶?duì)象),這個(gè)對(duì)象相當(dāng)于軟件樞紐,在這里,我們不討論Office,借此話題說(shuō)說(shuō)Application對(duì)象。大多數(shù)支持?jǐn)U展(Addin、Plugin)的軟件都存在類似的構(gòu)造。通常,一個(gè)系統(tǒng)得Application對(duì)象或者是一個(gè)COM對(duì)象,或者是一個(gè).NET對(duì)象,如果你的系統(tǒng)存在這類對(duì)象,你的系統(tǒng)就基本具備支持Addin、Plugin的機(jī)制了。一個(gè)理想的做法就是在一個(gè)MFC系統(tǒng)中,內(nèi)置一個(gè)ATL對(duì)象或.NET對(duì)象,稍后我們給出方案如何做到這一點(diǎn)。設(shè)計(jì)Application對(duì)象的關(guān)鍵是如何規(guī)劃這個(gè)對(duì)象的屬性、方法、事件。如果你希望系統(tǒng)具備良好的擴(kuò)展性,Application對(duì)象是十分關(guān)鍵的,這也是構(gòu)架藝術(shù)的體現(xiàn)。所謂Addin(Plugin),是系統(tǒng)運(yùn)行時(shí)根據(jù)需要加載的對(duì)象庫(kù),Addin(Plugin)之所以可以擴(kuò)展系統(tǒng),關(guān)鍵的因素就是系統(tǒng)加載Addin(Plugin)時(shí),將Application對(duì)象傳遞給Addin(Plugin)庫(kù),設(shè)想一下,如果Application恰到好處的觸發(fā)了系統(tǒng)事件,而Addin(Plugin)庫(kù)如愿的解釋了事件,一個(gè)Addin(Plugin)庫(kù)的任務(wù)不就OK了嗎!因此Application對(duì)象是系統(tǒng)設(shè)計(jì)的關(guān)鍵。
如果你精通ATL對(duì)象,在你的MFC系統(tǒng)中添加一個(gè)ATL對(duì)象,這個(gè)任務(wù)可以用VC Wizard完成。你已經(jīng)接受了一個(gè)事實(shí),就是MFC程序中存在一個(gè)CXXXApp對(duì)象(CWinApp的派生類),現(xiàn)在你要做的是增加一個(gè)對(duì)應(yīng)得ATL對(duì)象。這個(gè)對(duì)象可以在CXXXApp::InitInstance()中創(chuàng)建,如果ATL對(duì)象的類是CXXXAppObject,建議你在CXXXApp對(duì)象對(duì)象中增加一個(gè)成員變量,例如:CComObject<CXXXAppObject>* m_pAppObj,然后可以入下初始化m_pAppObj:
m_pAppObj = new CComObject<CXXXAppObject>;
注意程序結(jié)束時(shí)在CXXXApp::ExitInstance()中釋放m_pAppObj,語(yǔ)句如下:
delete m_pAppObj;
你可以將系統(tǒng)得關(guān)鍵屬性設(shè)置成CXXXAppObject的屬性,例如系統(tǒng)得標(biāo)題、是否為多文檔等等。系統(tǒng)希望外部調(diào)用的功能可以實(shí)現(xiàn)為CXXXAppObject的方法,這一點(diǎn)取決于你的需要。系統(tǒng)需要外部擴(kuò)展的功能,表現(xiàn)為CXXXAppObject的事件,關(guān)鍵是在恰當(dāng)?shù)奈恢糜|發(fā)事件以及提供的事件參數(shù)。例如,你可以在CXXXApp::InitInstance()觸發(fā)應(yīng)用程序開始的事件OnStartUp,Plugin捕獲事件后,可以進(jìn)行特定的初始化(身份確認(rèn)、初始信息查詢等等);你可以在CXXXApp::ExitInstance()觸發(fā)應(yīng)用程序結(jié)束事件,Plugin捕獲事件后,處理用戶需要的系統(tǒng)退出工作。所有的設(shè)計(jì)取決于具體設(shè)計(jì)。
如何加載Plugin,是一個(gè)有趣的問(wèn)題,如果Plugin實(shí)現(xiàn)為一個(gè)COM范疇(Category),可以運(yùn)用COM技術(shù)枚舉這個(gè)Category;可以將Plugin安裝到一個(gè)特定目錄,也可以通過(guò)注冊(cè)表。Plugin的實(shí)現(xiàn)可以用COM技術(shù)、也可以用.NET框架。適當(dāng)?shù)臋C(jī)會(huì)我會(huì)提供例子……
六、后記
一時(shí)心血來(lái)潮,就寫了這篇文章,很難說(shuō)是有心,還是無(wú)意。幾天前我在新浪網(wǎng)上看應(yīng)氏杯圍棋決賽,我覺(jué)得該贏了吧,作為一個(gè)圍棋迷,我們等了十幾年,等到了屬于國(guó)人的應(yīng)氏杯。記得7、8年前在還在大學(xué)工作的時(shí)候,有一次,一位同事興致沖沖的走道我面前對(duì)我說(shuō):"嗨,昨天馬XX贏了李昌鎬!",當(dāng)時(shí)我在系辦公室正在看報(bào)紙,那位仁兄見我頭都沒(méi)抬,非常不滿的搶下報(bào)紙,對(duì)我吼道:"喂!馬XX贏了李昌鎬!!你聽到?jīng)]有!!!",我對(duì)他說(shuō):"你大驚小怪個(gè)啥?!馬XX輸了李昌鎬多少盤,你知道嗎?",馬XX幾乎一直在輸給李昌鎬,人們已經(jīng)不奇怪了,偶爾贏一次,國(guó)人就把他捧得北都找不到了,李昌鎬弱冠17的時(shí)候就傲視這個(gè)世界了,可至今面孔不變,幾天前的農(nóng)心杯,中日聯(lián)軍5個(gè)人,被他打個(gè)落花流水,李昌鎬是公認(rèn)的世界第一,以至于有的高手知道下一個(gè)對(duì)手如果是他,就會(huì)去訂回程機(jī)票。這次應(yīng)氏杯,國(guó)人竟然感謝崔哲瀚,何也?因?yàn)檫@個(gè)弱冠19的小子,擋住了他的大哥李昌鎬才使得應(yīng)氏杯有了懸念。當(dāng)國(guó)人媒體在說(shuō)韓國(guó)僅李昌鎬一人厲害的時(shí)候,不知道是出何居心還是自欺欺人,李昌鎬年方30,不知道要力壓中、日多少年!面對(duì)這個(gè)名字,真有點(diǎn)麻木了,這個(gè)太極虎!
軟件界又來(lái)了我們一向不齒的印度虎,2001年我們的軟件出口額僅是印度的四十分之一,我們震驚了,怎么可能呢?這個(gè)四十分之一水分很大,很可能更可憐!當(dāng)時(shí)我在大連參加一個(gè)關(guān)于"大連軟件出口國(guó)內(nèi)第一"的官方會(huì)議,那位大人在會(huì)上說(shuō):"據(jù)說(shuō),我們大連軟件出口國(guó)內(nèi)排名第一,市有關(guān)領(lǐng)導(dǎo)希望今天的會(huì)議給出這個(gè)第一的數(shù)字依據(jù),希望你們把數(shù)據(jù)報(bào)上來(lái),去年的數(shù)據(jù)也可申報(bào),注意,我們要的只是數(shù)據(jù),你們仔細(xì)體會(huì),我們根據(jù)數(shù)據(jù),有獎(jiǎng)勵(lì),機(jī)會(huì)難得呀!"……。某一天,幾個(gè)朋友在我家看央視的對(duì)話節(jié)目,對(duì)話一方為國(guó)內(nèi)的軟件大鱷們(用友、阿爾派等公司的老總們),另一方為印度軟件的一個(gè)代表團(tuán)。當(dāng)問(wèn)及中、印軟件差距的時(shí)候,我們的劉老總(代表阿爾派)不以為然的說(shuō),據(jù)他的看法,我們已經(jīng)快趕上(印度)了,……,言下之意頗有印度的水平不過(guò)如此的感覺(jué),印度方的話我至今記憶猶新:"是否趕上,國(guó)際市場(chǎng)說(shuō)的算!在中國(guó)看來(lái),印度程序員的個(gè)性不足,技術(shù)也不怎么樣,其實(shí)是個(gè)錯(cuò)覺(jué),印度軟件首先注重個(gè)性,許多重要的美國(guó)商品化軟件都是在印度本土開發(fā)的……",我們的輿論總是將印度程序員的水平描述的平庸至極,可是差距日漸拉開,……,圍棋、足球(不好意思談,談不出口!)、軟件,我們被近鄰嚴(yán)酷的封鎖了,樂(lè)壞了記者們、給媒體帶來(lái)了生機(jī)……
日本江戶時(shí)代的圍棋,如果一個(gè)人要想世襲一個(gè)稱號(hào)(例如:本因坊),他必須戰(zhàn)勝所有的師兄弟,然后,住進(jìn)師父家的內(nèi)室,你知道以后的事情嗎?以后,這個(gè)棋手,就得為師父一家做飯、帶孩子、搞衛(wèi)生……,其余的門人則一心一意的下棋,這樣的人、方式,造就了一代一代的本因坊,他們的棋譜大多數(shù)都流芳至今,這就是早期日本圍棋的悟道模式。軟件總共有多少語(yǔ)句?我最早接觸的計(jì)算機(jī)軟件教材是一本英文版的(影印的D版),不同于我們,那本書的作者構(gòu)造了"X-語(yǔ)言",他們不講什么C、Pascal、Basic,一旦缺了什么機(jī)制,就給"X-語(yǔ)言"添加些成分。什么C、Pascal、Basic,你感覺(jué)差不多,但現(xiàn)在卻分出了等級(jí)!我們駕馭語(yǔ)言的能力弱得很,可是我們?cè)谡Z(yǔ)言的細(xì)微之處卻很講究,不知道對(duì)不對(duì),許多程序員也許是出于虛榮而用C++,事實(shí)上,地球人到知道,做數(shù)據(jù)庫(kù),Delphi、VB遠(yuǎn)比C++勝任,鋪天蓋地的C++的書,寫的東西幾乎雷同,因?yàn)椋杏玫幕蛘咦髡卟粚憽⒒蛘咦髡卟欢S袝r(shí)我在想,如果國(guó)內(nèi)沒(méi)有內(nèi)需,會(huì)怎樣?也許軟件內(nèi)需的存在,造就了中國(guó)軟件的特色,我認(rèn)為國(guó)內(nèi)業(yè)界并沒(méi)有充分利用中國(guó)軟件內(nèi)需的存在,也許中國(guó)軟件內(nèi)需的存在是軟件落后的硬傷。
我記得一部電影《神辮》,那個(gè)英雄的大辮子被洋人炸掉了,最終他成了神槍手,戰(zhàn)勝洋人用大刀、秘籍是不行的,用洋的東西戰(zhàn)勝洋的技術(shù)才是正道。我覺(jué)得,一個(gè)好的程序員必須了解軟件的歷史,學(xué)習(xí)歷史,你知道你為什么弱,別人是如何強(qiáng)大的。我們正在另一個(gè)戰(zhàn)場(chǎng)上抗美(可笑的是我們卻要趕超印度!),無(wú)論Microsoft、Borland如何爭(zhēng)斗,無(wú)論他們誰(shuí)統(tǒng)治誰(shuí),他們不影響美國(guó)的強(qiáng)大,朋友們,學(xué)習(xí)Microsoft,開發(fā)出讓國(guó)人感到牛的軟件!