让Internet Explorer成为你的软件集成平台(一)
最近一段时间,经常与朋友们探讨与浏览器相关的技术问题,多少年来,浏览器的问题一直是软件界的热点,无论是体验、操作习惯、安全,还是技术等问题,一直都是这样,毋庸置疑,现在的人们已经离不开这个东西了。1996年,在IE 3.0与Navigator 3.0激战正酣的时候,我在一次Microsoft的技术会议上领略了后来被称为IE4的Microsoft浏览器预览版本,那种震撼,一直延续到今天,老实说,今天的IE7,比起当年的IE4,个人觉得还是10年前的震撼更为强烈。想起1996年,今天我们真的感觉自己十分幼稚,如果真的会思考软件的话,也许今天的情形就大不相同了……。
浏览器方面的开发,一直是我的业余爱好,多少年来从来没有当回事,也很少关心这方面的话题。2005年年中,一个偶然的事情改变了我对浏览器开发的看法,当时CSDN的袁德俊先生在我家里谈到他关于协同开发平台的“雕塑”架构时,设想希望将架构实现在Windows的资源管理器之上,在与他的交流过程中,我在努力的揣摩他的构思,技术上我认为不是问题,但软件行为方面,还有许多想法不清晰,那一次交流,基本停留在探讨层面,第二天,我给他看了一张软件截图,他感觉很兴奋,匆匆的赶到我这里,以后的多次交流,使我重新将浏览器方面的开发列入视线……。当我在网络上搜索这方面的信息时,才感觉到自己恍如隔世之人,全然不知外面世界的喧嚣、热闹,身居斗室,真是孤陋寡闻。兴趣回归之后,一直在考虑应该做点什么,一时之间,我下载了几款第三方浏览器,想看看,除了IE默认的功能之外,大家都在做什么?这是一个比较有意思的问题,几天以前,Maxthon的Jeff与我谈了类似的话题,中国国内不缺乏好的技术开发者,真正缺的是“点子”,一个创意一旦出现,立刻就被挖掘得缝隙全无,我与其他浏览器开发者交流,也有类似的感想。在与几位很有经验的开发者的交流过程中,我一直在思考的问题是,浏览器为什么会如此的重要?浏览器给开发者带来了什么?对大众用户而言,浏览的目标、对象会如何改变他们的工作、学习、生活以及交流方式?浏览器会改变我们所开发软件的行为吗?一系列的问题,一直在困扰着我。学会思考,是我最大的收获,不断的交流,使我几乎每天都在坚定一个想法,也促使我重新认识许多过去被我忽视的问题,……。在WWW上,有许多心交已久的朋友,我考虑不到的问题,就是他们中某一位所擅长的,一个狭窄的想法是,从他们的思考中学会什么、吸收什么,这一点应该是交流带来的收获吧,当一个人的思维不够的时候,其他人及时补充你的想法,使得你的想法得以延续,这就是今天的WWW,潜移默化的过渡中,我们都在不自觉地改变着自己。
从第一个大众化的浏览器诞生至今,HTML一直是浏览器的主要浏览对象,在我们热衷于C语言的时候,HTML进入了我们的视线,一种文本的表达方式,牵动着这个世界,我们中的大多数人最初是看不起这类东西的,因为,没有技术含量,然而,历经十几年的变迁,这种看上去没有技术含量的东西,就像地球上的水一样,充满着WWW世界的每一个角落,可以说,HTML就是今天WWW海洋里的水分子,如果HTML是水,那么浏览器是什么?浏览器是船!据说,地球有水以后,经过漫长的进化,才导致生命的出现,今天的WWW也许就是在另一个宇宙里再现这个历程。从许多方面看,我们今天的船还是很初级的,这个海洋越大,这样的船就显得越小、单薄、脆弱,……,也许,今天的WWW海洋,总共只有有限的几类船舶,最大的船东,应该就是Microsoft,此外还有Firefox、Opera、Maxthon、……、以及各种第三方的浏览器,随着时间的徐徐流逝,这些舰船也在悄然的改进,人们的胃口也越来越挑剔。如果世界是一个湖泊,也许我们可以享受到湖面的平静,但WWW是海洋,短暂的平静之后,就是风暴、巨浪,也许还有更厉害的震荡。WPF,对今天的开发者而言,不应该是一个陌生的词汇,尽管还没有正式面世,但我们已经感觉到这一轮冲击的震荡,从形式上看,HTML具有有限的“标记”以及简单的脚本描述引擎,WPF完全建立在XML基础之上,而且带有可编程的脚本语言,二者对比,给人以“河水”向“海水”变迁的感觉,正像地球曾经有过的海洋生命爆发的时代一样,今天的WWW会不会也在上演着这一幕?
今天的开发者也许非常不幸,对我们这一代而言,这种不幸更甚!我们面对的是积累十年的技术,很可能被无情的抵消,一个结构十分复杂、综合的GUI框架,在过去,也许是一个很大的C++工程才能胜任,在今天,完全可以归结为一段简单的XML描述,这是一种变迁吗?如果是,应用软件页面化,就是这场变迁的开始!我们看一个XML段落:
<configuration>
<appSettings> </appSettings>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="bin;usercontrol;component;doctemplate"></probing>
</assemblyBinding>
</runtime>
<!-- -->
<Tangram MainAssemblyLib="TangramMainFrame" MainFrameAssembly="TangramMainFrame.Application" ExternalAppCOMComponent="" Tag="officexp">
<Caption>Welcome To Tangram World!</Caption>
<WorkSpace > </WorkSpace>
<Background Type="html">background.htm</Background>
<Registry Key="TgmExDotNetMainFrame2" StdProfileSettings="4"></Registry>
<Skin>Merlin ENI\Merlin ENI.uis</Skin>
<TangramToolBar>
<MenuList>
<MenuItem Caption="ksks" Name="menu1" ID="33" Icon="c:\a.ico">
<MenuItem Caption="kk&Menu" Name="file1" ID="31" Icon="c:\a.ico">
<MenuItem Caption="oooChildMenu1" Name="file1child1" ID="57600" Icon="c:\a.ico">
</MenuItem>
<MenuItem Caption="extendmenu1" Name="file1child1" ID="19010" Icon="c:\a.ico">
</MenuItem>
<MenuItem Caption="extendmenu2" Name="file1child1" ID="19010" Icon="c:\a.ico">
</MenuItem>
<MenuItem Type="separator">
</MenuItem>
<MenuItem Caption="ChildMenu2" Name="file1child2" ID="33" Icon="c:\a.ico">
<MenuItem Caption="oooChildMenu1" Name="file1child1" ID="57600" Icon="c:\a.ico">
</MenuItem>
<MenuItem Type="separator">
</MenuItem>
<MenuItem Caption="ChildMenu2" Name="file1child2" ID="33" Icon="c:\a.ico">
</MenuItem>
</MenuItem>
</MenuItem>
<MenuItem Caption="NewFile" Name="file2" ID="57600" Icon="c:\a.ico">
<MenuItem Caption="ChildMenu2" Name="file2child1" ID="33" Icon="c:\a.ico">
</MenuItem>
<MenuItem Caption="ChildMenu2" Name="file2child2" ID="33" Icon="c:\a.ico">
</MenuItem>
</MenuItem>
</MenuItem>
</MenuList>
<ImagelistList>
<ImageList Name="list1" ImageHeight="32" ImageWidth="32">
<Image File="d:\KuGooMusic.ico" ID="1" Type="icon"></Image>
<Image File="d:\icon\0.ico" ID="1" Type="icon"></Image>
<Image File="d:\icon\1.ico" ID="1" Type="icon"></Image>
</ImageList>
<ImageList Name="list2" ImageHeight="16" ImageWidth="16">
<Image File="d:\yy.bmp" ID="1" Type="bmp"></Image>
<Image File="d:\icon\7.ico" ID="1" Type="icon"></Image>
</ImageList>
</ImagelistList>
<ToolBarList>
<ToolBar Name="toolbar1" ButtonWidth="40" ButtonHeight="40" IconWidth="32" IconHeight="32" ImageList="list1">
<Button Caption="new file" Name="newfile" ID="30" Type="Button" Icon="0"></Button>
<Button Caption="new file" Name="newfile" ID="30" Type="separator" Icon="1"></Button>
</ToolBar>
<ToolBar Name="toolbar2" ButtonWidth="19" ButtonHeight="22" IconWidth="32" IconHeight="32" ImageList="list2">
<Button Caption="new file" Name="newfile" ID="57600" Type="Button" Icon="0"></Button>
<Button Caption="new file" Name="newfile" ID="5760" Type="Button" Icon="1"></Button>
<Button Caption="new file" Name="newfile" ID="5760" Type="separator" Icon="2"></Button>
</ToolBar>
</ToolBarList>
</TangramToolBar>
<Window>
<TangramNode Name="sp1" ID="TangramLiteTabWnd.CTangramLiteSplitterWnd" Width="" Heigh="" Tag="" Style="">
<Row>
<TangramNode Name="fm1" ID="mscomctllib.listviewctrl.2" CnnID="" Caption="fm1" Width="86" Heigh="483" Tag="" Style="">
</TangramNode>
<TangramNode Name="sp2" ID="TangramLiteTabWnd.CTangramLiteSplitterWnd" Caption="sp2" Width="514" Heigh="483" Tag="" Style="">
<Row>
<TangramNode Name="fm2" ID="TangramUserCtrl#TangramUserCtrl.TangramLitePropertyGridCtrl" Width="514" Heigh="152" Style="">
</TangramNode>
</Row>
<Row>
<TangramNode Name="tb1" ID="TangramLiteTabWnd.CTangramLiteTabbedFormView" Width="514" Heigh="324" Tag="" Style="" >
<Pages>
<TangramNode Name="fm3" ID="testvbctrl.ctrl" Caption="fm3" Width="229" Heigh="224" Tag="" Style=""></TangramNode>
<TangramNode Name="fm4" ID="forms.form.1" Caption="fm4" Width="457" Heigh="224" Tag="" Style=""></TangramNode>
<TangramNode Name="fm5" ID="forms.form.1" Caption="fm5" Width="229" Heigh="224" Tag="" Style=""></TangramNode>
<TangramNode Name="MDI2" ID="MDIView" Caption="MDI" Width="457" Heigh="224" Tag="" Style=""></TangramNode>
</Pages>
</TangramNode>
</Row>
</TangramNode>
</Row>
</TangramNode>
</Window>
<TangramDoc></TangramDoc>
</Tangram>
<TangramControlBar>
<ControlBar Name="Bar1" Caption="Bar1">
<TangramNode Name="Name0" ID="TangramLiteTabWnd.CTangramLiteSplitterWnd" Width="100" Heigh="150">
<Row>
<TangramNode Name="Name1" ID="wmplayer.ocx.7" CnnID="" Width="210" Heigh="267">
</TangramNode>
<TangramNode Name="Name2" ID="forms.form.1" CnnID="" Width="89" Heigh="267">
</TangramNode>
</Row>
<Row>
<TangramNode Name="Name3" ID="forms.form.1" CnnID="" Width="210" Heigh="247">
</TangramNode>
<TangramNode Name="Name4" ID="TangramLiteTabWnd.CWndSliderView" Width="89" Heigh="247" ActivePage="0">
<Pages>
<TangramNode Name="Name5" ID="forms.form.1" Caption="xxxxx66666xxyyyyyyyy" Width="100" Heigh="150">
</TangramNode>
<TangramNode Name="Name6" ID="forms.form.1" Caption="xxsssssssxxyyyyyyyy" Width="100" Heigh="150">
</TangramNode>
</Pages>
</TangramNode>
</Row>
</TangramNode>
</ControlBar>
</TangramControlBar>
</configuration>
上面这段XML代码,完全可以在运行时将其解释为一个真正的桌面软件:
(一:页面化软件范例,桌面软件是可以用XML描述的)
这一点意味着什么?也许,实现一个类似的软件结构,真的会与现在的Web开发者写一个HTML页面相当。应用软件页面化是指将特定的桌面软件XML化,使得其软件结构可以用十分清晰的XML方式清晰描述,然后在运行时给予复原,这一技术处理,将极大地简化应用软件的写作,并使得动态软件成为可能。如上图所显示的GUI结构,通常的方案就是用代码技术实现,今天,这个传统的软件开发模式就要没落了,WWW进化十年催生的新技术将使得类似的工作完全可以与HTML开发媲美。我们面临的时代,将变迁为以文档为核心的时代,对用户可见的一切,基本上都可以表示为某种类型的文档,二进制为软件主体表现形态的阶段,已经开始渐渐失去其中心地位。
然而,今天的开发者,又是非常幸运的,亲历一个时代的变迁并不是一件容易赶上的事情,Web开发与桌面软件的开发在方式上正在逐步缩小差别,我们即将成为消除差别的见证者。这种差别的消失,将使得WWW上出现大量的有别于HTML的“物种”,因此,软件的定义有可能发生改变以适应WWW的变化。在与几位开发浏览器的朋友多次探讨之后,我意识到,浏览器应用是十分重要的应用,也许,浏览器应该成为一个应用的“起点”,也就是说,在特定意义之下,任何一个软件都可能成为一个“浏览器”。现在的软件开发,还存在很清晰的界线,这种界线的存在使得软件彼此不同,这是传统开发模式带来的固有弊端。浏览器的开发能否成为消除这个弊端,进而促使“柏林墙”倒塌的导火索?大约一周前,我曾经拜访Maxthon,毋庸置疑,在国内众多的第三方浏览器之中,Maxthon是当之无愧的王者,隐约之中,可以感觉Maxthon在酝酿着一些变化,在WWW内容为王的时代,任何人都可能打算尝试变化。曾经有过考虑,也打算开发一个第三方浏览器,当考察几款第三方浏览器后,这个打算被否决了,原因之一是大家的工作相似的地方太多了,尽管“各村有各村的高招”,但除了一支独秀的几款,其他产品很难有所作为,当然,这是个人观点。根据个人的观察,国内的浏览器开发也许陷入了一个“歧路”,大家将侧重点几乎都放在“细节”方面,强调“用户体验”,例如,“鼠标手势”、广告拦截、Flash处理等等,这些东西是Microsoft浏览器的盲点,也许就是这些盲点的存在,使得第三方有了生存的空间。我们习惯了在本土内进行厮杀,在一些细节上,大家彼此的消耗着,几乎在做同样的事情。在今天的硬件条件下,我们将技术细节定位在资源消耗、速度对比等方面,我们没有在观念上产生突破,我认为这是很不可理解的事情。之所以如此,也许是因为我们没有意识到我们是身处大海之中!出于殖民的需要,西方人勇于探索大海,而我们却封疆闭土,没有观念上的突破,导致我们的定制化浏览器彼此越来越像,最终结果可想而知……。
浏览器能否作为一个应用开发的起点?这是我一直在思考的问题,也是一年来为之努力的目标。就软件的可扩展性而言,IE并不比FireFox差,即使今天的IE7,在插件开发的基本方法上依然停留在1996年的SDK水平上,这说明什么?只能说明策略上,IE7之前,Microsoft没有重视这个问题。我认为,绝大多数的第三方特色,在现在的IE框架上,都是可以实现的,从这个方面理解,许多第三方浏览器能够存在,的确是很奇怪的现象。就基础框架而言,IE本身的架构,第三方是无法与之相比的,那么,Microsoft失误了吗?Microsoft插件开发的门槛过高也许是导致IE不容易扩展的关键原因。第三方浏览器并没有在本质的一面增强IE,许多安全方面的问题,还是借助IE本身,因此,基本就是IE的另外一个“壳”。我考虑IE开发的出发点也许与绝大多数浏览器开发者是不同的,IE占据绝大多数的市场份额是不争的事实,因此,如何更好的利用IE,就成了一个思考点。如果能够充分利用IE的好处,使得开发者能够构造更好的网络软件,不失为一个明智的策略。那么,IE有什么值得利用的优势?我认为至少有以下几点:
1、 IE具有最广泛的用户群体,这是最重要的理由;
2、 IE的HTML模型可以使得软件得到极大的灵活性;
3、 IE具备一个健壮的脚本描述引擎,这个引擎,明显的优于开发者自身集成的脚本引擎;
4、 IE自身具有健壮的插件体系,对软件开发者而言,是一个天然的资源;
5、 在IE框架内,软件功能的“柏林墙”几乎不存在;
6、 可以直接将本地软件提升为WWW风格的软件系统。
基于以上几点,我认为:
1、 建立一个灵活的寄居在IE框架之上的开发环境是十分必要的;
2、 为IE以及IE控件提供一个灵活的扩展框架,可以良好的促进IE以及第三方应用的开发;
3、 第三方应用开发与IE的有机集成,会给WWW提供新的活力。
那么,这些目标能否实现呢?答案是肯定的。
在一个月前,Microsoft正式发布了IE7,这是5年来IE的一次重要升级。与IE6相比,IE7明显“漂亮”许多,在这里我们看到,Microsoft不再固执,已经采纳了一些备受用户喜欢的第三方特征,IE7与IE6一样,本身是多线程的,只不过显得更紧凑。在许多开发者的视界里,IE是一个浏览平台,大多数情况下,IE是用来浏览网页的。但我们深入其内部的时候,我们可以得出一个结论,那就是,IE7是一个绝好的GUI框架,即使是一个很优秀的技术团队,企图开发一个与IE7相当的软件框架都是相当困难的。我们非常高兴的看到,IE7给GUI扩展提供了很广阔的天地:
(二:IE7,程序员的软件集成平台)
针对每一个标签页,开发者可以加载完全不同的GUI扩展,看上去很像一个类似“Eclipse”类型的集成环境,因此,以下问题就浮出水面:
1、 我们如何有效的进行针对IE的GUI扩展;
2、 一旦扩展成为可能,扩展模型能够与IE的内部机制(例如,内置的脚本引擎)相容吗?
3、 扩展界面能否自然的与HTML交互操作?
4、 我们考虑的扩展技术与主流的开发工具之间的“gape”是否很大?
5、 适合什么样的开发者群体?
6、 能否协调的建立桌面组件与WWW服务之间的桥接?
FireFox针对开发者提供的一个重要工作就是一个基于XML的界面描述引擎,即众所周知的XUL,关于这一点,Microsoft现在没有对应的工作,由于缺乏类似的技术,综合、复杂的GUI扩展就成了IE的一个缺陷,因此,为IE提供一个类似的引擎,就成了解决问题的关键。
考虑到Microsoft平台上开发工具的特点,一个与XUL接近的GUI引擎必须能够充分发挥主流开发工具的效率、生产力,因此,对Visual Studio 6以及Delphi、VS2005等的支持就成为一个必须考虑的问题。一般说来,一个GUI框架的轮廓,是很容易被XML清晰描述的,因此,我开发的出发点就选择在GUI框架的XML描述与创建这一点上。通常,人们对平面区域的规划、利用,基本基于两种基本的结构:1:Splitter;2:分页行为的标签出口,比较综合的GUI架构基本就是如上两类结构的复合,问题的难点是标签窗口,这类窗口的风格比较多,因此,对应的XML节点也就相对复杂一些。一旦框架描述完毕,具体的内容就可以“填充”了。针对MFC开发者,我们考虑其自身的特点,允许这类开发者将“原子”级别的组件实现为C++的CView对象,针对VB6开发者,允许开发者直接使用VB6开发的ActiveX控件以及Active Document对象,特别,我们对.NET支持作了大量的工作,允许开发者直接使用大部分.NET User Control对象,如图:
(三:集成COM、.NET组件)
为了更加方便开发者在IE基础上打造自己的GUI扩展,一个集成在Office里的Form模型被引入IE的扩展环境,开发者可以直接用于IE的定制化开发,这个思路,受MS OutLook的启发,在OutLook中,其定制化开发的UI设计采用Form设计机制:
(四:OutLook扩展开发)
我们在IE的个性开发中实现类似的开发技术:
(五:所见即所得的定制化设计)
由于采用XML技术,使得GUI部分的描述与HTML页面结构极为接近,这样做的结果是:在IE浏览器内部扩展了另一部分内容,这部分内容是针对IE浏览器UI部分的,与HTML不同的是,这部分内容完全是桌面软件组件构成的,这样,浏览器可浏览的内容扩大了,同时也使得浏览器可以灵活的定制,开发者可以自如的在浏览器基础上打造自己的软件集成开发环境。