2011年12月30日星期五

一个密码生成程序

原文链接http://genghis-yang.tk/?p=97

本篇算是上一篇的续集,上次说了中国各大网站密码泄露事件,对于我这种各个网站密码都是一样的人,泄露一个网站可算是把所有网站密码全泄露了。所以写了这么个小程序,目的是:只要记住一个主密码,然后由程序帮你为每个网站生成不同密码,当你需要登录时只要在此程序中再次输入你的主密码,就可以得到密码了。看图:

其实这个程序思路很简单,就是把网站域名和你的主密码混合在一起。然后用windows xp系统中自带加密库Cryptdll.dll,使用其中MD5算法加密。加密之后得到一个128bit结果,利用一个字典和这个结果产生适当长度的密码。本想也放到Google Code上去,但想想这个太简单,又没什么实用性也就作罢。

说说我这个程序吧,希望可以抛砖引玉。

我是用VS2010建了个MFC-Dialog程序,只加了几个控件和处理函数。这里最值得一提的是我使用了Cryptdll.dll中的MD5算法(如果要最大程度保证安全性还是需要自己写一个单向散列函数),这个算法共3个函数:MD5Init,MD5Update,MD5Final,依次使用就可以得到结果。不过这几个函数是没有对应头文件的,要想使用必须用LoadLibrary或者GetProcAddress函数从动态链接库中加载。具体的用法可以看看MSDN上Message Digest页面的例子,我基本上就Copy这个。

得到的128bit结果是用unsigned char数组表示的,也就是16个元素。这写元素值是不确定的(很可能是非字符),不能直接用来当密码。我们需要把这16个元素转换成可以显示的字符串。我的方法是建立一个字典,此字典相当于一个“密码可用字符列表”,所有希望在密码中出现的字符都列在里面(我的字典仅包含数字和大小写字母)。然后用之前16个元素中每个元素对字典长度取余,取余的结果作为索引,将此元素转换成的对应于字典中的字符。这样循环16次我们就得到了一个16个字符的密码了,而且它随机使用字典中的字符,基本不会出现有意义的字符串,保密性良好。

可执行程序:点此下载

源代码:点此下载

我这个程序没花心思,写得很简单,其实很多方面可以做得更人性化。例如能够自动检测所访问网站的域名,自动填写域名一栏,那就方便多了。


阅读全文...

2011年12月26日星期一

密码已无家可归

原文链接http://genghis-yang.tk/?p=91

今年的冬至是整个互联网的冬至,随着CSDN上600万用户密码泄漏,紧接着就是人人、多玩、7k7k、天涯……悲情的我在这些网站上都注册过,真要改密码非得改到我手软。最后一想就CSDN上还有点积分,其他就不改了吧。看报道说CSDN和天涯等网站都已经报案了,真不知是哪个黑客这么牛,真心希望他不会被逮到。这不是反语,仅是真心的愿望。所有谴责黑客的人,都是些不懂密码学不懂互联网的,作为一个通信专业的研究生,我觉得我有理由这么说。CSDN、天涯等网站为了降低那么一点成本,就置用户利益于不顾,它们竟然还有脸报案,真是让人愤慨。

我说这些不是空穴来风,任何一个了解互联网通信,了解密码学的人都能够看出来。下面我从技术的角度来分析分析,为什么我们的密码会被盗取。

首先我们要知道,密码都出现在哪儿?密码可能出现在3个地方:1.你的电脑上(包括你在浏览器里输入密码和在笔记本里记录密码);2.网站服务器上;3.你的电脑和网站服务器之间,用来连接两端的网络中。如果非要有第4个地方,那就是黑客的电脑上。

其次我们看看黑客可能从哪些渠道获得我们的密码,碰巧了也是3个:1.入侵你的电脑,偷窥你的输入;2.入侵服务器网站;3.在你的电脑和网站服务器之间某个节点上截取你发送给服务器的密码。

如果将上面一对照,你会发现凡是密码出现的地方都会有泄密的可能。那么我们的密码岂不是毫无安全性可言?当然不是这样。黑客可不是城管不是国保,要入侵安装好更新补丁的个人电脑几乎不可能(乱下东西中毒的不在此列)。网络中你电脑和服务器之间的转发节点大都为硬件,如果不亲手碰到黑客也无法控制(电信联通的人可以),无法用来截取你的密码。唯一可能泄漏密码的就是服务器了,因为服务器运行大量的互联网程序,漏洞在所难免。而这一次各大网站密码泄漏就都是这个途径。

服务器被入侵就会泄漏用户密码吗?我想要告诉大家的是:即使服务器被入侵,密码也绝对不会泄漏!因为用户密码在服务器上根本看不到。比方说我的密码是“0123456789”,在服务器上存的却是“87ACEC17CD9DCD20A716CC2CF67417B71C8A7016”,如果密码是“ppnn13%dkstFeb.1st”,服务器存的就是“3FB8F80558CC39B09225122428947D07C82DF4C8”。黑客即使入侵服务器,看到一堆类似于“87ACEC17CD9DCD20A716CC2CF67417B71C8A7016”这样的密码也是无可奈何的。

为何我们的密码会被保存成那个怪样子?这就要涉及到数学和密码学中的一个概念:单向散列函数。对于这个概念足够写几本书,这里我只简要介绍。这个函数跟我们数学中的函数是一样的,它以我们的密码为输入,输出就是那一串怪模怪样的东西,只不过这个函数是不可逆的。也就是说我们知道输入可以得到输出,但如果只知道输出是无法通过数学方法得到输入的。所以即使黑客看到“87ACEC17CD9DCD20A716CC2CF67417B71C8A7016”也无法推算出我的密码是“0123456789”。

有了单项散列函数,我们的密码基本上就安全了,如果不懂密码学看到这儿应该还是云里雾里的。下面来看看单向散列函数是怎么起作用的。对于稍大型的网站,当我们注册时,我们在浏览器输入的密码(用A代替)都会通过一个叫SSL的东西加密成X,(SSL是用来防止密码在传输过程中被黑客截取,也就是防止前面说的途径3)加密之后再通过网络传给服务器,然后服务器再用得到的X进行SSL解密得到我们的密码A。接下来服务器不会保存我们的密码,而是对密码做单向散列函数,得到那么一个怪字符串AA,然后把这个字串AA存下来。下一次我们要登录时,我们输入的密码再一次通过SSL加密后发给服务器,服务器再通过SSL解密,再对密码做单向散列函数,又得到一个怪字符串B,服务器拿新生成的字符串B与保存的字符串AA进行比较,如果相同说明两次输入一致,如果不同就说明你密码输错了。这样一来我们的密码只是在服务器内存里短暂停留,根本没在服务器上保存。那么黑客如果入侵服务器获得AA呢?他只能无奈。因为服务器会对任何输入都做单向散列函数,如果他把AA当密码输入,就会对AA进行单向散列。可以想象同一个函数对不同的输入A和AA将得到的不同的值,输入A得到AA,输入AA就得到其他值Y,之后服务器一比较,Y和AA根本不想等嘛,黑客的登录也就失败了。

上面的方法对大多数网站来说已经能够很好的满足安全性需要了。但一些支付类网站,例如网银、淘宝等,因为其特殊性需要更好的保护密码。因此它们的密码流程与上面的描述又略有不同。例如支付宝会给你电脑装一个“支付宝安全控件”,一些网银也会装类似的控件,这些控件里就包含一个产生单向散列函数值的程序。这样一来,我们输入的密码A在我们自己的电脑上就变成了一串怪字符串AA,然后再通过SSL加密成XX发给服务器,服务器通过SSL解密得到AA,再进行单向散列函数得到AAA,然后把AAA保存起来。下一次登录时输入的密码经过同样的流程得到C,然后拿C和AAA比较。这样的方法,密码在整个网络中根本没出现过,除非你输密码时被人看见否则无法泄漏。

上面介绍的这些方法都很成熟了,黑客即使本领再大也不能违反数学定律。但为什么我们的密码还是被泄露了呢?因为这些网站偷了懒。上面这两种方法都需要在每次登录时在服务器上进行一次单向散列函数,单向散列函数的运算相对比较复杂,需要较多的运算时间,而大型网站每一秒都可能有人登录,大量的登录请求意味着需要进行大量单向散列函数运算,需要增加服务器成本。因此这些网站,如CSDN、人人网、天涯都把服务器上进行的这个步骤给省略了,仅仅将SSL解密后的密码A直接保存成A。黑客一入侵看到的就是A,自然毫无阻拦的完成了密码盗取。而淘宝虽然使用安全控件把你的密码变成AA,但如果服务器端不再次进行单向散列函数,直接保存AA的话,黑客可以伪造一个“伪支付宝安全控件”把他看到的AA发给服务器,服务器就会允许登录。前段时间我的支付宝密码就被盗了,我怀疑就是这个原因。

像我这样所有网站同一个注册名同一个密码,这次可是栽了,一个被盗,全就被盗了。心里怨恨也没用,毕竟不能指望中国这些无良网站,要安全还得靠自己。我的打算是:自己造个函数,根据每个网站的域名生成一个密码,以后把函数记住就行了,再被盗也只是某一个网站了。


阅读全文...

2011年12月25日星期日

代理自动配置脚本——PAC文件

原文链接http://genghis-yang.tk/?p=86

什么是PAC?

A proxy auto-config (PAC) file defines how web browsers and other user agents can automatically choose the appropriate proxy server (access method) for fetching a given URL.(摘自Wikipedia)

正如这句定义,PAC文件被用来决定某一次网络访问所使用的代理。说得通俗点,就是当你访问某个网站时,由PAC文件判断该不该使用代理,或使用哪一个代理。

为什么会用到PAC?

这有什么用?如果你发问,那你要么不懂网络要么肯定没在大陆待过。在大陆的人都知道GFW,它是互联网上的文字狱,是自由精神的枷锁,是中华名族的樊篱,如果要自由上网就必须“翻墙”。很多翻墙工具都是代理性质的(如Wallproxy、GoAgent等),但是这些代理在访问大陆网站的时候又会增加延迟、拖慢网速。若能在访问被墙网站(如Facebook、Twitter)时通过代理连接,在访问其他网站时直接连接,就能实现既“翻墙”,又不会因代理拖慢其他网站速度。实现这一想法的最便捷方案就是PAC文件。

还有另一部分人(包括我在内),使用中国教育网,只能访问极少一部分大陆网站,不能访任何外国站。这部分人对能够自动配置代理的PAC文件有更强烈的需求。因为教育网要访问外国站就必须加代理,但是通过代理又无法访问教育网网站。如果不能自动配置代理,那么上网过程将会伴随不断的切换代理。而切换代理那繁琐的过程相信没有任何一个人愿意忍受。

如何构造PAC文件?

PAC文件其实可看作是一个JavaScript脚本,只不过它仅支持其中一部分命令。PAC文件必须包含一个FindProxyForURL(url, host)函数,这个函数可以看作是PAC文件的主函数,任何网络访问请求都会由系统传给这个函数。参数url就是要访问的URL,host就是要访问的URL所包含的主机。例如访问http://en.wikipedia.org/wiki/Proxy_auto-config,URL就是它本身,host就是en.wikipedia.org。下面举两个Wikipedia中的例子来说明这个函数的用法:

function FindProxyForURL(url, host) {
return "PROXY proxy.example.com:8080";
}


上面这两句就可以作为一个PAC文件,它对所有URL都返回同一个代理。也就是说这个PAC会让所有访问都通过proxy.example.com:8080这个代理。


下面这个相对复杂一些:


function FindProxyForURL(url, host) {
//对于所有.edu.cn域名,直接连接
if (shExpMatch(url,"*.edu.cn/*")) {return "DIRECT";}
//对于10.0.0.0到10.0.0.255之间的IP地址使用代理
if (isInNet(host, "10.0.0.0", "255.255.255.0")) {
return "PROXY proxy.example.com:8080";
}
//其他网站尝试使用代理访问,代理无效时,直接访问
return "PROXY proxy.example.com:8080; DIRECT";
}


这个例子说明了JavaScript函数在PAC文件中的使用方法。例子中,所有以.edu.cn作为域名的网站都将采用直接连接,所有在10.0.0.0到10.0.0.255之间的网站都会通过代理服务器proxy.example.com的8080端口连接(即使这个代理不可用)。其他一切网络连接都将尝试通过proxy.example.com:8080连接,如果代理无响应则直接连接。关于PAC文件更详尽的格式说明请参考《Navigator Proxy Auto-Config File Format》,如果有兴趣你也可以阅读一些扩展内容《Automatic proxy HTTP server configuration in web browsers》。


有一点不得不提到的是:大多数系统和浏览器只支持ANSI编码的PAC文件,如果使用其他编码(如Unicode)将无法识别。


PAC文件怎么用?


对于Windows系统,直接在“Internet选项”中,“连接”标签,“局域网设置”按钮,选中“使用自动配置脚本”,下面的地址栏填写PAC文件的URL。例如有个auto.pac在你的D盘根目录,则填写“file://d:/auto.pac”;如果这个pac在网络主机上,你就需要填成类似“http://genghis-yang.tk/something/auto.pac”这样。


Windows代理配置图解


对于Firefox浏览器,“首选项”中“高级选项卡”,“网络”标签,“设置”按钮,在“自动代理配置URL”中填入你的PAC。


Firefox代理配置图解


对于Linux系统(以ubuntu10.04为例),在“系统设置”里面打开“网络代理首选项”,在“自动代理配置”中填入PAC的URL。






ubuntu代理配置图解


其他配置方式也很雷同,这里就不赘述了。



请支持我的GoogleCode项目


我在Google Code上开了一个项目——pac-maker,做教育网代理自动配置脚本,包括一个按月更新的PAC文件和一个PAC文件自动生成程序。它主要是为教育网这个特殊群体服务的,主要目的就是让教育网不可访问的IP自动使用代理,而可访问的则直接访问。这个工程刚刚起步,还存在一些问题,期待有人能加入进来,或者提交些Issues,把它做得更好。


阅读全文...

2011年12月24日星期六

酷狗云外链播放器——给自己的博客来点音乐

原文链接http://genghis-yang.tk/?p=83

今天无聊中想给自己的博客加点多媒体,让单调的界面活泛一点。于是找到了搁置已久的Kugou账号,进入酷狗的新产品——酷狗云音乐。看到博客侧边栏中的音乐播放器了吗?这就是从酷狗云链接过来的。

酷狗云音乐http://cloud.kugou.com/

这玩意儿相当于一个支持外链的音乐网盘,有5G空间。而且你不一定要自己上传,依托于酷狗强大的音乐库,你可以简单地通过搜索将你喜欢的音乐添加到这个网盘中。

至于制作外链也非常简单,选择好歌曲之后点击下图所示的“制作外贴播放器”。

如果你只选了一首歌,你得到的播放器是这个样子的:

如果选了多首歌曲,则是这个样子:

然后在下面会出现可以嵌入网页的代码。只要点复制,然后把他们放在自己页面上就能看到效果了。

跟其他音乐网站相比,酷狗的音乐还是比较全的,而且大部分都有比较不错的音质,毕竟它做得时间比较长了。可惜的是它的外链必须以固定播放器的形式展现,不能调用自己的播放器。不过它默认播放器的设计还算说得过去,我也就不挑剔了。


阅读全文...

2011年12月23日星期五

返还网,网购省钱好途径!

原文链接http://genghis-yang.tk/?p=73

返还网是今天上网时偶然发现的一个新奇网站。它是干什么的?说白了就是在你网购时帮你省钱的。这网站我是没听说过,不过看他们的介绍每个月都有:超5万笔订单、超6000万订单总额、超12万新会员加入……更有甚者他们的CEO还曾做客CCAV《奋斗》栏目。按他们说的这么夸张的扩张速度,我感觉他们很快就能赶上淘宝了,所以我把它拿出来说说吧。

返还网主页

第一个问题当然是:它怎么帮我们省钱?其实很简单,听说过“淘宝客”吗?淘宝客是帮助淘宝推销商品的人,如果别人通过他们的推介购买商品,他们就能得到商品总价一定百分比的酬劳。当然对于不同的商品,这酬金也或多或少,但总会有一点。其实不仅淘宝,很多网购网站都有类似淘宝客的推荐机制,这种机制在网站刚开始运作时效果比较明显,可以短时间带来较多用户。

我今天所介绍的返还网,就是一个把淘宝客做成网站的大胆创意。不过它所代理的网站不局限于淘宝,像什么京东、当当、凡客,非常多,基本上可以满足我们在各大网上商城的购物需要。

返还网合作商城

不过返还网也不是尽善尽美的。首先得注册(这好像是废话);其次必须通过返还网下面的链接进入各大商城才有效(比较麻烦,而且安全性……我感觉没什么问题);再次,当你的带返还金额大于50元之后才能给你返现,小于50元的部分只能在心理暗爽。

返还网这一创意也不是破天荒头一遭。把淘宝客当职业的也不在少数,就连我们学校也有人做类似的生意,代理了很多网站,可惜他们的规模没法跟人网站比。反过来看这些网购网站,它们能抽出这些钱给推广人,说明他们的利润还是比较可观的,如果我们不嫌麻烦,大可以自己注册成淘宝客,自己申请各大商城推广人,那样肯定省下更多。

最后我还是不得不替返还网的前途感到担忧,不论返还网最终能做多大,它还是处于各大网购网站的荫庇之下,拾人牙慧。如果某天各大网购网站取消了推广人制度,那也就是返还网的末日了。另外,返还网的CEO就是之前如果云的创始人,看如果云的烂摊子,我就……


阅读全文...

2011年12月22日星期四

DBank华为网盘推出图片外链功能

原文链接http://genghis-yang.tk/?p=67

这个月初,DBank数据银行改名为华为网盘,似乎标志着华为准备在云存储上大干一场。毕竟在今年的应届生招聘,华为圈了很多云计算工程师。图片外链功能也是不久前开始测试的,现在要使用这个功能还需要进行申请。所有申请貌似都会被批准,只是需要等待一两天。在试用过几天之后,发现还是很不错的,而且华为宣称外链永久有效,国内连接速度也很快,优势十分明显。我这个博客绝大多数图片都是从那儿链接过来的。

让人疑惑的是华为网盘的图片外链功能并没有拿出来大肆宣传,要想申请还找不到地方。看下图:

DBank华为网盘登录界面

看到右下角用红圈框出来的more按钮,点击之后进入华为网盘论坛。

DBank华为论坛置顶帖

在论坛置顶贴中有一个“DBank网盘图片外链功能试用第二批名额申请中”。点这进去,按照里面所要求的回复一下就算是申请了。

DBank华为网盘回帖

这是我申请时的回帖,改善建议好像可以不写。申请完别着急,等一两天就会开通了。

DBank华为网盘右键菜单

华为网盘获得图片外链也相当容易,在需要的图片上点右键,选择“获得图片外链”即可。不用像Flickr那么麻烦,还要点来点去的。

唯一的遗憾是右键功能在Firefox下无法使用(我猜Chrome下面也没法用),所以要获得图片外链必须用IE。为了不用启动IE,我直接给我的Firefox装了个IE Tab 2插件,切换起来很方便。


阅读全文...

2011年12月20日星期二

条件注释——解决浏览器兼容性的利器

原文链接http://genghis-yang.tk/?p=65

对于网页编程我是个菜鸟,从开始做这个博客,就遇到一个又一个浏览器兼容性问题。IE和Firefox、Chrome之间,以及IE各不同版本之间对Html和CSS的解释不尽相同。之前我都尽量规避,放弃使用那些有不同解释的语句。可在上一篇博文中希望嵌入一个Flash时,这个问题便不得不直面。不过在稍加研究之后,我就找到了解决这一问题的绝佳方案——条件注释。

其实条件注释随处可见,就连我这个WordPress的模版中也是大量充斥着。它长得和HTML的注释语句十分相似(其实也可以把它看成注释),<!-- --> ,也正因为它使用了HTML的注释结构,所以它只能在HTML中出现而不能用在CSS文件中。它不是脚本,而是实实在在的HTML语句,直接在HTML代码里执行。下面让我们看看它的一些常用形式:

   1: <!--[if !IE]><!--> 此处代码除IE外都可识别 <!--<![endif]-->
   2: <!--[if IE]> 此处代码所有的IE可识别 <![endif]-->
   3: <!--[if IE 5.0]> 此处代码只有IE5.0可以识别 <![endif]-->
   4: <!--[if IE 5]> 此处代码仅IE5.0与IE5.5可以识别 <![endif]-->
   5: <!--[if gt IE 5.0]> 此处代码IE5.0以及IE5.0以上版本都可以识别 <![endif]-->
   6: <!--[if IE 6]> 此处代码仅IE6可识别 <![endif]-->
   7: <!--[if lt IE 6]> 此处代码IE6以及IE6以下版本可识别 <![endif]-->
   8: <!--[if gte IE 6]> 此处代码IE6以及IE6以上版本可识别 <![endif]-->
   9: <!--[if IE 7]> 此处代码仅IE7可识别 <![endif]-->
  10: <!--[if lt IE 7]> 此处代码IE7以及IE7以下版本可识别 <![endif]-->
  11: <!--[if gte IE 7]> 此处代码IE7以及IE7以上版本可识别 <![endif]-->

如果学习过一些编程基础,一看就明白了,这都是些判断语句。每一条语句都会执行判断,如果满足条件,其中包含的代码就会被执行;如果不满足,就会被当作注释直接忽略。举个例子:



<!--[if !IE]><!-->
<!-- 如果是Firefox浏览器,调用firefox.css样式表 -->
<link rel="stylesheet" type="text/css" href="firefox.css" />
<!--<![endif]-->
<!--[if IE]>
<!-- 如果IE浏览器,调用ie.css样式表 -->
<link rel="stylesheet" type="text/css" href="ie.css" />
<![endif]-->


通过这两条判断就可以为IE和非IE载入两种不同的样式表文件,进而形成两个完全相同或完全不同的界面。利用它不仅可以解决兼容性问题,也可以对不同的浏览器行为做更细致的控制。


本片博文参考了百度空间中bj1686的博文《<!--[if IE]>….<![endif]--> (<!--[if !IE]>||<![endif]-->)》,在此向作者表示感谢!


阅读全文...

逆向学英语

原文链接http://genghis-yang.tk/?p=45

我上学那会儿英语学习从小学开始,现在的孩子更是提前到了幼儿园。但是教材和教师总是千篇一律的从我们的角度去研究英语。也许这样有利于年幼的孩子理解和记忆,可是对英语的真正感悟却是要大打折扣了。在现代这个没有距离感的互联网上,我们是不是可以从外国人学汉语的角度,逆向去接触英语文化呢。

早上在Facebook上逛了一圈,很多人在讨论金正日的逝世。就连Chinese也写出这么一句:“What does Kim Jong Il's death mean for the mainland?”跟评论的人还真不少,我也写了一条:“Most Chinese people do not care about this”。写完这句自我感觉良好的英文,我也些许地沾沾自喜起来。在Chinese继续逛逛,看他们给每一个中文词句写英文注释,我忽然间也感觉自己是来学中文的。于是乎我有了第一段所描述的那些感触,感觉这样学英语还是蛮不错的。从他们网站摘了个Widget放在下面,大家可以试试。

Either scripts and active content are not permitted to run or Adobe Flash Player version 10.0.0 or greater is not installed.

Get Adobe Flash Player

阅读全文...

2011年12月17日星期六

用图片隐藏种子文件

原文链接http://genghis-yang.tk/?p=35

这是很久以前接触的一项技术,没什么大用,就是拿来玩玩而已。具体的由来要从爱情动作片说起……(此处略去1000字)……这一省略也没什么好说的了。其实就是把不适宜光明正大传播的BT种子变成图片,贴在网上。别人看起来是一张图片,但是右键另存为之后,再用winrar打开就变成了种子,可以下载了。试试这张图片吧,比特鱼上的《失恋33天》。

《失恋33天》图片失效,请联系博主更新

试试在上面这张图片上点右键,另存为,保存到你自己电脑上。然后把后缀名jpg改成rar,打开看,里面就是电影的BT种子。

那么该怎么制作这么一张暗藏BT种子的图片呢?步骤很简单:

1.准备随意一张图片和一个BT种子文件,假设它们分别叫example.jpg和movie.torrent
2.将种子文件用WinRar压缩,得到一个文件假设叫compression.rar
3.控制台中输入copy /b example.jpg+compression.rar my.jpg

三步就完成了,那个my.jpg就是暗含BT种子的图片,当然名字可以随便。这么简单?对,就这么简单,这其中的奥妙全在第3步呢。看起来就是用了copy命令来合并两个文件,但是合并的两个文件顺序一定不能反,一定要图片在前压缩文件在后。为什么这样?这跟图片文件储存格式有关。从二进制的意义上来讲,图片文件在最开始的一块地方存放着整个图片的颜色宽窄大小等信息。合并文件时如果rar文件在前面,系统在my.jpg最开始的地方找不到图片的信息,就无法显示图片了。当然/b参数最好也别落下,/b的意思是用二进制方式合并,如果不加上很可能就用ASCII码方式合并,那就很可能失败了。至于为什么图片文件信息不会影响WinRar识别,那就不得不佩服WinRar的鲁棒性了。其实WinRar并不仅是压缩工具更是一款功能强大的软件,它有很多高级应用技巧可以在代理商的网站上看到http://www.winrar.com.cn/jq_jcjq.htm.htm

最后再贴两张图片,打开不是种子而是个txt文件,里面是《你看起来好像很好吃》和《时间规划局》的ed2k链接。这样大家就知道怎么隐藏非BT种子文件了 : )

《你看起来好像很好吃》图片失效,请联系博主更新   《时间规划局》图片失效,请联系博主更新


阅读全文...

2011年12月16日星期五

关于网盘

原文链接http://genghis-yang.tk/?p=29

我真正接触网络,是在刚上大学那会儿。以后的孩子肯定难以相信,大学之前我甚至不知道什么是网站。那时的网络正是处在春笋般的澎湃发展中,新兴的应用层出不穷,带给我的总是一个又一个惊喜。对于网盘,这个能把自己的内容存储在网络中,走到哪儿带到哪儿,不用花费一分钱一点力气的好东西,我有种难舍的执念。曾经在Google上一遍又一遍的搜索、注册,看着那些免费的几兆或者几十兆的内容,真的心动。需知在我大学之前接触过的最大移动存储设备是1.44M的软盘,几十兆的容量相当于我曾拥有的所有软盘容量之和。

互联网的发展太快,最初申请的那些网盘放在今天甚至连首歌都放不下。今天打开Firefox的收藏夹,里面躺着八个网盘:Skydrive、G宝盘、MoFile、永硕、纳米盘、Mega、115、Dbank。

前四个是08年之前申请的,其中“G宝盘”和“MoFile”已经很久很久打不开了。纳米盘也几经波折,从最初的小容量永久存储,到大容量限期存储,再到现在投靠Skydrive,彻彻底底变成了Skydrive的马甲。唯有永硕依然坚挺,上面还有我前两年保存的课程作业呢。可以看出来永硕确实是想做出自己的品牌,它不断做了很多改进,从以前的几十兆免费空间到现在400兆,最初只支持IE,今年也已经支持webkit。可是永硕的坚持也不能扭转颓势,面对雨林木风、华为等的强势进入以及他们所宣传的云存储概念,永硕能勉强守住自己的一亩三分地就不错了。可是面对我庞杂冗余的收藏夹,我还是不舍得删除它们,它们可都曾经在Google网盘第一页出现过,虽然已经记不得在里面放了什么,也许若干年后打开了还会有一段不错的回忆吧!

缅怀了先驱们,再说说现在的新兴网盘。115算是成名较早了,雨林木风停止美化Windows之后还是弄出了很多不错的东西,这就算其一。可惜的是115的网盘的分享和外链隔几个星期就得重新续期,Dbank貌似就是瞅准了这个,宣传的亮点就是永久有效外链。另外115分享的大文件必须用它们提供的下载器下载,而Dbank则没有此限制,甚至提供了迅雷下载的按钮。凭着这些优势,以及国外网盘在GFW限制下的不稳定,Dbank尽管容量才几个G,却大有种后来居上的意思。至于国内其他一些有实力的企业也推出了它们的云存储产品,但是为时已晚。这里面值得一说的只有金山了,去年还是前年推出了快盘,宣传的很努力,但是效果很一般。但仅几个月后它们就推出了足够噱头的金山T盘,这个产品着实影响不小,1T的容量还是很惹眼球的。但是当我好不容易抢到激活号,才发现这竟然是个同步网盘,要上传的东西必须在硬盘放着……这不是玩我吗,我那60G大硬盘,要让我放满1T不是天方夜谭吗。于是乎T盘火了一段时间也就沉寂下去。不过金山显然不服输,很快调整了战略,将快盘作为同步盘,T盘成了真正的网盘,但是容量却变成了20G,而不是原先的1T了。早知道这样当初就应该学Dbank,做个同步工具就行了,用户爱同步不同步,这样大家才容易接受嘛。

其实现在的网盘技术都已经很成熟,给你1G还是10G对那些大网盘影响不大,成本几乎不增加,要不它们怎么敢让你每天领取空间呢。别以为你上传10G电影,它就真拿出那么多硬盘空间,它其实只需要在数据库中增加几条记录就Ok了,连1M都用不了,它之所以每天送你点,就是为了吸引你,为了它的访问量。所以我打算过段时间做个脚本出来,每天自动签到,自动领容量。

又想到了那个硬盘以M为单位的年代,青蛙送我软盘的时候很激动呢,后来姑姑也给过我几盒Sony软盘,不过到现在还没来得及拆封。现在随便个网盘每天领的空间都是软盘几十倍,可是即便再有人送我移动硬盘也不会有当初的感动了。


阅读全文...

2011年12月8日星期四

一个有趣的徽标制作网站

原文链接http://genghis-yang.tk/?p=22

徽标是一个网站的门面,没徽标的网站看起来就不那么专业,至少说明管理员不够用心。当你全身心投入某一件事中,任何一个不完美的细节都让人难受。我的网站还没有徽标,Google搜搜,制作徽标的网站很多,大多很单一,上传图片,下载.ico。不过我今天推荐的这个着实不错,功能很多样化,速度也快,值得分享。先贴网址:http://free.logomaker.cn/

这个LogoMaker网站不仅具备普通的icon制作功能,其他还包括“图片圆角工具”(就是将矩形图片变成更美观的圆角矩形图片)、“网站页面Logo制作”、“动态链接Logo制作”、等等。每一个制作方式都有很多种风格可选,应该能满足大多数人的需要了。当然如果要求高,还可以使用LogoMaker的收费服务,想必那就是人工设计了。

下面贴几个徽标图示例。

  • 本网站首页的Logo就是在那儿制作的,很有Google范儿吧?

 

 

  • 还有我做的签名。

  • 圆角图片是不是比直角的美观些?

最后发几句感慨,与本主题无关。

现在的社会太浮躁,就拿本篇的标题来说,如果此篇让其他人写多半会写成“一个有趣的Logo制作网站”。面对这种情况我总是想愤怒的问他:“为什么不写成An Interesting Logo Maker?”他知道Logo拿中文怎么说吗?明明就是个“标志”,或者按国徽、会徽的方式翻译成“站徽”也说的过去,干吗非得说成Logo,是想说明自己高超的英语水平吗?

由此又联想到context一词,无数的专家学者在自己的译著中将这个词翻译成“设备上下文”!!我已经出离愤怒了!也许最初某个学者将他翻译成“设备上下文”是适当的,但在我所浏览过的所有文献著作中没见到过一处适当的。其实这个词翻译成“环境”就很清楚明白了,“设备上下文”反而让它显得艰涩难懂。也许那些所谓的专家就是怀着这样的目的吧。凡是看到“设备上下文”一词的出现,其作者都会被我鄙视。

说到这就不得不说罗云彬和他的《WINDOWS下32位汇编语言程序设计》,他在文章里面对应context一词的地方没有一次出现“设备上下文”。在此表达我对罗云彬的无限崇敬之情。


阅读全文...

2011年12月1日星期四

记我的第一次建站 附WordPress + 000webhost + tk解决方案

原文链接http://genghis-yang.tk/?p=5

最先接触的博客应该算是“QQ空间”了,虽然只有最简单的输入和回复功能,但在21世纪的头三、五年还是很有生命力的。那个时候也在上面写了不少原创的东西。后来用上“百度空间”,全因为看到百度空间可以嵌入自己的html代码,误以为这个应该比QQ空间专业的多。百度上基本都写了些专业技术,不过原创的少了。再后来学了网页相关的东西,才明白一切空间的浅薄。于是Google了一下Blog,就找上了Blogger,直接在blogspot上注册个帐号,开始写自以为专业的博客了。不过Blogger可不是这么好用的,仅仅想让首页只显示摘要就弄得我头大,更恼人的是还得翻墙才能看。

在这么些网站跳来跳去,但总寻不到归属感,毕竟都是人家的域名加我的后缀。于是最后我也牛气一下,弄个顶级域名玩玩。收费的咱买不起,免费的也有不少,可是免费午餐限制多多,要么不支持域名绑定,要么中国IP不能注册。找来找去这tk还真是不错,申请了个 http://genghis-yang.tk/ ,不到两小时校园网就能ping通了。域名问题搞定了接下来就是找个免费的虚拟主机,新浪的SAE貌似不错,可是好像对免费用户苛刻了点,最后看很多人推荐000webhost,看看这广告——“全能PHP空间1.5G ,支持PHP(不支持ASP),支持绑定顶级域名,无任何广告,独立控制面板,免费创建Mysql数据库,FTP上传下载,在线压缩解压,支持fopen()函数,可正常安装Wordpress,PHPWind,Discuz ,Joomla等软件。”——比国内这些芝麻绿豆大的空间好得多了。有了空间,绑定上我的顶级域名,接下来就是建站软件了。看着日薄西山的Blogger,我毅然的选择了WordPress。可能Blogger的Fans要声讨了,可我确实有种WordPress优于Blogger的感觉,也主要因为我的喜新厌旧吧。

接下来写写我在建站过程的主要步骤和遇到的问题,一方面给自己留个底,另一方面可以给需要的人解惑。

首先在http://www.dot.tk上注册域名,很简单,不断下一步,不确定的地方先随便填,反正之后也可以改。只有邮箱不能随便,因为国内很多邮箱貌似收不到确认邮件,因此还是用Gmail或者hotmail吧。用邮件确认之后这个顶级域名就属于自己了。登录进去后左侧就可以看见我的域名列表,还可以继续加入其他喜欢的域名。这一步结束之后先把它搁置在这儿,因为我还没有虚拟主机空间,这个域名还没有地方可绑定。

第二步在http://www.000webhost.com申请个免费PHP空间,注意!这个空间一定不能从中国进行申请,国外很多著名免费空间都屏蔽了中国的IP地址,所以一定要找个代理,或者出国旅个游。申请的时候会让填入空间地址,这里有两个选择:可以填入第一步申请到的顶级域名,也可以用000webhost提供给的二级域名。用顶级域名直接就可以把空间和域名绑定好,但是这样容易失败,建议先用它提供的二级域名注册个空间,完成后再绑定顶级域名。这里的注册邮箱也建议用国外的。注册好之后就可以通过http://members.000webhost.com登录进去,记得要邮件激活。

第三步,激活完成可以点go to cPanel进到空间后台控制面板,点Parked Domains用来绑定申请的域名,可以绑定好几个域名。在这儿绑定还不算完,现在依旧没办法用自己的域名访问刚申请的空间,因为欠缺一步。回到注册域名的地方,登录进去,找到已申请的域名进行修改,选择使用“自定义域名服务器”,然后填入由空间提供商告知的域名服务器,对于000webhost就填“ns01.000webhost.com”。接下来要等一段时间,就可以用自己的域名访问自己的空间了。但是这会儿空间还是空的,什么都没有,接下来需要给空间装软件了。

第四步,这一步就是装软件,开博客就装WordPress,开论坛就装Discuz!。就是不知道000webhost对论坛支持的怎么样,这里仅有WordPress的经验。先是准备工作,下个WordPress,然后登录000webhost,它自带有MySQL,随便填个名字密码建一个MySQL数据库。接下来要上传了。可以用1-Click Website Restore功能直接把WordPress的压缩包上传上去。不过这种上传方法之前需要把WordPress压缩包解压,解压后会是一个WordPress文件夹,进入这个文件夹后把里面所有东西全选后重新压缩成一个文件,也就是说要上传的压缩文件是脱掉一层文件夹之后的。更专业的上传方法是用ftp,ftp的用户名和密码跟000webhost的登录名密码不一样,需要在View FTP Details里面查看。把解压得到的WordPress文件夹里面的所有文件都上传到public_html文件夹下,上传工作就完成了。

最后迈向胜利的一步,建立WordPress博客。WordPress压缩包里面就包含一个readme.html文件,讲得也比较清楚了,这里也不赘述。建立完成后就可以通过你的域名访问到这个博客了,接下来对WordPress修修改改让它更美观更人性化吧!

写完了,享受顶级域名和自由空间带来的快感吧!!

我的域名:http://genghis-yang.tk 欢迎访问!!


阅读全文...

2011年11月29日星期二

在Debug和Release模式下编译执行不同的代码

关于Debug和Release最常见的问题就是:“这个DLL到底是Debug build还是Release build?”对于这个问题可以在网上找到各种解答,本文也不想讨论它。本文要说的是:如何在Debug和Release模式下编译执行不同的代码。

问题的来源是:最近用OpenCV做图像处理,需要将OpenCV的lib静态链接到我的程序,从而能够把我的程序拿到别的没有OpenCV的机器上运行。用#pragma comment就可以把链接库包括进来。但是Debug和Release时需要分别调用OpenCV库的Debug和Release版本,这样岂不是要在Release之前再改一次代码。

解决的方法是:如果是Debug模式编译,会自动定义_DEBUG宏,如果是Release则没有定义_DEBUG,(是否在Release模式下定义_RELEASE我就不知道了,有兴趣的可以一试)我们只需要利用预编译宏#ifdef就可以解决问题。
#ifdef _DEBUG
#pragma comment(lib, "opencv_core231d.lib")
#pragma comment(lib, "opencv_imgproc231d.lib")
#pragma comment(lib, "opencv_highgui231d.lib")
#else
#pragma comment(lib, "opencv_core231.lib")
#pragma comment(lib, "opencv_imgproc231.lib")
#pragma comment(lib, "opencv_highgui231.lib")
#endif
如上例Debug时程序将链接文件名带字母d的OpenCV库Debug版本,Release时将链接OpenCV库的Release版本。此处要注意_DEBUG的大小写和前面的下划线。
其他适用此方法的情况:很多情况下,需要在调试程序时输出一些调试信息,但不希望在发布程序中出现这些调试信息。我之前的做法是调试时用printf或MessageBox输出,Release时将调试用到的printf和MessageBox注释掉。但是当注释很多时就很麻烦了。如果利用前面的方法,在需要注释的语句前后分别加上#ifdef DEBUG和#endif这个问题就不再是问题了,无论Debug还是Release都不用再改动代码了。例如
#ifdef _DEBUG
printf(......);
#endif
上面的printf语句就只在Debug时编译,Release时将无视。
PS:我仅使用Visual Studio 2010,所以我所做的实验也是基于它的,之前的visual studio版本应该也适用,其他编译环境就无从考证了。

阅读全文...

2011年4月12日星期二

U盘病毒查杀程序开发历程

U盘病毒查杀程序开发历程

这是一个同学给我的小项目,客户要求做一个动态链接库(DLL),具体功能是在U盘插入电脑时调用两种杀毒软件依次对其查杀。另外可以从U盘中复制文件到电脑中其他位置。刚拿上手时觉得很简单,没有什么复杂的东西,而事实也确实如此。但是最后这一项目还是流产了,原因是客户在杀毒软件的选择上一定要用瑞星。也许这个世界上的杀毒软件质量参差不齐,但无疑瑞星是排名第一的烂,兼容性和查杀率的低劣大家都有目共睹,竟然连命令行参数都没有。抛开这些不谈,我还是想把这个DLL的开发记录下来,给以后留个纪念。

项目分解

这个项目就两个主要功能,查杀U盘和复制文件。分解开来看,有4个待解决的问题:
1.         检测U盘插入;
2.         调用杀毒软件;
3.         复制文件;
4.         编译DLL
这样分开来看,每一个问题都不是问题了,其中除了检测U盘插入以前没接触过,其他的都有现成的或半成品的代码。
鉴于MFC编写DLL在非MFC程序中兼容性打折扣的问题,我决定采用纯Windows API的方式完成此次开发。
因为DLL的调试比较繁琐,我决定先用普通Win32应用程序的思路处理前3个问题,待调试成功后再改写成DLL。最终的事实也证明这样的方法非常省时高效,前面的调试进行的很顺利,最后改写DLL的过程也只花了数十分钟就完成了。

检测U盘插入

当一个即插即用设备接入或移除电脑时,操作系统都会向所有顶级窗口发送WM_DEVICECHANGE消息,表示设备变动。(不知道什么是顶级窗口?就看做是全部窗口好了)WPARAM参数包含变动的类型,例如:DBT_DEVICEARRIVAL表示设备已经接入系统,DBT_DEVICEREMOVECOMPLETE表示设备已完全移除。而WM_DEVICECHANGE消息中的LPARAM参数会包含变动设备的一些基本信息,如设备类型,容量等。具体内容可以参见MSDN对这些消息的解释,这里不再赘述。我的目的是检测U盘接入,因此我只关心WM_DEVICECHANGE消息的WPARAM等于DBT_DEVICEARRIVAL的情况。并且要通过对LPARAM内容的判断,排除插入光盘等其他设备的情况。
接下来具体组织代码。先用CreateWindow建立一个对话框作为主窗口,写好基本的消息循环。将
                    Device_Changed(hwnd, wParam, lParam);
                    break;
加入到消息循环中去。这样在设备接入时程序就会捕获到此消息,并且调用处理程序。我这里给处理程序起名Device_Changed。在处理程序内部详细处理所捕获到的消息,通过WPARAM对它的动作进行分析,我只关心插入动作,也就只处理当WPARAM等于DBT_DEVICEARRIVAL的消息。另外,也要对LPARAM进行判断,排除其他设备类型。
switch(wParam)
{
case DBT_DEVICEARRIVAL:
                    if((PDEV_BROADCAST_HDR) lParam -> dbch_devicetype == DBT_DEVTYP_VOLUME)
                    {
                         if(((PDEV_BROADCAST_VOLUME) lParam ->dbcv_flags & (DBTF_MEDIA|DBTF_NET)) == 0)              {
                                Call_Anti_Virus(lParam);
                         }
                    }
……
上面的代码中DBT_DEVTYP_VOLUME表示设备类型为存储卷,区别于其他即插即用设备。DBTF_MEDIA表示光驱,DBTF_NET表示网络驱动器,除过这两种剩下的就是U盘了。至此检测U盘插入的工作就算是告成了。

调用杀毒程序

这一步里面我需要调用两个杀毒程序,依次对U盘进行查杀。这里涉及的问题有,如何调用杀毒软件,如何得知第一个杀毒程序已结束,如何让杀毒软件查杀指定U盘。
首先要明确一个概念:程序只能从外部调用杀毒软件。杀毒软件为了自身安全性,往往不会把内部接口开放给用户,因此,我们只能用命令行调用的形式从外部启动杀毒软件。这种方式受限于杀毒软件提供的命令行参数,如果杀毒软件没有提供足够的命令行参数,对其的控制就很难完善。例如瑞星,干脆没有提供命令行参数,程序就只能启动而无法控制它。其他一些杀软,可能没有提供杀毒后自动关闭的参数,那么程序也无法让它在杀毒后关闭,而因杀软的高权限,强行终止杀毒软件的进程往往很难成功。
明确了上面的概念,程序的行为就很简单了。(1)获取U盘路径;(2)调用杀软在命令行执行。而U盘的路径我们可以在WM_DEVICECHANGE消息的LPARAM参数中获得。将LPARAM参数看做PDEV_BROADCAST_VOLUME类型,其中的成员变量dbcv_unitmask就保存了设备盘符。dbcv_unitmask是一个DWORD类型值,共32位,它是用bit位来表示信息。它从第一位开始,每1 bit表示一个盘符。例如,A盘就是第一位置1D盘就是第4位置1。如果插入设备盘符是F,则dbcv_unitmask就等于十六进制的0x20,也就是第6位被置一。我们通过一个简单的程序来取出盘符:
char FirstDriveFromMask( ULONG unitmask )
{
                    char i;
                    for (i = 0; i < 26; ++i)
                    {
                         if (unitmask & 0x1)
                                break;
                         unitmask = unitmask >> 1;
                    }
                    return( i + 'A' );
}
将得到的盘符和冒号“:”、斜杠“\”等组合起来形成带扫描路径,然后根据所要使用杀毒软件的命令行参数规范,构成完整的命令行字符串。例如我是用的小红伞Avira的命令行就是“D:\\Program Files\\Avira\\AntiVir Desktop\\avscan.exe PATH=I:\\”。这里我没有添加运行完自动关闭的参数,但在应用中是一定要加上的,要不然第一个杀软杀完就停那儿了,第二个杀软就不知道自己什么时候开始了。那么第二个杀软是怎么知道轮到自己了呢?这就需要我们在调用杀软的时候,选择可以掌握运行状态的API,要能知道它们什么时候运行结束了。
调用杀毒软件其实就跟调用其他程序是一样的。Windows API中调用其他应用程序的函数有:
(1)       WinExec:原型是UINT WINAPI WinExec(LPCSTR lpCmdLine, UINT uCmdShow); 第一个参数是就是上面所说的命令行,第二个参数是控制显示方式,如最大化,最小化等。这个函数非常简单易用,但是缺点也很明显,控制力不足。
(2)       ShellExecute:相对于WinExec较为复杂,当然也提供了相对较多的控制,我的程序最就用了这个函数的扩展形式:ShellExecuteEx,关于这两个APIMSDN上都有讲。我们之所以选择ShellExecuteEx,是因为,它在执行后可以有一个变量存放被执行进程的信息。而通过这个变量就可以确认所执行进程是否终止了。
(3)       CreateProcess:功能最强大的函数,可以控制进程的几乎所有属性,但是随之而来的是复杂的调用。为了简单起见我并没有用它。从另一个角度讲,如果这个程序是我自己用的,我可能就会用它了,而这个本是给别人做的项目。
具体的调用代码:
SHELLEXECUTEINFO ShExecInfo = {0};
ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
ShExecInfo.hwnd = NULL;
ShExecInfo.lpVerb = NULL;
ShExecInfo.lpFile = command_path;
ShExecInfo.lpParameters = parameters;
ShExecInfo.lpDirectory = NULL;
ShExecInfo.nShow = SW_SHOW;
ShExecInfo.hInstApp = NULL;
ShellExecuteEx(&ShExecInfo);
WaitForSingleObject(ShExecInfo.hProcess,INFINITE);
代码倒数第二行调用了ShellExecuteEx,而前面的若干行都是在创建一个保存运行信息的SHELLEXECUTEINFO结构,这里面包含了命令行、参数、显示方式等,具体的还是MSDN说的清楚。而在最后面有个WaitForSingleObject函数,它用被调用进程的句柄作为参数,是干什么用的呢?其实无论ShellExecuteEx还是WinExec在执行完后都会立即返回然后就会紧接着执行下面的命令了。而我要做的是让第一个杀软杀毒完成后才开启第二个杀软。因此,要让程序在开启第一个杀软后进入等待状态,一直等到第一个杀软退出后才往下执行。WaitForSingleObject恰恰就有这样的作用。此函数第一个参数是句柄hInstance,第二个参数是毫秒数dwMilliseconds,它本来是用来阻塞程序直到第一个参数所代表的事件发生,或者超过所设定毫秒数才返回相应结果。我们这里用被调用杀软的进程句柄作为第一个参数,第二个参数设为无限,则程序在此处会一直等到被调用进程销毁,然后才返回。后面只需要紧跟第二个杀软的调用代码,这样就可以让程序在第一个杀软查杀时一直处于等待状态,一旦第一个查杀完成退出后第二个马上就开始了。
至此,U盘查杀的工作已经完全做完了,程序已经能够检测到U盘插入并依次调用两个杀软查杀了。

复制文件夹

最后一部分是关于复制文件的。客户之前的要求是,要能复制U盘文件夹到硬盘的某个文件夹,而不考虑单个文件的问题,因此我很快想到了SHBrowseForFolder函数。别会错意,这个函数可没有复制的能力,它是一个文件夹选择对话框。不同于文件选择对话框类CFileDialog,它只能选目录,不能选文件,而且是一个地地道道的Windows API,不是MFC的类,没有兼容性问题。
SHBrowseForFolder的使用非常简单
char szPathName[1024]
BROWSEINFO browse_info;
memset(&browse_info, 0, sizeof(BROWSEINFO));
browse_info.lpszTitle = "选择文件夹";
browse_info.ulFlags = BIF_RETURNONLYFSDIRS|BIF_DONTGOBELOWDOMAIN|BIF_RETURNFSANCESTORS;
LPCITEMIDLIST pidl;
pidl = SHBrowseForFolder(&browse_info);
if(pidl == NULL)
                    return -1;
SHGetPathFromIDList(pidl, szPathName);
最后一句中SHGetPathFromIDList函数取得所选路径字符串,存入szPathName中。这样我们就得到了要操作的文件夹路径,只需要代入复制函数中去就完成了。
至于复制函数,我试用过WinExec调用xcopy命令,完成复制文件夹没有任何问题。但是此法没有复制进度的提示,复制大文件时,时间一长人就受不了了,还是决定要弄个进度条出来。后来突然发现了功能强大的SHFileOperation函数。它可以对文件系统中的对象执行复制、删除、移动、重命名操作,而且看起来就跟系统自己操作时的界面一模一样。(是不是Windows系统的文件操作就用这个API?)由于这个函数很强大,我看了很久也只看了九牛一毛,只学了用它来复制文件和文件夹。
SHFILEOPSTRUCT file_operation;
file_operation.hwnd = NULL;
file_operation.wFunc = FO_COPY;
file_operation.pFrom = from;
file_operation.pTo = to;
file_operation.fFlags = FOF_NOCONFIRMATION;
SHFileOperation(&file_operation);
上面代码中显示出,SHFileOperation只需要一个SHFILEOPSTRUCT结构体作为参数,这个结构体中wFunc表示要执行的操作,我们这里选FO_COPY,就是复制的意思,pFrompTo这两个字符串分别是复制文件的源路径和目的路径。执行时结果如下图,是不是很顺眼。

改写成DLL

前面的步骤做完之后,直接调试程序,看看它在各方面表现是否正常,全都弄好之后就该把他改写成DLL了。说起来这最后一步也最简单,只需要修改WinMain函数就可以了。把WinMain函数换个名字,然后再加上DLL的声明。
原先的代码:
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
……
改为:
extern "C"
{
                    __declspec(dllexport) int CreateDlg(HINSTANCE hInstance)
                    {
……
还有别忘了把消息循环里面对话框不应该有的处理方式都变一变,这样就能够编译成一个DLL了。

总结

虽然这个工程很顺利的完成了,但是最后还是没能交给用户,因为这样的程序调用杀毒软件完全受限制,对于瑞星这样的杀软就一点办法没有。可那个该死的客户还说另一个怎么都行,就得要一个瑞星。也怪自己能力不够,没有能把瑞星的程序破解了。但是最后,还是有一种可行的想法:就是利用SendMessage模拟用户的键鼠动作来操作瑞星,但是这样一是太繁琐耗时间,二个对于瑞星这么热衷的人,我很不待见,也就不想再做了。我自己能力有限,写了这么个只为留个纪念,如果希望跟我交流非常欢迎,意见建议也可以。转帖一定要标出处。
最后再补充一下关于头文件的问题。这里面用了那么多Windows APIwindows.h自然是一定要了。DBT_DEVICEARRIVAL等消息都定义在dbt.h中,而SHBrowseForFolderSHFileOperationShell函数则是定义在shlobj.h中。

阅读全文...