打造免费个人计算机安全系统

最近一阵子,我试用了一些市面上常见的免费计算机安全相关软件,找到了两个较为适合个人计算机上使用的杀毒软件。我家用的电脑正在使用这两款杀毒软件,现在推荐给对杀毒软件不是太了解的计算机用户。

首先是小红伞(Avira),这是一款德国产的杀毒软件。它是我试验过的几款杀毒软件里杀毒率最高、系统资源占用也不高的软件。小红伞针对家庭用户有三个版本,最常用的是个人免费版和个人专业版。个人免费版已经包含了完整的监视和杀毒功能,足够个人使用了;个人专业版增加了清理间谍软件、快速升级等功能,其实用处并不太大。个人专业版是收费的,但是用户只要到小红伞的主页上递交一份申请,就可以免费获得它的使用密钥。小红伞是从傻瓜型软件,只要装上就不用再管它了。用户不需做任何配置,遇到病毒它会自己处理。适合任何用户。

另一款杀毒软件ThreatFire,原产于美国。这款杀毒软件有两个版本,个人版和商用版。两个版本功能基本相同,都具备完整的监控查杀功能。主要区别在于个人用可以免费;而商用则要收费。ThreatFire的病毒扫描功能很一般,略强于国产的X星、X霸杀毒软件,但是还不能与小红伞、卡巴斯基等相提并论。它真正擅长的是病毒监视功能。它是通过行为而非特征码来判断病毒的,类似国产的"微点"。通过行为判断病毒可以不依赖于庞大的病毒特征库,因此它在运行时占用资源极低,可以抵御新出现的未知病毒。ThreatFire的另一个非常有特色的功能是其社区功能,每个加入社区的计算机受到未知威胁后都会把信息发送给ThreatFire的服务器。ThreatFire通过统计数据就可以判断某一威胁是有害的病毒,还是一般正常操作。这样一来,不必专业人员参与,也可以自动完成定义病毒的工作。这应该是个前景看好的尝试。ThreatFile与小红伞相比占用资源低,适合给破机器用。但它的配置比较复杂,适合有一定软件知识的用户使用。

我现在是这两款软件共同使用,99%以上的已知病毒都可以被小红伞拦截住,其余漏网之鱼会被ThreatFire兜住。

不过,现在病毒还没泛滥到不可收拾的程度,并非其它杀毒软件就起不到保护电脑的作用了。一般电脑上按装上一款主流杀毒软件,就可以挡住绝大多数的威胁了。下面是我整理的一张表格,列出的都是我试用过的完全免费软件。如果是最近两三年购买的电脑,只要在每一栏中选择一款软件安上,再不用担心病毒侵犯了。

以查杀已知病毒为主的杀毒软件

小红伞AVGavist趋势360杀毒

病毒防御软件,拦截新病毒

ThreatFire

辅助安全软件,清除流氓软件,检查系统漏洞等。

超级巡警金山清理专家Windows清理助手360安全卫士

防火墙

XP、Vista系统自带的防火墙

对于使用年限较长,配置较差的电脑,同时运行几款安全软件对系统的速度影响很大。对这类电脑而言,可以仅装一个ThreatFire防病毒。查杀病毒以及辅助的功能没必要频繁运行。这些功能可以交给网上杀毒工具(百度安全中心金山在线杀毒)、绿色杀毒软件(大蜘蛛绿色版)和绿色辅助安全软件(超级巡警绿色版)去完成。这些绿色软件平时不运行,不占用计算机内存和系统资源。只要每隔几个星期,进行下载更新,并运行这些绿色软件给电脑做一次扫描检查即可。

我刚参加工作时,公司里的电脑还处于奔III时代,运行的是Windows 98操作系统,并且都没有安装杀毒软件。不过,那时候病毒的主要传播途径就是文件拷贝,只要不乱安装和使用盗版软件,基本不太会中毒。我的电脑很长一段时间都平安无事,直到有一天运行了同事通过邮件发给我的一个小程序,结果,没多久电脑就瘫痪了。

公司就在一家大型超市隔壁,那里有正版的杀毒软件卖。于是我立即去买了一套正版江民杀毒软件,那时好像叫KV200。江民杀毒软件是我大学时代所用过的最牛的杀毒软件,所以我想也没想就花了将近300块钱买了它。可惜,这个软件在易用性上实在是差劲了点。当时已经是Win98的天下了。它还在使用DOS界面,必须随软盘一起运行,也没有监视功能。所以没多久,就被我淘汰了。

公司的电脑后来全部安装了Mcafee企业版防病毒软件。公司的电脑在其保护下,之后七八年没中过毒。所以,我一直认为Mcafee非常强大,给我家里电脑安装的也是同一款杀毒软件。可是,去年,我家里开通了宽带上网,网络开通还不到一个星期,我的电脑就中毒身亡了。为啥同一款杀毒软件在家里就不起作用了呢?根据我后来的调查发现,Mcafee企业版的强大之处在于网管可以为其指定各种安全规则,并发布到终端机上去。比如,不允许运行临时文件夹下的任何可执行文件、不许使用P2P软件等。但我家里的电脑是常常用来娱乐的,有了这些限制,我没法上网玩游戏、没法下载电影了,电脑也就等于没用了。所以,我移除了家用电脑上的Mcafee所有限制。没了这些规则限制,Mcafee的安全性一下子变成二流水平了,根本抵不住病毒的进攻。这件事也让我意识到,一个防病毒软件是有适用场合的。像Mcafee的主要客户都是大企业,它的产品自然会侧重企业应用而不是家庭用。

去年,我的电脑牺牲没多久,生产360安全卫士的公司就宣布要提供永久免费的杀毒软件。还宣布杀毒软件的趋势就是免费,他们的言论引来国内多家杀毒软件公司的炮轰。我非常同意360的观点,针对个人市场的杀毒软件肯定会逐步走向免费的。实际上,现在市面上的免费杀毒软件非常多。但产品免费,公司一样可以从中获利,比如在产品上携带广告、利用免费软件收集信息,提供给商用软件,再从商业软件上盈利。

我在为自己家用电脑寻找新杀毒软件的过程中,试用和比对了数款常见的杀毒软件。经过比较,我发现免费的杀毒软件,其功能与效果,一点也不比收费的差。尤其是国产的三大杀毒软件,他们面向国内客户都是收费的,但效果与国外的几款免费软件比,甚至不在一个档次上。这确实令人失望。

技术文章和讨论》目录

Advertisements

计算机病毒防治的原理和未来发展

   本来我的专业与计算机病毒没有什么联系,而且公司的计算机安全工作做得不错,我的计算机有七八年没中过毒了,所以我一直没怎么认真留意过计算机病毒。前一阵子放假回家,帮助姑姑去修理电脑,发现她的电脑是被病毒搞坏的。然后帮她安装杀毒软件,清理系统,总共查出了二十多个流氓软件和五十几个病毒、木马。我这才意识到时下病毒还是蛮猖獗的,电脑上没个杀毒软件保护着绝对不行。

   这也勾起了我对病毒的兴趣,于是花了几天时间,阅读了一些有关病毒与杀毒技术的文章。下面总结一下这几年来杀毒技术的发展,以及我对这项技术未来发展的一些想法。在查阅相关文章时,看到一位网友以城市中的警察和小偷来比喻杀毒软件与病毒。我觉得这是个非常恰当的比喻,所以我在这里也借用这个比喻:

科普版

寓言版

电脑里除了我们所需的那些软件之外,有时还会混进一些专门搞破坏的软件——计算机病毒。计算机普及之后,使用计算机的人往往不是计算机专业人士,他们并不了解程序运行的原理也分不清楚哪些是正常的程序,哪些是病毒程序。所以,我们需要使用专门的杀毒软件来清除危害系统安全的病毒程序。

并不是城里每个人都是好人,有些人是专门混进来搞破坏的,城堡的主人不见得认识城中每个居民,他根本不清楚哪些是良民,哪些是坏蛋。于是,城堡的主人决定雇佣一些专职的警察来负责抓捕城中坏人,维护城堡的安全。

杀毒软件识别病毒的经典方式是特征码识别,通过病毒文件特有的一些属性、内容等找到它。比如说,文件名就是一个特征,某些病毒的文件名是固定的,所以一看到这个文件,就知道它是病毒。

作为警察,最简单的找到坏蛋的方法是:拿到一份公安部颁发的通缉令,上面列有所有已知坏蛋的姓名。警察们检查城中每一个居民,如果他出现在通缉令的名单中,就将其逮捕。

病毒可以轻易地给自己换个名字,以避开杀毒软件的检查。所以,大多数杀毒软件不用文件名做特征值,比文件名更不容易改变的就是病毒程序中比较关键的一段代码。比如病毒专用于搞破坏的那段代码,正常程序是不应该有这种代码的。而且,这段代码相对稳定,不论病毒其它部分怎么改,它要完成它的使命,就必须要有这段代码。

然而,名字是最容易改的了,坏人造个假身份证非常容易。所以,优秀警察在抓坏蛋的时候不是按照他的名字来判断。他们的通缉令上列出的是小偷的一些外观特征。比如,某小偷的特征是手持一把作案工具"螺丝刀",正常人不会时刻拿着一把螺丝刀。于是,警察把凡是手里拿着螺丝刀的居民都当作小偷抓起来。

病毒为了进一步躲避杀毒软件,需要隐藏自己的特征码。常用的方式是把自己关键的代码部分进行加密,不运行时,杀毒软件就检验不到相应的特征码。病毒运行起来之后,再把其具有破坏性的代码解码出来并运行。病毒如果只采用一种加密方式,加密后的代码很快就会成为杀毒软件追查的新特征码,失去作用。所以狡猾的病毒可以采用随机加密的方式,衍生出无数变种。

小偷也不笨,也会改变特征来对付警察。平时不犯案的时候,完全可以把螺丝刀揣兜里,作案时候再掏出来就是了。此外,再时不时换几件外衣,警察就更认不出来了。

对付变种病毒,有些杀毒软件就是简单地把变异后的新特征码添加在自己的病毒特征码库中。但是这种简陋的方法效率较低。所以,有的杀毒软件虽然病毒库非常庞大,杀毒能力却一般。能力更强的杀毒软件可以剥去常见的伪装外衣找出病毒。具有启发式查找能力的杀毒软件还会为病毒创造一个虚拟运行环境,让可疑程序在其中运行自己的代码,直到病毒露出马脚。

对付这种化了装的小偷,笨警察通过增加罪犯特征信息的方式来稽查坏人,比如在通缉犯特征列表里增加:穿黑大衣,左脸颊有块痣的;穿花格上衣,绿短裤,凉拖鞋的;穿白衣服,叼根烟,手上有块疤的,等等。聪明警察不用记那么多,聪明警察把所有被检查者的衣服都脱掉,再搜身,搜到螺丝刀的就是罪犯。聪明警察还知道引诱罪犯露出原形,比如把保险箱放在某人面前,而那人见到保险箱就立刻掏出来一把螺丝刀,则这人肯定是罪犯。

用于盗版的注册机一类的软件,通常需要把自己挂到别的程序上,或者从别的程序进程里读数据出来。这些行为跟病毒干的事情非常类似,所以注册机程序经常被杀毒软件认作是病毒。

警察有时会抓错人的,比如看见锁头习惯性掏出螺丝刀的不一定都是小偷,也可能是开锁匠。

早期,杀毒软件的主要工作是查杀磁盘上的病毒。扫描磁盘上每个文件,检查其中是否有与病毒库中特征码相同的代码。若找到,则清除病毒。现在的电脑硬盘都比较大,一个电脑里可以包含几百万个文件甚至更多。把这些文件扫都描一遍,可能要耗时数个小时,占用了大量计算资源。

最初,警察稽查坏蛋的方法是挨家挨户搜查。当年城堡规模都比较小,全搜查一遍也花不了多少时间。但现在城市动则几百万人口。挨家挨户的去搜查效率实在是太低了。

病毒只能通过网络、文件拷贝等方式进入一台计算机,只要在文件进出本机时进行监察,就可以杜绝病毒的传播。同时,存在于硬盘上的一个病毒,如果不被运行或转移,也不具备任何破坏性。所以,保证系统安全并不需要检查硬盘上的每个文件,只要监管住主要的几个地方就可以了。

当前,口碑最好的几款杀毒软件中,就有些是以查杀效果见长;而有些是以监控效果闻名。如果监控的当,让病毒根本没有机会进入电脑或在电脑上运行起来,查不查硬盘也就无所谓了。

其实,警察并不需要经常性的普查每个人,也可以保证城堡的安全。他只要把守住关键的区域就可以了,比如,在城门、城中心广场等场所检查每个进出的人;在银行检查每个有资金流动的户头等。如果坏蛋老老实实呆在家里是不会对治安产生威胁的,只要在他干坏事前抓住他就可以了。


 

以前,病毒制造者往往只是想炫耀一下自己的编程水平,他们通常不会从制造病毒中获得经济利益。所以,新病毒出现的速度并不是很快。然而,这几年,病毒产业突然发现了新的利润增长点:偷取计算机主人信息、资料、密码等,然后卖钱。在利益的驱动下,病毒制造业迅速发展,新病毒增速每年都翻几番。

最初,混进城的坏蛋只是想搞搞破坏。这种损人不利己的事只有少数变态才会做,所以警察的任务并不太重。但后来,坏蛋们意识到,可以从城中的银行偷钱出来。于是,各种小偷蜂拥而至。

新病毒数量的膨胀造成了查毒软件病毒特征库的膨胀。巨大的特征库占用了大量资源,在存储空间上需要占用更大的内存,比对过程也需要更长的计算时间。

面对着那拿丝刀的、拿扳手的、拿锤子的、拿自行车条的……各式各样的小贼,采用传统的按通缉令比对的方式,即便是聪明警察也快要招架不住了。通缉令已经长得令人眼花缭乱了。

解决这一问题的办法之一是云存储和云计算,这正是最近一些杀毒软件公司热炒的概念。杀毒公司拥有比客户更强大的计算和存储资源,所以,具有云计算功能的杀毒软件只把最常见的部分病毒的特征码放到被保护的计算机上。杀毒软件若发现被保护的计算机上有可疑文件,不能确认是否有病毒,则把可以文件交给杀毒软件公司。杀毒软件公司的服务器拥有庞大完整的病毒特征库,可以对可疑文件进行完整检查,以确认该文件是否包含病毒。然后将结果返回给杀毒软件客户端。

为了减轻警察们的负担,公安部决定只把近期破坏性最大的通缉犯列表发给各地警察。警察若发现不在列表中的可疑分子,可以将他们直接交给公安部。公安部有完整的通缉犯名单,并且可以调动更多的警察。他们可以以最快的速度查出可疑分子的身份。

实际上,病毒还有比病毒特征码更为本质、稳定的特征,就是病毒的行为。病毒千变万化,但表现出来的行为特征就只有那么几条。比如自我繁殖和传播、试图取得计算机的控制权、试图查看改变其它可执行文件、试图访问某些数据等等。

外部特征并不是罪犯的最本质特征。之所以称其为罪犯,是因为他有犯罪行为。

监视病毒的特征码,一定要在病毒被人发现,提取了它的特征码之后,才能对其进行监视。这时,病毒可能已经造成某些损失了。更何况,现在新病毒的增长速度远远尝超过杀毒软件公司更新病毒特征库的速度。杀毒公司对新病毒的反应速度只会越来越慢。

以外观特征来识别罪犯,必须要等到该人被确认为罪犯,公安部门整理出他的外观特征后,才能提供给其他警察进行比对。但是,对于没有案底的犯人来说,警察就无法将其识别出来了。一个人一旦进了通缉令,说明他已经为社会带来过危害了。

监视病毒的行为,可以彻底解决提取病毒特征码带来的防毒滞后问题。监视病毒行为的软件,可以在不知道病毒特征码的情况前,根据一个软件的行为来判定它是否是病毒。

有没有更有效的制止犯罪的方法呢?可不可以在罪犯还没造成任何损失的情况下就将其制服呢?这也是有的,这就是对各种犯罪行为进行监视。

监视程序行为的软件早已有之。最简单的监视方法是控制住系统中所有关键位置,比如某些文件夹,某些注册表的键值等。凡是试图改变这些部位的操作都会被暂时阻拦住,然后,询问电脑操作者是否允许这些操作。在得到计算机使用者的许可后再进行操作。时下,流行的计算机辅助软件都有这个功能。安装了它们,就会经常收到他们弹出的提示窗口,询问是否允许某某操作。问题是计算机的使用者也不一定知道这些操作是什么意思,是否安全。所以这类监视大多数情况下除了增添麻烦,并无任何意义。

最初级的监视方式是对城中的关键区域进行监控,比如说银行、交通要道等。凡是试图进入银行的人都会被拦阻,然后询问主管,是否允许其进入银行。不幸的是,主管并非上帝,他也不知道进入银行的人是为了正常业务,还是企图抢劫。所以,这种监视方法,除了增加主管的负担之外,并没有加强城堡安全。

近年来,也有一些行为监控软件中添加了智能判断的功能。他们可以忽略那些安全的操作,只把病毒的作为显示给电脑操作者。如果电脑使用者选择清除病毒,它们还可以把病毒的所作所为都复原。这些软件也被称为主动防御型的防毒软件。

好在,最近出现了一批具备智能判断能力的警察。他们并不阻拦人们进入银行,而是只在有人行窃时,才将其逮捕,并追回赃款。

主动防御型的防毒软件与传统按照特征码查杀病毒的软件相比,是个新兴技术,很多方面还有待完善,所以并不是在所有情况下都比传统杀毒软件更好。但是,主动防御型的防毒软件可以彻底脱离病毒特征码进行工作,可以及时阻隔新出现的病毒。它更适应当前新病毒数量激增的形式,所以可以肯定地说,它会是将来所有防杀毒软件的发展方向。实际上,很多传统的杀毒软件也已经开始在其中添加主动防御功能了。

新警察虽然技术水平更高,但缺乏经验,有时候并不比老警察表现更好。不过,具有智能识别犯罪行为的警察可以彻底摆脱公安部的通缉令,独立工作。并且可以在一个人初次犯罪时就将其拦截。这必然是今后所有警察的培训目标。


 

计算机的出现的是为了让人们从简单重复的工作中解脱出来。但是,就防病毒这项工作来说,人们目前还是无法彻底从中摆脱出来,完全交由计算机去自动完成。尽管目前优秀的杀毒软件可以不需要终端用户的参与就独立维护终端计算机的安全,但它的背后还是离不开杀毒软件公司对其进行不断的维护。不论是升级病毒特征库,还是制定新的防病毒行为规则,都离不开专业人员的参与。
将来,新病毒的行为也会变化得越来越快,令杀毒软件编写人员应接不暇。所以,早晚有一天,计算机应该可以脱离人类的帮助,独立地抵御病毒的入侵。

考虑一个有机的生命体,比如一只小兔子,它不需要外界(比如上帝)的帮助,就可以独自抵御疾病。

计算机进一步发展,肯定也会需要建立一套类似生物体内免疫系统一样的机制,用来抵御计算机病毒。免疫系统始终监视计算机的健康状况,一但健康出现问题,比如可使用资源异常减少,磁盘被垃圾文件占据等,则将近期新进入计算机的程序当作引起系统异常的罪魁祸首加以清除。如果清除了这些文件后,系统重回健康状态,则再也不允许这类文件进入系统。

当某种病菌第一次进入小兔子的身体后,小兔子不会立即对其作出反应。一旦病菌繁殖起来,小兔子的免疫系统就会意识到这是个危险的外来物,于是开动免疫机能将其消灭。小兔子的免疫系统是会记住入侵的病菌的,若同一种病菌再次侵入。小兔子的免疫系统会直接将其消灭。

有的病毒一旦发作,可能就很难将其彻底清除。但是在一台电脑被病毒破坏至崩溃之前,至少还可以把病毒的信息发送给其它电脑。这样,其它电脑可以在病毒发作前,就识别出它并将其清理。

有些病菌是非常厉害的,单个生命体无法抵御其入侵。但是,所有生命体组成的物种却不至于被病菌消灭。这是因为个体虽然在病菌的进攻下死去,但它却把病菌入侵的信息提供给了其它个体。在这方面人类的表现是很有代表性的。某些人染病死去,其他人可以通过研究死去者获得抵御这种病菌的疫苗。疫苗能够帮助所有其它个体抵御这种疾病。

技术文章和讨论》目录

正常访问Google网页快照的方法

转载的,原文在:http://www.williamlong.info/archives/634.html
真不知道为什么,要把网页快照封掉!


  目前,Google的网页快照几乎完全无法访问,对Google的使用者来说非常不便,本文将从Google网页快照无法访问的原理出发,逐步分析出一个可以正常访问Google网页快照的方法。

  根据Google自己的介绍,“Google储存网页的快照,当存有网页的服务器暂时出现故障时仍可浏览该网页的内容”。因此说,网页快照服务器本身出问题的可能性非常小,否则就成笑话了,那么为什么我们都无法访问Google网页快照呢?我们只要分析出不能访问的具体原因,就能知道正常访问 Google网页快照的方法。

  举个例子分析一下,比如使用Google来搜索“搜索引擎”这个词,可以看到如下图的界面。 

  这时我们看一下“网页快照”的URL地址,可以发现是下面的地址:

  http://72.14.235.104/search?q=cache:aPVaeKi1wxcJ:www.baidu.com/+%E6%90%9C%E7%B4%A2%E5%BC%95%E6%93%8E&hl=zh-CN&ct=clnk&cd=1

  根据我们的测试,72.14.235.104这个IP是可以访问的,完全可以ping通,如下图所示,这说明网页快照服务器本身实际没有任何问题,完全可以直接访问到。 

  但是我们点击“网页快照”链接后,却出现“该页无法显示”的提示。如下图所示,这显然是关键字过滤的现象。

  为了分析出具体是什么词语影响,我们还可以在Yahoo下搜索“search?q=cache”这个词,会发现Yahoo也出现了“该页无法显示”的提示。

  现在,聪明的读者应该已经明白这意味着什么了。既然知道了原因,那么解决方法应该很简单了。就是在search?和q=cache中插入一些字符,将这个词分开即可,就可以让Google的网页快照“恢复正常”。

  还是上面提到的这个页面的网页快照,我们将“网页快照”的URL地址复制到地址栏,然后将“search?q=cache”中间插入一个“&” 符号,使得该词语变成“search?&q=cache”,这时候按下回车,我们就可以看到了久违了的Google网页快照,如下图所示。

  当然,这是分析出网页快照无法使用的原理,具体使用中,如果我们每次都这样用快照,那就显得非常麻烦了,如果大家需要频繁使用,建议安装一些浏览器的开发插件,自动将搜索结果中的字符串进行替换,这样就可以完全自动实现Google网页快照的正常浏览访问,关于详细的代码安装和下载,请查看文章《正常访问Google网页快照的插件代码》。

 

 

TIOBE 2006年6月最流行开发语言排名

    TIOBE 语言排名一个月更新一次。它的统计方法是基于全球有经验的工程师,科目和第三方厂商. 同时也参考来自google,msn,yahoo等搜索引擎计算得出的结果。当然,这个排名并不说明哪个语言绝对最好,但是它可以给你一个参考,当你构建一个新的软件系统时,应该采用什么样的语言。

    LabVIEW 位列第33,差得还很远啊。不过 LabVIEW 去年4月的排名是第39位使用率0.152%,所以还是有了明显进步的。

原文链接: http://www.tiobe.com/index.htm?tiobe_index

Position
June 2006
Position
June 2005
Delta
in Position
Programming Language Ratings
June 2006
Delta
June 2005
Status
1 2 Java 21.128% +2.56% A
2 1 C 18.253% -1.11% A
3 4 C++ 10.670% +0.95% A
4 6 (Visual) Basic 10.185% +3.41% A
5 5 PHP 9.593% +1.62% A
6 3 Perl 6.002% -4.37% A
7 8 Python 3.464% +0.66% A
8 9 C# 3.238% +0.45% A
9 7 Delphi 2.393% -0.50% A
10 10 JavaScript 1.456% +0.07% A
11 14 SAS 1.373% +0.28% A
12 24 12 * Visual FoxPro 1.036% +0.66% A
13 11 PL/SQL 0.959% -0.37% A
14 12 COBOL 0.650% -0.73% B
15 15 Lisp/Scheme 0.644% -0.22% A–
16 18 Ada 0.536% -0.14% B
17 19 Pascal 0.486% +0.00% B
18 26 8 * D 0.485% +0.13% B
19 23 Ruby 0.479% +0.10% B
20 31 11 * ColdFusion 0.453% +0.18% B

 

其它语言:

Position Programming Language Ratings
21 VB.NET 0.442%
22 ABAP 0.435%
23 Fortran 0.431%
24 dBASE 0.414%
25 Awk 0.363%
26 IDL 0.344%
27 MATLAB 0.328%
28 Prolog 0.305%
29 T-SQL 0.288%
30 Bash 0.288%
31 ActionScript 0.246%
32 Logo 0.233%
33 LabView 0.184%
34 RPG 0.172%
35 S-Lang 0.168%
36 CL 0.163%
37 REXX 0.158%
38 Forth 0.141%
39 Icon 0.134%
40 Smalltalk 0.133%
41 Tcl/Tk 0.132%
42 VBScript 0.109%
43 csh 0.097%
44 Postscript 0.096%
45 Lingo 0.091%
46 OCaml 0.090%
47 ML 0.087%
48 Objective-C 0.087%
49 Bourne Shell 0.085%
50 Maple 0.077%

 

接下50 种语言:

ABC, Alpha, APL, AppleScript, Beta, Boo, cg, Ch, Clean, Clipper, cT, Curl, dc, Dylan, Eiffel, Erlang, Euphoria, Felix, Haskell, Inform, Io, J#, Limbo, LotusScript, Lua, MAD, Magic, Mathematica, Modula-2, Moto, MUMPS, Natural, Oberon, Occam, OPL, Oz, Pike, PILOT, PL/1, Powerbuilder, Progress, Q, REALBasic, Scala, SIGNAL, Simula, VHDL, XSLT, and Yorick.

抢先试用新 Google 界面!

 首先在 http://www.google.com 里随便搜索一个词, 然后将下方代码复制到地址栏, 代替原来的地址, 然后按回车 (注意, 下面的代码只有一行, 并没有换行, 换行不会成功)

javascript:alert(document.cookie="PREF=ID=fb7740f107311e46:TM=1142683332:LM=1142683332:S=fNSw6ljXTzvL3dWu;path=/;domain=."+location.href.split(‘/’)[2].substr(location.href.split(‘/’)[2].indexOf(‘google’)));

这时会弹出一个对话框, 点击确认。

 

重新进入 google,你就能看见新版的 Google 搜索界面了 :)

Google 推出个人主页服务

我觉得主页到底是比 blog 维护起来要麻烦了些。恐怕不是 MSN Space 的对手。

我的 Google Page:http://ruanqizhen.googlepages.com/

 

Quote  Google推出線上網頁製作工具

Google在23日推出一款免費的線上網頁製作工具,透過此工具可以在幾分鐘之內製作出自己的網頁,Google將此工具命名為「Google Page Creator」, Google Page Creator 是應用AJAX技術的編輯器讓使用著能用WYSIWYG(所見即所得)的方式輕鬆建立網頁。這無疑又是一項創新,自Google走紅以來已經發佈多款創新網路服務,大概是希望把網路服務發揮到極致吧。

 

http://pages.google.com

  • 免費提供100MB的空間使用..
      
  • 不能貼語法,就算是貼上自家的Google Video也不行 
      
  • 可以上傳任何檔案
      
  • 有多種佈景主題和版面可以選擇
      
  • 可以使用HTML編輯部分網頁
        
  • GET timeout = 1 min
    (也就是一分鐘之內還沒下載完檔案會自動斷線,所以別想在這放置大型檔案或MP3囉)
      
  • 只要有 GMail 帳號 ,就可直接使用。
     
     *如何得到GMail邀請函,請上搜尋引擎看看有誰分享,向他要一個吧..CLICK
    不過這還不行,目前Google已經有限額使用此服務,所以有興趣的人要在網頁右下方的框框填上自己的Email,預定名額…

       

 

VC中的字节对齐

 
    当在C中定义了一个结构类型时,它的大小是否等于各字段(field)大小之和?编译器将如何在内存中放置这些字段?ANSI C对结构体的内存布局有什么要求?而我们的程序又能否依赖这种布局?这些问题或许对不少朋友来说还有点模糊,那么本文就试着探究它们背后的秘密。
    首先,至少有一点可以肯定,那就是ANSI C保证结构体中各字段在内存中出现的位置是随它们的声明顺序依次递增的,并且第一个字段的首地址等于整个结构体实例的首地址。比如有这样一个结构体:
 
  struct vector{int x,y,z;} s;
  int *p,*q,*r;
  struct vector *ps;
 
  p = &s.x;
  q = &s.y;
  r = &s.z;
  ps = &s;
  assert(p < q);
  assert(p < r);
  assert(q < r);
  assert((int*)ps == p);
  // 上述断言一定不会失败
    这时,有朋友可能会问:"标准是否规定相邻字段在内存中也相邻?"。 唔,对不起,ANSI C没有做出保证,你的程序在任何时候都不应该依赖这个假设。那这是否意味着我们永远无法勾勒出一幅更清晰更精确的结构体内存布局图?哦,当然不是。不过先让我们从这个问题中暂时抽身,关注一下另一个重要问题————内存对齐。
    许多实际的计算机系统对基本类型数据在内存中存放的位置有限制,它们会要求这些数据的首地址的值是某个数k(通常它为4或8)的倍数,这就是所谓的内存对齐,而这个k则被称为该数据类型的对齐模数(alignment modulus)。当一种类型S的对齐模数与另一种类型T的对齐模数的比值是大于1的整数,我们就称类型S的对齐要求比T强(严格),而称T比S弱(宽松)。这种强制的要求一来简化了处理器与内存之间传输系统的设计,二来可以提升读取数据的速度。比如这么一种处理器,它每次读写内存的时候都从某个8倍数的地址开始,一次读出或写入8个字节的数据,假如软件能保证double类型的数据都从8倍数地址开始,那么读或写一个double类型数据就只需要一次内存操作。否则,我们就可能需要两次内存操作才能完成这个动作,因为数据或许恰好横跨在两个符合对齐要求的8字节内存块上。某些处理器在数据不满足对齐要求的情况下可能会出错,但是Intel的IA32架构的处理器则不管数据是否对齐都能正确工作。不过Intel奉劝大家,如果想提升性能,那么所有的程序数据都应该尽可能地对齐。Win32平台下的微软C编译器(cl.exe for 80×86)在默认情况下采用如下的对齐规则: 任何基本数据类型T的对齐模数就是T的大小,即sizeof(T)。比如对于double类型(8字节),就要求该类型数据的地址总是8的倍数,而char类型数据(1字节)则可以从任何一个地址开始。Linux下的GCC奉行的是另外一套规则(在资料中查得,并未验证,如错误请指正):任何2字节大小(包括单字节吗?)的数据类型(比如short)的对齐模数是2,而其它所有超过2字节的数据类型(比如long,double)都以4为对齐模数。
    现在回到我们关心的struct上来。ANSI C规定一种结构类型的大小是它所有字段的大小以及字段之间或字段尾部的填充区大小之和。嗯?填充区?对,这就是为了使结构体字段满足内存对齐要求而额外分配给结构体的空间。那么结构体本身有什么对齐要求吗?有的,ANSI C标准规定结构体类型的对齐要求不能比它所有字段中要求最严格的那个宽松,可以更严格(但此非强制要求,VC7.1就仅仅是让它们一样严格)。我们来看一个例子(以下所有试验的环境是Intel Celeron 2.4G + WIN2000 PRO + vc7.1,内存对齐编译选项是"默认",即不指定/Zp与/pack选项):
  typedef struct ms1
  {
     char a;
     int b;
  } MS1;
    假设MS1按如下方式内存布局(本文所有示意图中的内存地址从左至右递增):
       _____________________________
       |       |                   |
       |   a   |        b          |
       |       |                   |
       +—————————+
 Bytes:    1             4
    因为MS1中有最强对齐要求的是b字段(int),所以根据编译器的对齐规则以及ANSI C标准,MS1对象的首地址一定是4(int类型的对齐模数)的倍数。那么上述内存布局中的b字段能满足int类型的对齐要求吗?嗯,当然不能。如果你是编译器,你会如何巧妙安排来满足CPU的癖好呢?呵呵,经过1毫秒的艰苦思考,你一定得出了如下的方案:
       _______________________________________
       |       |\\\\\\\\\\\|                 |
       |   a   |\\padding\\|       b         |
       |       |\\\\\\\\\\\|                 |
       +————————————-+
 Bytes:    1         3             4
    这个方案在a与b之间多分配了3个填充(padding)字节,这样当整个struct对象首地址满足4字节的对齐要求时,b字段也一定能满足int型的4字节对齐规定。那么sizeof(MS1)显然就应该是8,而b字段相对于结构体首地址的偏移就是4。非常好理解,对吗?现在我们把MS1中的字段交换一下顺序:
  typedef struct ms2
  {
     int a;
     char b;
  } MS2;
    或许你认为MS2比MS1的情况要简单,它的布局应该就是
       _______________________
       |             |       |
       |     a       |   b   |
       |             |       |
       +———————+
 Bytes:      4           1
    因为MS2对象同样要满足4字节对齐规定,而此时a的地址与结构体的首地址相等,所以它一定也是4字节对齐。嗯,分析得有道理,可是却不全面。让我们来考虑一下定义一个MS2类型的数组会出现什么问题。C标准保证,任何类型(包括自定义结构类型)的数组所占空间的大小一定等于一个单独的该类型数据的大小乘以数组元素的个数。换句话说,数组各元素之间不会有空隙。按照上面的方案,一个MS2数组array的布局就是:
|<-    array[1]     ->|<-    array[2]     ->|<- array[3] …..
__________________________________________________________
|             |       |              |      |
|     a       |   b   |      a       |   b  |………….
|             |       |              |      |
+———————————————————-
Bytes:  4         1          4           1
    当数组首地址是4字节对齐时,array[1].a也是4字节对齐,可是array[2].a呢?array[3].a ….呢?可见这种方案在定义结构体数组时无法让数组中所有元素的字段都满足对齐规定,必须修改成如下形式:
       ___________________________________
       |             |       |\\\\\\\\\\\|
       |     a       |   b   |\\padding\\|
       |             |       |\\\\\\\\\\\|
       +———————————+
 Bytes:      4           1         3
    现在无论是定义一个单独的MS2变量还是MS2数组,均能保证所有元素的所有字段都满足对齐规定。那么sizeof(MS2)仍然是8,而a的偏移为0,b的偏移是4。
    好的,现在你已经掌握了结构体内存布局的基本准则,尝试分析一个稍微复杂点的类型吧。
  typedef struct ms3
  {
     char a;
     short b;
     double c;
  } MS3;
    我想你一定能得出如下正确的布局图:
        
        padding 
           |
      _____v_________________________________
      |   |\|     |\\\\\\\\\|               |
      | a |\|  b  |\padding\|       c       |
      |   |\|     |\\\\\\\\\|               |
      +————————————-+
Bytes:  1  1   2       4            8
          
    sizeof(short)等于2,b字段应从偶数地址开始,所以a的后面填充一个字节,而sizeof(double)等于8,c字段要从8倍数地址开始,前面的a、b字段加上填充字节已经有4 bytes,所以b后面再填充4个字节就可以保证c字段的对齐要求了。sizeof(MS3)等于16,b的偏移是2,c的偏移是8。接着看看结构体中字段还是结构类型的情况:
  typedef struct ms4
  {
     char a;
     MS3 b;
  } MS4;
    MS3中内存要求最严格的字段是c,那么MS3类型数据的对齐模数就与double的一致(为8),a字段后面应填充7个字节,因此MS4的布局应该是:
       _______________________________________
       |       |\\\\\\\\\\\|                 |
       |   a   |\\padding\\|       b         |
       |       |\\\\\\\\\\\|                 |
       +————————————-+
 Bytes:    1         7             16
    显然,sizeof(MS4)等于24,b的偏移等于8。
    在实际开发中,我们可以通过指定/Zp编译选项来更改编译器的对齐规则。比如指定/Zpn(VC7.1中n可以是1、2、4、8、16)就是告诉编译器最大对齐模数是n。在这种情况下,所有小于等于n字节的基本数据类型的对齐规则与默认的一样,但是大于n个字节的数据类型的对齐模数被限制为n。事实上,VC7.1的默认对齐选项就相当于/Zp8。仔细看看MSDN对这个选项的描述,会发现它郑重告诫了程序员不要在MIPS和Alpha平台上用/Zp1和/Zp2选项,也不要在16位平台上指定/Zp4和/Zp8(想想为什么?)。改变编译器的对齐选项,对照程序运行结果重新分析上面4种结构体的内存布局将是一个很好的复习。
    到了这里,我们可以回答本文提出的最后一个问题了。结构体的内存布局依赖于CPU、操作系统、编译器及编译时的对齐选项,而你的程序可能需要运行在多种平台上,你的源代码可能要被不同的人用不同的编译器编译(试想你为别人提供一个开放源码的库),那么除非绝对必需,否则你的程序永远也不要依赖这些诡异的内存布局。顺便说一下,如果一个程序中的两个模块是用不同的对齐选项分别编译的,那么它很可能会产生一些非常微妙的错误。如果你的程序确实有很难理解的行为,不防仔细检查一下各个模块的编译选项。
    思考题:请分析下面几种结构体在你的平台上的内存布局,并试着寻找一种合理安排字段声明顺序的方法以尽量节省内存空间。
    A. struct P1 { int a; char b; int c; char d; };
    B. struct P2 { int a; char b; char c; int d; };
    C. struct P3 { short a[3]; char b[3]; };
    D. struct P4 { short a[3]; char *b[3]; };
    E. struct P5 { struct P2 *a; char b; struct P1 a[2];  };
 
 
 1、 sizeof应用在结构上的情况
请看下面的结构:
struct MyStruct
{
double dda1;
char dda;
int type
};
对结构MyStruct采用sizeof会出现什么结果呢?sizeof(MyStruct)为多少呢?也许你会这样求:
sizeof(MyStruct)=sizeof(double)+sizeof(char)+sizeof(int)=13
但是当在VC中测试上面结构的大小时,你会发现sizeof(MyStruct)为16。你知道为什么在VC中会得出这样一个结果吗?
其实,这是VC对变量存储的一个特殊处理。为了提高CPU的存储速度,VC对一些变量的起始地址做了“对齐”处理。在默认情况下,VC规定各成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数。下面列出常用类型的对齐方式(vc6.0,32位系统)。
类型
对齐方式(变量存放的起始地址相对于结构的起始地址的偏移量)
Char:偏移量必须为sizeof(char)即1的倍数;
int:偏移量必须为sizeof(int)即4的倍数;
float:偏移量必须为sizeof(float)即4的倍数;
double:偏移量必须为sizeof(double)即8的倍数;
Short:偏移量必须为sizeof(short)即2的倍数。
各成员变量在存放的时候根据在结构中出现的顺序依次申请空间,同时按照上面的对齐方式调整位置,空缺的字节VC会自动填充。同时VC为了确保结构的大小为结构的字节边界数(即该结构中占用最大空间的类型所占用的字节数)的倍数,所以在为最后一个成员变量申请空间后,还会根据需要自动填充空缺的字节。
下面用前面的例子来说明VC到底怎么样来存放结构的。
struct MyStruct
{
double dda1;
char dda;
int type
};
为上面的结构分配空间的时候,VC根据成员变量出现的顺序和对齐方式,先为第一个成员dda1分配空间,其起始地址跟结构的起始地址相同(刚好偏移量0刚好为sizeof(double)的倍数),该成员变量占用sizeof(double)=8个字节;接下来为第二个成员dda分配空间,这时下一个可以分配的地址对于结构的起始地址的偏移量为8,是sizeof(char)的倍数,所以把dda存放在偏移量为8的地方满足对齐方式,该成员变量占用 sizeof(char)=1个字节;接下来为第三个成员type分配空间,这时下一个可以分配的地址对于结构的起始地址的偏移量为9,不是sizeof (int)=4的倍数,为了满足对齐方式对偏移量的约束问题,VC自动填充3个字节(这三个字节没有放什么东西),这时下一个可以分配的地址对于结构的起始地址的偏移量为12,刚好是sizeof(int)=4的倍数,所以把type存放在偏移量为12的地方,该成员变量占用sizeof(int)=4个字节;这时整个结构的成员变量已经都分配了空间,总的占用的空间大小为:8+1+3+4=16,刚好为结构的字节边界数(即结构中占用最大空间的类型所占用的字节数sizeof(double)=8)的倍数,所以没有空缺的字节需要填充。所以整个结构的大小为:sizeof(MyStruct)=8+1+ 3+4=16,其中有3个字节是VC自动填充的,没有放任何有意义的东西。
下面再举个例子,交换一下上面的MyStruct的成员变量的位置,使它变成下面的情况:
struct MyStruct
{
char dda;
double dda1;
int type
};
这个结构占用的空间为多大呢?在VC6.0环境下,可以得到sizeof(MyStruc)为24。结合上面提到的分配空间的一些原则,分析下VC怎么样为上面的结构分配空间的。
struct MyStruct
{
char dda;//偏移量为0,满足对齐方式,dda占用1个字节;
double dda1;//下一个可用的地址的偏移量为1,不是sizeof(double)=8的倍数,需要补足7个字节才能使偏移量变为8(满足对齐方式),因此VC自动填充7个字节,dda1存放在偏移量为8的地址上,它占用8个字节。
int type;//下一个可用的地址的偏移量为16,是sizeof(int)=4的倍数,满足int的对齐方式,所以不需要VC自动填充,type存放在偏移量为16的地址上,它占用4个字节。
};
所有成员变量都分配了空间,空间总的大小为1+7+8+4=20,不是结构的节边界数(即结构中占用最大空间的类型所占用的字节数sizeof (double)=8)的倍数,所以需要填充4个字节,以满足结构的sizeof(double)=8的倍数。所以该结构总的大小为:sizeof (MyStruc)为1+7+8+4+4=24。其中总的有7+4=11个字节是VC自动填充的,没有放任何有意义的东西。
VC对结构的存储的特殊处理确实提高CPU存储变量的速度,但是有时候也带来了一些麻烦,我们也屏蔽掉变量默认的对齐方式,自己可以设定变量的对齐方式。
VC 中提供了#pragma pack(n)来设定变量以n字节对齐方式。n字节对齐就是说变量存放的起始地址的偏移量有两种情况:第一、如果n大于等于该变量所占用的字节数,那么偏移量必须满足默认的对齐方式,第二、如果n小于该变量的类型所占用的字节数,那么偏移量为n的倍数,不用满足默认的对齐方式。结构的总大小也有个约束条件,分下面两种情况:如果n大于所有成员变量类型所占用的字节数,那么结构的总大小必须为占用空间最大的变量占用的空间数的倍数;否则必须为n的倍数。
下面举例说明其用法。
#pragma pack(push) //保存对齐状态
#pragma pack(4)//设定为4字节对齐
struct test
{
char m1;
double m4;
int m3;
};
#pragma pack(pop)//恢复对齐状态
以上结构的大小为16,下面分析其存储情况,首先为m1分配空间,其偏移量为0,满足我们自己设定的对齐方式(4字节对齐),m1占用1个字节。接着开始为 m4分配空间,这时其偏移量为1,需要补足3个字节,这样使偏移量满足为n=4的倍数(因为sizeof(double)大于n),m4占用8个字节。接着为m3分配空间,这时其偏移量为12,满足为4的倍数,m3占用4个字节。这时已经为所有成员变量分配了空间,共分配了16个字节,满足为n的倍数。如果把上面的#pragma pack(4)改为#pragma pack(16),那么我们可以得到结构的大小为24。
2、 sizeof用法总结
在VC中,sizeof有着许多的用法,而且很容易引起一些错误。下面根据sizeof后面的参数对sizeof的用法做个总结。
A. 参数为数据类型或者为一般变量。例如sizeof(int),sizeof(long)等等。这种情况要注意的是不同系统系统或者不同编译器得到的结果可能是不同的。例如int类型在16位系统中占2个字节,在32位系统中占4个字节。
B. 参数为数组或指针。下面举例说明.
int a[50]; //sizeof(a)=4*50=200; 求数组所占的空间大小
int *a=new int[50];// sizeof(a)=4; a为一个指针,sizeof(a)是求指针的大小,在32位系统中,当然是占4个字节。
C.参数为结构或类。Sizeof应用在类和结构的处理情况是相同的。但有两点需要注意:第一、结构或者类中的静态成员不对结构或者类的大小产生影响,因为静态变量的存储位置与结构或者类的实例地址无关。第二、没有成员变量的结构或类的大小为1,因为必须保证结构或类的每一个实例在内存中都有唯一的地址。
下面举例说明,
Class Test{int a;static double c};//sizeof(Test)=4,静态成员不对结构或者类的大小产生影响
Test *s;//sizeof(s)=4,s为一个指针。
Class test1{ };//sizeof(test1)=1,没有成员变量的结构或类的大小为1
D. 参数为其他。下面举例说明。
int func(char s[5]);
{
cout<
//数的参数在传递的时候系统处理为一个指针,所以sizeof(s)实际上为求指针的大小。
return 1;
}
//sizeof(func(“1234”))=4//因为func的返回类型为int,所以相当于求sizeof(int).
以上为sizeof的基本用法,在实际的使用中要注意分析VC的分配变量的分配策略,这样的话可以避免一些错误。
 
相关文章:
 
 

让系统时间更准确

使用NTP协议可以让你的计算机自动与服务器上的时间同步。从而保持最准确的时间。
中国国家授时中心的IP地址是:210.72.145.44。
 
在 Windows XP/2000 可下使用以下命令设置计算机的时间同步:
 
在控制面板,管理工具,服务中找到 Windows Time,设置启动类型为自动,再按下启动按钮。
在 DOS 命令行下让 Windows 使用国家授时中心的时间服务器:net time /setsntp:210.72.145.44
要想立刻与时间服务器同步需要重启时间服务,相应的命令是:
net stop w32time
net start w32time
以后你的机器就会有一个准确的时间。

今天把我的 Hotmail 变成了 Live Mail

  

图片:

图片:

今天看到在Neowin有人找到一个不用邀请也能把Hotmail 变成Live Mail Beta的方法,但成功率只有50%罢了!
也有人说你的hotmail用了3年的成功转换机会比较高,N多人都已经成功了!!!

1.首先要把你的个人资料改去
Language –> English
Country –> United States
State –> Florida.

2. 把这个网址LINK 放在浏览器(只是IE)
http://by101fd.bay101.hotmail.msn.com/cgi-bin/BetaOptIn?page=option&curmbox=00000000%2d0000%2d0000%2d0000%2d000000000001&a=b9a426ebd4880ad9d14db4b4c55a69f8bb8dea2282102422220030b2b6bb98c8

3.Sign in

4.你应该登入不到,再把网址放在浏览器。

5.当你看到"Participate",那么你就成功了。

 
 
Live Mail 功能介绍:
 
Live Mail 最主要的升级一是支持拖放,这样在网页上操作信件就和在终端上一样方便了,二是容量扩大到2G了。

LabVIEW 读取 DLL 函数中的字符串的一个小经验

我们以前在编写 LabVIEW 调用 C DLL 的程序的时候,使用以下策略读取 DLL 函数中的字符串:
1. 如果能够确保在符串小于 256,比如参数名的字符串等等,就直接在 LabVIEW 中开辟一块大小为 256 的内存。
2. 如果不能保证字符串大小,就要为一个读取字符串的 VI 提供两个 DLL 接口函数,先调用一个函数得到字符串的大小,然后在 VI 中开辟内存,之后调用第二个函数得到字符串。
我在使用中,发现第一条策略不保险,应该全部使用第二条策略。

MSI Installer 中的升级

    这是我遇到的一个 MSI Installer 的问题。
    当目标机器已经装有一个旧版本的软件,现在我们又产生了一个新的安装包,并且在新安装包中制定了升级策略。在目标机器上安装新版本软件后,发现一些文件没有被安装上。使用 MSI Installer 的修复功能,缺失的文件才被装上。
    这是 MSI Installer 的 Component 的升级策略所决定的。MSI Intaller 规范认为,所有的 Component 在不同的版本中只应有文件的更新,而不应有文件数量的增加或减少,或文件名变化。并且,MSI Installer 为了提高效率,在安装时,是先安装新文件,再删除旧版本。由于我们平时在制作 Installer 时,为了方便,没有完全保证 Component 在不同版本下保持一致。这就造成了升级策略的混乱。在安装包运行到移除旧版本这一步时,本来不应当被删掉的 Component 也被删掉了。
 
    一个简单的解决办法是,让 MSI Installer 先卸载旧版本,再安装新文件。具体办法是把 RemoveExistingProducts Action 向前移到 InstallValidate action 和 InstallInitialize action 之间。Platform SDK上有详细说明。 这样,在升级时,会慢一些。但不至于造成混乱。

用WiX编写MSI安装包

 

WiX(Windows Installer XML)是Rob Mensching(Windows组的一个SDE)写的一个用来编写MSI安装包的工具集,已经被微软内部的很多产品组采用,例如Office组,以及我所在的MSN组,等等。

下面是WiX的一个简单例子(相当于高级的Hello World!的级别),在这个例子中编写了一个SimpleCopy.msi。安装SimpleCopy.msi将能够:

  • 创建C:\Program Files\SimpleCopy目录并拷贝一系列文件;
  • 创建HKEY_LOCAL_MACHINE\SOFTWARE\MPG Lab注册表键,该键下的DestPath变量存储了一个文件路径,DestPath可以在msiexec命令行中用DESTPATH来指定;
  • 创建名为SimplyCopy的Scheduled Task,该任务每小时运行一次,执行C:\Program Files\SimpleCopy\SimpleCopy.exe,将该目录下data\source.xml拷贝到DestPath中指定的目录;
  • Uninstall时,安装时拷贝的文件、创建的注册表键和Scheduled Task都将被删除。

下面就是用WiX编写SimpleCopy.msi的步骤:

1. 从http://sourceforge.net/projects/wix下载wix的2.0.3220.0版本并解压到硬盘,将candle.exe所在的路径添加到Path环境变量中;
2. 用C#编写SimpleCopy.cs并用csc.exe在同一目录下编译成SimpleCopy.exe:

using System; using System.IO; using System.Reflection; using Microsoft.Win32; namespace SimpleCopy ...{ internal class Application ...{ [STAThread] private static void Main(string[] args) ...{ string sourcexml = GetExecutableLocation() + @"\data\source.xml"; if (File.Exists(sourcexml))...{ DateTime now = DateTime.Now; File.Copy(sourcexml, Application.QueryDestPath() + @"\source_" + now.ToString("yyMMdd_HH.mm.ss") + ".xml", true); } else...{ StreamWriter writer = new StreamWriter(QueryDestPath() + @"\error.log", false); writer.WriteLine(DateTime.Now.ToString()); writer.WriteLine("Cannot find source file: " + sourcexml); writer.Close(); } } private static string QueryDestPath() ...{ RegistryKey regkey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\MPG Lab"); if (regkey != null)...{ object obj = regkey.GetValue("DestPath"); if (obj != null)...{ return obj.ToString(); } } if (false == Directory.Exists(GetExecutableLocation() + @"\regkey_not_found"))...{ Directory.CreateDirectory(GetExecutableLocation() + @"\regkey_not_found"); } return (GetExecutableLocation() + @"\regkey_not_found"); } private static string GetExecutableLocation() ...{ return Directory.GetParent(Assembly.GetEntryAssembly().Location).ToString(); } } }

3. 在SimpleCopy.cs同一目录下创建"data"子目录,在data\下创建一个任意内容的source.xml;
4. 在SimpleCopy.cs同一目录下编写SimpleCopy.wxs,其Schema文件wix.xsd可以在wix下载解压后的doc目录中找到。SimpleCopy.wxs内容如下:

<?xml version='1.0'?> <Wix xmlns='http://schemas.microsoft.com/wix/2003/01/wi'> <Product Id='c859431f-086d-4840-b2d7-a84b3bce50f2' Name='SimpleCopy' Language='1033' Version='1.0.0.0' Manufacturer='MPG China'> <Package Id='2738eb03-978b-4712-8e21-7e1868c74c2f' InstallerVersion='200' Compressed='yes' /> <Property Id='DESTPATH' Value ='C:\'/> <Media Id='1' Cabinet='product.cab' EmbedCab='yes' /> <Directory Id='TARGETDIR' Name='SourceDir'> <Directory Id='ProgramFilesFolder' Name='PFiles'> <Directory Id='AppDirectory' Name='SimpleCp' LongName='SimpleCopy'> <Component Id='ExecutableFile' DiskId='1' Guid='379ccaeb-a8c9-448e-a4b3-fa9884676492'> <File Id='SimpleCopy_exe' Name='SimpleCp.exe' LongName='SimpleCopy.exe' src='SimpleCopy.exe' /> </Component> <Directory Id='DataFolder' Name='data'> <Component Id='SrcXml' DiskId='1' Guid='746496f1-d2b1-4334-9b6f-00f71938c459'> <File Id='Source_xml' Name='source.xml' src='data\source.xml' /> <Registry Id='4e10403a-1976-447f-b38c-59839cb7c5cb' Root='HKLM' Type='string' Key='SOFTWARE\MPG Lab' Name='DestPath' Value ='[DESTPATH]'/> </Component> </Directory> </Directory> </Directory> </Directory> <Feature Id='AllFiles' Title='Simple Copy All Files' Level='1'> <ComponentRef Id='ExecutableFile' /> <ComponentRef Id='SrcXml' /> </Feature> <InstallExecuteSequence> <Custom Action='CreateScheduleTask' After='InstallFinalize'>NOT Installed</Custom> <Custom Action='DeleteScheduleTask' After='InstallFinalize'>Installed</Custom> </InstallExecuteSequence> <Property Id='SCHTASKS'>SCHTASKS.exe</Property> <CustomAction Id='CreateScheduleTask' Property='SCHTASKS' ExeCommand='/Create /RU "" /SC HOURLY /TN SimplyCopy /TR "%ProgramFiles%\SimpleCopy\SimpleCopy.exe"'/> <CustomAction Id='DeleteScheduleTask' Property='SCHTASKS' ExeCommand='/Delete /TN SimplyCopy /F'/> </Product> </Wix>

5. 打开命令行,进入SimpleCopy.cs所在的目录,先后运行candle SimpleCopy.wxs以及light SimpleCopy.wixobj,然后就得到SimpleCopy.msi了:

6. 在命令行运行“msiexec /i SimpleCopy.msi /quiet /log log.txt DESTPATH=d:\”就可以安装了。

相比较其他MSI编写工具(例如Visual Studio 2003/2005,以及InstallShield等),WiX的优点是:

  1. 便于版本控制(wxs是纯文本的);
  2. 便于自动化(编辑工具candle.exe和light.exe都是命令行的)。