All Stories

野战,拓展训练

  昨天算是项目部年终活动吧。  上午跑去南澳打野战去了,是用激光感应的那种,不过感觉不好玩,对着打都没反应,一点真实感都没有。中午在那儿吃饭,说实话,饭菜的味道也很一般,倒是那儿的风景还真怡人,很适合像我这种人偶尔去去,放松一下心情,拍了一些照片,可怜我的T200当时买得也太冲动了,不但贵,还浪费资源,总是闲置着。  下午跑到海滩边搞拓展训练。说是训练,其实娱乐成分更多一点。先是让我们在10s钟内尽快拍手,我当时还估计大概能拍25下吧,结果实际上好像是拍了75下,大大地出乎我的意料,还有人声称自己拍了八九十下的,应该也是有可能的。还有个活动是看4个人光是用各自双手食指,就把1个胖子顶起来,也是很让我吃惊,很多时候只要方法得当,看起来不可能的事情还是被很轻松地完成了。接着我们18个人玩盲人方阵游戏,要求是所有人在30分钟内在蒙着眼的情况下,用2根绳子分别围成一个正方形和一个内切圆,并且要求正方形各边上的人数对应。结果据说我们是用了31分钟完成的,看完成后的效果似乎还不错。中间有一段混乱,也是必然的,缺少精细而有效的计划,并且缺少强力的领导。不过总的说来还是完成了,那教官还说我们是他看到的这么多HW队伍中最出色的了。我现在想想,觉得这也是可能的,我们算是测试的人,很多人却做些开发的事,所以两种人的特点都会有,对于发现问题、解决问题也就更可能会有直接快速的观点和方法了。再后来,就带我们去高空断桥,也就是八九米高的地方,从一边跨到另一边。我是第一个上的,当时隐隐有点儿兴奋,到了上面,架子晃起来了,就有点儿怕,于是不管三七二十一,就跨过去了,到了中间那段,晃得更厉害了,直没站稳掉下去,还一个劲地想站稳,结果还是不行,最后忍不住了,不稳也冲过去了。后来看别人跨的时候才意识到,这种事情应该是一开始就一鼓作气一路冲过去,在还没意识到恐惧之前,就已经完事了,呵呵。像我这样晃了好久,还试图让它不晃,根本就是白费力气。  这拓展训练,还是略有收获的。

又荒废了一天

  今天只是加了隐藏进程的特性。这是一段从CodeProject上找的代码,原理很简单,就是hook掉NtQuerySystemInformation。代码直接就可以编译通过,不过实际上使用的时候,发现好像只能在系统自带的任务管理器上有效果,连我自己写的那个ProcessHelper都逃不过,晕死。本来还想hook掉OpenProcess或NtOpenProcess的,不过不会弄,郁闷,先就暂时这么着吧。  今天又发现另外一个问题,程序在退出时需要很长时间,都过了MainFrame的OnClose了,进程会占满CPU近1分钟,都不知道在干什么。难道是那几个线程?以前一直都没问题的啊。而且程序启动得也是越来越慢了,想想也是会慢的,起来的时候,会连接远程数据库,打开本地数据库,打开一个UDP端口监听,起n个线程分别监视n个硬盘分区的文件系统变化,现在又多了hook API,还有Xtreme Toolkit Pro这套界面库会作不少操作,比如画出界面,又要初始化界面语言!要做的事情还真多,不慢才怪呢,比那Impeller都慢了,而且整个解决方案中已经有6个工程了,虽然有1个是原本设计的现在已经被废弃掉的服务器端,另外5个分别是客户端、Shell扩展、进程隐藏的hook用dll、远程数据库操作的COM组件,以及自动升级程序。  突然想找几本讲MFC的书看看,跑去公司图书馆一看,居然在关门整顿,白跑一趟。其实也就是想看看有什么讲画图方面的内容,这两天这样闲散下来,可以慢慢做些技术预研,呵呵,说得也太好听了点,哪需要什么预研啊,就是卷起袖子,一边试一边翻资料呗!说不定,过年前真的可以做出来哦,感觉这东东其实没多少内容,也许一个星期就能做出个粗糙的原型出来呢。只是没有上头的支持,我自己又不感拍胸脯,况且即使做了,也未必会被说好,唉,算了,走一步算一步吧。

又到编程低谷了

  这样的情形每过一段时间好像就会出现,怎么都提不起兴趣写代码。以前在学校的时候,几乎是半年一次,所以往往一个学年里,有一个学期是经常写代码,另一个学期就荒废掉了。可是现在处境不一样了啊,也许真的是被工作上的事情折腾的,无论在公司,还是回到家,就是不想写代码,好像转到现在的项目组之后,已经有过几次了。仔细想想,可能是因为一段时间的高度紧张,之后神经突然松弛,短期内就很难再紧张起来了。  今天在公司几乎也是无所事事地度过了,本来打算整一下调用脚本语言的那部分,后来还是没发心,只是决定还是不在公司里搞那个了,那套东东在公司里用不上,还是回家来搞。公司里应该考虑一下流程图的问题,决定要做一个简单的流程图编辑器,要自己定一种文件格式,能画,能显示。先做显示部分,因为无论是什么方案,这部分是都用得上的。早点搞完这个,早点从这个项目中抽出身来。

把界面改了一下

  今天把界面改了一下,本来默认用的Xtreme Toolkit Pro库的时候加载的资源是用英文的,但我的程序界面是中文的,虽然粗略地说可以使用,但毕竟感观上还是有点影响的,于是下决心看了一下它自带的sample,有一个就是演示了如果切换成其它语言的。把它里面的几个函数直接抠出来,贴到我的程序里,再把translations目录都复制过去,就能切换了。不过有点郁闷的是,用VC7.1编译这些资源dll时,有十几个编译不过去,不知道哪里出问题,还好我最需要的中文能编译出来,所以也先暂时不管这么多了。  一直想给列表上加个cool点的tooltip,可是换成了XTP的Report控件后,就再也找不到办法了,也只好暂时放弃了。  之后就一直无所事事。画图的方案还得上面的那些人拍板决定,所以我也懒得再花心思。最后快下班的时候翻出ruby来看看如何集成进C/C++程序中来。说起来我个人感觉,Ruby这套机制相比Lua、Python、TCL来,是最难用的了,太丑太傻了。不过也许是我用C/C++的思维太习惯了,以前看Lua、TCL的那套,很明显就是继承了C的思想,看到Ruby这套就觉得恶心了。每次调用一个脚本中的函数,都需要提供一个回调函数,这让我觉得很不爽,也许是我没用对,也许是它真的本来就是这样,而且《Programming Ruby》一书中就说,Ruby原本就不是设计用来嵌入到其它地方的语言,我再抱怨有什么用呢。

受不了了

  真不知道他们怎么想的。都已经到了要自己画出节点,画出节点中的文字,画出节点连接线的地步了,为什么还死抱着用Excel画出然后copy图片不放呢!自己做个编辑器,跟研究一套还不知道能实现多少效果的东西,需要的时间差别应该不大吧。时间其实都是在这种犹豫不决、优柔寡断中浪费掉的。  总之,我很无语。

要好好设计一下皮肤机制

  换墙纸的东东本来主业是为了能自动换墙纸,结果现在重心却移到了日历和时间显示上去了。关于界面方面的技术问题基本已经都解决了,主要是学那些日历软件的换肤功能,可以把PNG文件直接作为皮肤来加载,接下来就是要好好设计一下皮肤的机制。  早在做输入法时,就已经能实现换肤和异形窗体,那时只能支持BMP格式的图片文件,但所有代码全是用纯GDI完成,所以实现起来很简单,用API就能直接画出来,在窗口上写字什么的也很方便。但现在为了能使用PNG格式,就不得不用了GDI+,用PNG的好处在于,从图片上就能直接应用某些区域部分不同程度的透明化,BMP是很难达到这样的效果的。于是,从实现角度看,区别还是挺大的,而且不知道是不是我用得有问题,有时候它占用CPU有点多。不过暂时不管这些,毕竟能用了,先考虑一下如何有效地加载皮肤,并能比较灵活地定制和扩充窗体。  最先开始动手做这个东东的时候,原始的想法是时间显示是一个窗体的实现,日历显示是另一个窗体的实现,这样可以预见到的是对于界面部分的代码必定很大程度上是可以共用的,还甚至想过怎么把这部分抽象提取出来呢。到今天突然觉得,其实这个完全可以用同一个实现,至于显示什么内容,可以通过设计一个具有良好弹性可扩充性的皮肤机制来实现。初步想法是,一个皮肤至少包括一个图片文件和一个配置文件,图片文件用来最终描绘窗体,而配置文件则描述剩下的其它内容,比如在什么位置,使用什么字体,显示什么内容,这内容部分也是由主程序定义的一堆描述性的转义命令,例如当前日,月,年,小时,分等等。现在的困难就是配置文件要被定义成什么样,这个皮肤机制才能有足够的灵活性和后续可扩展性。比如显示内容,我可以让它是定义字体后再通过程序来输出文字,也可以是直接将另一个图片文件中的内容贴上去,我应该怎么选择呢?另外,因为想用一套程序代码实现时间和日历的显示功能,所以定义的转义命令也要考虑得周全一点,除了当前年月日,时分秒外,还需要星期、月历,也需要任意指定的某年某月某日的日历或月历,除了要有公历外,还要有农历和二十四节气、节日等等。  而这些,则还完全只限于实现一个时间和日历的功能,像现在的雪狐日历精灵,已经可以以皮肤的形式还实现计算器,游鱼等更实用或更娱乐化的内容。如果考虑到这些,这个皮肤配置文件就需要设计得更灵活强大才行。顺带还有另外一个待决策问题,这个配置文件用XML描述好呢,还是用Lua之类的脚本语言描述好?从我个人的熟悉程度来讲,XML明显好过Lua,从表达能力上讲,也许Lua更强一些,但ANT不也用XML实现了一套比较强悍的语法了么!  总之,这皮肤的机制得专门花时间认真设计一下了。

感冒了

  昨天感冒就比较严重了,流鼻涕不说,连嗓音都变了。人也有点昏昏沉沉的,不想干活。  无所事事了快一天,下午的时候终于下决心用VBA在Excel中写个宏,可以在工具栏上添加个按钮,点击这个按钮,可以把当前sheet中的内容导出成xml格式。这是那工具的一部分,因为要维护一个人员组织结构关系数据,我当初为了实现方便简单起见,就用xml格式来表现,因为xml本来就是一个树型的结构,跟我需要的完全一致。可是后来马上就引发出另一个需求,这个xml文件需要有人维护,而如果从头开始完全手工维护则太麻烦,于是就需要有个工具,能够从另外的地方得到数据,最后生成目标xml文件。  这件事本来一直搁置在一边没管,最近因为工具已经给几位老大演示了,于是让我感觉似乎这个应该花点时间先弄一下了。我们公司特别喜欢用Excel来存储和传递数据,所以很理所当然的,这个原始数据也是放在Excel中的。于是我先是犹豫了一阵子,这个工作是用VBA写好呢,还是用VC写好呢。如果是以前,我肯定不加思索地直接硬着头皮地用VBA写了,因为不懂如何用VC操作Excel,现在不一样了,哈哈,于是再一次印证,没有选择也是一种幸福呢!  开始前天的时候用VBA写了一会儿,发现很不习惯,有点想放弃了,到时候用VC随手写一个算了。昨天下午还是决定继续用VBA写,简单定了些限制和规则,可以直接按组织层次结构生成xml格式的文件了。后来又通过Lotus Notes的COM接口,通过工号查询到该用户的域账号。  基本完成,哈哈!剩下的就是主程序在启动时,装入这个数据前,需要能自动从网上升级。另外还要做的是,要hook掉NtOpenProcess,这样一般通过Windows的任务管理器就不能杀掉我的进程了,而同时在托盘右键菜单中加入一个退出功能,退出前会要求输入验证码,现在我把这个验证码设计为当前登录域账号的SHA512值,但我想,这个算法应该能自动切换,不同的时间自动使用不同的算法,这样就用户就可能很难猜出用什么了。

这东东还有得做了

  本来老大说要跟大boss去说先放缓其中一个需求的实现,结果看样子好像他也说不过,于是来跟我说要再好好讨论一下之后怎么做。下午,晚上,老大断断续续地提到过几次,都是关于那个需求的实现问题。原来的设计方案是完全行不通了的,还说下午大boss打电话给他,大boss自己在那里想了一个下午,关于工具的好多想法。把我们老大有点吓到了,一个二级部门主管,亲自过问一个工具的设计、实现细节,由此可见其重视程度,反过来讲,他是不是工作量不饱满啊,哈哈。  老大后来说了句,看来要自己做一个流程文件编辑器了。这是我从这个项目开始,就已经预见到的结果,似乎还隐隐地有点儿兴奋。不过我的想法跟老大的不一样,组里有一个三人组,对这方面技术的喜好几乎一样,认知程度也似乎很相近和类似,也就是绕着ATL、COM转,偏执地认为COM几乎可解决一切问题,什么东西都要跟COM挂上钩。这次的事情要跟COM搭上边,就是老大认为MS Office里有个Graph组件,所有的Office中的画图功能都是用它来实现的,鉴于Office中COM接口暴露得一直比较多,于是老大觉得这个Graph肯定可以通过COM来调用,为我所用,一旦研究成功,以后其它地方也是大有用武之地的。  但是在我看来,与其花时间去研究那些COM接口,似乎根本就没有任何可参考的资料,还不如研究一下图形学呢。相比之下,最大的难点在于线条的绘制,线条可以是直线、曲线,还可以有方向和端点,可以根据两端的节点移动位置而自动伸缩和旋转。研究那些COM接口,可能需要的精力和时间都不比研究图形学少,而且后者是一种通用的技术,一次学会,到处可以用,换一种平台也可以用,比如从Windows切换到Unix-like的系统,或者要在以OpenGL、DirectX之类实现的地方用,Graph那套东西就废了。  再次抱怨一下,过度的偏好,影响了客观评价能力。

改了一天还没改完

  说什么没有层次感,所以我就决定把ListView换掉,换成Xtreme Toolkit Pro里的Report控件。这个控件主要功能还是类似ListView的,以多列显示多个记录的各个字段内容,它多出来的功能就是能自动按指定的列分组,并排序。  于是今天就动手改,结果改了一天还没改完,工作量真有点大,毕竟也确实写了不少代码的,呵呵。而且顺便发现了一个严重的bug,以前居然都没意识到。简单描述一下,首先我从数据库中查询出所有的数据来,存放到STL容器vector中,然后每次用户通过右键菜单选择,或双击时,都是针对当前选中的项进行操作,这时就有问题了,我只是单纯地获取选中项在ListView中的序号,再对应到vector中找到那条记录,如果ListView中的内容自添加完之后一直没修改过,那么这样操作是没有问题的,但是如果通过点击ListView的头来进行过按列排序,那么这样做应该是不对了吧,这个ListView中的序号跟vector中的偏移已经不能对应上了。真险啊,幸亏现在就发现这个问题了,而且刚好反正是要修改这块代码。  另外一个问题是,需要把每条记录的唯一标志,比如vector中的偏移量,记录下来,在需要的时候可以马上获取到,这也浪费我不少时间,到下班还没搞好。  还有就是shell扩展总是有问题,问题源自于通过ADO访问Access数据库。本来我让shell扩展和主程序同时访问同一个Access文件的,后来发现主程序总是不能正常退出,看现象感觉是因为ADO访问同一个Access文件导致COM接口可能不能正常释放,所以进程退不出,到时候其它资源全释放了,却还有个残留映象在那里。于是我后来改成每次shell扩展需要查数据库时,都复制一个备份的Access文件,shell扩展就访问备份的这个。用了一段时间后,发现这样每一次查询操作都要先进行一次文件复制操作,效率太低了。于是改成让主程序每次修改了数据库后,主动生成一个备份文件,这样shell扩展就不用作文件复制操作了。但今天又发现问题了,有时候并没有生成这个备份文件,而我在shell扩展中并没有防御性的代码,直接就explorer.exe崩溃了。看来还得改呀!