Category imported from CSDN
尽管是后半夜2点才睡的,早上7点20又自己醒过来,真郁闷,于是开始打点,洗澡、洗头、刮脸、洗脸等等,然后上了一会儿网,到8点40的时候,开始收拾要带的东西,就是换的衣服、泳裤、太阳帽、拖鞋这些,就在要出门的时候,同事打电话来催了。这次忒方便,就在小区门口的公车站上车。老大的帽子和太阳镜好 fashion!
先骂两句,这个csdn的blog太太太太太不稳定了,其稳定性只能用一个字来形容,“烂”,如果可以用两个字的话,就是“很烂”,再长一点三个字,“非常烂”,四个字的版本是“咋那么烂”,假如一定要用五个字的话,我想说“烂得不得了”!
用鱼鱼桌面秀装扮了一下桌面,视觉效果不错,不过最大的一个毛病,就是总要把程序焦点抢过去,所以导致有时候为了做点事情,不得不先把它关了。这样一来,它就真的只是个中看不中用的东东了。另外就是,它居然用Object Pascal作为它的脚本语言扩展,好像InnoSetup也是用OP,网上有个RamObjects的project,不知道有没有什么联系。鱼鱼提供了一大堆的函数,不过看了一下论坛上的扩展,似乎绝大部分第三方的插件都仅限于在官方插件的基础上换个皮肤,没有其它更有创意的东西了。以前用鱼鱼日历秀的时候,在Windows的进程管理器中看到它占用的内存很小,很惊奇,昨天才用LLYF ProcessHelper看了一下,其实它占用的内存峰值还是超过30MB的,估计是不停地调用EmptyWorkingSet造成占用物理内存低的假象吧。
今天下午去跟一个同事买电脑,先是跟xcc走来走去,逛了2个小时,然后找到同事,一起去逛电脑市场,同事看了几个本本后,毅然决定买一个,而且在那样的价格底线下,同时又要追求一定的外观和性能,只有那么几款了,就只追着HP的DV1600系列看,最后,想要的DV1617也没有了,无奈之际,只好转向 Compaq,看中一款2626AU,似乎外观稍微次一点,但其它的都还可以,基本能满足同事平常娱乐消遣的需求了。装的软件全是D版的,晕!不过怎么说,也算是可定制程度高啊,像IBM的,就那么弄死了。
这句话是从一个同事那里听来的,那时还蛮不在意的,觉得只是随心之语。
在VCKBASE 上看到一段代码,觉得好玩,打开VC2005 试了试,得出一大堆数据来,高兴死了。于是想增强一下ProcessHelper,把代码从VSS 里Check out,打开BDS2006来,整了一会,发现有一部分代码总是工作不正常,而同样的代码在VC2005 里面却工作得好好的,这是怎么回事!不禁又要抱怨一番,总感觉除了VCL,Borland 的C++ 编译器套件不如Microsoft 的好用(其实是我自己的问题啦)!稍微仔细地观察一下问题现象,发现似乎是结构体里面引用成员变量时错位了。我马上想到,是不是字节对齐的缘故。然后加上调试语句,看这个结构体的大小,果然在BDS2006里是 56bytes,而VC2005里是64bytes,差了整整8个字节,还以为是编译选项没选好,就在这个结构体声明的地方加了强制8字节对齐。试了试,还是老问题。于是索性在使用这个结构体的地方,把各个成员的起始地址都打印出来看,好像两边都一样。后来,想想用sizeof看看里面各个成员变量占用多少空间,发现BDS2006里最后两个成员,都只占用1byte,而VC2005里都占用4bytes!看到这两个变量的类型,都是枚举类型,突然想起C++ Builder里有个编译选项可以设置是否把枚举类型当作整型来处理,找了一会,勾上这个再编译,运行,果然好了!
我不知道应该怎么把宿主程序提供功能并开放接口给插件。不知道用COM 行不行?
以前写什么程序,都是随着自己的兴趣来的。那个LLYFSpy,完全是看着MySpy 和Spy4Win,觉得可以把它们两个的功能整合一下,再加一点其它的功能,于是就成了现在这个样子,而且前段时间有一次为了研究一个别人的程序,发现有些时间只有用Spy++才行,于是责问自己,为什么LLYFSpy 不行,不是早就得意洋洋地认为全面超越了Spy++的功能了吗?再早一点的ProcessHelper,也是因为看到优化大师里的那个进程管理器,觉得可以撇开Windows 的进程管理器的功能,再实现一个自己想要的功能的程序。还有那个阿菲连连看,动机更简单,就是为了享受阿达连连看那样的视觉和听觉上的效果,又苦于网上找不到好用的破解,就自己写一个,写完不久,就全丢了。还有其它的一些小程序,比如IPKeeper,为了在学校的时候被人冲IP 掉线的时候能自动修复网络连接等等等等。上次硬盘出问题,结果弄丢的计划书,看来也许是反而有点好处的,可以让我再重视仔细审视一下写程序的目的,为什么要写这样的程序。以前计划了好些,模仿QQ 游戏的程序,现在想来,没多少意义,对于现在的想法来说,确实没有多少意义,现在我只关注的是,能不能用程序来做点有用的事情。看到按键精灵,觉得它很赚钱,于是也想弄一个类似的,但还要强的东西。看到鱼鱼的日记本,我突然很沮丧地觉得,我一直想做的,被他做了。我现在要做的,应该是经过调查后确认有意义,才做的。那个YuyuNES 是绝对有意义的,因为一方面,可以对虚拟机的实现有所研究和实践,另外还可以对 Windows平台上用DX进行图像和音效处理有相关的经验,这正是Windows上进行游戏编程的两大基本技能。LLYF VirtualTyper 呢,一来想尝试一下新的软件架构的想法,二来为了去分一杯羹,呵呵。
今天,是我旁边这个同事最后一天来这里上班了,明天开始她就请假不来了,下周就去北京报到了。她是个很厉害的人,所以公司也不舍得失去这样的人才啊!愿她在新的工作岗位有新的发展,呵呵!
今天在公司,感觉没什么事可以做的,其实零零散散还是有些事,但就是没提起劲来。突然觉得在这里混不下去了,有点需要重新正视自己,我是不是有些什么问题,怎么没人会喜欢我呢,连工作的时候跟领导关系都搞不好,领导都不喜欢我,当然混不出啥名堂了。一旁的同事在那边收拾东西,她终于可以如愿去北京了。另外一个最近经常一起吃午饭的同事,说已经跟领导说了,要辞职了。我问他去哪里,他说还没找,就在这里找一下,想找个自己感兴趣的岗位。还说,上次问过我想不想干些自己有兴趣的事,而我似乎没怎么积极地响应他。我是又发现了自己一个缺点:胆小。我是肯定没有这么洒脱,敢这样不找好后路就辞职。但是,我今天也确实觉得很不爽,觉得自己混不下去了,一定要换个环境才行了。也许我真的是太心高气傲了。我要辞职,脑海中就只有这么个念头,连和我一起大队培训,一起到部门报到的那个同事都辞职了。只有我,死守着这块没有生机的土壤,不敢有任何异动。给afei发了条短信,她也没多说什么。突然很想知道,小玉玉现在怎么样了,那个一直吵着要离职要回家的小女孩,有没有哪个人可以让她安心留下来呢,就像小妞那样。
不知道是不是因为周日晚上的关系,网速特别慢!因为人们都在这个时候回到家,然后觉得有必要上一下网。L.L.叫我去看她的blog,想留言,却硬是有点问题,不知道是MSN 的blog 和FF 的搭配使用本来就有点问题,还是MSN 的blog 的自己的问题,或者是FF自己的问题,再或者是因为网速慢的缘故。自从搬过来这边能上网以来,一直都是使用FF的,装了几个插件,但今天才发现,原来FF占用的内存非常大,最小化的时候系统还不回收一下,它占用的CPU 也经常很多,说实话,我个人很菜地认为,这方面,FF 确实比不上IE!而我现在用它的理由是,一来它开源,它免费,二来,很多流氓软件,流氓代码都只对IE有效,FF的免疫力暂时还不错,三来,FF 有一个比较方便的标签浏览功能,IE 好像还没做到这么好,有个假的糊弄人的!冲着这些,我用坚持用FF 已经1个多月了,几乎不用IE来看网页了,即使是些IE Only的网页,也用IE Tab 扩展搞定了。
早上还在睡觉的时候,Softtrain就发来一条短信,说在搬家了,要11点到,然后我就迷迷糊糊临时修改行程计划,等他过来了,在这边一起吃个饭,再过去。等过去了,就被说成我放人家鸽子了,郁闷,有点不好意思,确实似乎是放人家鸽子了。在空调下面吹了一会儿,Softtrain就说要走了,要去华强北,我又临时改变主意,我不想动了,然后就落在那里不走了。过了一会儿,去红树林,打了几个小时牌,斗地主。然后去吹了吹海风,天气可真够热的。还去下面捉了两只只有我大拇指指甲那么大小的蟹,好乖哟,结果给了一个小孩子,还被他的大人说,快点谢谢叔叔,郁闷!那大人还是反应比较快的,马上改口说,快点谢谢哥哥。想起那次和小玉玉在百草园超市的时候,一个小女孩先是叫我叔叔,被小玉玉趁机嘲笑了一番,小女孩又叫小玉玉阿姨,我就趁机嘲笑回来。看来我的长相确实比较老。
整了几个小时Scintilla ,不知道我嵌入后,那个WM_NOTIFY 被VCL 从哪里截走了,就是找不到了。我还指望它来实现代码折叠的呢,这种时候RAD 的就是要费更多时间来找其中的机理了,在公司的内部网络上,也看到过几个帖子涉及到VCL 的消息传递机制的,当时还充当过大牛的样子呢。郁闷,不过显示行号的功能倒是搞出来了,看到几个网上的文档,加上SciTE 和Notepad++ 的源代码,勉强可以凑合,但是代码折叠的不是Scintilla 的问题了,现在的瓶颈是VCL 把我的WM_NOTIFY 藏起来了。
晚上让Softtrain在下面等了大半个小时后,终于解脱了,然后带他去毛氏吃饭。其实是想不出其它我喜欢的地方,所以就去了,好久没去了,居然遇到小妞和小思宇,然后就和她们俩一起吃。真是好久没吃了,就是想不起能点些什么菜,看了菜单也没啥想法~
整了下Scintilla,把它弄进去了,初步了解了怎么让它支持某种语言的关键字高亮,还是非常非常方便简单的!以后还要加入代码折叠,行号显示以及自动完成功能。如果是要专心地完成一个编辑器,要做的事情还是比较多的,看一下SciTE 和Notepad++ 就知道,不过我可能不需要做那么完整,只要有个看起来比RichEdit 强一点的编辑框就够啦,哈哈!这部分代码以后重用的机会肯定还是有的,比如MspEmu 中。另外就是,对关键字高亮的支持,应该写一个通用的接口,然后把语言相关的信息全都写到外部的配置文件中,这样才是比较经济又灵活的方案,呵呵,然后要动态判断是属于哪个语言的代码,再动态地修改Lexer 属性。这样以后可以在不修改主程序的情况下,动态地添加对新的语言的支持。
按键精灵,模拟精灵,按键游侠,都提供了不同程度的对Windows 平台下鼠标键盘的输入的程序模拟,可以实现无人值守的自动化某些机械重复的操作。其中模拟精灵的功能整体上远远强于另外两款,它似乎是真心致力于成为一个通用的自动化工具,而不像按键精灵,打着合法的旗帜,提供了一系列的功能方便用户写出挂机脚本,大规模地流行于网游玩家之间,但是反复地强调自己的合法性,却死守着不愿意增加某些特性,并以此为自己辩解;按键游侠则似乎还没有多少明显的论调或态度,从它提供的功能来看,它是直接宣告自己的辅助网游工具的角色了。三款工具,模拟精灵的功能最为复杂,能做的事情整体来说,应该也是最强大的,但是正是这些强大的功能导致的使用比较复杂,吓走了大量的低中级网游玩家,而投入按键精灵的门下,按键精灵经过几年的发展,功能上也大致够用,技术上的积累基本已经走到尽头,现在已经疲于干些网游外挂才干的事,一心想的就是如何能防封杀,从现在最新的发布版本5.92来看,按键精灵的VBS 支持以及DLL 插件的架构,几乎已经可以实现所有需要的对于按键模拟的功能,而不用修改主程序,主程序确实只要把精力放在如果提供更好的反反挂能力上,但因为大量的按键精灵用户都是只会一点点VBS 的初中级用户,稍微需要点Win32 API 知识的问题,VBS 直接解决不了的问题,用户都会等着官方版本的升级来解决,而按键游侠,也没有多少新的创意,几乎是按键精灵的翻版加上一些用户迫切需要而按键精灵出于某些原因暂时没有加入的功能,从用户积累,品牌效应以及技术等方面看,按键游侠要在短期内超过按键精灵是不太可能的。
前一天晚上,afei 在MSN 叫我今天去她那里,我还说,下班太晚了,不去了。结果今天中午去食堂吃饭的时候,被z3 诱惑了一下,就说要一起去了。
坐我旁边的同事,终于辞职了。今天看她在那里一项一项地给其他同事交接工作,不禁感叹,这个世界变化也真算快的。去年7月我来到公司,在导师旁边坐了两个月后,从9月开始就一直坐她旁边,在工作上,她真的给我莫大的帮助。每次有什么问题,我总喜欢问她,而她也一般都会知道这些事情。一方面她确实是个很认真很能干的人,另外一方面我有时候觉得,读过研的人,在某些方面,考虑问题的全面性深刻性就是比只上过本科的人要强。现在她终于决定走喽!少了一个幽默又爱搞笑的人喽!
中午去食堂,排队打完饭,走到平常一直去的位子附近,扫视了一遍,却没想到什么东西,大脑一片空白,甚至只看到一个个的人坐在那里,却看不到这些人的脸长什么样,似乎连其它声音都听不到了。
上午刚起床不久,在上网的时候,一个陌生的号码拨进我的手机,听到的是一个软绵绵的语速缓慢的女声,还在那里问我知道是谁不,我说知道啊,她说怎么会知道,知道就怪了,我就说不说是某某吗,然后她就觉得有点吃惊说,听得出来啊。呵呵,当然听得出来了,这么有特色的语气语调,认识我或我认识的人中,也就这么一个人了。然后她说,今天到我家来玩吧,坐几路几路车在哪个站哪个站下看到哪栋哪栋建筑往哪条哪条小弄堂里走就能看到那个叫啥子啥子的小区了。我就接着说,是那栋那单元那套房吧?她就在那里叫,啊,你跟踪我。我才不会这么费劲呢,只是刚好前一天看到旁边那个人的邮件上写着这个地址,看过一眼,刚好到现在还记得罢了。
用Borland 的编译器直接编译了一个lua5.1的源代码,生成了一个lib文件,链接进我的工程里,就是不能用,工程的编译链接都可以通过,但是到运行可执行文件的时候,就直接弹出个访问违例。倒是那个我用VC7.1编译的dll 文件,从中导出一个lib 文件一直用得好好的,晕!
我终于放弃了嵌入Python 解释器的努力,反正经过Lua 和Tcl 两种语言的嵌入工作,看到Python 的简直想吐,为什么要弄得这么复杂?先把这部分屏蔽掉吧!
界面稍微改了一下,把协议模拟的按钮和菜单项隐藏起来了,因为肯定没时间做了,另外在工具栏上添加了个按钮,可以拉出菜单,选择运行插件。
原来在getglobal 函数名前,loadfile 后,要先pcall 一次,0参数的,然后就可以正常地调用脚本中的函数了。这点白天就想到了,晚上回到家,看到mail list 上也有人说了。
在脚本里写了个很简单的函数,然后在宿主程序里调用它,死活调用不成功,看一下错误信息,说是试图调用一个nil 值,可是我明明在脚本里定义了这个函数的呀。其它部分倒还好说,在宿主程序中可以取得全局的脚本中的变量值,脚本也可以比较顺利地调用宿主程序定义了并注册给解释器的函数,现在就是这个搞不定,郁闷,只好操上蹩脚的english,上mail list 里问一下了。如果不行,还有一条路可以走,想办法能不通过函数调用就取得宿主程序中的变量值。开源的,文档就是少啊!
白天跟旁边一个同事说,我最讨厌跟人打交道了,同事说,你性格有缺陷,然后又不失时机地说,加油!我只好硬着头皮给那些人打电话,发邮件,爱理不理我也不管了,自己心里想开点想通了就好了,都是给人打工的,没什么差别的,有什么好怕的,有什么好拽的。
回来的时候刚好遇到雨最大的时候,只是保护了上身没被打湿,hoho~~~
今天看到小妞了,中午在食堂底楼靠边的地方,还是那个样子,圆圆的脸,披着一头长发,慢条斯理地吃着菜,估计是在等人。我当时有点意外,因为没想过会遇到,都快忘了她在每周最后一天经常可能会来“贩卖人口”。我只是说了句“又来……”后面的没说出口,一时语塞。
想起那次在茂业被说成是兄妹,呵呵。
突然觉得我这些天一直在做着一件毫无意义的事情。也不管那么多了,现在只能咬着牙,硬着头皮把它整完了,这季度考评中有5分还全指望这个了。
增加了浏览脚本源代码和用外部程序打开脚本文件的功能。读文件部分直接用Win32 API 来做,感觉有点怪怪的,还是习惯用C 库,连C++ 标准库都没啥了解,也许过些天心血来潮会把它改掉用iostream 来实现吧。现在插件管理功能基本已经达到预期目标了。
意外地发现,只要对hhctrl.ocx 执行implib 导出的lib 文件就可以直接用在BDS2006 的工程里了,再也不用LoadLibrary 和GetProcAddress 了,再也不用为什么时候FreeLibrary 而发愁了,一切都变得那么美好,意外地发现,sf.net 上还有个叫bccSDK 的项目,专门把MS 新发布的一切库移植到可以用Borland 的C 编译器下使用,其实就是一堆的lib 文件,当然还有那个htmlhelp.lib,不过我没有用,因为我已经自己暂时解决了,只是奇怪的是,以前明明我也这样做过,为什么不行呢?
看起来对应用程序与Tcl/Lua/Python 脚本语言之间的链接没多少问题了。至少到现在为止,给MspEmu 加上了最简单的链接嵌入,运行时从进程的模块列表中可以看到,三个dll 都赫然入目。每一种交互都需要一个初始化和清理扫尾工作,这个似乎都是约定俗成的。稍微抱怨一下,这方面的资料还真是少,google 了一番也没找到多少有用的信息,还是因为我的信息收集能力太弱了。
昨天突然发现,外接硬盘中有个分区打不开了,连卷标都丢失了,很郁闷的是,这个分区里放了些对自己很有纪念意义的照片,以及一些才收集来的文档和资料,所以很不甘心,文档资料可以再去网上找,但丢失的照片是只有这个“孤本”的,所以晚上就睡得有点不舒服。早上起来,还想能不能放到别人的电脑上去看看,能不能读出来,后来想想算了,估计也是没希望的,于是就在Windows 自带的磁盘管理功能里把这个分区删除了再添加上,盘符还是改成和原来的一样。然后尝试打开它,当然打不开了,它提示没有格式化,死马当活马医,就快速格式化了,文件系统也用和以前一样的NTFS,然后很怀旧地建了个一个和以前一样名字的文件夹。突然想起那些数据恢复工具不知道有没有用,于是上网搜了一下,down 下一个EasyRecovery 的专业版来,试图用Unformat 来恢复,搞了半个小时,没找出东西来,用Undelete 也没用。正当要放弃的时候,看到还有个RawRecovery 功能,就试了试,还真能找到一些文件,只是文件名全改乱了。太开心了,下午就出去了,让它自己在那里恢复吧。等晚上回来,重要的那些东西恢复了多数,主要是那些照片,还有些文档也恢复出很多,只是很多都损坏了,不能再打开了。整理了一部分,发现一个现象,ZIP 的包损坏率比RAR 的高出很多,可能是RAR 包的自我修复能力比较强吧。还有些doc 和pdf 文件,打不开了,不过不是很重要,也就随它去了,反正大概估计了一下,那些近期想要的文档都还知道网上从哪里能找到。
afei 她们事业部开“本部之星”的K歌比赛,xcc几天前开始约我有没有时间一起去,我当然欣然同意了。我们可真是翻山越岭啊,跋山涉水啊,历尽千辛万苦啊,转了几次车啊,先从我家门口坐328 到梅林,然后再坐334 到南山海雅,再坐226 到目的地新桃园酒店。结果我们迟到了1个小时,还好,只是前面唱过几个人,afei 还没上台。过了一小会,就是afei 上台了,离上次见到她又是有几个星期了吧,xcc 虽然是跟她一个公司的,但工作地不在一起,所以也应该很久没见过了,路上的时候我还向他介绍说afei 现在变瘦了,变漂亮了。现场的气氛很好,下面的观众都很配合台上的表演者,afei 那首《听海》也是唱得很有水准,有点像张靓颖的风格,嘿嘿,xcc 说不知道什么时候变得这样了,跟平时说话的时候完全不一样了,肯定是练了很久了。前面4个选手没听到,反正后面的6个我都觉得很明显唱得不如afei 好。台下的观众真的很热情,想想我们当时整个光网络产品线搞节目,产品线总裁在台上嘶声力竭地喊“大家一起来”,结果台下的人还是反应平平,木然地摇着手中的道具,傻傻地坐在座位上。
这周考了三场,周一到周五隔一天就一场,每门都是要求85分才算通过,这才是最让人郁闷的。不知道从何时开始,我就对考试怀着一种畏惧的心情,总是给自己心理暗示,说自己不擅长考试。还在大学的时候,60是最后的底线,但往往只要能找到足够数量的比自己还要堕落的人,还要低的分数,就算再低的分数也是能死里逃生的。现在就不行了,反正85分是硬指标,当然同时也是最终结果,至于过程如何,就看各人各显神通了。想起《Naruto》中的中忍考试笔试部分,就被称为是为了考验考生的情报收集能力,隐藏能力云云。结果看来我的情报收集能力似乎还算过得去的,只是自我保护意识薄弱了点,隐藏能力欠缺了点,呵呵。
看了一下把Lua嵌入到MspEmu中去,虽然从官方网站上down 到了据说是兼容BC 的编译器的二进制lib 文件,但实际用的时候似乎还是有点问题,说_errno 的引用找不到之类的。顺便在google 上找了一下Tcl 和Python 的内容,本来这些动态语言在与应用程序交互嵌入的时候都是优先考虑 VC的,有的几乎就根本不考虑其它编译器的情况,包括Borland 的。看了一下,有两种方案,一种是,如果已经有lib文件了,但是用VC编译器生成的,就用Borland 的一个随它的C++ 编译套装一起发布的小工具coff2omf 转一下格式,因为MS的二进制映像是coff格式的,而 Borland的则是omf格式的,这样转一下就可以链接到Borland 的C++ 工具生成的项目里去了,具体我也没实践过,不知道是否能用,总之看起来似乎没什么错,有道理的。另外一种是,找到那个dll 文件,用Borland 的一个小工具impdef 导出DLL 中的函数名,然后有个tcl 写的脚本,把别名处理一下,生成一个新的函数名列表文件,用这个新文件作为参数运行Borland 的另外一个工具implib ,就可以得到一个lib 文件了,直接用implib 也可以从dll 文件导出lib 文件,但也许VC生成的dll 中导出函数名与BCC 有区别,不一定能用。
用BDS2006发现好像编译速度变快了,快了不止一点点,尤其在make 一个project 的时候,如果有好些源代码文件,而其中只有一个文件是改动过了需要编译的话,感觉特别明显,比起用BCB6 时加上pch 插件还快。
昨天,哦不,应该是今天凌晨,熬夜装好的BDS2006,晚上回来就试用一下。把那个写了一半的数据分析程序从BCB6.0 移植过来,很顺利,因为我都没有使用其它任何第三方的控件。传说中改进了内存管理器,但这一点我是没什么切身的感触。有时候我在想,我为什么要升级,从BCB5.0升到6.0的时候,只是看到IDE中编辑器的代码提示功能相对好用了稳定了些,其它的都还没来得及比较,因为对于我来说,根本用不上那么多特性。这次升级到2006,看起来也只是IDE 变得更漂亮了,带来的副作用就是需要更大的内存,更快的CPU……另外的好处就是前面提到的,Borland帮我在后面默默地把内存管理做得比以前更好了,还有就是也许VCL之类的有些小改动,再看一下编译器,从5.6.4升级到5.82了,不知道有多少实质性的进展,更好的标准符合度?更强的代码优化?还有呢,对于我来说,大概就这些是有影响的吧,其它的实在也看不出来多少必要。
才说要考试的,说要85分才通过的,结果因为动用了一些不正规手段,虽然得了86.5,结果被逮出来了,老大说,有没有觉得冤枉之类的其它想法,我说没想法,既然被逮到了,就没话好说了,谁叫只有我们三个人过了85呢,而且对的错的又全都一样。
历尽千辛万苦,在eMule 上下了一个多星期,当然不是每天24小时开着,总算把前面3个CD 的镜像拖下来了,开始还以为不能用,因为看了网上n多的帖子文章,说前2个CD 的要repack 的才行,果然在Alcohol120% 里加载那几个cue 文件时,都说不能访问文件,用UE打开一看,里面的文件名似乎有点问题,改成对应的bin 文件的名字,再来加载,就可以了,如果只是要装一下C++Builder 和Delphi 的for Win32部分,很快的,不用第4个CD 的,我都没down 完,反正可以装了,装完之后,C++Builder 部分显示的是Preview 的,但是可以正常启动使用,也可以编译程序用,简单拖了个窗体,放个Button 和TMainMenu,都可以用。然后去Borland 的网站上down个Update2 的包下来,我的是Arch 版的,Update2 包也要对应的Arch 版的,装上后,从原来不要求注册的,变成要注册了的。在google 搜索的话,可以找到很多patch 的下载,其实有个更简单的方法,用UE 打开BDS\4.0\bin目录下的sanctuarylib.dll 文件,十六进制显示,搜索8D742444B90400000033D2F3A75F7504,把最后的04改为00,保存一下,再启动BDS,就可以发现不用注册了,而且C++Builder 也不再是Preview 了,哈哈,happy!
昨天,终于让我见识到晚点7小时20分钟的火车,本来说好是15:33就可以到站的,结果一直拖到22:50以后,在从火车站回家的公车上,xcc 发短信来说,刚刚从新闻上看到,这趟车昨天晚点9个小时,我不禁苦笑,看来今天运气还是不错的,只晚点这么点。从下午就开始计划的,xcc 无聊了跑到我这边住的地方,两个人也还是很没事做,他在那里上会儿网,我则在床了眯了一会儿,大半个小时吧,好满足啊!然后实在不行了,挨到快6点的时候,就说还是出去逛一圈吧,于是说去梅林吧,吃个饭,顺便逛一下家乐福,然后消磨点时间,再去火车站。于是跟z3一起去了,去了一家湘菜馆,味道还是不错的,价格也公道。吃了三碗饭,快一个小时吧,接着去了家乐福,xcc 特别喜欢在这方面的事情上鼓动我,他和他女朋友都特别关心我这事。我这次是完全没有这个心思,全是当作朋友之便。于是去买席子,居然买到那种一年四季都可以用的。然后xcc 和z3 在那里帮我想,要买些什么东西回去,什么牙刷啊,毛巾啊,牛奶啊,饼干啊,还有卫生纸-_-b等等等等。现在的我,变得特别心疼花钱,在拿出卡来刷的时候都还是觉得有点舍不得,但是为了面子上过得去,我在这时花钱往往还是很大方的。从家乐福出来,z3 就先回去了,帮我提了点东西,我和xcc 为了去买一张手机卡,为了买得不花多的冤枉钱,走啊走,雨也是下一会停一会,郁闷,终于在一家店里买到一张含51元话费卖55的动感地带的卡,号码也感觉不差。这时都已经9点了,那边的某师兄打电话来了,我匆匆忙忙爬上公车赶去火车站。车开得比我想象中快多了,9点半的时候就到了,顺便去熟悉了一下火车站的环境,看了一下出站口,候车厅这些地方,才去找那某师兄,两人等了一个小时,这某师兄也是很热情一个人,我都没想过,他说要买站台票进去,于是和他一起进去了。又换站台,这火车还真能折腾人,终于等到它进站了。还好,我很快就在窗外认出来了,虽然一年不见了,只在电话里听说过又染发又烫发,还变得又黑又胖又长了好多痘,看样子也只是脸真的比以前更胖了。前一天在QQ 上,我还吓唬说,我现在的发型很怪,不要认不出来,然后她说,你认得出我来就行了,结果还是被我耍嘴皮子戏谑了一番。折腾到0点半才到家,小思宇的那双因为夹脚处很硬而被主人遗弃的拖鞋也派上用场了,席子,毛巾也都有用了,胡乱洗了个澡就睡下了,累。
那天说到日历软件的界面实现,鱼鱼的桌面日历能把窗口一直停在最下面,无论怎么拖动,窗口还是停在其它进程的窗口下面。上google 搜了一下,发现其实要实现这个很简单,只要截获WM_WINDOWPOSCHANGING,把LParam 参数指向的结构体中把hwndInsertAfter 的值改成 HWND_BOTTOM就可以了。现在几乎所有的日历软件需要的界面技术都可以实现了,相比之下,我个人更喜欢鱼鱼的方案胜过于ADC的方案,呵呵。
看了一会儿NES的 相关资料,都是硬件相关的,一般也就是硬件资料是需要了解的,包括经典的Marat Fayzullin 的NES.doc,看得头昏脑胀。果然,发现自己不是个能静下心来搞研究的人,哈哈,afei 还说过如果我想成为技术高手,就应该如何如何的,嘿嘿,我怎么会试图希望自己成为一下技术高手呢,我只是单纯地期望能解决眼前那堆琐碎的事情而已,呵呵。直到最近,才领悟了自己学习编程的真谛,写程序是一种手段,一种能提供自己偷懒机会的手段。
来这以后,开始大半年是因为没有电脑,所以没写过代码,在公司里即使没有说忙得昏天黑地,但也已经懒得再去动额外的脑筋了。说起动脑筋,想起有个笑话说,爸爸教育儿子,你以后要学会动嘴皮了,就可以去作市场管理了,如果只会像我这样动脑筋,就只能做这可怜的程序员了。扯远了。
随着今天下午搬走了最后一批东西,包括一张床垫一个皮箱一包衣服和一箱书,我可以说已经正式告别了这个住了一年的地方,这个自我走出学校进入社会后第一处自己花钱住的地方,留下了很多回忆的地方。
今天和小思宇去那边把餐具收了一下,就是几只碗,不锈钢的汤盆,还有个美的的电饭煲。女人的想法就是有点怪,叫她把所有的碗和盆都拿走,开始死活不要,说只要有个碗就行了,因为碗好看,而且只是用来一个人泡泡面吃。后来好说歹说,才把所有的东西都装在塑料袋里都拿走了,还一边走一边说,说了好几次哦,真的好几次哦,说自己像个收破烂的,把她们不要的东西都收回去了。到了她自己住的地方,和她再出来的时候,她还在嘀咕,你说她们知道我把这些东西都拿来了会不会吃惊啊!真是个有趣的女人,还说要省钱,这不就是省钱之道吗?然后我就直接坐车到这些天一直睡的地方去了,因为有网可以上,所以都不回那边去了,导致昨天偶然回去一看,那天走的时候居然没关空调,让它白白在那耗了48小时!郁闷,也许,等后天,我真的把东西全都搬走的时候,我会舍不得那里吧,毕竟在那住了一年了,所以才会跟同学借了相机在那小小一块地方都拍了150张照片。
今天看了一下两个日历软件的界面实现,一个是老外的ADC,还有个是国产的鱼鱼桌面日历秀,它们都有一个特点是,能把日历显示在桌面最底层,就算你用鼠标在上面点,划,都是相当于直接点在桌面上,但是视觉效果上,它们又是确实存在的。
昨天下午和小思宇一起跑去华强北买东西,结果用小思宇的话说,我们两个人四只眼睛还是没看清楚,买的转接头还是有问题,是反的,不能用,小思宇估计是要郁闷死了,为了个硬盘转接头耗费的精力不知道有多少了。晚上回来,就在各自的屋里用各自的电脑打着各自刚刚买来的摄像头在那里玩视频,用玩QQ 还用MSN ,还真是会闹,自己回想起来就觉得有点好笑。
我什么都不知道,只是在这心情极其糟糕之际随便发了一通毫无作用毫无意义的牢骚,float 突然给我发短信问我咋了,我只是简单地告诉她,我伤害了一个我很喜欢的小女孩,float 简单而直接地问,喜欢她为什么还要伤害她?我如果知道原因的话,就不会这么郁闷了!好了,看看他们的点名游戏,第一次玩,不过我似乎找不到这么多的二次转发人……
从未有过的懊悔,从未有过的心碎。\
难道人就是一定要在犯错误的过程中才能成熟,可是这个代价也太惨重了。为什么要伤害一个这么柔弱的,一直想着要以自己的力量自己的方式来保护的人!
这两天把这个MD5 计算工具修改了一下,主要是为了自己的需要,比如我想用它来计算光盘中所有图片文件夹下的图片文件的MD5 校验值,所以就添加了搜索文件夹或包含子文件夹下所有文件并进行计算的功能,果然是手生了,反正慢慢吞吞的,还犯一些很低级的错误。顺便也能把文件夹进行拖拽了,不过现在看来对大文件,或是被其它进程占用的文件会出错,那些个错误提示框还真是难看,需要改一下。
经过昨天晚上和今天晚上的消磨,把几个LLYFSpy 原本就集成的功能用插件方式写了一遍,插件都是用SDK 的方式写的,用VC.NET 2003 编译的,所以又小又紧凑,还是花了一些时间,我一边移植,一边还在想,这样做的意义有多少-_-b
打算做一个电子相册程序,是为了那些毕业时照的照片刻成光盘后便于整理和管理的。本来是希望能做成多媒体光盘的,无奈我实在是没有艺术细胞,没有美工做个屁的多媒体光盘啊,所以就做个简单点的程序算了,大概想了一下功能需求,有个图片浏览功能,外加评论编辑显示功能就基本成形了,不过如果只是这样的话,就太寒酸了,就多添加一点附加功能呗。比如相框功能,大头贴功能,这两个功能很相似,我的想法是相框功能比较简单,只是给图片外边框加上一圈其它的图案就行,大头贴功能就复杂点,需要能自由选取图片中的任意一块图形,并能缩放大小。还有一个功能是日历月历制作了,所以要加一个日历节气计算功能,似乎这部分是整个程序里唯一有点麻烦的地方,节气日历的计算有点复杂。要加个背景音乐播放功能,用BASS 就能解决,因为时间比较短,就一切从简。
这是一个对原有项目的改装工程,目标是实现一个可自动装卸的系统,使日渐庞大的原有项目能以另一种轻巧的形式存在。
这是一个比较庞大的计划,甚至可以说是一个好高骛远的计划,不过权当作一种业余时间的消遣活动和提高自身附加价值的手段吧。
现在来写我的2005年终总结,似乎有点不合时宜,但似乎也找不出其它更合适的时候了,因为我是有一大串真正的苦衷的。
大四真的轻松。暑假的时候,xcc从重庆跑到杭州去玩,然后叫了我一起去湖州ShuoNiMa家,然后又去我家。那次暑假真的出奇的热,而且最郁闷的是,我们那里隔一天就要停电,因为电力供应不足!xcc在浙江呆不住了,就鼓动我早点回学校,其实是他想回家了!
最开始灌水,应该算是在People 版,尽管更早地去Software 和Windows,但那时都不在那里灌,只是纯粹地为了帮助别人,回答问题。 People版的那段日子,是我在BBS上玩得最开心的日子。而后转移阵地到chat版,因为那里有float。其他没有写到的,却和我一起灌水的各位,或是因为和我只在网上接触,而生活中接触太少了,所以没有多少可以让我扯的,或是因为和我在生活中接触太多太多了,以至于不能归到BBS水友一类了。
没有像holyzzd,youshow他们那样的文采,但我也要记录一下我这四年来的经历。
大二完的那个月,我报名了2003年10月的软考高程。暑假在家,无事可做,就看一下高程的教程,做点辅导书上的题,其他的都还好说,都只是记忆性的,就是发现编译原理最难懂了,根本无从下手。开学回到学校,开始上自习准备应考,也就是做了往年的几套真题。大概认真准备的就是回到学校后的考前1个月了,不过,也是因为暑假看过教材的基础,所以做题也不觉得多少困难,虽然很多不会,但估计勉强能通过考试了吧。于是也不再去顾忌学习上的事,有空就到汇鑫打浩方,还有个主要原因是很多隔壁班上的堕落男都在汇鑫。打浩方,有一半时间是在打3C,还有一半时间是打LT,以2V2居多,胜率还有点高的样子,大概是因为浩方上的人比较水。那段时间是最堕落的,还去通宵打,大一大二都从没去网吧通宵过。大概就是为了发泄,放纵自己被想做好孩子的想法压抑已久的精神吧。通宵的时候,都是和RuQ、lano他们一起才去,也就是打大半个晚上的War3,然后看看xx网站。
大一没多少好写的,就是来报到啦,然后军训啦,什么事情都是一个人啦,独来独往,因为不喜欢几个人一起的时候会出现的意见分歧的情况,所以一直都是没什么特别亲密关系的朋友啦。
说是忙,也不算忙,因为一般都只是上午才会写一点程序,但是进度却还是要赶的。唉,其它时间就无所事事了,偶尔看一点书。程序还是有个瓶颈没用突破,是否要绕过去呢?
修改了插件配置对话框的界面,用嵌入IE 浏览器控件来实现,不过很多特性都没法实现,应该是因为我没找到实现的方法吧,因为感觉看CyberArticle 就好像实现了那样的效果。不过现在马马虎虎可以运作了,哈哈,真是一种有趣的技术。
大熊猫输入法是不断地在更新啊,现在候选框界面做得模拟成五笔加加(极点)的样子了,不过使用习惯上面还是不如用五笔加加,因为用惯了五笔加加Plus 中五笔、拼音、英文混合输入的方案啊。而且似乎程序的稳定性还是不如五笔加加,呵呵,我是加加系列的忠实fans,不过现在的拼音加加似乎不行了,不如微软拼音了。
这次版聚我盼了好久了,因为一有人提出来,我就开始等啊等~~~ 想去参加版聚是有一点点小小的企图的,结果比较可惜的是,图谋了那么久,最后还是落空啦,呜呜
我其实并不是为了学习COM 而才去学习COM 的,而是因为想给LLYF Spy 加上插件功能,插件已经可以支持一点了,但只限于普通DLL。听说现在用COM 实现插件的软件很多,所以我也想试试。图书馆找不到什么书看,一开始借了本潘爱民译的《深入解析ATL》,是讲如何用ATL写COM组件的,也不怎么看得懂,看到书中提到一本《Inside COM》的,但在图书馆外借室没找到。于是只好借来讲MFC的2本书上点点关于COM 开发的内容看看,还是不太容易,因为太多用MFC 实现COM 组件的细节了,还有《COM本质论》也是抽象,太高阶了点,不合适我。前天偶然发现2楼阅览室中有一本《COM 技术内幕》,应该就是所谓的《Inside COM 》了吧,于是马上站着翻看了一遍,讲得比较通俗易懂。今天中饭吃完,又去借了一下看看,真不错。于是又去1楼外借室借了本《COM精髓》,要学习一下COM了,只要够用就行,不用很精通。
昨天在装了个VSS,好像是VS6.0里带的那个,反正是从E383(这是我们学校校园网上一个很有人气的软件下载站点,由几个爱好者主持各种事务,机器放在信科某机房内)上down 来的,装了就开始用,把LLYF Spy,还有ProcessHelper、IconHelper、DebugCapture 以及毕业设计在做的那部分都Check in 了,试了一下,还不错,因为它只是保存修改的部分,这样就不用自己用WinRAR来压缩整个文件夹来备份了,而且可以看到任意一个状态的内容。
虽然以前也装过VSS,但都没有好好用上,因为自己写代码不到一定规模,觉得用VSS 嫌麻烦,而当有了一点数量的代码之后,用WinRAR 这样备份的方法弊端就太多了,VSS 的优势突显。
列个基本的计划,只是为了和导师打声招呼,可以开始做了吧。
到了学校,就明显感觉没有在家里那样的充实了,好像每次都这样,在学校一直都无所事事的样子,以前电脑在学校,家里没事做,就看书,基本上每次假期在家都要看好些东西。这次寒假在家有电脑玩,就总是看些奇怪的编程技巧之类的,然后自己写程序玩,最主要是写了个LLYF Spy,在写这个程序的过程中,尝试了一些以前都没用过的东西,比如远程线程、消息钩子等等,还是比较有意思的。
昨天中午回到了学校,稍微整理了一下,去剪了头发,然后去找学院的领导,想要申请提前去单位报到,可是院长是很不赞成,于是我只好说,等我先去和导师商量了再说。然后遇到了辅导员,他把我叫去说了一下关于毕业设计的事情,我顿时更加沮丧,我们班被分到电路实验中心,这是我最不擅长的,要是网络,软件之类的才是我最熟悉的部分,可偏偏是电路。从大二开始,电路分析,电子线路,高频都没有学好,就像多米诺骨牌一样的连锁反应。后来索性叫了chuanking 和king 他们一起去吃火锅,有点好笑,自己心里默默地为自己庆祝生日,他们都是不知道的,也许还真以为我是心血来潮。等吃完火锅回到寝室,寝室里只剩下一个室友了,另外一个搬走了,人少了,东西却不见怎么少,寝室里还是那么乱,呵呵。
稍微整理了一下代码,把几个只用到Win32 API 的全局函数移到一个DLL 中去了,本想这样可以减小点主执行文件的尺寸,其实也小不了多少KB。网上看到一篇文章,提到VC 程序员和BCB 程序员的代码风格问题,说一般经常看到VC程序员的代码风格要好一些,我也有些感触。用BCB 这么久,还是习惯于C语言的过程式编码风格,从来也设计一个类。
照着bingle的代码,改了一下自己用,用来搭配LLYF ProcessHelper,现在ph.exe 可以以SYSTEM 身份运行了,至少在Administrator 组用户下可以以SYSTEM 身份运行了,其实也就是能多看到其它两三个进程的命令行和模块列表,至于kavsvc.exe和kav.exe 还是不行的,也真是厉害,能保得这么严,当然IceSword 的进程也打不开。
昨天在给LLYF ProcessHelper添加TrayIcon功能,代码是从LLYF Spy 那部分完全Paste 过来的,结果编译的时候说NIF_INFO没有定义,还有szInfo、uTimeout这些凡是说要IE Version5.0 以上支持部分都说没有定义,可是我在LLYF Spy 里好好的呀,还以为是XP 的问题,马上退到2000 下,结果一样。于是我打开ShellApi.h看,在那个函数和结果定义前加上#define _WIN32_IE 0x0600,编译是勉强通过了,但是功能没有实现,并没有Balloon ToolTip 出现。后来在看Project Options,发现有个NO_WIN32_LEAN_AND_MEAN定义,是因为有一个函数里调用了SHBrowseForFolder,要加shlobj.h 这个头文件,于是意识到可能和这个有关。搜索了一下,我的程序里并没有调用到这个函数(我晕),于是把这个函数体全部注释掉,把这个头文件和宏也删了,编译和运行都正常了。
从这篇文章中可以知道,通过简单的几步设置,便可模拟OutputDebugString,可以用下面的代码描述:
学编程是从DOS下开始的,用了一定时间的TC2.0,使得养成了用printf 输出变量值进行调试的坏习惯。到了写窗口程序时,就遇到了些麻烦。
窗口程序没有方便的进行控制台输出的方法(其实是我不知道),于是,用了几年的用MessageBox 进行输出的调试手段,太麻烦了,因为MessageBox 会打断程序流程,还要人为手动让它继续运行,这是最让人恼火的。
今天看了一下Shotgun 那个端口进程关联的代码,那是在Win2000 下可以运行的,虽然得不到(System)8#进程的信息,但可以在普通账号下运行。到XP 下有点小问题,只是因为2000 和XP 对句柄类型表示的枚举值不同,2000下是0x1A,而XP是经0x1C,改了就可以像2000下运行了。
这是一个用于拦截WinSock API 的程序,主要的目的并不是为了截获数据包,而是为了能从第三方角度方便地观察二进制程序调用WinSock API 的情况,最直接最原始一点的想法,是为了能比较方便地调试自己写的Windows 网络应用程序。
完成多系统共享BCB6之后,我开始尝试多系统共享Delphi 7 Studio Enterprise (简称D7)和Delphi 2005 Studio (简称D7)。
同一个硬盘上装了多系统,原来一直用Win2000 来写程序,在Win2000 下装了Borland C++ Builder 6,还有一些其它的编程工具,每次写完一个完整点的程序,在Win2000下运行正常后,还要跑到WinXP 下试试,于是想要有时候能在WinXP下也运行BCB6。不想再装一次BCB了,主要是因为光驱坏了,硬盘上也没有BCB6 的光盘镜像,所以就试试能否共享原来安装在Win2000 下的那份BCB6。经试验成功:
今天给LLYFSpy加了进程信息查看功能,可以查看当前进程所有模块信息,内存信息,文件映射,所有进程列表,服务列表,以及设备驱动程序列表,其实就是把原来LLYF ProcessHelper 里的代码搬了过来。虽说没有写新的代码,但我想这样可以给我组织程序结构有些启发。
前天花了一天时间用BCB 做了个MDI界面的抓图程序,当然功能非常简单,连DX的图都不能抓,但不知道怎么的,注册热键的时候有问题,郁闷。还有就是MDI 的我用TabControl 来切换页面,想方便一点,还会发现,在切换时,桌面会刷新。晕得很。
昨天在看雪论坛精华中看到一段代码,看一了下,在VC2003 下可以正常编译,并dump 出PE 文件的节信息,导入导出函数表,嘿嘿,正好加到LLYF Spy 和LLYF ProcessHelper 中,只不过那个快速排序的算法好像有点问题,有时候程序会死掉。我还没看出来为什么一定要加这个排序过程。好在程序基本上用的都是C 标准库函数,可以没任何障碍地从VC 移植到BCB 下用。
今天发现,在XP 下,WH_CALLWNDPROC和WH_CALLWNDPROCRET这2个钩子函数,如果是空的,只是直接返回CallNextHookEx,也会出错,看来不是我的程序问题了!万般无奈之下,仍旧换回BCB6来编译这个DLL,却意外地发现,竟然不出错了,只是似乎被探测程序运行更慢了:(也许只是先入为主的思想,心理感觉而已吧。
刚刚给它做了个简单的CHM 格式帮助文档,都是用的以前给阿菲连连看的帮助文档模板,呵呵。是中文的,尽管程序界面是英文的,可是我的英文还是差啊,郁闷,只是因为写程序时觉得中英文切换太麻烦才不用中文的
```cpp void __fastcall TMainForm::GetTreeViewContent() { //TODO: Add your source code here int nItemCount; int i; char chBuffer[256]; DWORD dwProcessID; HANDLE hProcess; void * Pointer; SIZE_T nNumberOfBytesRead; TTVItem Item; HTREEITEM hTreeItem;...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30...
```cpp
void __fastcall TMainForm::GetTabControlContent()
{
//TODO: Add your source code here
int nItemCount;
int i;
char chBuffer[256];
DWORD dwProcessID;
HANDLE hProcess;
void * Pointer;
SIZE_T nNumberOfBytesRead;
TTCItem Item;
```cpp void __fastcall TMainForm::GetHeaderContent() { //TODO: Add your source code here int nItemCount; int i; char chBuffer[256]; DWORD dwProcessID; HANDLE hProcess; void * Pointer; SIZE_T nNumberOfBytesRead; HD_ITEM Item; 1 2...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30...
```cpp void __fastcall TMainForm::GetListViewContent() { //TODO: Add your source code here //* int nColumnCount; int nItemCount; int i,j; char chBuffer[1024]; DWORD dwProcessID; HANDLE hProcess; void * Pointer; SIZE_T nNumberOfBytesRead; AnsiString...
在CSDN的论坛上看到一些老较经典的帖子,就把代码用在自己的程序里了,给LLYF ProcessHelper 添加了一个特性,就是显示进程的完整命令行,真是个有意思的功能。不过,之后,发现VCLSkin 太不稳定了,要出错,也许是用的crack 的原因吧,索性就不用VCLSkin 了,这样程序的体积还可以小一些,速度快一些
装的IDE是Dev-C++ 4.9.9.1 和MinGWStudio 2.05,它们自带的MinGW 里GCC 的版本都是3.3.1的,自己把GCC 升级到3.4.2 后,用来写些小的SDK 程序真是不错,哈哈。不过现在 VS.NET2003 的IDE 也做的真是太好了,再加上我装了Viusal Assist X,就更好用了,尤其是它的代码提示和自动完成功能,太方便了,还有在粘贴时的代码自动格式化功能,也很实用!
今天猛然发现那个DialogBox 上有一个DateTimePicker 和两个Updown,于是把它们删了后,发现可以显示出来了!
好好的,在用VC7.1 和SDK 写着程序,主窗口几天前就画好了,不用VCL、MFC 之些,画个简单的窗口都这么烦!!结果今天想给它添加一个新特性,于是,在菜单上加了个新项,让它点击后能弹出个Modal DialogBox来,结果,死活弹不出来,我可是安步就班地按照Charles Petzolds 的经典书《Windows 程序设计》上面来的,查看一个DialogBox的结果是-1,就是说,要用GetLastError 来看,弄来一看,说是“找不到窗口类别”,晕得很啊,于是我尝试把DialogBox templete 从id 换到string,当然我心里也很清楚地明白,事情不会这么简单。看了很久的MSDN 和《Windows 程序设计》,也没看出什么名堂来,无聊了,就重启系统,进入XP+SP2 里转转,结果发现这个DialogBox 在这里可是好好的啊!很正常的啊!
今天拿到协议书了,原来真的不用再寄回去了。昨天下午还特地跑到辅导员那里去找,结果说上午就都给那同学了。单位又发来Email,说下学期,如果毕业设计任务不重的话(我是这么理解的),可以提前去单位报到,而且待遇和正式报到一样,有点诱人啊。可是不知道我们学院能不能搞快点,连毕设的题目都不知道,其它像计算机、自动化这些学院都已经连题目都确定了。晕
突然发现,最好把一些常用的功能封装成类。今天在用MySQL 的C API 的时候,才觉得,用类来封装对MySQL的操作,是件理所当然的事,不然,程序太难写了,寸步难行的感觉。然后,进而想到了对XML文档的操作,因为用到的是MSXML DOM,每次这样弄长长一段初始化什么的代码,看起来都不爽。用类来封装,以后扩充都要方便点(这只是我现在的看法)。所以说,面向对象这种方法的意义,对于我这样的人来说,不应该是一种谈资,而应该是能切实改进生产效率的一种手段或途径!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 相信 在寒冷的 冬天 没有 我的 祝福 您也一 样 的快乐 有 了我 的问候 您 会 更 加...
最后的最后,我终于发现了关于完成端口第一次WSARecv 投递失败的原因!
为了写WinSock程序,找了几个抓包的程序,CommView 4.1 和IRIS 4.07,发现它们两个界面都差不多,好像IRIS 的功能稍微多一点点。但是不知道为什么,在设置Filte r的时候,IRIS总是有问题,IP栏里不能输入3位数的十进制数,也不像是能输入16进制值的。在Address Book里,只能输入最前几一个IP值,就是aaa.bbb.ccc.ddd,无论如何输入,最后只会留下aaa,而后面的全都变成了0。晕死,难道是因为用的破解的缘故?CommView 还好至今没发现什么大问题。不过似乎它们两个都是抓的链路层的帧的,而本机调试的时候,发送到/接收自本机的TCP 数据包难道是不通过链路层的?反正我用它们两个是抓不到这些包。
大学里最后一次Christmas Eve 了,说实在的,这个只是西方人的节日,照理我应该不是很在乎的才对。但是看着外面日渐热闹的节日气氛,自己心里不免有些触动。
开始用完成端口写Server,郁闷,照着书上的例子来,还是有错,总是到bind,WSAAccept 后的第一个WSARecv 的时候,说10045 错误。
最近懒得很,代码也很少写,就在灌水,其实自己都觉得灌水是件很无聊的事情,但还是百无聊赖地在灌水,没人陪起一道灌的时候就到外面看看网页,网页只是看看论坛,论坛上没什么内容的时候,就看Blog,Blog 没什么内容的时候,就看自己的Blog,无聊死啦。
昨天上五笔爱好者论坛的时候,发现有了个大熊猫输入法,可以拼音五笔互换,还是个GNU 的,从FreePY 改过来的,下了它的源代码,编译了再安装上试了一下,感觉还是比不上五笔加加,至少比不上五笔加加PLUS。现在五笔加加PLUS 都出了2.5版了,真是佩服EasyCode,通过逆向工程能坚持补完五笔加加到现在这种程度。
今天早早地就被那个傻乎乎的电话吵醒了,尽管在做梦,还是做的美梦,呵呵。电话打了2个多小时,准确地说是2个小时16分钟(依据手机上的通话记录),一直打到手机没电,自动关机为止,相应的赔上的是给中国移动的巨大贡献。手机停了之后,傻乎乎的又打到座机上,不知道过了多久才说完。室友在那里说什么关系不正常呀云云,还以他自己和他女朋友为例来阐述自己的观点。嗯,昨天都答应人家了,这样就算是出生以来第一次脱离单身了,只不过,是建立在电话线上的恋情。
打折下来,一套加上送货费,也得花掉128元大洋呀~~~ 本来也不是这么坚决的,前几天在网上书店看了又看,各种介绍,书评,还是犹豫了很久最后没买,今天在BBS 上看到holyzzd说在看这三卷本,于是猛然狠心上网马上订了一套要缩衣节食了哇,呜呜~~~
好多的人啊,来的单位倒没几个,都是深圳的,都没多少兴趣,于是挤来挤去,弄得满头大汗。后来看到有家单位,据说那人是我们学校的,于是就过去看热闹,看了20来个人来递自荐书,看出他的习惯,一般问你会什么语言,说C和C++的多点,然后会进一点问用C多点还是C++多,再问做过什么东西,一般只要能说出真的自己做过程序,规模大小无所谓,什么俄罗斯方块,五子棋之类的,说得出来就得,那男的就会把这自荐书拿去给旁边一女的看,说一会,那女的就会把自荐书单独抽出来塞进抽屉。其中有一个过了6级和高程的人来,看起来是最有资本的一个人了,可是我看着觉得好水啊。唉,中国教育的失败啊。
Category Film & ACG
周日去电影院看了《沉睡魔咒》。本来打算周六去的,结果相当不愉快的一次网上订票,先去大众点评网上买了两张团购券,还以为每张可以便宜7元钱,结果到嗨电影网上订票还要再付12元,也就是说每张票才便宜了1元钱,还花了一些时间折腾微信支付什么的,我只能说这两家网站的用户体验做得很烂。而且当时没订票成功,我又看手机上收到了两条短信以为已经订票成功了,其实是大众点评网发来的,于是兴冲冲跑去电影院,然后妹子发脾气了,关在卧室里整整一个下午。叹气。
周六之后,一直在看小说和动画片。越来越觉得没有好看的小说了,于是试图把自己的注意力转移回动画片上去。看完了13集的《Working!!》和12集的《江户盗贼团五叶》,还看了没有完结的36集《妖精的尾巴》。最合我口味的是《妖精的尾巴》,差不多一直是高潮,没什么铺垫和伏笔之类的,所以很轻松,没用费脑子。画面也是最合我口味的那类传统大眼睛好身材的人物造型,还算细致的物品和景观。《Working!!》的结局不是很喜欢,感觉不像结局,中间的情节倒是还行。《江户盗贼团五叶》有很浓重的日风,但人物造型实在不习惯,那个面部轮廓、五官都不习惯,我好像是第一次看到这种类型的,但其他方面都画得很精细,音乐也好,情节么,还行吧,总共12集我直到第10集才大致明白整个的来龙去脉,但我仍然觉得这没什么特别的,好像这种讲述方法的动画片也不少。不过我觉得吧,这三部里最赞的还是《江户盗贼团五叶》,从另一个角度讲,如果中国动画片在遥远的未来能有所发展的话,可能《江户盗贼团五叶》这样的是最后被模仿达到的。
周六周日花了两天时间看完了《结界师》。一开始是在PPS看到的,看了一集,后来就不停地卡,于是去tudou网上看,看了5、6集,受不了那个糟糕的画质了,最后发现youku上的画质还不错。一共52集,不算短,但比起《海贼王》、《火影忍者》、《死神》这些来说已经是很短了。
总的说来,这个画风勉强在我可接受的范围内,但男主角的成长实在让我有点不能忍受,至少前30集都没看到无论是从技能还是性格上有所进步。我不喜欢只会大喊大叫的那种男主角。情节上么也没什么突出的地方,但结局还比较喜庆。
其中有个叫神户百合奈的小姑娘,感觉挺像@ainesmile在推特上表现出来的形象,哈哈。
小师妹有一天晚上跟我说一个人看《倒霉爱神》傻笑了一晚上,推荐我也去看看。也确实很久没有看碟了,这些年来这方面的兴趣渐缺,在深圳时还偶尔跟人一起去下电影院,现在连这种机会都没了。今天闲来无事,到PPS上找来看了看。总的说来,主线情节是比较老套的,虽然看时间也是2006年的作品了,不过放在4年前来看,估计还是有这种感觉吧。
男主角是个生来倒霉的家伙,会一脚踩到水坑里,会弯腰撕开裤带,会抓到沾了狗屎的钞票,会出门被鸟屎砸中肩膀……这些是纯粹的晦气,让我觉得更在意的是,在事业上的寻求机会而不得果,甚至差点要被自己的队友们抛弃。
女主角就运气好得跟童话似的,出门不带伞而瞬间天气放晴,在电梯里能遇到搭讪的钻石王老五,代上司谈生意能意想不到的成功,随便买张彩票也能中奖,更过分的是能让别人送错裙子等等等等。不过这些事情,在我看来是不可靠的,人不能指望每时每刻都有这些光环加身。
之后的发展以及各种转折,基本是在我的预料之中,不过我仍然看完了,有一点小感动,特别是到最后女主角决定放弃新工作的机会而去找男主角,毅然吻住了男主角。看到这一段,我突然觉得,世界上尽管有很多邪恶,丑陋的人和事,但那些都于我无关,我只要处理好我的那份责任,那就够了,实在没必要去计较那么多。要相信这个世界上仍然有一些角落,还是有一点点美好的,只不过需要自己去发现,去创造。
好些天前,估计至少有半个月前吧,跟小妞一起吃饭,她便使劲儿推荐我看一下《奋斗》,当时还满不在乎的,听小思宇也说过,她还买了书的,一次偶然看到VeryCD上有下载的,便全下了下来。电视连续剧看着就是比较费劲儿,而且我感觉挺浪费时间的,不过我终于看了1个多星期,把它全部看完喽。 片子一共32集,在我看来算是比较长的了。里面讲的故事真如小妞小思宇说的,很贴近生活,贴近我们这类人的生活的。主角大学毕业,然后经历事业、爱情上的各种风风雨雨,有的时候不禁就会拿自己的经历来比较。 总的说来,陆涛我挺喜欢的,但挺讨厌夏琳的,挺同情可怜米莱的。我觉得陆涛做的百分之八九十我都是很赞同的,但夏琳在陆涛搞房地产那段时间对他的冷冷的,让我讨厌死她了,呵呵。最同情的还是米莱,外表乐观坚强,其实内心一直脆弱得很。 这片子看着看着就会引起点儿共鸣,真能鼓舞点儿人的。
本来只是下了一部剧场版的来看,觉得还可以,于是上VeryCD找来TV版看,一共24集,昨天熬到后半夜2点,困得不行了,才看到14集,今天再接再厉,把剩下的10集都看了。其实,从情节上讲,也不是特别有新意,从人设上讲,也有点落俗套,有一个温柔得甚至有点懦弱的男主角,但男主角就是有能力吸引住女主角。 看到后半部几集时,给我一个特别深的印象,或者说教育,就是“动什么千万别动感情”,本来女主角夏娜作为一个Flamehaze应该和一个人类,确切地说是一个Torch,带着零时迷子宝具的Myste是不应该有什么牵连的,但偏偏就是喜欢上了,然后中间一段弄得很被动,甚至对于完成自己的使命都变成了障碍。 片中的男主角是很多日本动画片中都会有的那种类型,很温柔,但剧情发展到一定阶段就会变得很自我为中心,完全不顾旁边最亲近的人的立场和想法,我行我素地去做些从客观上讲应该算是不正确的,但可能以他的立场是一定要做的事情。我个人是很讨厌这样的情节的,不过剧本如果不这样写,就没什么可写的了。说到底,我也没什么资格可以对别人这样说三道四,换作我自己遇到这样的事情,可能处理得更不当呢!
看完了《零之使魔:双月骑士》,心中有点点回味。这部动画片宣扬的反战、和平的观念,很对我的口味,难得日本人也有这样的想法哦。中间夹杂的一点爱情,就很老套了,很多动画片、漫画里都是这样的情节,或节奏。不过虽说老套,我却也总不免有点向往,或是羡慕,呵呵。这部片子一直都是很轻松的情节发展,也不长,才12集,半个晚上就看完了。总算自己还略微有点喜欢看,一直希望自己能培养点业余兴趣爱好出来,也不至于平时太过无聊,其实这看动画片也勉强算是一项吧,只不过看起来似乎太过平淡,没什么让人激动,或者说对其它方面没什么帮助,呵呵。
昨晚回来后,连夜从VeryCD上下了《爱情呼叫转移》,并看完。虽然xcc说很搞笑,但我看的时候,却不怎么觉得,也许是因为从去年那段时间以来一直遗留下来的忧郁干扰的吧。忧郁于我来说,是太过容易的事情了。 片子让人感觉有点拼凑的嫌疑,其实像是讲述一个个的小故事,可硬要串在一起作为一部完整连续的影片。不过整体教育意义上的表现还是有点可取的,爱一个人就要爱她的全部,没有深入了解,就不要武断地判决一个人。
开始一段,那个逃命的黑人兄弟身手真够矫健的哈,007是全凭点小聪明才能弥补身体技能上的差距哈。邦德女郎的长相不是我喜欢的类型,不过最后他们在床上时她露出来的美腿还是多诱人的,哈哈。 我觉得这里最酷的台词是邦德说你不是我喜欢的类型,女郎说因为我聪明,邦德说因为你单身。哈哈!
完全不知道在讲什么,反正就是噼里啪啦打了一阵,有乱伦,有恶搞,最后是屠杀。一点不好看,连色彩、声音都让人觉得没什么值得说的,怎么说《夜宴》至少这点上还是继承近几年来国内大片的特色的。 不过,小马哥还是又帅又酷的,巩俐阿姨的演技确实也是一流的,可惜的是剧本太烂了。刘烨也还成,好像后来看到他演的角色都是不太好的,不像那部那部叫什么来着,和孙俪一起演的,多好的一角色,《茉莉花开》里也是个讨打的角色,呵呵。周杰伦就真的太丑了,Jay啊,不要出来演戏了,就好好写你的曲,唱你的歌吧,影视圈不适合你! 到最后,就又跟看《夜宴》时的感觉一样,突然听到怎么好熟悉的音乐啊,才想起来最近不就一直在听《菊花台》吗,当时感触还多大的,感慨Jay是个才子,什么样风格的歌都能唱,所以所以,我在再次大声呼喊,Jay,不要演戏了,好好写你的曲,唱你的歌吧!
在线观看了《云水谣》 ,感人肺腑。两位配角之痛,不亚于两位主角,任何刻骨铭心爱过的人,都会被感动。当第一女配角在结婚的时候说:“姐姐,他一直在等你,是我不让他等了,对不起……”我真的被着实感动得热泪盈眶了。片子最开始一段,特别唯美,从光线、声效、音乐到节奏,让我有当时看《不可不信缘》时的感觉。 不过,陈坤跑步的姿势也太难看了,尤其是和徐若萱分别那一段,黑的夜里,大雨,追着车跑,好丑!
从网上down来的《灌篮高手》剧场版,直接用MPC打开居然没有字幕,看了论坛里的帖子说的文件是没问题的,内嵌了天香字幕的。偶然间发现下面有个跟贴说,要Haali Media Splitter这个东东。主要是MPC能直接打开播放mkv格式的文件,所以我一直没在意。把这插件down下来,安装的时候可以选择把MPC内嵌的splitter禁掉。再用WMP打开,都能播放了,而且字幕也有了,用MPC播放也有字幕了。 好怀念啊,尤其是那主题曲。初中的时候,天天守着电视上播放的来看。高中的时候,学校里也播过一段时间。到大学时,同学在寝室里看的时候,我不再去看了。现在来看这剧场版,听到这音乐,仿佛又回到那十三四岁的时候。高中的时候,每天早上要全校晨跑,每当跑得觉得累了要停下来的时候,就想想这激动人心的主题曲,支撑我跑完全程。 有Internet的感觉真好!曾经一个网友说,老外们上网,为了工作,中国人上网,为了娱乐。看来我还真是一个彻底而典型的中国人呢,呵呵。订阅了Boost和Lua的maillist,还有comp.lang.c++和comp.lang.c++.moderated的newsgroup,上面真的鲜有中国人。也许有不少像我这样订阅了,但不发言的。但我却是连内容都很少看的,还是对英文的,静不下心来看啊!
还在学校的时候,RuQ就跟我讲过《死亡日记》是如何好看如何精彩,那时他是守着在网上看的漫画,但是只凭他的讲述,丝毫吊不起我的胃口。最近在verycd上看到都开始有动画片出来了,更新了四五集了,偶然间还看到有真人版的电影,于是把电影拖下来看了下。果然是很好看的一部片子,而且大概也比较忠实地反映了原著,因为RuQ跟我讲过的几个他觉得精彩的情节,电影里面基本上都有了。主角夜神月,从开始的一个惩治罪恶的正义“救世主”,在和神秘侦探的斗智过程中,渐渐变成一个为达目的不择手段的恶魔。最后,死神流愚说的那句“你比死神还要死神”,让人唏嘘不已。但同时仍然让人不得不佩服月缜密的心思,布下的周密的计划完美的达到自己的目的,而作为配角出现的L也是很成功的一个角色。日本的漫画业真是让其它国家,难以望其项背啊! 困死了。 小丫头,居然只是在客厅的一个角落里摆了张床,就当起了她的小窝,她的栖身之地。遗憾的是,我没能力,也没理由能帮她这些事情。 昨天傍晚跟爸妈打电话,我说我跟一个女同学去逛公园了,他们似乎比我还高兴,晕倒!
终于把《魔界战记》看完了,总的说来这是一部很有趣的动画片,短短12集的短剧,风格很像给10来岁的小孩子看的,但里面表达出来的世界观人生观却同样值得细细体会。片中宣扬的爱与温柔这样的主题很合我的胃口。再一次,从中窥视到日本人对于生存的强烈渴望,斗争本能就是这样强烈。放弃自己的生命,是一种极大的罪孽!另外就是其中有句话,“两个人悲伤的爱,是让人多么难以忘记啊”, 不禁又想起那个家伙,不过这次倒没怎么酸,似乎已经有点麻木了。虽然结局我不太喜欢,那个比较蛮横,但还是显得多可爱的小魔王,最后竟然变成了一只普里尼,不过这也是没办法的,因为前面的这样的条件限制,他放弃自己的生命来让那个小天使复活,所以他只能变成普里尼来赎罪。还好,本来差点以为结局会像《封神传说》里那样,对所谓的最高统治(秩序守护)者进行反抗,总算不是那样,不然肯定会失望被猜中结局。另外一点是,这部动画应该是小成本制作了,片制就不长,才12集,中间的情结也不复杂,而且人物也不多,不过编剧很有意思,中间好多次插入搞笑的台词,诸如“说不定是哪个字幕工作组”,“又让他抢了10秒钟动画真不爽”,“这次好像是他是主角”,“当了这么多回跑龙套的这回也该让他出出风头了”等等,很有趣的风格。 突然发现,对于提高键盘敲击速度,还是有必要的。以前,自从有了键盘加速器后,我就一直以为键盘敲击速度不够快已经不成为限制我提高速度的障碍了。现在才明白,像我这样一般都是先旋转,再左右移动,再下落的打法,键盘敲击速度是其中很重要的一项因素。旋转就需要敲击速度快,才能减少时间,然后左右移动是大大利用了快键盘的优势,但我一般不能一次移对格数,肯定是需要再敲击几次来调整,所以也是需要有快速的键盘敲击,下落一般只按一个按键,所以单就这一项来说,不是很受影响,但三项活动之间的时间差,也是需要通过提高键盘敲击速度来提高的。我一般下块速度是1.1x,敲击速度是3.x,自从有意识地去加快敲击速度后,下块速度便成了1.2x到1.3x了,效果还是很明显的哈,不过不稳定,呵呵,想前段时间为了能稳定在1.1x也是花了好长时间的,直到和江江悍超大牛他们打了几盘后才变得稳定起来。
看完了《大雄的结婚前夜》,也许就像某位网友说的,看到大雄和静香结婚,心里最高兴的,应该是从小看电视台上每天播出的机器猫长大的男性朋友了,反正我心里就觉得很过瘾,很痛快。 一直喜欢着一个小女孩,一个笨笨的好吃懒做的小男孩,尽管他缺点太多,但是却能引起我们的强烈共鸣。多年以后,再回头来看,当年孩童时代看过的动画片,带来的无尽的快乐和无穷的遐想,是一生都值得珍藏的宝贵财富。
Category Water
连续几天早上起来开机出现Fan error,我都是通过拍、摇等手段试图让风扇转动起来。虽然确实都能转动起来,但发现的声音却是很大。今天早上起来,终于再怎么摇怎么拍都不行了,问了一下小区门口的维修店,大概要200多,还要明天才能修,关键一点是还要我今天就把机器放店里。于是我想还是自己跑一趟徐家汇吧!
问了一下雯雯怎么坐地铁,然后大约1个小时后终于到了徐家汇,随便找了家柜台,说是只修不换,180,无又不了解市场行情,也不想怎么折腾,就修吧。
中间大半个小时出去逛了一下,徐家汇也没什么地方可以逛的,再联想起上次去不夜城,还领了张罚单回来。感觉还是比较喜欢华强北那种人挤人的状况,唉。
最近总是想念起在深圳的各种安逸和自由。上次跟阿菲打电话,她还说让我去深圳也行,我说回不去了,至少现在不会去,得在这边做出点样子出来,唉。
今天遇到了骗子,只差一点点,有惊无险,记之以作警示。
全程经过是这样的。今天刚好去市区,到了目的地,就接到一个电话,号码是13201792864(疑点一),接听后是一个说普通话的女人,自称车管所的,我大惊,以为哪次闯红灯被逮到了?结果是问我是否xx(我妈的名字,因为后面提到的买车时登记的车主是她),是否在两个多月前买了车。都确认后,她就问我,难道没有接收到车管所发去的通知,根据xxx号文件的指示,小车购置税可以退3%(疑点二)。我说没收到啊,她就问,不是浙江省xx市xx地方吗(确实跟登记的地址一模一样,我已经开始相信是真的),我很抱歉地告诉她,我们搬家了,不住在那里了。她就说,这个通知被退回来了,现在把这部分钱转移到国税局去处理了,你赶紧联系一下国税局,今天是最后一天了,然后告诉我一个电话号码,是4006811987,还有个6位数的退税编码。我看到是400,觉得好像是正规的哈(完全相信),于是打过去,又是一个说普通话的女人(后来回忆了下,似乎跟前面的那个人的声音一样?),我说了一下事情,她就说,把退税编码报过来,我就说了,然后她就说,是不是名叫xx,xx车啊,我说是的,她就问我车身价多少(疑点三),我说10w零多少吧,我不在家,没有发票,说不出具体数字。她也没追究,直接说你可以退三千几百几十几元(后面的我忘了),我很开心啊,这钱相当于白来的嘛,就问她要走什么手续,她说中行建行农行邮政的都可以。我问了一下我身旁的我阿姨,她有个农行的卡(我还真没有这些银行的卡),那女人说,你找到就近的自动柜员机,我们会指导你进行相关操作,把钱转给你(疑点四),我问一定只能转账吗,她说是的(疑点五),此时的我正沉浸在天上掉馅饼的巨大喜悦之中,就硬是让我阿姨放下生意,带我去找农行。找到农行的柜员机后,我让阿姨跟那个女人通话,因为银行卡是她的嘛,要她输密码什么的总不好我来。结果就出很大的漏子了,阿姨跟那女人说上话后,插卡,然后就报了下自己的卡里的余额,我就迷惑了,是你要给我钱,我告诉你这个干吗。这时我阿姨也反应过来了,问我该不会是骗子吧,我心有点慌,支吾了。阿姨就问她,你是哪里的。她说,国税局的。阿姨说,国税局就在这里xx路上啊,我们直接去办理行不行。那女人说,不是你们那里的国税局,是绍兴的。阿姨就说,你绍兴的,就说绍兴话好了,那种话我听不懂,然后那边就没声音了,也没挂断……这时基本可以确认是骗子了,我又打了个电话到买车的4S店里问了一下,店里人马上就说,这是骗人的,我们这里已经有人被骗2w多块了。我说那他们怎么会有我这些资料的,店里的人说,可能是从车管所买来的吧。我郁闷,我现在还在猜是你们店里卖出去的呢!我草,我说你们也有责任通知一下你们每个客户,提醒一下他们注意啊,我今天就差点栽了!
马后炮分析:其实事后回忆整个过程疑点非常多,但我一直被他们说出的完全正确的个人信息和购车资料给迷惑了。后来我又反查了一下最开始那个手机号码,所在地竟然是陕西西安!郁闷,如果当时我的手机上的来电通是正常工作的,我估计不会跟着她这么去折腾吧!现在想起来还是有点心有余悸,羞愧难当啊!
打击诈骗,人人有责!
我是突然发现,原来我患的是这个病:成功恐惧症!在《反模式》中看到,原来我这样的病症并不唯一,很多人都会有,以至于他们都把它写到书中去了!
说到底,还是出于不够自信,以及毅力缺乏。古时候有句话,叫“行百里者半九十”,其中有一层含义就是最后那10%的工作是最难完成的,不光是因为可能工作内容的难度增加,还有执行者心理上的障碍,就像我这样。
一直以来,我都是一个缺乏毅力的人,很少会从头到尾认认真真地完成一件事情。不论是工作,还是其他生活中的琐碎的小事,比如看书,总是会把最后一部分丢掉。以前有领导说我,做事情总是喜欢只做到90分,而不去追求那完美的100,我不以为然,我是有点小骄傲的,有点自以为是的,这种关键部分有技术难度的部分完成了么,剩下的修修补补让别人去做好了!
现在不行了,所有的事情都得亲历亲为了,这个毛病带来的隐患就爆发了,将将引起严重后果了。记得类似的严重情况在公司时有过一次,那是我第一次独立负责一个特性,不但要完成自己的功能,还得提供接口给其他人使用,到了最后那段时间,心里非常焦虑,极度没信心,到后来都是只敢埋头写代码,不敢调试运行,生怕调试不过,把自己打击得再无法拾起从头来过的勇气了。最后运气很不错,因为本来也只是简单地调用别人的接口,我自己的特性完成后,提供给别人的接口基本功能也是能保障的。
眼下我那个调试器部分,已经持续2个月了吧,一直没有正常的进展,实在是挑战我的心理承受能力。我只能强行扭转自己的心理喜好习惯,自我灌输些心理暗示,希望能顺利度过这一关吧!
我有经常看一下Google Analytic的习惯,差不多每天上网的话都会去瞧一下。发现有好些访问,从从搜索引擎(Google)那里通过关键字“星座”、“双鱼座”等等过来的,今天还发现有个“双鱼座今年会和喜欢的人在一起吗 ”,让我觉得比较好笑。
我是个有点迷信星座的人,但只迷信它的大概的说法,对于每日/每月/每年的运程,我就不太信了。已经不记得在什么时候了,看过一段有点“伪”科学的解释,星座按出生月份划分,正好当时母亲在怀胎十月以及分娩时分受天气变化的影响,由此可能影响了胎儿的大脑等,就会影响到人的性格,而性格决定命运,所以我觉得似乎是有些道理的。
跟小师妹聊天时,偶尔会提及到我的缺点短处,我常会说“双鱼座就这样的啊”,小师妹就说我太宿命化了。以前确实没想到这层面上去,但被小师妹这么一说,我虽然表面上还说什么扬长避短之类的来狡辩一下,实际上心里有点惊悚的。照理说,我一直以为自己是一个不甘于受命运摆布的人,怎么这事上,就这么懦弱了呢?我一直认为人的出身已经注定,但通过后天努力是可以在一定程度上修改自己的命运的,可是现在想想,对于那些已有的缺点,我或无视之或逃避之,对于它们可能造成的不良影响完全无动于衷,这不是掩耳盗铃儿响叮当嘛!是该好好反省下了。
话说,昨晚居然梦见跟小妞一起看一本围棋书,醒来后真是心有余悸而力不足,不过好像在周公解梦中,男人梦见读书好像是好事呢!
澳洲甜美歌声,我听了Lenka的12首歌,最后的结论是,只要听这一首就够了!歌词如下: trouble will find you no matter where you go oh oh 麻烦会找到你 不管你往哪里走 哦哦…… no matter if you're fast no matter if you're slow oh oh 不管你是赶路 不管你想停留 哦哦……...
因为前些天小师妹在网上跟我说,喝豆浆养肠胃。嗯,我肠胃不好已经很久了,我爸妈的肠胃也不好,所以我觉得买个豆浆机很有必要。
今天去4S店拿行驶证和发票什么的,昨晚聊天太晚了,今天老是走神,真危险呀。看来开车是个很耗体能和精力的事情,以后在前夜一定要保证精、气、神的良好状态!
吃过中饭去一百,先看到美的,看了一会儿,抬头看到九阳的柜台,于是直奔过去,买了个很便宜的,不能打冷饮的,呃,反正现在只是想喝豆浆而已!
大清早的,被老妈叫起,驱车去4公里外的集市吃早餐。要了一客小笼包子,一碗馄饨,说起来从上大学开始这八九年来,还真很少吃得到这样的早餐。上学的时候嫌贵了,工作了之后就一般只在公司食堂里吃,周末虽然在家,但都睡过去了。偶尔为之,真是享受啊!
昨天突然想起,我的编辑器只能打开ANSI格式的文件,如果是Unicode,UTF-8之类的文件,打开是一片空白的,于是想改一下吧,打开时检测一下文件头部的BOM,用iconv转换一下再显示到编辑器。本来以为这将是很顺便的一件事情,从网上下载了Windows下可用的iconv库和头文件,最后却无奈地发现一个诡异的事情。原本至少ANSI格式的文件中的中文是可以正常显示出来的,如果用了iconv库,无论有没有进行编码转换,中文就全部变乱码了,而且显示乱码后,Scintilla就会报断言失败,然后整个程序就崩溃了。最后我不得不相信,这应该是iconv与wxWidgets或Scintilla配合有问题,至于到底是什么问题,我就不深究了。
没了iconv,于是我只好转投ICU门下了。还有点比较头痛,却又让我觉得解脱的一点是,我C++程序将是用MinGW编译的,而ICU当前的4.2.0.1版本曾经尝试了很久,都只能让VC编译通过,MinGW无奈地败下阵来。这就说明,我这编码转换的功能不能通过C++实现了,也省得我再费心思去琢磨到底把这个功能放在哪里实现了。Luaforge上有个叫ICU4Lua的项目,可以在Lua中使用ICU,这个库我以前也编译过,拿出来试了试,非常简单易用,只好把读取和保存文件的功能也用Lua实现成插件了。
以前蹲公司时,最开始是需要每天在notes上填工作日志的,几点几分到几点几分做了些什么事,涉及到哪些人。当然,没人教过我具体应该怎么填,我只是按照自己的喜好,也许是每天下班前花些时间填一下,而且还常常忘记。而恰恰这个工作日志又是需要每周让主管审核的,我就被逮到过,主管发来邮件让我补齐落下的日志,觉得很丢脸。
后来,除了要每天填notes上的工作日志外,又多了项不定期地向主管反馈工作完成进度,是用Microsoft Project管理的。主管会发来预先已经安排过的工作项目,我们则根据实际情况填入各个项目花费的时间,再通过邮件发回给主管,主管以此来跟踪下属们的工作进展。事实是,我常常不记得每项工作到底花了多少时间,所以上报的数据估计有3成到5成是不准确的。
再后来,另外有个主管自己用Excel的VBA编写了一套宏,然后放在公共服务器上,让我们每天往里面填写内容。工作内容主管已经事先在其中已经安排好了,我们需要的只是简单地写上ok或受阻等几种简单的情况。这种日子一直持续到我换部门,后来如何我就不得而知了。
到了新的部门,首先让我觉得很奇怪的是,他们居然不用填工作日志,他们认为要求填工作日志实在是件很过分的事。一开始我还有点儿不习惯,尽管不需要再向主管反馈了,自己仍然为了证明上班时间没有偷懒而继续自得其乐地填了几个月。后来实在是因为觉得没什么实际的作用也放弃了。
后来很长一段时间处于混乱的无组织状态。直到我被派去给别的部门做一个工具时,因为各方领导对该项目的重视,要求我每天反馈进度,于是在RedMine上通过一个自研的插件,只要我每天往RedMine上填写新闻,那么RedMine就会在每天午夜时分自动将该新闻作为邮件内容发送给各个关心该项目的领导们。我在新闻上写的内容可谓五花八门,每天遇到什么问题,如何定位bug,如何作出技术抉择,发布日期又要跳票了等等,觉得很开心很安逸,这才是比较适合我的方式。这个项目我一直做了一年半,然后又交给其他同事,我则被调回做其他项目。
调回后,项目组中又开始尝试敏捷和迭代开发,主管倒是做过一些努力,结果仍然是无序的。这样的无序状态我一直经历了半年多点,直到辞职。其间最常用的办法是,把最近一天或几天内要做的事一条一条写在笔记本上,然后完成一条就在上面划掉一条。事后回顾,也是很有成就感的事情。
这里牵扯到一个问题,说大了,是项目管理,说小了到个人,则是时间管理。以前看到过有人说,某老外的时间管理可以精确到一刻钟。当时是没有多少想法的,只是觉得这样细化的计划或回顾可能价值不大。
这几月来在家写代码,一直以为自己一天十几个小时都扑在电脑前了,应该产量很高吧。直到昨天偶然在网上找到一个叫Manic Time的免费小软件,可以记录下每天使用各个软件的时长。今天看了一下,才猛然发现,我这一天,花在编码上的时间竟然不到2个小时!真是触目惊心的数据啊,我实在是太堕落啦!
我需要好好反思!
今天在hugege.com上买了个空间和域名,从此咱也走上了独立blog的道路。
让GFW见鬼去吧!!
好运的部份:2010年终於开始有苦尽甘来的感觉了,木星将从1月中进入双鱼座的命宫。你会觉得自己是属於你个人的,可以摆脱身不由己的感觉,而且生命是全新的。有许多的新资源会在今年奇迹式的展现,帮助你实现你的梦想,让你的才能得到发挥,感情也会遇到你生命中非常重要的那个人,请好好把握,因为今年是你「对」的一年,不要在今年闹情绪或任性,把这些幸运都丢掉了,要记住,2010年只要是你愿意丢掉不幸的心情,迎接幸福,都可以心想事成,除非是你自己愿意不幸。
厄运的部份:经过土星行经下降位置的锻链,双鱼座的人历经亲密关系的离开,因此,当土星进入第8宫,双鱼座的人对於自己的欲望,会变得有不敢奢望任何好事的情况存在,有可能因此面对喜欢的人,自身的行动都是悲观和消极的。以及由於土星与海王星都在双鱼座的健康宫位(8宫与12宫),双鱼座会有3年身体上相当虚弱的问题存在,体力会显得比较差,会常有一些疾病让你苦恼,皮肤、骨头、牙齿会常常有一些疼痛,睡眠依然会有常常做梦、无法熟睡的情况发生。以及千万注意不要帮人作保、不要欠债与贷款,这3年都容易背负庞大的债务,以及有可能家中会有需要你长期照顾的长者。这都会让双鱼座的健康运势下滑,可以的话,双鱼座应该开始锻链你的身体了,储存多一些的体力,预防健康上会发生的问题。这些问题你现在(2009年11月)应该已经有所感觉了。这种情况会持续3年,请一定要好好注意养身,可以从事一些修养身心灵的运动。
工作运:双鱼座的人今年会开始有机会实现自己的梦想,只要是你想做的工作,想发展的志愿,都可以奇迹式的获得机会发展,甚至是无心插柳的一个想法,都会获得很大的回响。上半年的工作十分忙碌,可能还蛮多麻烦事的,不过双鱼一定要把握今年的好运势,把你过去想做却被束缚的想法全部付诸实现,你将会在6、7月的时候发现,你对工作上的努力会化成大量的金钱回馈给你。 是相当幸运的一年。
感情运:2009年鱼的感情运历经了相当严苛的考验,如果还能继续延续的感情,真的是得来不易的一段感情,请好好珍惜。2010年双鱼座的桃花旺盛的狂开,尤其是2、3月过生日的时候,还有金星加持,并且没有不良的相位影响,感情可以说是心想事成,比较伤脑筋的部份是,今年双鱼座的人心情上会比较悲观,反而会让很多好机会溜走了,4、5、6月的时候,土星会逆行回处女座,是让双鱼决定一段感情的关键期。到了下半年,一切都会变得稳定与明朗了,如果是有喜欢的对象,双鱼座的人要大方一些,不要搞暧昧,今年会遇到对你生命中非常重要的那个人,千万不要错过了。
健康运:双鱼座唯一比较糟糕的部份是健康运势不太好,如果可以的话,请现在赶紧找出治疗你身心灵的活动,因为你即将有3年体能不佳的情况存在。大小病痛都会不断,就算是身体底子好的双鱼,也会有睡眠障碍、精神不济的情况存在,请好好注意身体健康、稳定心灵,不要情绪化,保持心灵平静,对你的健康有益。
整体运:(5颗星) 今年是双鱼座非常重要的一年,梦想与感情都会心想事成,幸福决定权全在你自己手上,你必须要清楚明白自己要什麽,不要什麽,那些幸福才可以掌握,如果你迷迷糊糊,对於自身的感情与梦想无法确定的话,就会浪费2010年这麽好的能量了,可以的话,现在就开始计画吧!迎接属於你的2010年。
昨天脑袋发热,去买了个新凯越,心里很难过,死要面子活受罪。 今天早上醒来,心情更加的压抑和沉重,深深的孤独感和失落感以及挫败感。晚上做了个梦,梦见那个小姑娘,叫我帮她的同学(?)远程协助考试,考试的范围是一篇叫《西梅北》的文章。我无比清晰地记着这个题目,想起那个小姑娘,那个让我很后悔的小姑娘。 看到《间客》中的一句话:“如果将来这个联邦要收拾你……我很想在联邦之外给你留条后路。”不禁热泪盈眶。
昨天拉肚子,拉了一天,上了5次,拉得四肢乏力,全身脱水,口干舌燥,真是太惨了。好在晚上去二伯家拿了一些药,效果还是挺明显的,早上本来的时候,肚子没怎么乱叫了,经过一晚上的休息,总算也恢复了一点体力!
今天去市区买电脑桌,我需要的是是圆角的那种,上面还连着书柜的,去找了几个地方,很贵,嗯,至少是超出了我的预计,不过最后还是买了一个那里看起来最便宜的一款。 既然去了市里,就趁此机会去见一下老同学,自从高中毕业以后,至今已经八年多没见,missdeer这个id的由来的那个家伙。昨天在msn上跟她联系过,今天我先打电话到她家,是她妈妈接的电话,我却以为是她在逗我玩,娘俩的嗓音是比较接近,让我差点儿摆了乌龙,还没有多说话而说错话。 倒是想过不少再次见面时的场景,不过现实是让我有点儿意外,她居然叫我去她爷爷家,我比较汗!路上买了点儿水果,呃,确实没这种上人家家里的经验,也没人告诉过我,不过我想有长辈么,带点儿水果应该不算失礼,也不算唐突吧。 实际上,我比我自己想象的要不拘谨得多,这让我自我感觉良好,哈哈。不过毕竟分开得太久了,而且两人的经历差异也太大,让我觉得实在很难找到话题。 这丫头现在瘦得不成样子,164的个子才92斤,真是皮包骨了,还说现在上海就是流行这种骨感的。看那小腿,大概真只有我上臂的粗细了,还是喜欢她以前稍稍有点肉嘟嘟的可爱模样啊!
嗯,今天是国庆节,是的,我得祝贺,说实话我的心底还是热爱这个国家的,热爱这个国家中的人民的,当然这种热爱并不表示我会同样热爱这个国家的执政党。 上午还是看了国庆阅兵的一部分直播内容,呃,我不是个军事迷,对那些部队装备和武器是一窍不通,不过这不影响我对阅兵式的观赏心情。总的说来,作为一个仅仅60年历史的政府来说,能做到目前这样的程度,真的很不错了,人渣和败类是很难免的,这需要经过长时间的修正才能慢慢做得更好! 祝贺伟大祖国60华诞!
中午去吃午饭,楼梯上遇到王同学,依然是一脸茫然困顿的样子,问我去不去吃KFC,我大汗,这个时候选择去吃KFC还真是意外,问她为什么,说是要去洗头,只好去那旁边的KFC店里解决午饭了。而我原本是去食堂的,根本没带钱出来,两手空空,王同学只带了30元,外加几张KFC的优惠券,两个人就这么冲过去了。 花光那30元钱,外加一些她车上的几元零钱,基本心满意足地吃完KFC,又让王同学带我去洗头。洗完头,吹干,看起来舒服多了,这几天台风来,气温降,早上都懒得洗头洗澡,确实脏了点。猛然发现自己头顶好几根白头发,恐慌,恐惧,恐怖!
今天,也是无所事事地点开在csdn的blog来看,并不特意是为了看什么,只是一种下意识的行为。惊讶地发现,居然成了博客专家,我狂晕!就凭我那一年有数的几次心血来潮,偶尔想到了,才会用Windows Live Writer顺便把文章发到那上面去,到目前为止,也总共才8w多的访问量,其中不少还是自己点的,排名居然也有1500。自从确定在blogger上放置blog以来,对那的关注度实在很少很少。 由此可见,csdn真是没落了啊!想当年,大一上学期,几乎天天跑去网吧,混迹于汇编和C/C++板,下学期买了个电脑后,开始学习C++Builder,就在C++Builder板混,当时的技术氛围多浓厚啊!可是现在,那些已经消失N久的id,也早已从记忆中淡出! 呃,csdn blog expert,还真是让我觉得有点尴尬的称号呢!
不知怎的,昨天我突然想起北京这个一直只在书报、电视、网络上才能得到些许印象的城市来。 想到是不是该挑个什么时候去北京玩一下。想想在北京,认识的人还真不少,有中学同学,有大学同学,有以前一起灌水的网友,有以前的同事,甚至还有关系比较奇怪的,当年帮人家做毕业设计的,呃,勉强可以算是朋友吧。 想到这些人,就更想去那里旅游一下,顺便想去爬下长城,逛逛故宫。想做的事情还真多啊!
昨天上午跟大领导谈了后,基本确定下来辞职的事实。这2周多来,几次同领导们沟通,都被问及到底是什么原因要离职,我都一直以身体抱病需要休息,家人意见要我返回老家以及失恋之后精神不济,工作状态极差等等这些事情做为理由。嗯,其实我说的都是事实,当然也许还有一些没说出口的原因,毕竟作出一个决定,尤其是对自己来说是个关系比较重大,影响比较重大的事情,肯定是有很多原因掺杂在一起,只不过有的比重大些,有的小些而已。 昨天中午跟王同学在食堂吃饭,我兴高采烈地跟她讲我怎么和领导沟通,我要怎么处理剩下的事情,以后我有什么理想等等,荣荣就说我好兴奋啊,还真是脱离苦海了。兴奋只是暂时的,之后便是接踵而来的麻烦事情需要处理。 星期天在江江家打牌时,看到一个电视剧,里面一个坐在轮椅上的青年男人歇斯底里地大喊“我受够了,我什么都没有,我没有钱,没有健康,没有爱情……”,沉重地拨动了我的心弦。那不正是现在的我的真实写照吗?记得前些日子跟王同学在QQ上聊天,她还说“可怜的胖胖,出来几年,带着一身病回去了”,我当时可真是郁闷坏了,我可不希望这样被人同情,被人怜悯!但那却是事实。当在电视上听到那几句嚎叫时,我的心情很压抑,不过好在我马上想清楚了,我跟电视上的人是有区别的,最大的区别就是我没有绝望。我仍然对自己的未来充满了希望,尽量到目前为止,情况并不乐观,但我的选择是挣扎,而不是放弃。我不过分乐观,保持着一点应有的悲观和警惕,却不失强大的自信。我有的是远大的而自认为还算高尚的理想,并且坚信自己一定能通过努力在这条路上走下去,直到收获成果。 这些日子的所见所闻,加上和人讨论得到的启发和自己的思考。我略有点惊讶地发现,原来自己还是有点儿事业心的,只不过跟旁边的大多数人都没取得过一致意见而已。就说那天去江江家打牌,事后回想起来,真觉得有点后怕,人多了还可以一些打个牌,聊个天,要是两个人这么静悄悄的下午呆在家里,可以做些什么?还有上次,小思宇来深圳,把我叫去一起去小妞家里,那第二天下午,4个人打牌打累了,就一个一个倒在客厅的沙发上睡过去了,我也觉得后怕。那不是我想要的生活,至少不是现在的我想要的生活,那太缺少激情和活力,懒洋洋而无所事事是我很害怕面对的状态。我希望在自己有精力有能力的时候,做些事。难得活一次,做一回人,总得做点事情,留下点痕迹,证明自己在这个世界存在过……
昨天在公司里说到,以后要多作培训,多作交流,这种事情我倒是有点儿兴趣的。培训、交流,那么幻灯片是必不可少的,于是回来后就开始捣鼓Beamer。 因为就我了解的用LaTeX做幻灯片就只有PDFScreen和Beamer两种方式,而看过实际效果后,更喜欢Beamer生成的那种。以前也用Beamer做过一个非常简单的,这次我想好好研究一下,可以做出一些比较好看的效果来。 经过昨晚和今天上午的折腾,基本掌握了一些常用的用法。总的说来,还是比较满意的,虽然速度上比较起PowerPoint这种工具慢了不少,但心中还是比较满足的,主要还是熟练程度上的不足,以及缺少良好的工具支持(呃,就是直接拿UltraEdit编辑的)。所以更坚定了我要做一个TeX代码编辑器的想法。 因为这半年来使用MediaWiki的粗浅经验,让我对TeX的用法有了更多的理解。这所谓的“所想即所得”实在只是为了就对Word之流“所见即所得”才勉强杜撰出来的词汇。在我看来,这个TeX的设计思想,就是典型的西方人的思维方式:懒散、直接、天马行空。对于几千年来接受着严谨、务实、勤勉思想熏陶的中国人来说,一时间还真有点转不过弯来。在TeX中用这样的描述方式:我把这些文字作为标题,把那些文字作为章节名,还有些其他的就是正文,而至于标题、章节名和正文应该用什么字体,什么大小,什么颜色,什么对齐方式则不是当前我应该关心的事;而我们往往已经习惯了这样的做法:我把这些文字设置成黑体四号,居中对齐当作标题,那些字是楷体小四,左侧对齐,当作章节名,还有剩下的就宋体五号了,首行缩进两个字符,就是正文该有的格式。 就这么对比着来看,所见即所得容易催长用户做出花哨的排版,用户放了较多的精力在如何定制排版格式上;而TeX的所想即所得则比较适合于循规蹈矩的排版任务,在排版过程中可以少费脑筋。这也就是我说西方人的懒散、直接、天马行空的原因。由此也更好理解,为什么Nokia的手机里没有树型结构的文件系统,全靠文件名来索引;为什么wiki也是这样只靠文章标题进行检索;为什么国外品牌的PC机硬盘只有一个分区了……
在食堂跟江江、bobo一起吃过晚饭,晃晃悠悠走向F3,没想到在楼下遇到疯丫头,最近见到她有点多啊,前不久教授来深圳,一起吃饭时就见过一次,再之前是马姐姐召集大家吃饭,也见过。她在这边刚开完会,于是就和她聊起来,我告诉她我要辞职回家了,她倒是表现出一点惊讶的样子,比较有趣的是她也跟我说一个“绝密”的事,她老大同意把她调到北京去了。 这让我越来越觉得用“铁打的营盘流水的兵”这句话来形容我司实在太合适了,真是半军事化的管理,连里面的人这方面的行为都很半军事化啊!想想我进公司这4年来,陆陆续续离开(不一定是离职)的人中,有多少是跟我比较熟的。雨烟离职去了北京,跟老公一起走的;教授是最近才离职的,不过中间也是几经波折,现在是去tsinghua读博了;骨狗是个比较有趣的家伙,离职前的告别邮件还是中英文双语版;小思宇是去巴基斯坦陪彭彭的;孙同学没离职,却想方设法调到武汉去嫁人了,瀑布汗;还有一些不是很熟的同事、同学离职的;剩下几个准备行动的,这中就包括疯丫头,猫猫也许算一个吧,一直嚷嚷着要去南京;小丫头说是年底会去上海,也算是一个吧,也是一直吵着要离职的家伙……总之,大的趋势看,都是往着离自己老家近的地方挪,嗯!
早上醒来,习惯性地找床头的iPhone看时间,居然没找到,很奇怪地起床,找挎包,心想昨天记得把手机拿出来了的啊,结果连挎包也不见了,越发奇怪,等到发现卧室门打开着,才开始有点焦虑,走到客厅一看,挎包被丢在靠近门口鞋架的旁边,里面的东西已经被翻过了,钱包里面大约有1千的现金已经不翼而飞了。这时我才确认,昨天晚上有贼入室了,这才稍微有点后怕,晚上有人进来我居然什么都不知道,万幸的是,只是丢了点钱和一个iPhone,至少连T43都没丢,T200也在,PSP,NDSL都在,连一起放在挎包里的Nano都还在,除了这些,人身也是没损失。 情绪理所当然地比较差,但也不知道到底是什么心情,没有恐惧,没有愤怒,没有后悔,没有惋惜,只想躺床上睡一觉。大约的损失总共是5000RMB,却没有一点心疼的感觉,对金钱的态度自己都觉得有点不可理喻。想要钱,却不在乎钱。 这该死的国家,该死的社会,我诅咒这个世界,却对那个小偷什么想法都没有,连骂几句,憎恨一下的念头一丁点儿都没有。 还是得靠自己,拥有了强大的力量,才能保护好自己和对自己来说重要的人或东西。
今天疯丫头发邮件来,随便聊起各自的近况。这个性格柔弱却有点儿自己的小固执的姑娘,看着就是那种让人忍不住想欺负一下,却又忍不住要好好疼惜的人。想起以前一起玩耍的日子,还有她对我的各种大决定的意见,有时候让我觉得有点儿困惑。 也许我在她眼中真的就是一个小弟弟,偶尔在她的面前会表现出一些小孩子脾气来,也许有时候我在她眼中又是一个男人,站在女人对面的男人,希望能做些理应不该由女人担当的事情。 原本被我深深压抑在内心底层的那些亘古遥远的回忆和情绪,又都活络起来。也许唯有时间可以化解这一切。
早上听同事说起,那个杰克逊死了。当时还没什么特别的想法,心想也就一个出名的歌手吧,死就死吧。 下午小妞发来一个mp3,名字是《Heal the World》,很好听。突然想起初中时班上一个转学生,一个身材纤细,特长舞蹈的女生,据说她的偶像就是杰克逊。那是我第一次知道有杰克逊这么个人,看到那CD封面上的照片,心中一点都不感冒,尤其不能接受他那种打扮。心中还纳闷为什么这么一个清纯的小姑娘会把这样的人当成偶像。那个女生后来在初三最后一个学期又转学了,大概因为户口之类的原因需要回原籍去中考,再后来就一直没见过了。记得在我在高一的时候,那段混乱而手足无措的日子,还偶尔听到过一两个男生在那里对她的yy,那时我只觉得这太假了,虚伪得太明显了。 春去秋来,不知道那些曾经从身边经过的人,现在都在哪里,过着怎样的生活……
历经约2年的安逸生活,blogger终于又不能访问了,这次的决绝,让我惊异和始料不及,这次似乎不是伟大的GFW动的手,而是人家服务器端直接自己被我屏蔽了,悲叹啊! 命运不能掌握在自己手中的感觉,实在太不好了!
托小妞在淘宝上买了块手工皂,照片很好看,那种那糕点,用小妞的话说,就是黄豆糕内嵌紫色布丁。昨天中午跟小妞他们两口子去万科城的夜郎国吃田鸡,把手工皂拿了来。包装也比较可爱,最外边是一个绿色的硬纸壳,纸壳夹起手工皂,两边没封起,可以看到里面,用一个塑料袋装着手工皂,塑料袋和纸壳在最上边还用一根绿色的小绳串起来打了个活结,很是吸引那些小女生的样子。 手工皂很小一块,小妞说大概每天用一下,能用两三个月吧。嗯,我明明记得以前是小妞跟我说的,男人过了25就应该保养了,可是上次她硬是说自己说的是女人,我大汗,不过看着自己脸上日渐粗大的毛孔,我就只认我记得的了,哈哈。
google上有个讨论组,一直标榜自己高质量,可是为什么我订阅了这么些日子后,越来越感觉到这些个主题不知所云了,难道所谓的高质量在我看来就是装B的意思? 我狂烈地晕啊!
我的自负掩盖不了内心深处的自卑,灿烂的阳光抵挡不住浑身的寒冷。 难道我真的错了?我不知道,我更不愿意承认。 我要继续坚持自己的信念,即使满身伤痕,也要蹒跚着勇往直前!
今天用Foxmail收邮件的时候,才稍微留意了一下出错信息,原来我在学校bbs上的id已经没了,消失了,生命值减到0了! 上去试了一下小丫头的id,也没有了,离开学校的日子,终于超过1年没有记得要登录bbs。 用guest登录上去看了看,以前经常驻留的几个版面也找不到了,像People,留下回忆都没有! 翻出Foxmail中保存的一些bbs上的聊天记录,还有邮件,想起在学校或开心或悲伤或迷茫或骄傲的时光。 一站的终结,逼近着新的开始。
今天一个同事发来告别邮件,没多少意外,因为上个月就已经听其他同事提到过。这同事是个比较有趣的人,告别还要写个中英文对照的双语版,而且内容严肃,很像领导讲话。除此之外,他爱好摄影,关注电子产品,这是我比较钦佩和羡慕的一点,我一直希望自己也能拥有一项比较健康的业余爱好,不过直到现在,尝试了不少活动,最终还是没找到。 同事邮件中说到一句话,我很是有点感触:“事业上所有的成功都弥补不了家庭的失败。”他说这是一句台词,我觉得在我的内心深处也许我是很赞同这种观点的,但这些年来,我却时常认为,男人在30岁之前应该能作出一番事业来,至少能让事业走上正规,而这之前,感情的事应该让路。但是我有时候对感情的渴望也是强烈得一塌糊涂。 同事还说,在这个月要去四川进行一场心灵之旅。真是一个煽情而风骚的男人啊!曾经我有一段时间也是对自己对生活失去了信心,小思宇问我想干活,我说想去旅游,小思宇说总不可能旅游一辈子吧,于是让我打消了这个念头。现在回想起来,小思宇真是个感觉敏锐的人,还是说很多女人真的有这种被人称之为“女人的第六感”的能力。 同事要走了,引发我一些思考,最近甚至想到我这半年或一年中要做哪些事,可是我往往最终只留下一个美好臆想。 祝同事以后的工作生活都一帆风顺吧!
在Kugoo上随便按排行榜搜索的歌曲列表,几乎是重装一次才会更新一次的列表。这次偶然发现列表中一首很抒情的歌曲《白狐》。虽然听了也好些日子,而且都是一个人在静谧的夜里听,但直到今天,我才实在忍不住心中的好奇,上网搜索了一把。 搜索了才知道,原来还有一个合唱版本的,于是马上开Kugoo来听,男声稍微有点让我失望,也许是从小看电视《聊斋》而被先入为主的思想主导,我特别希望男声是像电视中的那种书生腔调。不过总的说来词、曲,以及女声,都很打动人,在百度百科中,也有不少相关的信息,原来蒲松龄不是第一个写书生和狐独的故事的,只不过是他把如此凄美而又有新意的情爱带到了大众面前。 不知怎的,尽管让人觉得悲伤,我却有点神往。
昨天晚上6点半的飞机,回到深圳住处已经10点了。在西安过了6晚,有4晚出去转了转,给我印象比较深刻的是那里的吃的和人文景观。 22号傍晚到的西安,结果最郁闷的是被人忽悠了,居然有两个名字一样的酒店,而且我明明说得很清楚是哪条路上的,结果司机还是把我带到了另一个酒店那里,太扯了,比国产007还要傻冒。马上出来打车走,结果说明了是东仪路,那个司机硬是开到了东一路,我大汗!好不容易啊,才到了最终目的地。一个小小的窄窄的地方。放下东西,去酒店附近一个砂锅店吃了些东西。第一天,给我最大的感受是,西安美女挺多的!在的士上时,就看着路上的行人中,很多漂漂的mm,后来去砂锅店,就又看到一个很漂漂的mm一个人在那里很优雅地吃着粉丝。 23号晚上,听从王同学的建议,去大雁塔喷泉广场转了转。到了那里才郁闷地发现,这明显是个情侣才来的地方啊。可怜我一个人,天又冷,好凄凉!随便走到路边的一个店里,买了点东西,回去哄一下家里的大小美女。其中一条街上,一家一家的小店,叫百工坊,都是当地特有的手工艺作品,主要特色是可以让游客DIY,但是我看到基本没有什么人进去,不知道是不是因为已经是晚上的缘故,或者是天气冷,游客不多的缘故。正当我无所事事准备回酒店的时候,广场广播突然说有什么水舞表演,于是好奇地停下来等。水池旁边站满了人,中间也有很多人,我挤进一个地方,原来就是喷泉配合音乐,喷出不同的水柱,所谓水舞。不过也是第一次看到这种东西,还是有点新鲜感的。 24号晚上,我本想去买些玉的,因为蓝田就在西安附近,所以西安就有很多卖玉的,问了下王同学,她说去书院门买。结果等我打车到了书院门,那里的店铺都已经关门的了。没办法,于是只好走到对面去看城墙,反正王同学也说,这好歹也是西安一景啊,哈哈。门票40,我不清楚这种行情,直接进了里面。刚好有什么大唐灯会,于是在城墙上走了一两个小时,天还是很冷,回! 25号晚上开始下雪了,而且从公司出来打车,居然打不到,走来走去,过了一个小时才打到,汗!直奔回民街,跟司机聊起,他居然是上海人,一下就猜出我老家是哪儿的,哈哈。到钟鼓楼下了车,绕了一圈才发现那条回民街,真是条小巷子,而且人不是很多,我不知道是因为天气不好人少了,还是因为已经有点晚了人少了。走到另外一边,时代盛典那里,也有一条回民街,人更少,店都关门吗。没办法,打电话找王同学确认一下,王同学也跟我说不清楚,不知道她哪里找来另外一个mm来跟我说,我才明白,第一次进去的那条小巷子是对的。于是对跑过去,吃了笼贾三灌汤包就很饱了,晃悠晃悠晃到另一边,随便找了个泡馍店,进去点了个牛肉泡馍,不得不说,这味道真的比公司食堂的好太多了,肉嫩味美。 26号,下大雪了,早上起来发现屋顶上,车顶上都积了几厘米厚的雪,白天也是飘着鹅毛大雪。只好不出去了,老老实实呆在酒店里看小说看电视。 27号,想着第二天就要回深圳了,下了班立马又跑到回民店买些吃的带回去。顺便去吃了下之前那个mm推荐的红红炒米,感觉跟蛋炒饭差不多,不过是里面有些肉丝和酸菜。又叫了几个羊肉串,还有不知道是什么肉串,味道都不错,至少这羊肉串我是比较得出来的,比起其他地方吃过的,这里的特别嫩,而且膻味不大。吃完后,晃悠了两圈 ,进到一个大一点的店铺里,买果脯,就挑那种平常在深圳不太有得买的,我也不知道价格上有没有问题,不过想来再亏,数量也不大,也就不去计较了。 偶尔去下这种从没去过的地方,还是挺有意思的,不过一个人毕竟乐趣就少了些了。
一周前就被告知要去西安出差,心里还是有点忐忑的,说起来有点丢人,还是第一次一个人去一个陌生的地方,真正的人生地不熟啊,哈哈。以前去重庆,有同学一起,来深圳,也有校友一起,去贵阳,有表哥和小妞接待,这次可是真的一个人咯。
8点钟才从公司出来,坐上B666回住处,也不算太晚。快到小区门口的公车站时,我已经站起来走到门边,一辆SUV却超上前拦住了公车。从SUV下来五六个30来岁的男人,都是圆寸头,拍开驾驶室的窗很嚣张地对司机说,叫他以后不准再开,要是明天再被他们看到要怎么怎么的。这样捣鼓了几分钟,终于走掉了,我还一直担心他们会不会上车来抢劫。 记得从上中学开始,每当说起以后娶妻生子的事,我就有点烦躁和恐惧,我总是担心自己的小孩没教好,变成流氓。我妈知道我的想法后,曾也和我说过,只要好好管教,是会好的。今天看到这些人,我又想起这些来,不禁又想,这些人的家人都是做什么的,他们有没有父母,有没有妻儿。 这个世界,真让人憎恶。
今天突然说起情人节来,小妞问我有没有约mm,我说我一到关键时刻就哑火了,小妞就说约一下又不会死人,我说没有想约的人,是不是我要求太高了。小妞就说觉得我是麻木了,什么样的人都觉得一般。我无语。也许吧。
今天是元宵节,据说今天晚上10点多将是近50多年来月亮最圆的一次。下班后跟F还有孙同学一起去超市买了点汤圆,然后回家自己煮。三个人吃两包汤圆明显是过量了,最后实践证明,我们顶多只能吃掉一半。当然我们也煮了一点米饭,一人不到一小碗,不过也刚好用来调味,汤圆毕竟太甜了。 吃完后,孙同学又一次把我的厨房大清洗了一遍,灶台上厚厚的油渍也被擦干净了。我开玩笑说,你是不是现在故意来刺激我的啊,以前怎么没发现你有这么贤惠啊!她就说,可惜了吧,后悔了吧。呵呵! 真的很有点心灰意冷了,要撤退了!
去超市买了点儿肉和菜,回来哧哧喳喳弄了大半个小时,整出3个小菜来,跟同屋的那个江西老表一人倒了大半小饭碗的女儿红,打开电视,看着国内国际时势政治,摆下龙门阵,点评下天下时局,人生真是惬意啊!
真是捉弄人的命运啊!有句话说,命运负责洗牌,而我们才是玩牌的,牌太差,无论技术如何,都是于事无补的。 今天在公司里用错了_tcsncpy和_tcsncat,因此引发的bug找了半天才明白原因,汗颜。 另外,Launch里好严重的内存泄漏,确实,都是些很低级的失误,review很重要。
感兴趣的事情太多,精力太有限,克制自己的求知欲真的很重要!
可是怎么我一点都不激动,不兴奋呢,反而有种失落的感觉!
上午在公司开了两个小时总结会,总的说来,对自己在这一个季度的表现还是比较满意的,虽然中间过程有些不爽,但总体上结果还是勉强能够自我安慰的。
下午在公司,又开了两个小时的会,这倒没什么内容了,我本来这一年来就没有参与这些项目活动,冷然一个旁观者的身份。
下了班,跟F还有两位cm0大大一起去华强北吃海鲜,虽然那家叫明香的馆子屡次路过,也听人提起过很多次,但来深圳3年半了,还没去过一次。吃得很安逸,也正是这一刻安逸的短暂,才让人觉得眷恋。
吃完晚餐,4个人一起去逛街,真是不得不感叹作为一个男人,F居然那么喜欢逛街,我本来一直以为自己逛街的能力也够强的了,被小妞她们培养了近一年的,结果我发现差距了,我完全是被动型的那种耐力好,而F是主动型的精力充沛,兴趣盎然!倒是把两位cm0折腾惨了,还穿着高跟鞋,最后是见到凳子就想坐了,哈哈!
回家了,明天的现在,我应该是在家里的床上了,哈哈,这世上没有过不去的坎!
星期天去参加1783的石头河溯溪,结果被小路晃点了。溯溪回来跑去南山找阿布拿手机,然后去他家吃晚饭,见到了他老婆,真没想到啊,他儿子居然2岁多了,真以为是90后的呢!吃完饭,坐了一会儿,一群人决定去唱K,结果不知道喝了多少酒,反正第二天是谁把我送到的士上的我也不记得,迷迷糊糊回到家,倒头就睡,于是,一天没上班! 今天去上班,不知怎么的,情绪很低落。整了个版本给人测试,发现根本没法用,几个严重问题,崩溃、崩溃、还是崩溃!以前的设计有问题,或者说压根没考虑到后来会需求会变化那么大,这实在是可以原谅的。这次还有一个重大的变化是,模板文件中加入了宏,于是用COM操作后再关闭会问你要不要保存修改,尝试了半天,发现只要先关闭workbook,再关闭workbooks,再退出就可以了。因为关闭workbook时有个参数可以指定是否要保存修改,而且关闭workbooks时则没有,会自行弹出个消息框来确认。
昨天晚上是网络产品线的新年晚会,下班后从公司坐车去宝安体育馆。今年的待遇好很多,每个座位上都有一包小东西,里面有几个小面包,一盒牛奶,还有造势用的东东。 晚会内容倒是没什么新意,年复一年,于我无关。 一切皆是浮云。
昨天晚上跑去KTV唱歌,后来唱歌腻了他们就放起的士高来,我是不会蹦迪的,可是看着那些人在那跳得那么起劲,我也有点蠢蠢欲动了,于是去胡乱蹦了几个。结果,今天就显效了,虚脱了,背痛,下午一下就睡着了,好久没在家里睡过午觉了,醒来的时候发现天灰蒙蒙的,还有雨声,还以为睡到天亮了,心里不禁大喊,天呐,我居然从前一天下午睡到第二天早上,还没吃晚饭!后来挣扎着要不要起床,看了一下时间,才18点,心里顿时安定了不少,原来还没到第二天啊,刚刚还郁闷着这周末就不知不觉地让我睡过去了呢! 再说点正儿八经的事。话说我一直想要设计一个基于C++ GUI框架的脚本扩展架构,不过到目前,还没有一个完整的清晰的思路,我只有一个大致的目标。一直想着,这样的架构实现后,只要C++部分实现一些基本的底层支撑,剩下的脚本就可以直接拿出复用,实现所有业务逻辑。为了证明这个架构的通用性,我觉得自己似乎有点儿贪心了。我希望在MFC+XTP的基础上、WTL+TabbingFramework的基础上,以及wxWidgets的基本上都实现一遍。MFC的是因为工作上的需要,WTL则是因为想写一个WIND,而wxWidgets的则是想写一个通用的跨平台IDE。今天只想到一点,所有的逻辑处理都应该交由脚本实现,C++部分只提供最基本的底层(原子)操作。
老大叫我整理一份项目组内成员的C++相关内容的培训计划。我还是兴冲冲地去弄的,不过基本上是参考我自身的情况制订的,内容方面不是我比较熟悉的,就是我比较欠缺但又在工作中比较需要的。 主要分了8大类,分别是C++对象模型、C++模板、STL、Boost、面向对象程序设计、Windows API、MFC、COM。每一类,都又划出好几个培训课程,我还根据自己所了解的,分别给每一类都备注了参考资料,每一类的的参考资料大多只是两三本经典书籍,比如COM类的,我就写了《COM本质论》和《深入解析ATL》,而Windows API类我就写了《Windows程序设计》和《Windows核心编程》,等等。 等我把这份列表发给老大,老大又转给更大的老大,更大的老大则回复说,内容太多了,要分轻重缓急。我觉得很有道理,这样的培训是很耗费资源的,当然应该拣最有用的来。不过他列出的前3位是Windows API、MFC和COM,对于我来说,就有点兴味索然了。虽然这些方面我也远远说不上精通,甚至连熟悉都不够,但我自以为,应付工作上的要求是够了。比COM举例来说,我虽然排斥COM,但必须用地方还是会用的,我会调用COM服务器,同时我也写过COM组件,我觉得自己够了。 既然不能把这份列表作为组内的培训计划,我看了看,觉得依照这些列出的参考资料,也可作为我自己的增强计划。这8类我都有所了解,在实际工作中也都或多或少地有所运用,但我不禁要考虑,学到什么程度算是够? 我个人倾向于学习和使用一些比较通用的技术,比如STL、Boost之类平台无关的知识我就很有兴趣,而COM则是有点深恶痛绝的感觉,MFC稍微好过一点,不过也不是很喜欢。这不是我研究了这些东西后主动有了喜恶观念,而是不知不觉在一个比较长时间内养成的兴趣倾向,直到后来自己总结的时候才发现这个规律。 其实我根本没多少想法,要尝到什么程度,目前而言,我只好给自己暂订个目标,STL、Boost、C++模板和对象模型,以及面向对象程序开发,是能学多少算多少,而其他的,则是够用就行。
本来计划是明天的,因为冬至要吃饺子,结果F说明天要加班,于是只要提前到了今天。 那几个家伙也够懒的,能睡那么久,不过也让我有点羡慕,因为我到了早上7、8点的时候,就开始睡不着了。 结果等cm0同学过来的时候,已经1点了,然后跑去超市买菜。安排的是中饭吃炒菜,晚饭吃饺子。买了130多的东西,当然不全是吃的,还有cm0买的什么卫生纸之类的东西。F去超市旁的KFC买了鸡米花、圣代、薯条、蛋塔,因为实在不知道我们什么时候才能吃上中饭。 中饭的菜基本上是我弄的,也跟平时我自己弄的一样,一个肉丝、蒲瓜、金针茹、香干丝混炒,一个白灼基围虾。味道自我感觉还是满意的。吃完就已经4点半了。 吃过中饭,就打了一会儿升级,我的手气不是一般的差,不知道那个跟我搭档的cm0有什么感想,哈哈,反正我们一直都是打2,没升过级,而对方已经打到7了。 7点时,开始准备晚饭,即饺子。我没有动手,因为我实在没有经验,就看着他们三个包,份量挺大的,满满一大盆的馅,厚厚的两叠皮。最后吃剩下15个左右,没办法了,只好浪费了,唉,可惜! 另外还剩下鸡汤和鸡肉没动呢!
大牛上周从俄罗斯出差回来,今天给了我好大一块巧克力,哈哈! 单从包装外来观察,这块巧克力厚就不止1cm吧,宽不止10cm,长不止20cm。包装上全是俄文,我也找不出哪里写了具体的体积规格参数,手头也没有尺子可以量一下,反正就是很大一块。中午猫猫还说,大牛把最大的一块给我了,给她的就没有我的大,哈哈,想起这个就觉得开心! 我们公司的人去国外出差,习俗就是带当地的巧克力回来给同事朋友们尝尝。以前吃过那位cm0同学不知道谁给她的德国巧克力,薄薄的一盒,里面是一小条一小条,味道比小卖部的德芙好多了。只可惜我是没什么机会出国出差了,除非赚了钱自己去旅游去。 其实我很喜欢吃巧克力的,只是太容易长胖了,哈哈!
部门组织去杨梅坑游玩,之前只看别人去玩过,自己却没去过,所以在出游前,一直有点儿兴奋。 早上等车等错了地方,有点囧,有点恼。坐了一个多小时车,终于到了目的地。每人都去挑了自行车,好久不骑了,有点感怀。租好了车,却一直不出发,等几个自驾车过来的人,有点不耐烦。估计等了有十几二十分钟吧。 一路逆风,而且风很大,路上看到不少前面的人被风吹掉的旅游帽。大概骑了半个小时,到了目的地,一个别墅,再过去就是悬崖了,悬崖不高,下面是海!在这么偏僻的地方看到悬崖,不禁想起很多肥皂剧里的那些跳崖的剧情,有点无语,当时的人们想像力还真是不够丰富啊。 悬崖上也风很大,拍了几张合影,也没什么玩的,就回去了。回去是理所当然的顺风,大概15分钟就当了,然后就是吃中饭。中饭比较合我口胃,是海鲜,但称不上大餐。价格不便宜,但也算不上贵。海鲜也是最常见的虾、蟹、鱼、花甲、扇贝,其他的就没什么值得说了,不过我还是吃了3碗饭,哈哈。 吃过中饭,就去桔钓沙。上一次去桔钓沙应该是2006年9月9日吧,记得当时小丫头不在深圳,说得她很遗憾的样子,小丫头应该很喜欢去海边玩吧。这次时节不适合下水了,风也很大,于是我只是躺在席子上用手机上网看小说,就这么过了一下午,直到4点半,打道回府。
约了几个同事(F、S、W)来家里烫火锅,早上还是跟平时上班时一样准时自动醒来,已经麻木地不知道郁闷,在床上赖了一会儿,起来开电脑,看了一下更新的小说,然后无所事事,整那些代码,一直到9点多,出去剪头发。剪头发这件事已经酝酿了很久了,但一直没有兑现,今天终于狠了狠心,看了一下记录,上一次剪头发是3个多月前,汗! 剪完头发,离约定的时候还早,便又回到家中玩电脑,一直到W给我打电话,匆匆赶出去,一起去超市买菜,买了不少,我也没有估计我们食量的能力,所以就尽量多买点。 吃了两顿,挺好玩的!
今天中午偶然得知在会展中心有房展,于是临时决定去参观一下,虽然买房对于现在的我来说还是比较遥远的事,但是感受一下那种气氛,了解一点市场行情还是可以的。 本来以为会展中心可以坐391直达的,结果后来才发现,391早已经不知什么时候改线路了,而且改了线路之后我曾经坐过,只是当时没有留意而已。于是下了车,一直走路过去,大概也就是十几分钟的样子吧,不过也出了一身汗。 展厅里外都有很多人,果然比较热闹啊!对于房展,需要关注些什么,我是一点经验也没有,所以像无头的苍蝇到处乱走乱看,看到很多地方都排起了长队等待领取纪念品,觉得还真是无聊。另外就是看到几处文艺表演,有个还算pp的mm在拉节奏轻快的小提琴,看她嘴角弯弯的样子,让我觉得像马姐姐,于是拍了两张照片下来,不过马姐姐的身材可比这mm的好得多!后来看到一处有六七个像幼儿园的小女孩在跳舞,也是很轻快活泼的节奏和旋律,很可爱,但似乎脸上又带有一种跟她们年龄不相符的成熟的神情,看了一会儿,想拍照,总是有人挡在前面,找不到好的角度,不禁又佩服起这些小女孩的体力还真不错!再后来,看到有两个mm在跳比较热辣的舞了,穿得也少,同样是有n多人挡在前面,还有不少人总是在她们前面1米左右的距离横穿而过,甚至有个中年妇女抱着个婴儿,直接坐在那个舞台边上拍照,唉! 对于房子,倒真的没怎么关心,偶尔留心了一两处,总觉得价格上太划不来,比如有一处复式的空中别墅,167个平方,在盐田,总价大概三四百万,心里就很不屑,觉得太不值了。 出来后,又走了很多路,累死了,还是得自己有车啊。
中午睡过午觉走下楼,在拐角的地方看到一个男的,直觉得好眼熟,想了一会儿终于想起来,不就是这些天在食堂吃早饭时经常看到的那个男的吗,当时还心想这男的长相也实在不咋的了点。可是这次匆匆路过的一瞥,却让我自惭形秽了起来,我缺少成熟的气质,而且缺乏自信。所以我一直都有意无意地走着邋遢路线,装着吊儿郎当的样子,抱守着那残存的点点自尊心,却是没来由的自负。 为什么没有自信,说到底还不是跟自身拥有的客观条件有关系。真正拥有强大自信的人,实际上要么确实是自身拥有超乎常人的才能,或者是有其他强势的物质依靠,而这些也正是我缺少的。
记得曾经有一段时间,我把自己的昵称或ID说明栏上改成“从今天开始魔王”,这是一部日本动画片的名字,当时觉得这个标题很适合自己的处境或心境或志向的,也不是说魔王要干坏事,而是要像入魔一样地写程序。当时确实有那么一小段时间,读书的时候也好,工作了以后也好,有点空闲的时间就去写代码,或者上网看编程相关的内容,或者买书看,或者就泡那些编程论坛BBS。结果后来还是不了了之,尘世的诱惑实在太大,哈哈! 今天心血来潮打开久违的VS2008,打开最近创建的一个工程,看了一下SVN里的提交记录,最近一次是22天前,而想想22天前的那次提交,其实也不是自己写的代码,只不过是把别的地方的一些代码复制过来而已。 这些代码在那样的需求下,工作得很好,可是我需要它能再更进一步。昨天重装了VS2003、VS2005和VS2008,但发现2008那个RC1107错误依然存在,于是外事不决问google,发现一篇文章,果然不止我一个人有这问题,很快解决了,看了看我的配置项,最后一个include的目录尾部的字符赫然是个反斜杠,换个末尾字符不是反斜杠的放在最后,试了试OK了,哈哈,仰天长啸! 另外又看了看CppNPv2,里面关于ACE_Message_Queue的说明,原来这个消息队列有一种功能,可以限制存放在里面的最大的数据量,默认为16K,回想白天在公司里,因为我给每条记录是1024个字节,每次16条记录不就刚好是16K嘛,我汗颜! 用VS2008写代码特别安逸啊,本身就已经做得挺不错的了,而且加上VAX的辅助,现在我已经真的再也离不开它的自动完成和重构功能了!也不知道是VC2008的编译器确实改进了,还是我的机器的内存足够大(1.5GB,用XP一般情况下根本用不完),反正觉得它编译速度好快啊!想想在公司里那个P4 2.6G,因为搭配了512MB的内存,用VC2003编译个东西,那个老牛拖破车啊,不过我已经申请加1GB内存了。 还有,就是前段时间买的那个键盘打字果然很舒服啊,仿笔记本的超薄型,现在天气热,再放在本本上要烫死了,打着打着就会不自觉地加重手势,感觉超爽,哈哈! 从今天开始重新魔王!
时间过得真快,我们国家为了承办奥运会,准备了那么多年,从第一次申办失败,到后来申办成功,再到各项准备承办,两三年前就开始倒计时,还有几百天开幕。而8月8日开幕式,感觉就是昨天一样,当时还忿忿不平地说开幕式不好看。今天就是闭幕式了,还是老样子,除了排场足够大以外,其他的我确实找不出好的来了,从色彩,到音效,或者意境,反正没有一项是我喜欢的,也不知道花费了多少人力物力,当年各种专家预测的,奥运会期间给中国经济带来的巨大好处,不知道是否都应验了? 作为东道主,中国确实历史性得获得了金牌榜第一的骄人战绩,但又一想,金牌多带来的又是多少好处呢?看到一些报道说,有些国家,比如美国、加拿大,那里的很多运动员都是业余的,平时都是有各自的工作,政府并不给运动员们发放多少金钱上的补助,相比之下我们国家的运动员呢?出了成绩,还说得过去一点,但成绩很差的那些呢,比如男足,那些钱都是从哪里来的,最后又花到哪里去了,是不是浪费了?我们国家作为发展中国家,却在这些方面作为远不如那些发达国家英明和有远见。 算了,也是一家之抱怨,没意思啊!
一周一次的例会,没有什么新奇的内容,我猛然发现自己连原本仅存的那点激情和盼望都没有了,残念! 下午帮一个同事定位内存泄漏的问题,倒是没有完全解决,只是指出了几处可能造成泄漏的代码,让他自己有空去调去吧。 那天cm0说自己很迷茫,我想了想自己,我是有目标的,知道自己想要什么,却没有动力,完全颓废了,唉!
昨天下了班,跟两个cm0同学去喝粥,然后慢慢晃悠到百草园门口等车。到家的时候,奥运会开幕式已经开始了一小会儿了。 排场是很大,很有张艺谋的风格,中间还让我想起过去阳朔玩时,隔岸观看的印象刘三姐的场面。但是我其实一点儿都不喜欢这样的节目,太古朴了,气氛太沉闷压抑了,我还是喜欢充满青春活动,满是激情和阳光的那种。不过我们做为四大文明古国之一,当然是一个好机会好好炫耀一下自己的古代文件,什么四大发明啦,四书五经啦,乐曲戏剧啦等等等等,倒是近代之后,却真的没什么值得称道的东西拿出来说,真是遗憾啊! 文艺表演持续了没多久,不到两个小时,其中还有刘欢和“月光女神”莎拉布莱曼的合唱,也是让我好生失望,对于刘欢唱的歌,我并不熟,有印象的只有蓝色妖姬、新笑傲江湖和新水浒中的主题曲,水浒中的还感觉不错,到笑傲里就觉得恶心了。这次听来,也觉得不爽,而把人家“月光女神”请来,却来唱几句不伦不类的汉语,实在寒心到了极点。 接着是200多个代表团入场,太多了,我就忍不住了,一直等到点火炬的时候才回去看,原来的体操王子长成这个样子了,瀑布汗! 最后再没心没肺地重复一遍,这开幕式也忒难看了点,好生失望!
想起一句老话,天下乌鸦一般黑。回头想想其实现在也挺好的,写写代码,拿点小钱,混个日子。于是突然又想起自以为很真理的一句话“最好的软件是自己写的”,客户为导向的策略告诉我们,最好的产品就是客户想要什么样的我们就做成什么样的,于是需求收集分析就是非常重要的环节,如何正确理解客户需求,满足客户无休止的要求,是我们制造业工人的头等大事。再回过来看,自己想用什么样的软件,当然自己最明白,所以省略了信息传递过程中信息损耗、变形的过程,最后可以得出前面提到的结论“最好的软件是自己写的”。
平常经常抱怨,怎么也不见买什么东西了,怎么工作几年了还是没攒下钱来,真是太奇怪了。其实仔细算算,每笔钱的去向都是有据可查的,只不过我没有记账的习惯,更谈不上理财了,因此就有了所谓“你不理财,财不理你”的可悲下场。 今天又跑去华强北一趟,已经计划很久了要去买些平常穿的衣服和鞋子。照例没吃早饭,结果看小说看到连中饭的时间也过了,后来实在心里记挂得厉害,就随便收拾了一下便坐车到了华强北。 先跑去KFC里,吃掉¥36.5。 然后去红利多看键盘,家里那套微软的无线套装,键盘用得很不舒服,现在天热了,手放在本本上也觉得烫,所以也筹划了几个星期了想换个好点的外接键盘。红利多也没有多少可选择的余地,当初我曾还想过去万商那些小铺子里买个二三十的就行了,结果同事说还是得买个好点的像微软、罗技的,说实话,有了之前的经验教训,短期内我是不会再买微软的了,感觉性价比太低,而罗技的,从大学起,就一直没多少好感,尽管这牌子的键盘鼠标确实做得挺火的。最后选了个LaVIEW,以前没用过,因为我其实只买过3次键盘,第一次是装第一台电脑时一起配的,大概就是30块钱的,不记得什么牌子了一直用得挺好的,直到大四时电脑搬回家,因为想减轻点分量,就把键盘丢下了,到了老家又买了个新的USB接口的,现在也不记得什么牌子了,因为本来就很少回家,所以用得少,印象极其不深刻,也不记得多少钱了,应该也不会超过100块吧,再后来就是在这里给本本买的微软无线套装了,除了无线这个看起来牛B哄哄的特性外,实在找不出它其他的优点了。今天买键盘,主要看手感和外观两方面,最后以129块的价格买了一个超薄的,手感跟本本键盘类似。 买了键盘就去茂业买衣服。先到adidas买鞋,我也算是龙浩的比较忠实的客户了,每次买鞋首先想到的就是ad、puma之类的。随便挑了双很轻看起来很透气的运动鞋,打了8折还要576块。接着去买衣服,去杰克琼斯看看,好多人,因为在打5折,于是买了件T恤,也要124.5元。 采购完毕,回家,看看也很不起眼的几样东西,除掉路费不算,今天下午就是860多花出去了。钱就是这样花掉的!
今天突然发现,我在公司里有使用权的机器有好几台了,除了本来一直在用的,从进部门开始就配备的那台联想台式机外,还有一台2001年的老爷机,一台双核2G内存的工作站,一台双核双至强1G内存的IBM服务器,还有一台双核2G内存的服务器。这么多可用资源,现在却发挥不出作用,对工作没有什么帮助,实在让人觉得可惜。 但是如何利用这些机器资源呢?我确实也想不出好的点子来。可以建些版本控制、数据库、HTTP之类的服务,但还是大材小用。隐隐约约脑中一个概念闪现——分布式计算!可是现在分布式计算能大众化实用化的也没怎么看到了解到,曾经用过一个号称可以加快编译速度的利用VC的分布式编译工具,但当时试用的效果并不好,四五个机器一些联合编译,最后不但编译出来的文件有问题,耗时也比单机编译的多,真让人失望。 继续想、继续想,如何利用这些机器资源呢?
唉,回到家照往常一样打开电脑,发现explorer.exe是起来了,但界面没出来,倒是弹出个出错消息框,说是哪个进程不正常,看这名字就感觉不是正常的。等了老半天,没耐心了,重启系统,倒是能像平常一样进来了。偶然发现system32目录下有好几个奇怪的文件名诸如oooooo.dll、ffffff.dll之类的文件,而且会自动注入到其他进程中去。windows目录下也有几个文件名很怪的.exe文件,还都放到了系统启动项中了! 似乎中毒了!真烦人啊,编译个wxWidgets也是没完没了了,以前可要快得多啊!唉,得下下决心,整台好点的台式机来,装Linux来,就用来平常看网页和写程序吧。
嗯,这个活动在上个月的时候就筹划过了,不过我并没怎么投入,呵呵,都是bobo在那里捣鼓说五一3天假期里可以抽一天出来,然而,bobo组织不力,3号那天上午我迷迷糊糊发了个短信给bobo,最后结果是cancel掉了。 这次好像是猫猫牵头联系了其他人的,在公司里是一点风声都没有,只是有一天晚上在QQ群里猫猫跟我提了一下,要到我家里来烫火锅,其他时候则是只字不提,联系都没有。 直到今天上午10点多了,我发了个短信喊猫猫起床,她才给我打电话,说11点在我们小区对面的超市门口见,叫了某某和某某。等我11点10分跑去,也才看到舒蕊一个人在那里等着,这个猫猫越来越不像话了,都没有时间观念啦。又过了一会儿,才见大部队浩浩荡荡从天桥那边走过来,猫猫、江江、bobo、大牛和他媳妇。一共7个人,到超市里买菜,这种感觉还不错。买了盒装的肥牛和羊肉,贡丸、虾丸,还有很多素菜。又买了些碗筷,本来家里是有一些的,不过这次人多了,不够用,所以要再添点。 买了回家,我就没怎么动手了,只是找出椅子等必需用品,收拾一下东西。这次买得多了一点,后来刘献文也来了,9个人把肉类都吃掉了,素菜却剩下不少。总的说来,我对火锅的味道要求很低,我几乎感觉不出什么好差来,呵呵,所以这次也吃得比较满足,关键是一群同事一起玩,有一份惬意。 可惜,相机没电了,不然也可以留下点什么留念,一大遗憾啊~
去东门逛了一下午,买了件比较板的衬衣,一条黑色的休闲裤,薄薄的,适合夏天穿,为了搭配这身衣裤,还特地买了条皮带,这样800大洋就花出去了。然后是一双休闲类的皮鞋,又是400多大洋。好久没有这样添置自己的行头了,也许真应该好好地改变一下自己的外观形象,明天穿着人模人样地去公司晃悠一下。 不过逛得好累哦!
同学去巴基斯坦前留给我一瓶李施德林漱口水,放了好些天一直没开封,这种东西还没用过,感觉有点新鲜。今天好奇心起,拆开来倒了一点,说明上说20ml即可,我没有这样量化的概念,就倒在它的瓶盖上,然后含嘴里,照说明上说的30s后吐出,可我好像不到30s就辣得不行了,忙不迭跑到卫生间吐出来,连忙倒了几杯自来水漱了几次才缓过来。晕倒,学不像啊!
又是一个节日,又是一个人过,又是一次难过。什么时候才是个尽头啊!今天,我突然顿悟到一种奇怪的念头。付出是不一定会有回报的,而且是有很大几率没有回报的。而有时候,什么都不做,却什么事情都往头上摊。无可奈何啊,茫然而麻木地做着这些事,只是为了企望以后能少点遗憾和后悔。
定价¥680,用卡打88折后¥598.40元。今天可谓是速战速决,吃完中饭回来休息了一下,立马决定去买东西,刚出小区大门口,就看到辆满载着人的335缓缓驶来,挤上去,男的在这方面就是有优势,不怕被人趁机骚扰的同时,内心邪恶点的可以趁机骚扰一下车上的ppmm,不过我的胆子还不够大,革命尚未成功,同志仍需努力!好不容易晃悠到华强北,直奔茂业大楼,到阿迪专柜看了看,马上看到一款保暖鞋,第一印象这就是我想要的款式,底是胶底的,面是牛皮的,颜色是黑的,价格对我来说是高的,但我还是二话不说,只试一下大小就开单了。
在看《奋斗》时,很讨厌夏琳那个角色,只觉得她把陆涛弄得这么痛苦,为什么陆涛还是不死心,对米莱和灵珊两个富家女视而不见。其实在看片的时候,我就很强烈地意识到,某种角度讲,我不就跟陆涛很相似吗。可是最后陆涛还是跟夏琳在一起了,在他再次一无所有的时候夏琳又回来了,这似乎从深层意义上看,也许是陆涛内心深处的仇富心理,以及夏琳的心高气傲所带来的局限性。从现实角度看,我注定不会有陆涛那样的命运了,我的各方面条件都不行,陆涛在剧中是作为一帅哥角色的,而要以我的样子来出卖色相,实在太困难了,陆涛自身是个很有能力的人,温柔而且聪明,这些方面我也是望尘莫及,最后,他有个很富有的亲生父亲,这个出身是不能选择的。 所以我只能好好地走自己的路,工作,想办法多赚点钱,最好能找一个自己喜欢的女孩当女朋友,然后尽自己努力让家人过得好一点。 事到如今,我真的应该放开点,以前的事慢慢淡忘。我只是一个非常非常普通的人,做什么都不会太出色,只能走着平凡人该走的道路。有的事情不能强求,我应该另找出路,也许真的是错过的,但也已经过去了,再懊悔也无济于事,总是回头看,独自一人在黑的夜里舔舐着鲜血淋漓的伤口,除了自己没人再会看到这惨痛的一切,与其如此,不如向前看,或许更美好的在前面等待着。
昨天测试部年终聚餐,疯丫头又当主持,又跳印度舞,跳得挺好看的,只是我的相机啊,郁闷死我了,想要连拍,结果拍下一些很模糊的下来。还有另外一个mm跳劲舞,也还好看,遗憾的是拍下的是更模糊的。说是聚餐,但好像菜上得并不多,味道不差,不过我全找人喝酒去了,一个测数据的小mm经过我们桌,硬是被我拉住喝酒,哈哈。找各种理由和人喝了一些,结果喝了个烂醉,去洗手间抠了一下,吐空了,摇摇晃晃地坐班车回来,那室友还说要在路上看住我,自己在车上就吐得起劲。回到家胃难受死了,躺在床上实在不舒服,就翻出手机,又想不出打给谁好。打了一会儿电话,还是难受,冲到卫生间里,趴在马桶上想吐,但要真的没什么东西可以吐了,抠也抠不出东西来,这么不爽还是第一次。后来不知不觉,总算睡着了,一直到凌晨4点多才睡来一下,接着就睡到上午10点多,安逸啊! 我用了双缓冲,居然不起作用,估计是没用对,气愤加郁闷。还得改呀,不过有参与的例子代码,应该没啥问题吧。现在对于这个简单的编辑器,还有4个大问题:1、需要能拖动线条的一端;2、移动节点时,线条要能跟着动;3、线条要有箭头;4、线条与节点的交点处要截断。
又到了年终总结的时候了。感觉这一年过得飞快啊,刚刚翻了一下上个元旦放假时的blog,原来我和跟雨烟一起去打了个耳洞,现在雨烟和小于都已经在北京了好久了。上个元旦还跟一群同事一起去笔架山,然后去吃自助烤肉,这次只是一个人在屋里蹲着,今天白天去购书中心逛了一会儿,觉得挺无聊的。总之似乎生活越来越单调枯燥了。 首先回顾一下即将结束的2007年吧。在原来的测试组中度过了第1个季度后,便被释放到了现在的系统组,从纯粹的测试工作中解放出来,做工具开发,当时还心里隐隐有点兴奋,以为可以大展身手了,结果当然跟许多故事一样,现实总是不能跟理想完全一致的,相反反而过得很无趣很苦闷。有几次我都想起当年自己不知从哪里听来的一句话,把自己感兴趣的事当作职业,是男人最不成熟的表现了。当然不得不承认的是,我确实不成熟,已经被好几个mm说过好几次了。也许我真的是一种奇怪的存在,与现在社会流行的类型风格步调格格不入。再转回正题,转到系统组后,先无所事事地看了足足一个月的文档,真的是无所事事哦! 终于一个月后,一个工具项目因为进度紧张,把我召唤过去支援,支援了5个月,从5月一直到8月底,那时统计了一下,5个月共写了有效代码6000行,不计注释和空行。这样算来大概平均不到60行/天,呵呵,似乎挺少的。当时觉得有点沮丧,我的产能这么低,其实回想当时在大队培训教材上看到国外的人均日产代码量,似乎也是几十行吧,呵呵。 9月份开始,就把我从该项目中抽出来,单独回去再搞原来的一个文档共享系统,美其名曰,业务流程一体化平台,其实概括一下,就是一个可以自定义文档组织方式的可以点对点传输文件的共享系统。就为了这么简单一个东西,跟那帮人扯皮扯了近两个月,几乎天天是无所事事的状态,因为总是要讨论需求,因为怕到时候做不出来。而我则是每次讨论完花个30分钟回顾整理一下讨论的内容,然后继续无所事事等待下一次讨论。 终于到10月底的时候老大拍板说可以做了,我感觉顿时像一只出笼的鸟儿。不过一直到现在,才勉强算是有个东西了,毕竟2个月时间能做出个啥东西呢!一个人的项目,自由度还是比较大的,比如我用了Boost,这个东东据说在Impeller时期,被老大驳回的,真不知道出于什么原因。其它的,真的一点技术含量都没有,所以做得一点兴趣都没有,一点成就感都没有。整来整去就是写几句SQL,调一下界面控件。 回顾完工作,再来回顾点别的。小丫头被我稀里糊涂地弄到成都去了,这让我当时很咬牙切齿了好一阵,这变态的人生,这变态的命运。然后是一年来在感情上一无所获,屡屡受挫。 总之,2007,一无所有的一年,再见了。 接着是即将来临的2008了。仍然先从工作开始说吧,其实工作上的事自己能把握的太少,只是我现在还是满怀期望地把手头那个一体化平台项目甩手后,把投入到Impeller中去,把想做的东西做一下,就是前两天说的,先把查找替换功能重构了,再把编辑器支持脚本扩展部分先自己给它做了,他们总是想着用COM来做,我并不喜欢,所以不认同,我要用SWIG的方式来做。然后是一个simulator,可能还有图形部分的内容。我现在最想弄的就是socket、图形、脚本与C/C++混合编程这几方面的东东了,呵呵,当然这全是我自己一厢情愿的美好愿景而已。 我一直很清楚,要从公司那老实安分地干下去,靠那点儿钱是没指望的,我要买车买房,讨老婆生小孩,好多事要做,好多钱要赚。所以还得想办法怎么多赚点钱,也许小思宇和孙同学说的真的很有道理,只要有钱了,愁啥。 接着就是上半年学车,考完后,靠工资和年终奖,去买个车。 最后还是一年复一年的期待,希望新的一年里,能遇到命中的那个人,嗯! 你好,2008,我来了!
真tmd的太郁闷了,平常要上班的日子,早上总是醒不来,闹钟响了之后还想继续睡,起不来。每到周末节假日可以好好休息的时候,却又睡不着了,早早就醒了,郁闷死了! 在家里写代码总是不行,是不是没有压力的缘故啊,感觉在公司里就流畅得多啊。现在在整的一个用来自动换墙纸的东东,用MFC怎么都弄不好啊,晕,连界面都费好多时候来整!
昨天晚上,跟小思宇在电话里,又跟孙同学在QQ语音上聊了很久,最后她们竟不约而同地叫我好好工作,多赚点钱,之后就好了。都说现在的人现实得很,我也没有其他办法了。 早上醒来,突然想到一个两年计划,就是之后两年里,要实现的几个大目标,当然这些要在这里实现,才更有意义。首先,过完农历年回来,开始去学车,一边学车,一边攒钱,等车学完,买个十来万的车来用用。然后,再攒钱,看在两年之期内能攒下多少钱,对于买房这个目标,能有多少完成度。两年,就到2009年12月31日为止。反正我还小,到那时也才26,接近27而已。我还有时间。
实在觉得奇怪,为什么,我到底哪里错了?很是怀疑背后有一只手在操控这一切,可是这只手在哪里,谁的手,为什么什么要这样?
我都厌倦那一直失败的感觉了,说磨难也算是经历够了吧。明天,希望一切都顺利啊!给我一个寄托,给我一个精神依靠和支撑!
今天项目组组织活动爬笔架山,然后去华强北毛家饭店吃中饭,吃完中饭就地解散,我去地铁站办了张深圳通,顺便去问了一下内存条。一问现在930可以买一根1G的原装,750就有TPOP的,立马就心动了,跑回家,背了电脑出去加了一根TPOP的。现在就有1.5G内存了,心里感觉就是爽啊,哈哈!
最近感觉是又累又困,每天早上起床都很是困难啊!今天在公司里几乎没做什么事,这几天心里焦虑感很重,唉,不知不觉的压力就这样袭上来。 好像脾气也变得比较急躁了,或者说神经也更脆弱了,很是在意别人的话,也许根本不是针对我的。 昨天弄到快凌晨2点才睡觉,asio还是有点难用,主要是参考资料太少,自带的文档看得不明不白,例子程序也是不明不白。 我有病,真的。
今天小妞把项链给了我。这是我前些天托小妞去香港的时候带的,周大福的,在我的要求下,据小妞说这链子是加长18寸的,应该能够我妈带了,呵呵。原价是一千一,可以打九折,就是九百九了。其实最开始的时候,我还以为只要三四五百就够了,后来跟小妞说的时候就随口提高了上限,说一千以下就可以了。看光泽还是不错的,嘿嘿。 小丫头给我传了些她的照片,脸好圆呀,呵呵,越看越觉得可爱。
周四的时候我开始计划张罗组织原来的3500测试组还留在深圳的人一起出来玩一下。至于我为什么要来组织,这目的我自己都觉得有点不可思议,也许说出来也没什么人会相信,但确实除了这个理由,我找不出其它的借口。仅仅是因为有一天中午睡午觉前江江随口说了一句哪天一起去爬山吧。本来说好大概有十来个人,一起去爬莲花山,放风筝打牌,晚上去泡吧。晚上的时候,宣宣发短信说可以周六去她家玩,提供晚饭和水果。 结果周五的时候,疯丫头发了个茂业打折活动的邮件,有几个人就闹着要去逛街,我再次发邮件问还有没有人活动时,就没人回了。晕倒,而江江和bobo那天刚好请假了不来,我只好遗憾地宣布活动cancel。中午吃饭时,疯丫头就在那里撒娇说要去宣宣家。我则已经兴味索然了。快睡午觉时,宣宣和疯丫头就来鼓动人一起去玩,结果还真说动了剩下的一些人。唉,美女跟男人的号召力就是不同啊,悲哀一下。 昨天早上8点便起了床,8点半出门坐车去梅林找疯丫头,果然说好是8:45的,一直等到9:20多才出来,我就有点生气,一边走一边也不说话,疯丫头说,你要是再不理我,我就回去了。我就开玩笑说,拜拜。她还真的调头就回去了,呵呵。这丫头,我只好折回去把她拉过来。跟宣宣约好要10点去买菜的,只好又打的,花了55块钱。花了点时间找到宣宣,4个人一起去买菜。买了好多东西,购菜车都装满了,我还两只手全提满了,买菜就花了250左右。 意外的是,本来说好买菜的4个人中午只是随便吃点泡面之类的东西就算了,下午1点半后去爬山。而那些家伙居然都不吃中午直接跑过来了,于是就开始做中饭。而小思宇给我打电话,说要一起爬山。时间刚好差不多,快3点的时候小思宇才跋山涉水地赶到,而那边则刚刚做完中饭开吃。吃完饭,那群人就一个两个地想罢工躲在家里,没几个人想爬山。小思宇说她是专门赶过去爬山的,于是我就义无反顾地背上包要出门。后来也不知道怎么一说,那群人最后全都出来了。一共11个人,分3辆车打到海关登山口,都是4点多了。下山后都是6点半了,天都很黑了。小思宇还想过去逛街抢购,最后看着天太黑了,放弃了。回到宣宣家,大牛又当了一回大厨,做了整整一桌的菜。比中午的在丰盛多了,两条清蒸的鱼,多合我口味的,哈哈。
今天偶然说起我大学时写的几个小程序,什么窗口类观察器,进程管理等等,然后一个同事就在那里说牛x啊什么的,说得我都不好意思了。不过说实话,我倒真的不觉得周围哪个人牛的,呵呵,当然我自以为也不牛,不是谦虚,是实话。见不到牛人,也就自己也难以提高,真是一大遗憾啊!
最多只能集中精力半个小时,就坐不住了,就觉得头昏了。 良好的可扩展性,以及交由用户放任的自由,在有些类型的软件上,是一种很有吸引力的策略。这类软件一般说来面向的是比较熟练的电脑用户,比如你怎么也不能假设隔壁的阿姨会用Total Commander来管理自己的文件。 今天突发奇想又玩了一会儿doxygen,不知道哪里出错了,我试图document我的代码,但总是不照我想要的效果出来。不过我想还是要用用,这东东特别适合给代码作文档了。
星期五晚上在网上看小说,一直看到凌晨5点多,第二天星期六是要部门活动的,于是7点多就起来了,只睡了2个小时,当时刚睡下的时候还担心会睡得太死睡过头,结果还好,手机设的闹钟还是把我叫醒了。星期六跑去东部华侨城去了,其实没什么好玩的,只不过看看自然风景,看看表演,以及一些人造景观。中饭还是在KFC里站着解决的,我一想,反正是集体的钱,就多吃点,吃了一个汉堡和一个鸡肉卷,这是比较多的了,因为一直到吃晚饭的时间都没觉得饿。晚上是开回到万科城吃湘江老厨的,13个人加2个婴儿,在包间里居然只吃了383块钱,想那次我们8个人就吃了630多,晕! 这次用T200和N73拍了300多张照片,当然两个都到没电为止。也让我知道了大概的极限,T200如果在条件允许时,不开闪光灯,应该可以拍250张没问题,如果默认的自动闪光,估计200张还是可以的,如果是全闪光的话,可能不到150张了。N73不开闪光灯大概可以拍90张,开闪光灯就不好说了。另外就是T200的效果还是不错的,只是变焦的话,都有点白茫茫雾蒙蒙的样子。N73拍近景也还可以,但稍微远点的就模糊了。 突然想试一下ACE这个东东,嗯!
被小思宇知道我借给小妞相机,却不借给她,然后就演变成“思思很生气,后果很严重”,于是我只好打电话很谄媚的样子求饶,最后就很自然地被敲诈了一顿湘江老厨,两个人吃了点了一个干锅田鸡,一个串烧虾,一个老南瓜,一份莲藕百合龙骨汤,吃撑死掉。 得知阿菲家里被盗了,连忙打电话去了解一下情况顺便安慰几句,阿菲情绪很低落的样子,那是肯定的,谁遇上这种事心里都会郁闷,而且很长一段时间内都会有严重的心理阴影,照她的话说,现在回家走楼梯里总觉得背后有双眼睛在看着她,好恐怖好吓人,跟电视上一样。 七天长假能安然度过,还有一件事情,那就是我在网上发现一个论坛,该论坛是个还在上大学的小女孩办的,里面都是些基础的算法题。虽说基础,但我能独立做出来的却没几个,真是惭愧,不过好在现在做软件开发的对算法的要求降低了,说夸张点,会四则混合运算和初中英语的人就可以写代码了。那论坛里有些题看似简单,其实会用一些很变态,或者是平常很难想得到的数据去测试,所以往往都不知道错在哪儿,这小女孩很有做一个优秀测试人员的天份啊,哈哈。不过话说回来,我对算法真的很无知啊,这是很大一个弱点,很可能会影响以后的发展。 听说重庆又发现车祸了,一辆从万盛到重庆的公车在路上爆炸了,给float打了个电话问了下,那天她差点就可能上了那辆车,真险啊! 人的生命就是这样脆弱,该享受的时候就该好好享受啊!但是还是得好好想想办法,怎么多赚点钱呢!
和上半年的五一一样,无聊地呆在屋里,就这样七天也过去了,每天睡到不想睡的时候起来,然后开电脑,上网,无所事事,可能会看点碟,到时间了就打电话叫外卖,吃外卖的时候会打开客厅里的电视机,就趁这几分钟看一会儿电视。也许还会实在不想呆在家里了,就出去逛一下街,其实我个人并不是特别喜欢逛街的类型,只是工作后,跟着她们几个逛了大半年,就渐渐有点习惯逛街这项活动。以前我最喜欢的是逛书店,可是后来我意识到我买书纯粹是一种浪费,我总是会在买到书之前觉得我会买来书以后好好读的,但总是在买到书之后就潜意识里认为我已经拥有了该书中所讲述的所有知识,所以就会一次又一次地把买来的书立马束之高阁。不过这次我还是去买了几本书,我自己后来也对自己的一时冲动感到可笑。今天又心血来潮跑到深南路上的深圳购书中心去逛了逛,这个中心规模比图书馆边上的书城好像要大点,书也要多点。看着几本有点意思的书,就用手机拍下封面来,看看网上买不买得到打折的。最后,买了个MAME 0.105的ROM全集,实在懒得自己去网上收集了,呵呵。而其实,我买这种东东回来,也是直接丢进抽屉,不知道什么时候再次心血来潮才会翻出来呢。 明天又要去上班了,说起来现在觉得公司也是个挺可怕的地方,不但可怕而且可恶啊!我一定要放松,再放松,不要给自己太大压力。慢慢来,我不要给自己压力,把所有压力都转嫁给他们吧,哼哼! 今天我在想,要是能衣食无忧,又不会太忙,这样的生活会不会很好啊,哈哈,然后被人说我好可爱的想法。试试喽,没试过咋知道!
今天,少了那些家伙,中午在食堂老地方吃饭,明显感觉人就少了很多,冷清了很多,心中很是感慨啊,比毕业离校那段时间的不舍有过之而无不及啊。 中午吃过饭,走到睡午觉的地方,人也很少很少了,江江也是一脸孤寂的样子。算算他们应该下飞机了,于是先给教授打了个电话,然后给猫猫打了个电话。猫猫说,现在知道为什么粉红色的要是限量版了,因为好看啊。让我心里不免有点得意。 下午好不容易熬过去了,晚饭在食堂真的没人了,于是打了两个玉米饼匆匆回来了。 一个室友搬走了,新的还没搬进来,另一个室友回老家了。这里好冷清。给小丫头又打了大半个小时电话,总是觉得小丫头很可爱啊! 无聊的国庆假期开始了,能干些什么呢!
日子真的过得挺快的,真的到了SDH部分搬迁成都的时候了。明天,他们就直飞成都了,就见不到那几个总是一起在食堂一楼吃饭的家伙了,竟有点不舍,也许是因为心中有更多的惆怅。一起玩得最好的,教授、悍超、猫猫、晓妮都要走了。 这周好多晚上的吃饭活动,让人感觉像是回到了大学毕业前的时光。昨天晚上,另外叫了大牛和疯丫头一起,去湘江老厨吃了一顿。我的酒量是越来越差了,可能也是跟心情有关系,记得以前在学校喝个五六瓶也大不了像现在这样。饭后,我坚持要送疯丫头回家。334颠簸得厉害,很想吐,问售票员要了两个塑料袋,难过了大半程,把坐在一旁的疯丫头吓坏了。334绕很远的路,真是难受啊,疯丫头好几次要我早点下车,她可以自己回去。入了关后,总算吐出来了,胃空了,人也舒服了。在酒精的刺激下,我的胆子也更大了。只是最后把疯丫头弄哭了,在梅林阁下了车,她朝一个方向走,我朝另一个方向走。打了个车,很郁闷,打电话给小丫头,找个人倾诉一下。一直打到家里,挂了。又打给小妞,小妞也很温柔地像安慰小孩子一下安慰了我好一阵,一直到我手机没电为止。还是觉得很不痛快,于是给教授打,打了一个小时,倾诉过后,心里就稍微好过一点了。 唉,今天还被老大训了,当然老大说的是有道理的。旁边两个同事见我郁闷,也偷偷安慰了我两句。 晚上跟小妞去吃了顿小肥羊,便宜量又足,还送可乐。吃完后,两人慢慢走到万科城,再慢慢走回百草园,到小妞屋里看照片。小妞过得很幸福啊,她说明年就要结婚了。跟小妞她们在一起,能让一个男的懂得如何变得体贴温柔。可是,光有体贴温柔,有什么用呢? 看看周围的人,有过得好的,当然也有过得郁闷的。套用某人的话,希望喜欢我的人和我喜欢的人都幸福!各位奔赴成都的同学,我们有缘再见!
又是一年中秋节。公司里的活动还是跟往年一样,两年了,发一两个月饼,然后开个茶话会,一群人聚在一起聊聊天,吃吃东西,而杀人游戏好像是在公司里的人唯一热衷而且老少咸宜的活动。这次的杀人游戏规则我不习惯,而且时间也不多,才玩了3轮。茶话会后,告诉我有两个东西要我接手,都是人家弄好了的,那同事要离职了。有点无聊的东东。 下班后,跟以前测试组的同事们跑去肥牛府吃了一顿。因为人太多了,服务员们都忙不过来,所以无论叫什么,都响应很不及时,有点气人哦!不过吃得还是挺开心的,今天教授还一反往常的矜持形态,一个一个敬过来,大概他真的有点不舍这边的这些同事吧。吃完后,只有江江一人是住百草园的,其他人都在对面的公车站坐车走。我反正已经习惯了跟小妞,小思宇她们一起吃饭后送她们回百草园的行为,于是自告奋勇地陪江江走回到她楼下。 回到家依然是懒洋洋的,给小丫头打了个电话祝福一下。小丫头说正一边洗头一边接电话呢,我说你当时就可以不接的呀。小丫头真的很温柔啊,太可爱了。 正无所事事的时候,小思宇突然打电话来,说都已经睡了,但有些问题想不通啊。然后我就只好假装很在行很专业的样子安慰她,开导她。其实我什么经验都没有,哪有资格说那样深明大义的话哦,呵呵!
不经意间来到Tencent的网站看了看,发现现在它真的是战线全面铺开了,中国互联网霸主地位非它莫属了! 即时通信工具和游戏不说。看看其它的现在中国网民最常可能用到的工具,邮件客户端、汉字输入法、下载、视频直播、桌面Widget、浏览器、IE工具栏,它全都有。 感觉它是越来越像微软了,靠其中的一两样东西发家,然后看人家做什么火,它就也跟着做什么,虽然是后发制人,但即很可能把人家拖挎。
今天下班后,坐同事的顺路车回家,结果大概是因为周末的缘故,在高速公路上就开始堵车,真是太神奇了,于是有了时间聊天和上网。在网上看到新闻,说中国目前已经有很大一批富有的阶层了,现在亿万富翁有1万多人,千万富翁有30多万人,而百万富翁则占了总人口数的1.5%。这样的数字还是很让我吃惊的,原来中国富人这么多啊,尤其是百万富翁,这么多! 8点半才到小区门口,然后我去对面一个快餐店吃饭,偶然间听到里面的服务生在谈论他们的工资,一个女孩在说她有1200一个月,每月吃什么的花100多,还要买衣服什么的大概300多,差不多每月可以存下800块。听到这些,我心里有些感触,为什么人和人的差别可以这么大。
今天先是小妞突然发邮件来问我定了几级,我说还没定呢,过了一会儿,疯丫头发邮件来问我定级了么,我说没定呢,后来是JR来问我定了什么级,然后我就火了,今天已经是3个人来问我了,到底咋了,难道我绩效差就没级了!JR说人家都定了啊,我说我绩效差啊,JR说绩效差还能进系统组啊,我说偷偷告诉你,别人我都不说的,到系统组的都是在测试组混不下去的,如果在系统组干得好的,就能转测试组。 下午5点多快6点时,领导打电话来叫我去,我预料到应该是这事儿了。跟什么年终奖沟通之类的是类似的过程,就是先说一通公司的形势政策,再说一通个人的表现好坏,然后说一下结果,最后问有没有什么意见建议或者疑问,如果没有就签个字走人。虽说钱是加了一点,但我一点高兴的劲儿都没有,就像以前一个同事跟我说过的,感觉就是应该的,而且像我这样的应该是最少的了。再说了,我都打算要走了,加不加,能加多少,似乎不是很关心了,而现在唯一关心的是,下一份工作,能给多少薪水。 沟通完后,给小妞小思宇发邮件约吃饭。去关东风吃了一顿,三个人越来越吃得少了。谈起这个事来,最后一比,我还是最少的,呵呵,真是没用啊。 一心想着一件事,很沉重。
喉咙好痛,尤其是早上刚醒来的时候,咽一下口水都痛得受不了,郁闷!~
其实是因为人太懒,要做的事情很多,我却宁可无聊地消磨时间! 明天打算去看一下相机,要是价钱合适就买个。
仍然没什么食欲,中午故意拿了一碗少点的米饭,吃是吃完了,不过真的是硬塞下去的,没啥胃口啊,倒是快下班的时候确实感觉到饿了,可是到了食堂打了一盘面后,还是不怎么想吃。 今天又解决了一些比较紧急的问题,明天下午就是1.1.0版本的发布会了,搞得还很隆重的样子呢,呵呵。这个版本里我悄悄藏入了一句话,一句我最近很想说,却又不好意思直接说出来的话。说明显也很明显的一个地方,不过大部分人应该都不会关注那里的吧,就算发现了,也应该是无意间在看其它东西时偶然发现的吧,呵呵。 项目组要组织出去游玩了,去阳朔。去年五一的时候跟小妞和小玉玉一起去过,倒也还算开心。还是那句老话,关键不是去哪里玩,而在于跟什么人一起去玩啊!
难道真的是因为工作太累了!怎么办呢,最近心情一直很压抑啊,呜呜!
前两天回到家,都不开电脑,只顾着看玄幻小说去了,还真着迷,有一天看到后半夜3点多,第二天虚了一天,直到今天还是精神萎靡。不过有比较舒服的一点是,那东东快要完了,虽然下面等着我的是似乎更让人头痛,不过一个人开始一个新的项目,还是比较感兴趣的。只是目前手头上那点任务,还是有点难过,bug太多了,真是有点于心不忍啊。 今天负责人整理了一下遗留问题和新需求,我看了一下,又加了几个新需求,真是永无止境啊!不过那些新需求不会是由我来做了,我其实还是有点兴趣的,不过还是得放手了啊!下周把手头最紧迫的问题解决掉,看看如果还有时间多,就做点新需求相关的工作吧!下周一过,就是9月了,新的挑战啊! 这周其它过得很压抑,不是因为工作上的事。突然很想找个人,然后安定下来,然后一起努力,平平稳稳地过完这一生。
今天不知道为什么,心情比较糟糕。一整天都无精打彩的,真是郁闷啊。而且好像昨天去吃火锅有点吃伤了,今天舌头有点木,吃什么都没什么味道。 然后到下午5点多的时候,实在不怎么想干活了。 看到小丫头漂流去的时候拍的一张泳装照,脸还是那么圆哦!小丫头的腿真的很漂亮啊!
真是郁闷啊,睡不好觉!早上好不容易挨到9点多,实在睡不着了。于是起来玩了一会儿电脑,然后在那里看小说,看得眼花缭乱。一直到下午,收拾了一下去华强北逛,问了一下原装的内存条1G的卖2200啊,真贵了,比起半年前要便宜一些了,但还是很贵了,只好继续忍下去了,因为收入有限啊!去石头记看了看,好多人,只好退出来了。 没逛多久xcc打电话来,叫我可以过去了。于是去找车,等了好久哦,差不多20分钟吧,还等错地方了,这地儿是不停的,晕。好不容易上了车,好多人,还是个没空调的,好热,幸亏我站到天窗对下的地方,开的时候有风灌进来。后来有位儿了,因为好像还有比较长的时间,于是打了个盹儿。到了老石火锅,doggy已经在了,xcc在门口接我。1年多没见doggy了,真是怀念啊!过了一会儿,afei也来了,终于也见到了她们家的帽子,开始看着觉得有点面熟,还以为是这长相比较大众化吧,后来xcc提起来,原来是去年去看afei唱歌时,跟她一起合唱的,怪不得眼熟哦!心里还是觉得挺开心的,不知道这样的机会还有多少! 吃完回来,随便找个了车,结果,又因为睡着而坐过了站,然后多花了19块钱打的回家,晕!
好久没去华强北啦,记得上次去,好像是那次看完《变形金刚》然后去K歌,再去吃华神,都是上个月的事了。今天下班就跟大牛高导一起跑去了,先是逛了哈街,再去吃滋味堂,好多菜都没有,难道是因为去晚了,晕! 高导明天就回北京啦,不知道什么时候还能再见哦!
几个月前1.34发布前,就已经开始说要迁移,先是把sandbox迁过去了,但主库一直还在sf.net上去。现在1.34.1发布了,终于有公告发出来说要迁到印第安那大学的OSL服务器上去。总的说来,SVN相比CVS从很多方面都有改进,虽然CVS仍是相当流行。居然老大说CVS不安全,比较无语的说。 在网上看到别人的blog,想想自己真是叶公好龙啊。现在公司里的任务老大似乎是很想玩B/S的东西,想完成目前这个项目后全都迁移到ASP.NET上去,要学C#了,我真的不是很感兴趣,昨天的考评沟通又把我小小地打击了一把,唉。想想自己也真是没用,要是有正式工作之外的比较稳定经济收入来源,怕他个鸟啊,直接fire老板。可惜啊,一直有贼心没贼胆啊。雨烟也辞职了,下一个会是谁呢?
今天跟彭彭、小思宇、小妞一起吃饭去了。我发现我现在渐渐地放不开了,不如单独跟小妞一起吃饭时那么放得开了。 一无所有的人将永远一无所有,这是我今天吃饭得到的教训。所以我不能一无所有,我要努力。
今天拿到体检报告,说我超重了,要多做锻炼,多吃蔬菜水果,少吃肉类。其实体检出来的体重数值已经比我预期的轻了,人越来越懒了是没错。人是怎样变懒的呢? 现在每天回到家,都有点感觉累,不想动,于是就这样一天一天颓废堕落了。
今天在网上闲逛看别人的blog,在csdn上看到一个blog,博主写了篇《过去这两年》的文字,博主82年人,应该是和我同届的,文中他画了张图,总结了自己的工作学习的情况。 再回头看看我的情况。我2005年7月1日直接从重庆学校飞到这边,算是7月4日入职的,到现在也十足两年了。两年中,做SDH设备的软件测试不计节假日共约21个月(2005年7月中~2007年3月底)。当时得知自己去做测试,心中也不免诸多怨忿和失望,完全全新的领域,加上并不感兴趣,而且劳动态度不端正,以及自身先天(?)的素质影响下,成绩如何可想而知。不过到后来便有点麻木了,觉得干什么都一样,而且男人选择自己感兴趣的行业作为职业似乎是种很不成熟的表现,呵呵。 两年来,几乎什么都没学到,什么荣誉都没得到,什么好处都没捞到。真是失败啊,对比那位博主,只能感叹人与人之间的差异很多时候是没法填补的。 只能说,在以后的日子里,在自己力所能及的范围内,尽量努力,不为什么,只为能赚更多的钱,这是最直接最首要的目的。
两天没写blog了,这两天主要是想加个在线造词功能进去,可是没成功,让人比较泄气。所以说,五笔加加真的是设计得很好的一款软件,各方面都比较完善,各种细节点闪现着作者的缕缕灵气。 公司里的事就太多了,这两天打过来一堆的问题,估计总共有50多个吧,解决了一些,到现在还剩下近40个,而且很多很多是暂时解决不了了,架构方面就有问题。有些则是技术方面的问题暂时得不到解决,唉! 得快点把输入法搞定,其实也就剩下两个问题了,造词和状态栏窗口刷新。之后就赶紧做辅助工具,Boost又丢下好久了,要趁写其它程序里好好跟进学习啊!
在回家的路上又被堵了很久,让我再一次觉得很气愤,深圳的开车的人是全国素质最差的,明明已经堵车了,明明走不 通了,明明再挤进去会变得更糟,可是他们还是会乱闯乱挤,除了道德上的因素,我都要怀疑他们智力上是否也有问题。 人又懒下来了,回到家,只是看了看如何加入造词功能,其实这些代码原来的人已经都写好了的,我拿到后觉得没什么用,删掉的,注释掉的,确实精简掉了很多至少我自己用不上的功能。现在只是到了放开的时候,在输入上屏后,要记录下来历史记录。以后按到快捷键,就进入半自动造词模式,就可以从历史记录中取出内容来。顺便还把添加历史记录的部分代码优化了一下,应该能增加些速度吧。 公司里还是像往常一样,搜简历,然后看代码,增加新代码,修改老代码。暂时接手维护了另外两个模块,还好功能都是基本上已经完成了,只要再加一点点就行了。突然老大说,上面的头儿说要做成C/S模式的,主要是为了信息安全,真晕!本来还暗暗高兴了一下,可以趁此机会好好学习一下网络编程了,结果他们好像决定用DCOM、WebService这样的东东来实现,唉,不感冒啊!~
把输入法改成可以支持多用户配置了,把一部分的配置信息移到配置文件中来了,但有点没弄好的是,安装的时候需要问当前默认的输入模式是拼音还是五笔,本来是写入到注册表中去的,所以比较简单,不知道写ini文件用InnoSetup是不是也支持得比较好呢! 状态栏也可以支持换肤了,呵呵,有一点不同的是,状态栏是有默认自带的皮肤的,但我自己实在做不出什么好看的来啊。 用Intel编译器编译出来的Release版本,居然超过10个字符不会崩溃,晕。总是不放心啊,感觉像是哪里我的代码是写得有问题的。
早上搜完这周的任务分配的简历,开始了无所事事的一天。其实还是有事情的,比如那个sharepoint的,但我懒得动了,反正我只是个执行者,前期的所有事务最后的敲定还是得看老大们,我不想再很认真很投入很负责地去费这个神了。他们说怎么样就怎么样吧,我无所谓了,反正就是按部就班地实现呗。 看完了《Rootkits》一书,感觉收获不大,因为没有这方面的底子,书中讲得又泛泛。想学点编译原理吧,很头痛,静不下心来啊。于是东翻翻西看看,这样昏昏沉沉过完了一天。 输入法引起屏幕闪烁的问题昨天果然改好了,只要把有些不必要的通知中的刷新界面的代码去掉就行了。目前最大的问题是,release模式下,五笔在输入分号转英文或首字母大写转英文时,如果长度达到10个字符以上时,下一次再敲任务一个键,都会引起主程序崩溃,但是debug模式下的却没有这样的问题,所以都不好调试了,郁闷!
鉴于昨天我的8310已经为国捐躯,隐隐地感到有点高兴,终于可以换新手机了,哈哈。今天跑去华强北,在乱哄哄的电子市场,随便找了一家,看着价格在我的心理底线以内,又看着这个售货员长得比较漂漂的说,后来一聊,居然也算是老乡,呼呼。买了个N73回来,然后打电话给小丫头,炫耀了一番,呵呵。
自己可以弄到试用版的C++Builder2007来,花了好多时间,重装卸载了好几次,终于还是放弃了,怎么样都不行,总是在启动的时候报个错就退出了。真是失望啊!这样一来,也促成了我不写代码的借口,呼呼。 上午去百草园的社康中心看了看,好多人在体检,看个病还得预约啊!不过,医生说我只是咽液性囊肿,不要紧,总算放心了。 又改了两个输入法的bug,现在在msn messager里也能正常显示内容了,真是奇怪,有的程序就是不发消息过来,晕!想想五笔加加真是牛啊,这么多年前的东西,做出这么稳定、兼容性这么好来,不得不佩服啊! 总是嫌钱少,可是又没什么行动。我得打三份工才行啊!
话说当时,自以为5月底能全部做完的事情,其实直到今天都没有完全完成。不过总算总的框架搭出来了,绝大部分应该有的功能也都有了,剩下的就是修修补补了。但再想想,更多的时候,是很没自信,那些功能的代码也写完了好多天了,但一直都没信心,连运行一下都不敢,生怕有什么问题。这是一种病态的心理,而且这样对于事情的发展没有丝毫的好处,显而易见的是各种坏处,躲得过初一躲不过十五,总归要做的。昨天把一个重要部分重构了,真是爽快啊,以后有些东西的修改,只要改一下外部的配置文件就行了,不用改代码重新编译了。今天确认完成了另外一个重要部分的功能,也基本能用了,易用性方面还有待改善。 再来说说这个输入法。说到那个某些程序下候选窗口出不来的问题找到原因后,异常兴奋,至少这个输入法已经从不可用,变为偶尔可用一下的地步了。到今天,又找到了另外一个严重问题的原因。有时候词库会乱,是因为词频调整部分没仔细,很容易遇到写乱的情况。另一大进步是,总算搞清楚了几种词库格式,可以写个词库维护工具了,呵呵。
下午打开了久违的BDS2006来写了几行代码,觉得非常不习惯!可能我已经更习惯于用VC了,VC加上VAX,还有VC的宏定义功能,简直是无敌的。因为不习惯了,所以没写几行,就不想继续下去了(这个借口比较好,呵呵),于是又开始无所事事。 真郁闷,我已经用不回VCL了,因为从心里开始抵触了。以后只能用用WTL(或者MFC)了,不然直接用SDK画界面实在是浪费时间,不明智之举。Delphi 2007装好后,从来没用过。现在C++ Builder2007也已经有试用版可以下载了,不过我最多是装上看看,估计不会怎么去用了吧,因为现在在我看来,无论是Framework还是IDE,亦或是Compiler,都已经比不上VC系统了。 我真没用!
不知道是不是心理作用,总觉得这几天我的霉运来了。今天早上在楼上还看是没下雨的,艳阳天来着,走到楼下突然下起雨来,我也懒得再回楼上拿伞了,就直接走了。晚上下班的时候,吃饭前还是阴沉的天,吃完饭就是倾盆大雨了,还没带伞,刚好看到jr和他lp一人一把伞在那里晃悠,就向他借了把。坐车出了公司区域,猛然发现这边地都是干的,我想把车砸了! 坐在车上,想着其他的事情,联想起小丫头的生日也快到了,然后又联想起其他的事情。回到家,翻出久久未动过的输入法,一边看一边改,想用UNICODE来编译,一直是编译后不能正常运行。但是依稀记得曾经似乎好像是正常过的呀,现在这样纠缠也没用了,仔细看看代码,很多地方确实没有处理好编码问题,都是照着多字节字符集编码方式来写的代码,要改的地方还有点多,有些地方都不知道怎么改得好。现在至少得解决以下几个问题,才能算得上一个可以拿出来用:1、五笔状态能分号转英文,首字母大写转英文;2、拼音可以连打;3、状态窗应该能稳定地显示出来;4、候选窗在FF/Opera等环境下能显示出来;5、一个直观方便的途径可以进行设置。
当年在学校看《君が望む永远》,男主角好温柔,我也被整个故事好好感动了一把,当时我还想,我也要像这个男主角一样做一个很温柔的男人。 昨天在MSN跟阿菲聊天,阿菲说我性格好好,让我的虚荣心狠狠地满足了一把。 可是,就像动画片中那样,温柔只是我一厢情愿地以为好而已,就像剧中的台词所说的,有时候太过温柔也是一种残忍啊! I put it down on my lifeThat I love you from the bottom of my heartCause you the sweetest thing ever in my lifeI cry So many timesSo many...
爬的南山,很热啊!也有点累,然后下山,吃了个湘菜馆,回到家4点了。 唉,打了两个电话,讲到后来都不爽啊,唉,我怎么这么郁闷啊!
儿童节哟,我的童心似乎还残存着一点点,因为比起很多身边的人来,我还不时地看些动画片,呵呵。早上还有同事发了个什么测试题,就是一些我们这代人小时候接触到的流行的东西,还是比较让人怀念的。 今天总算是有突破性进展啊,虽然最后还是没有完成自己给自己定下的目标,但是至少思路是有了啊,而且经过简单的测试,VSS的接口封装也是可用的,哈哈,之后的大部分是简单的代码堆砌工作了。估计下周内,绝对是可以做完了,嗯! 下午下班了才看到小妞的邮件,于是给小妞打电话,然后一起去吃饭,走到百草园门口居然遇到小思宇和另一个男同事,后来俊英也来了,五个人吃了一顿,还是那位男同事买的单。然后去小妞屋里喝咖啡,小妞有人送了她一套煮咖啡的用具,然后小妞就弄得兴高采烈,呵呵,一直坐到10点半才回来。
从电骡上拖了个VS2005Pro下来,之前装的那个Team Suit居然没有MFC和ATL,我也不记得是不是我当时自己就没装上,感觉这种可能性不大,还是弄个Pro版来用用,公司里装的也是Pro版,虽然公司里现在是用2003来工作的。我心里想着是慢慢摆脱BCB,从VCL中解脱出来,转用MFC或WTL。其实说实话,我还是多佩服VCL的易用性的,只是它跟Boost的兼容性实在不如VC啊,为了一个类库而放弃使用了5年多的东西,还是有点点犹豫的,毕竟很多时候,遇到一个问题,用VCL的话,是很快就能想到怎么做,用WTL或MFC就不行了。 现在反而开始来学10年前流行的东西,真是讽刺啊!很茫然啊,小丫头说我连自己养都不够钱花,我也很心虚啊,一个人过惯了大手大脚不计后果花钱的生活,要是突然真的两个人了,还真的很难适应呢,说不定还会引出一大堆的问题来。说到底,就是得想办法多赚钱啊。
挺无聊的,在公司里,在家里,都无聊。这些天突然觉得很迷茫了。
今天收邮件,发现有封主题是“我是Afeilink的忠实用户”的,里面提到他最近在玩1.0beta版,问我里面一首背景音乐的事。真是让我意外啊,竟然还有重邮以外的人玩这个,呵呵。想当年,一方面为了逗阿菲,另一方面为了能让自己玩过瘾连连看,才整的这个小游戏,当初整出最早的版本后,就只在学校的E383上发了一下,在BBS上稍微宣传了一下,一段时间内还把BBS上自己的昵称改为“阿菲连连看xxxx...”,真是令人怀念的时光啊!当时BBS上Software版的人开了个群,xiaotnt在《电脑迷》工作,NAOH就把这个东西传给她,她就压到某一期的光盘里去了,还说有20块钱的稿费!有那么段时间,我还多想见见xiaotnt本人的,其实也是chuanking的原因吧,可惜的是,直到我毕业离校,也没有见到xiaotnt,而曾经一起在Software灌水的人,也没剩下几个还有联系的,当然那20块钱的稿费,也被xiaotnt拿去买零食吃掉了吧,呵呵。 有的事总要过去,有的人总要忘记……
这两天在公司里,真是忙得有点昏啊,连邮件都经常是过好久才看一下回一下。其实静下来想想,也不是很忙吧,只不过是我自己偷懒闲惯了,这样有点事情做就不爽了。今天下午的时候还在想,今晚要加班了,不加班完成不了了,结果到下班时间,又决定不加了,还是回家算了。分给我的任务其实真的很少,代码量和难度都应该算是最低的。就是以前没这样被逼着干过,所以突然有点适应不了,甚至差点儿睡觉的时候都在想那里应该怎么写,真是郁闷啊,被逼到这份儿上。不过现在已经完成得差不多了,核心功能基本实现了,明天去把那些扫尾工作处理了,18号应该能顺利交付吧!完成了这个,应该就要投入到那个单板软件开发,和SharePoint架设上去了。都是没经验的,正好学一下,这两样东西也是两个截然不同的方面的东西。现在做的是Windows桌面应用开发,用MFC,说起来MFC并不是以前想像中那么不好用,呵呵,也许是因为前段时间直接用API写Demo写得快吐血了吧,又画TreeView又画分隔条,还要实现TreeView之间的拖拽,唉,当时没问清楚,做了很多无用功啊,早知道就应该把精力重点放在核心接口设计上。之后的单板软件开发让我既兴奋又紧张,这样的嵌入式软件开发参与一下,才不枉来公司一次啊!SharePoint倒不是很期待,好像目前的需求要实现的话,基本只是填几个框,鼠标点几下就好了。 今天看了别人的blog,才明白过来,不要用代码量来衡量一个人的水平。代码量过少,固然很可能实践经验不够,但当达到一定量后,之后就是瓶颈期了,很可能3w代码量经验的人,水平跟30w代码量经验的人差不多呢!代码写得精炼、优美才是作为一个编码人员应该追求的。
看到云风blog上关于C和C++的争论,有点反感。本来对云风的印象也不深,只知道当时网上有个关于游戏编程的个人主页,上面有些有趣好玩的东西,一个学生写出一个游戏开发包,也有点让人佩服的。自从他出了本书,看过那本书后,印象就不怎么好,总觉得书上全是吹嘘自夸的,没有多少实际有用的东西。现在再看这blog上的一些他的做法、观点,实在有点恶心。 他居然说用C写的模块比用C++写的好维护!真不知道怎么妄自得出这样的结论来的,难道那些研究出OO,发明改善C++的先辈们真的全是做的无用功。只是写过个游戏开发包,做过一两个网游,就敢这样大放厥词,实在让人不爽啊!而且看过他在书上列出的那点代码,也实在没什么水平可言,总让我感觉是自己不行然后去批判别个不好用。再怎么样,说说我们公司那些产品,应该也是几百万行代码规模吧,也是嵌入式,又是对性能要求比较高的场合,现在不也是用C++了么,不也是用STL了么,还是本领域内市场占有率世界第二呢!有点想骂人,唉……
下班回家坐328,结果渐渐闻到一股什么东西烧焦的味道,结果车停下来了,坐后排的人往后面看了看,还说这车子烧着了,突然一车的人都开始往外跑,几个女的还被弄倒在地,还有丢掉鞋子的,呼呼。
正式版就要发布啦! 好困好累哦!都不想动了!开心就好!
雨绵绵,let's move! 在网上找到一个叫Firebug的Firefox扩展,Mozilla的插件扩展机制也真tmd牛x啊!
七天长假哦,哈哈,不过也没怎么觉得兴奋,只是想着可以懒洋洋发躺在床上发呆了就感觉安逸。再想想还有一天一千的两天旅行,呵呵,对我来说很奢侈啊! 最近写blog的频率似乎降下来了,因为回到家都不怎么想动了,就看几集动画片,被小丫头知道后还要被嘲笑就这么点追求。工作忙也可以算是这么一个借口啊,怪不得我发邮件问一个人为什么不继续更新他的blog时,他会说最近很忙这样的理由出来啊。现在自己也算是稍微体会了一把。 好穷啊好穷啊好穷啊,只能怪自己太颓废堕落了,呜呜。
鄢哥这是第三次来我们公司培训了,每年一次啊!记得上次是差不多一年前来的吧,那时候小思宇刚刚搬出去了,鄢哥过来了,公鸡也跟着过来耍一下,我当时还有点懒得走,结果被小妞小玉玉鄙视了。于是约好在万科城的肥牛府吃一顿,一张长条桌,三男三女坐在那里。今年就只有鄢哥一个人了,小思宇她们也都各自有着各自的事情。真是去年今日此门中,人面桃花相映红啊! 鄢哥其实来了已经一星期了,我早就通知了阿菲,喊她抽空出来吃饭。昨天早上照例8点半醒来,给阿菲发了个短信,这短信还被她后来抱怨了一通,说我太早了。约好傍晚五点半去华强北茂业见面,然后吃饭。我早已睡不下去了,就起来玩电脑,但又没什么特别的兴致。打开Foxmail,翻看起以前从学校BBS上收下来的邮件,里面记录了我在大学四年里的BBS经历。真是令人怀念啊,想当年也算是小有名气的吧。想想当时在学校,是多么的呼风唤雨、叱咤风云啊,看着别人都是菜鸟,可是从学校出来两年,自己成为菜鸟,白白浪费了两年时间不说,之后的路怎么走,可谓是越来越迷茫了!邮件中还保存了很大一部分的聊天记录,依稀可以看到我的感情经历,从afei到ilikeyou,再到最后的lookfor,前两次的小心翼翼,胆怯不前到最后一次的无赖泼皮,死缠烂打。现在看来,我都隐约觉得奇怪我当时居然能说出这么肉麻的话来。也算是我的青春无悔的见证了,哈哈。对于那个家伙,或许我的内心深处真的是怀有感激之情吧,因为她,才使得我后来变得不像以前那样自卑,所以后来虽然几次三番觉得很受伤,但我还是愿意真心诚意地好好待她,而无论结果如何。如果我不说,或许她是永远都不会明白为什么了! 看邮件看得百感交集,下午看到男妹妹在QQ上,于是顺便叫了一下她。虽然大家都在深圳两年了,但居然从毕业后都一直没见过她人!几个人从不同的起点,到相同的目的地,果然五点半的时候,找到了阿菲和鄢哥,看样子男妹妹得过一会才能到了,就下去麦当劳一人点了杯喝的聊天。一直等到男妹妹过来,居然华强北的路都认不到,呼呼。四个人去吃了顿民间瓦罐煨汤,然后送男妹妹上车。鄢哥跑来我屋里睡,跟同住的同学一起聊天到快3点。睡觉,一直到12点,出去吃了顿中饭,鄢哥就回旅馆去了。
呆在家里实在有点不甘心,总是想出去,不留在屋里就好。于是跑到华强北去买衣服,夏天快来了,需要准备一下了,从上衣到裤子,还了鞋子,都要买。2点到的华强北,因为没吃早饭和中饭,所以就先去麦当劳吃了4个鸡翅和1包薯条,喝了杯可乐。然后逛到茂业,运动品牌的T恤实在是贵啊,只好去买JSW的,51块钱还能买2件。再去买鞋子,Puma有几个款式的我倒是喜欢,但没有大码的,没办法,最后只好去买了双Nike的比较休闲的。 买鞋子的时候,xcc和他女朋友也来了,买完鞋子就三个人一起去电脑市场。又去买硬盘了,呵呵,比阿菲买的时候又便宜了一些。然后又去买U盘,一直逛到5点多。我和xcc去梅林吃饭,他女朋友则回去了。说起来,从我生日过后,都没跟xcc一起吃饭了。吃完后,又去他家里坐了一会儿。
用missdeer.blogspot.com这个域名访问不了这里好多天了,然后改成用pkblogs.com,这样坚持了一段时间,终于也不行了,换用inblogs.net,最后也不行了。呵呵,算了,反正本来就没什么人看,就当是写日记的地方好了,自己写了自己看,呵呵。 小妞要在Excel里计算一个东西,我不知道有没有方便的方法,反正用VBA写个宏是可以的,不过还是花了我一点时间。 唉,不能太堕落啊。
转了项目部,还以为今天要去爬梧桐山的,结果提前决定不去了,因为觉得天气不好,所以很快就决定去参加原来的测试组活动。活动内容还是很简单,就是吃饭和K歌。这次活动的地点在南山,中午吃了顿海鲜,下午去海上明珠K歌,这是第二次去那里,第一次是前年十一的时候,跟她们三个,还有另外三个男的,其中一个现在成了小妞的男朋友了。回想当时还真是幼稚,甚至想以后再也不跟她们一起玩了,呵呵。这次从1点半一直K到5点半,乱吼了一气。疯丫头没来,这个家伙不知道昨晚去哪里鬼混了,居然到今天下午1点半的时候还在睡。 唉,也许以后就不会这样跟他们这样出来活动了吧,最多可能私下里还会跟其中几个人一起玩一下。
大吃两顿。本来是只想吃一顿就够了的,结果中午吃完是2点半了,我跟雨烟去修手机,一直弄到快5点,打电话问他们在干吗,说是在KBox里,还大概有1个小时,于是就过去了,后来又加了一个小时。出来就已经是7点了,8个人磨叽了一阵,最后我和雨烟、疯丫头、教授一起去吃了顿肠粉和粥,味道还真不错,价格也不是很贵,4个人才吃了50块钱。出来后,走到石头记,刚好雨烟说要买银针,就进去看了。疯丫头看到一块绿色的石头很喜欢的样子,可惜她这个家伙没钱了(居然穷到这份上,也不容易啊),就狠不下心来买,我就随口说说买了买了,结果营业员当真了,晕,于是就假戏真作了,疯丫头和雨烟当然不肯让我买单。后来雨烟硬是塞给我200块钱。呼呼! 下周就我生日啦!我来请了。 疯丫头说她要下下周请大家,说是生日,其实是加上她转到其它组去的告别会吧,呵呵。
xcc叫我一起去吃饭,下了班就过去梅林,说去吃豆豆鸡煲吧。那里的生意还真的旺的,很多人,差点要等一会儿才有座儿的。三个人点了个鸡煲,10+2串羊肉串,12+1个生蠔,4瓶啤酒,还是多开心的。突然觉得要是能一直这样生活下去也挺不错的,赚点钱然后自己花。可是爸妈终归是要老的,人终归是要结婚的。说起来,我们原来那个老大,跟一个才认识18个月的女孩结婚了,动作真是快呀,不过他也是快30的人了,是差不多时候了,而那女的,跟我差不多大。现在总是认为谈恋爱不能谈太久,太久了就很可能结不成婚了,像他们这种才是最稳当的做法,认识了,然后谈一小阵子,然后结婚。不过像他们这样的,生活基本上也就是固定下来了,不出什么大的意外的话,大概一辈子都像现在这个样子了。而我的漂泊感还是很重,归宿感还没有找到。爱情这种东西,也许是只有在年轻的时候体会一下就够了,以后的,照中国人的常规做法是,在责任心的基础上,建立起也许在欧美人看来质量并不高的婚姻。爱情不能当饭吃,以后是为了生活,而不是像电视上那样死去活来,普通人是经不起那样的折腾的。
这几天真的堕落了。一直没有动手,就在看漫画,消磨时间,浪费青春啊!
唉,突然想起一些很无聊很无趣的事,却为这样的事情烦恼啊!怎么会这样失败呢! 昨天是元宵节,去雨烟家吃饭了,还有教授和猫猫,上午就去了,11点开始出去买菜,一直到下午2点才买回来,呵呵。下午打了一会儿牌,5点的时候雨烟开始弄,我只是帮忙把虾皮剥掉,其它的什么都没做。因为比较困。五个人吃了很多,吃撑死了。说起来略微有点伤感,都说以后可能很少有这样的机会了,因为各个都嚷嚷着要跳槽,雨烟也说了很久了,我也酝酿了很久了,只是一直没做好准备工作。连猫猫都说要走,这个倒是有点没想到,不过她也可能只是凑热闹吵吵的吧。 烦啊!这样的日子什么时候才是个尽头啊! 我真的是个很小心眼的人啊!
一下就跟人叉起来了。可能也是因为最近心情糟糕的缘故吧,反正就是很不爽。再后来想想,其实也不是什么大不了的事,他爱怎么就怎么着呗,跟我又真没什么实质上的利益冲突。 想想以前的事,我确实是个自私而无趣的人。希望以后能有些许改善吧。
这个春节不快乐!愧对列祖列宗啊!今天去参加了一个初中的同学会,班上60来个人,到了20来个,男生们个个意气风发,女生们婀娜多姿!这样的形容词真贴切。再一次认识到自己有车的重要性了。 唉,郁闷,老天啊,什么时候让我摆脱这个郁闷的境地呢!
今年过年回家,受一大刺激,有车真方便啊。先进一点的亲戚都陆续买了车了,现在发现车的好处真是多啊,活动范围和活动时间都大大地扩展啊!应该努力啊,想办法怎么能多赚点钱啊!
表哥过年把女朋友带到老家来了,我倒是去年国庆去贵阳时就已经见过啦,呵呵。他女朋友家里应该算是有钱有势的那种吧,呵呵。仔细思量一下自己,如果我遇到了这样的情况,我会不会妥协呢,嘿嘿。虽然现在心里还是想着要自己好好干,努力赚钱讨个老婆做家庭主妇,或者让她出去找个轻松的工作也得。但是如果真的遇到了这种情况呢?估计照我现在的挑剔程度,还是不会要长成那样的女孩子吧,嘻嘻。
神啊,请赐我一个温柔似水的圆脸mm吧!Thank you!祝所有我认识的,认识我的,我不认识的,不认识我的人2007年情人节快乐!愿天下光棍早日找到另一半,呼呼~~~
翻起blog,点开那些链接,想起以前在一起的人,现在呢,在那样的日子里,水一样摇摆的日子里,现在呢,人一个一个从我身边走过,什么都没有留下。
真不知道,QQ这么个小破聊天软件,为什么能做得这么大,80多MB的东西可不是随便能写出来的,实在是佩服啊,也看不出它都实现了哪些炫目的特色功能,除了聊天还能干吗。 今天下午睡了午觉起来,头竟然是昏的,眩晕!TSE坐在我旁边跟我说话,我强打着精神,努力不让自己说错话或者漏过他说的话,吃力啊!不知道是怎么了,晕了好久,去喝水,冷水冲脸,都没好转。后来时间慢慢过去了,稍微好一点了,但还是不正常,就是晕!从来没有过这样的情形啊!
今年的测试部聚餐改到了南山的毛家饭店。说实话,除了那盘虾,其它的菜我觉得做得实在不行。而且最为让人奇怪的是,为什么不同的人,运气好坏的差别就会那么大呢。对于抽奖这种全凭运气的好事,从来都轮不上我,倒是一些倒霉事情也许可能偏偏会找到我头上来。虽然,《火影忍者》里的阿凯说,运气也是实力的一部分。但这样抽奖的事,实在是跟自己一点点都打不到边的,划拳打牌什么的也许还可以算是自己有一部分人为因素,比如临场反应力,观察力等等,唉! 只休息一天,有点不爽。明天去买机票吧,然后是请假,早点回去。
沉重地叹息,孤独地忧伤,无奈地哀愁,心慌意乱地继续找寻……
2007年到喽,第一天,发短信问候祝福,爸爸妈妈应该都早就睡了吧,同事朋友们该干啥干啥呢,大家新年快乐呀!。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。餮饕餮饕。。。。。。。。。。餮饕餮。。。。。。。。饕餮饕。。餮饕餮饕。。餮饕餮饕餮。。。。。。。。。餮饕。饕餮饕餮饕餮饕餮饕。。餮饕。。餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮。。。。。。。。。。。餮饕餮。。饕餮饕餮。餮饕餮。。。。。。。。。。。。饕餮饕。饕餮饕。。餮饕餮。。。。。。。。。。。。饕餮饕。饕餮。。。餮饕餮。。。。。。。。。。。。。餮饕餮饕餮。餮饕餮饕餮。。。。饕餮饕。。餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮。。。。。。饕餮饕。。。。餮饕餮。。饕餮。。。。。。。。。。饕餮饕。。。。餮饕餮。。饕餮。。。。。。。。。。饕餮饕。饕餮饕餮饕餮。。饕餮。。。。。餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮。。饕餮。。。。。。。。饕餮饕餮饕。。。。餮饕餮。。饕餮。。。。。。。餮饕餮饕餮饕餮饕餮。餮饕餮。。饕餮。。。。。。。餮饕餮饕餮饕餮饕餮饕餮饕。。。饕餮。。。。。。饕餮饕。饕餮饕。饕餮饕餮饕。。。饕餮。。。。。。饕餮。。饕餮饕。。。饕餮饕。。。饕餮。。。。。餮饕。。。饕餮饕。。餮饕餮。。。。饕餮。。。。。餮饕餮饕餮饕餮饕。饕餮饕。。。。。饕餮。。。。。。。。。。饕餮。餮饕餮。。。。。。饕餮。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。饕餮。。。。。。。。。。。。。。。。。。。。。。饕餮饕。。。。。。。。。。。。。。。。。。。。餮饕餮饕。。。。。。。。。。。。。。。。。。。。餮饕餮。。。。。。。。。。。餮饕餮。。。。。。饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕。。。。。饕餮。。。。。餮饕餮。。。。。。。。。。。。。餮饕餮。。。。。餮饕餮。。。。。。。。。。。。饕餮饕。。。。。。餮饕餮。。。。。。。。。。。餮饕餮。。。。。。。餮饕餮。。。。饕餮。。。。饕餮饕。饕餮饕。。。。餮饕餮。。。餮饕餮饕。。。。。。。饕餮饕餮饕餮饕餮饕餮饕餮饕餮。餮饕。。。。。。。饕餮饕。。。。餮饕餮。。。。。。。。。。。。。。饕餮饕。。。。餮饕餮。。。。。。。。。。。。。。饕餮饕。。。。餮饕餮。。。。。。。。。。。。。。饕餮饕。。。。餮饕餮。。。。。餮饕餮饕。饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮。。。。。。。。。。。餮饕餮。。。。。。。。。。。。。。。。。。。。。餮饕餮。。。。。。。。。。。。。。。。。。。。。餮饕餮。。。。。。。。。。。。。。。。。。。。。餮饕餮。。。。。。。。。。。。。。。。。。。。。餮饕餮。。。。。。。。。。。。。。。。。。。。。餮饕餮。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。饕。。。。。。。。。。。。。。。。。。。。。。。饕餮饕。。。。。饕餮饕餮。。。。。。。。。。。。饕餮饕。。。。。饕餮饕。。。。。。。。。。。。。饕餮饕。。。。。饕餮饕。。。。。。。。。。。。。饕餮饕。。。。。饕餮饕。。。饕餮。。。。。。。。饕餮饕。饕餮饕餮饕餮饕餮饕餮饕餮饕。。。。。。。饕餮饕餮。。。。饕餮饕。。。饕餮。。。。。。饕餮饕餮饕餮饕餮。。饕餮饕。。。饕餮。。。。。。饕餮饕餮饕餮饕餮。。饕餮饕。。。饕餮。。。。。餮饕餮饕餮饕餮饕。。。饕餮饕。。。饕餮。。。。。餮饕餮饕餮饕。。。。。饕餮饕。。。饕餮。。。。。餮饕。饕餮饕。。。。。饕餮饕。。。饕餮饕餮饕。。。。。饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕。。。。。饕餮饕。。。。。饕餮饕餮。。。。。。。。。。。。饕餮饕。。。。餮饕餮饕餮。。。。。。。。。。。。饕餮饕。。。。餮饕餮。餮饕。。。。。。。。。。。饕餮饕。。。。餮饕。。餮饕餮。。。。。。。。。。饕餮饕。。。饕餮饕。。餮饕餮。。。。。。。。。。饕餮饕。。餮饕餮。。。。饕餮饕。。。。。。。。。饕餮饕。。餮饕。。。。。。餮饕餮饕。。。。。。。饕餮饕。饕餮。。。。。。。。饕餮饕餮饕。。。。。饕餮饕餮饕。。。。。。。。。。餮饕餮饕。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。饕餮饕。。。。。。。。。。餮饕。。。。。饕餮饕餮饕餮饕餮。。。。。。。。饕餮饕餮饕餮饕餮饕餮。。。。。。。。。。。。。。饕餮饕。。。。。。。。。。。。。。。。。。。。。饕餮饕。。。。餮饕餮饕。。。。。。。。。。。。。饕餮饕。。。。。饕餮。。。。。。。。。。。。。。饕餮饕。。。。。饕餮。。。。。。。。。。。。。。饕餮饕。。。。。饕餮。。。。。。。。。。。。。。饕餮饕。。。。。饕餮。。。。。餮饕餮。。。。。餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕。。。。。饕餮。。。。。。饕餮。。。。。。。。。。。。。。。。。。。。。。饕餮。。。。。。。。。。。。。。。。。餮饕餮。。饕餮。餮饕餮。。。。。。。。。。。。饕餮饕餮。。饕餮。。饕餮饕。。。。。。。。。。餮饕餮。。。。饕餮。。。餮饕餮。。。。。。。。饕餮饕。。。。。饕餮。。。。饕餮饕。。。。。。餮饕餮。。。。。。饕餮。。。。饕餮饕餮。。。。饕餮饕。。。。。。。饕餮。。。。。餮饕餮。。。餮饕餮。。。。。。。餮饕餮。。。。。餮饕。。。。餮饕。。。。。饕餮饕餮饕餮。。。。。。。。。。。。。。。。。。。。。餮饕餮。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。餮饕餮饕。。。。。。。。。。。。。。。。。。。。餮饕餮饕。。。。。。。。。。。。。。。。。。。。餮饕餮饕。。。。。。。。。。。。。。。。。。。。。饕餮饕。。。。。。。。。。。。。。。。。。。。。饕餮。。。。。。。。。。。。。。。。。。。。饕餮饕。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。餮饕。。。。。。。。餮饕餮。。。。。。。。。。。。饕餮饕。。。。。。。饕餮饕。。。。。。。。。。。饕餮饕。。。。。。。饕餮饕。。。饕餮。。。。。。。餮饕。。。。。。。。。。。。餮饕餮饕。。。。。。。。。饕餮饕餮饕餮饕餮饕餮饕餮饕。饕。。。。。。。。。。。。。饕餮饕餮。。。。。。。。。。。。。。。。。。。。饕餮饕。。餮饕餮。。。。。。。。饕餮饕。。。。餮饕餮。。。餮饕餮饕。。。。餮饕餮饕餮饕餮。。饕餮饕。。。饕餮饕餮。。。。。。。。饕餮饕。。餮饕餮饕餮饕餮饕餮饕。。。。。。。。。饕餮饕。。。饕餮。。。餮饕餮。。饕。。。。。。。饕餮饕。。。。。。。饕餮饕。。餮饕餮饕。。。。。饕餮饕。。。。。。。饕餮。。饕餮饕餮饕。。。。。饕餮饕。。。。。。餮饕。。。饕餮饕。。。。。。。饕餮饕。饕餮。餮饕餮。。。餮饕餮。。。。。。。。饕餮饕餮饕餮饕餮饕。。。饕餮饕。。。。。。。。。饕餮饕餮饕餮饕。。。。餮饕餮饕餮。。。。。。。。饕餮饕餮。。。。。。饕餮饕。。餮饕餮。。。。。。饕餮饕。。。。。饕餮饕。。。。餮饕餮饕。。。。。。餮饕。。。饕餮饕餮。。。。。。饕餮饕。。。。。。。。。饕餮饕餮。。。。。。。。。餮饕。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。餮饕。。。。。。。。。。。。。。。。。。餮饕餮饕餮饕。。。。。。。。。。。饕餮饕餮饕餮饕餮饕餮饕。饕餮。。。。。餮饕餮饕餮饕。饕餮。。。。。餮饕餮。。。。。。。。。。饕餮。。。餮饕餮。。饕餮饕餮。。。。。。。。。。饕餮饕。。餮饕餮。。饕餮。。。。。。。。。。。。。餮饕。。。饕餮。餮饕。。。。。。。。。。餮饕。。。。。。。。。。餮饕。。餮饕餮。。。。饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕。。。饕餮饕。。。。餮饕餮。。。。。。。餮饕。。。。餮饕餮。。。。。餮饕餮。。。。。。饕餮。。。。。。。。。。。。。餮饕。。。。。。餮饕餮饕。。。。。。餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮。餮饕。。。。。。。。。。。饕餮饕。。。。。。餮饕。。。。。。。。。。。。。饕餮饕餮饕餮饕餮饕餮饕餮。。。。。。。。。。。餮饕餮饕餮。。。餮饕餮饕。。。。。。。。。。。。餮饕。饕餮。。饕餮饕餮。。。。。。。。。。。。饕餮饕。。餮饕餮饕餮饕。。。。。。。。。。。。餮饕餮。。。。饕餮饕餮。。。。。。。。。。。。饕餮饕。。。。餮饕餮饕餮饕。。。。。。。。。。餮饕。。。。餮饕餮饕。。餮饕餮饕餮饕餮饕餮。餮饕餮饕餮饕餮饕餮。。。。。。。。饕餮饕餮。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。餮饕餮饕。。。。。饕餮饕。。。。。。。。。。。。餮饕餮。。。。。。饕餮饕餮。。。。。。。。。。。餮饕餮。。。。。餮饕餮。。。。。。。。。。。。。餮饕。。。。。。餮饕餮。。。。。。。。。。饕餮饕餮饕餮饕餮饕餮。餮饕。。。。餮饕餮。。。。饕餮饕。。。饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕。。。饕餮饕。。。饕餮饕。饕餮。。。。。餮饕餮。。。。饕餮饕。。。饕餮饕餮饕餮。。。。。餮饕餮。。。。饕餮饕。。。饕餮饕餮饕。。。。。。餮饕餮。。。。饕餮饕。。。饕餮饕餮饕餮饕。。。。餮饕餮。。。。饕餮饕。。。饕餮饕。。餮饕餮。。。餮饕餮。。。。饕餮饕餮饕餮饕餮饕。。。饕餮饕。。餮饕餮。。。。饕餮饕。。。饕餮饕。。。饕餮饕。。餮饕餮。。。。饕餮饕。。。饕餮饕。。。饕餮饕。。餮饕餮。。。。饕餮饕。。。饕餮饕。。。。。。。。餮饕餮。。。。饕餮饕。。。饕餮饕。。。。。。。。餮饕餮。。。。饕餮饕。。。饕餮饕。。。。。。。。餮饕餮。。。。饕餮饕。。。饕餮饕。。。。。。。。餮饕餮。。。。饕餮饕餮饕餮饕餮饕。。。饕餮。。饕餮饕。。。。。饕餮饕。。。饕餮饕。。。饕餮饕餮饕餮饕。。。。。饕餮。。。。饕餮。。。。。。。餮饕餮。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。饕餮。。。。。。。。。。。。。。。。。。。。。。饕餮饕餮。。饕餮饕。。。。。。。。。。。。。。。饕餮饕餮。餮饕餮饕。。。。。。。。。。。。。。餮饕餮。。。餮饕餮。。。。。。。。。。。。。。。餮饕餮。。。餮饕餮。。。。。。。。。。。。。。饕餮饕。。。饕餮饕。。。。。。餮饕餮饕。。。。。饕餮饕。。。饕餮饕餮饕餮饕餮饕餮饕餮饕。。。。餮饕餮饕餮。餮饕餮。。饕餮。。。餮饕。。。。。。餮饕餮饕餮。餮饕。。。饕餮饕。饕餮。。。。。。饕餮饕餮饕。饕餮。。。。饕餮饕。饕餮。。。。。。饕餮饕餮饕餮饕餮饕餮。。饕餮饕。。。。。。。。餮饕。饕餮饕。。。饕餮饕餮饕餮饕餮饕。。。。。饕餮饕。饕餮饕。。。饕餮饕。饕餮饕。饕餮。。。。。。。。饕餮饕。。。饕餮饕。饕餮饕。饕餮饕。。。。。。。饕餮饕。。餮饕餮。。饕餮饕。。餮饕餮。。。。。。饕餮饕。。餮饕。。。饕餮饕。。餮饕餮饕。。。。。饕餮饕。饕餮饕。。。饕餮饕。。。饕餮饕。。。。。饕餮饕。饕餮。。。。饕餮饕。。。饕餮饕。。。。。饕餮饕餮饕。。。。。饕餮饕。。。。餮饕。。。。。饕餮饕餮饕。。。。。饕餮饕。。。。。。。。。。。饕餮饕。。。。餮饕餮饕餮饕。。。。。。。。。。。饕餮饕。。。。。。餮饕餮。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。餮饕。饕餮饕。。。。。。。。。。。。。。。。餮饕餮饕餮饕餮饕餮饕餮。。。。。。。。。。饕餮饕餮饕。。餮饕餮饕。。餮饕餮。。。。。。饕餮饕。饕餮饕。。。饕餮饕。。餮饕餮饕。。。。。。。。。饕餮饕。。。饕餮饕。。。饕餮饕。。。。。。。。。饕餮饕。。。饕餮饕。。。。。。。。。。。。。。。饕餮饕。。。饕餮饕。。。。餮饕餮。。。餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮。餮饕。。。。。。。饕餮饕。。。饕餮饕。。。饕。。。。。。。。。。。饕餮饕。。。饕餮饕。。餮饕餮饕。。。。。。。。。饕餮饕。。。。餮饕。。餮饕餮饕。。。。。。。。。饕餮饕餮饕餮饕餮饕餮饕餮饕餮。。。。。。。。。餮饕餮饕餮。。。餮饕餮饕餮饕。。。。。。餮饕餮饕餮饕餮饕。。。。餮饕餮饕餮。。。。。。。餮饕餮饕。饕餮饕。。。。餮饕餮饕。。。。。。。。。。。。。饕餮饕。。。。餮饕餮饕。。。。餮饕。。。。。。。饕餮饕。。。饕餮饕餮饕餮。。。餮饕。。。。。。。饕餮饕。。餮饕餮。餮饕餮饕。。餮饕。。。。。。。饕餮饕餮饕餮。。。。饕餮饕餮。餮饕。。。。餮饕餮饕餮饕餮。。。。。。。餮饕餮饕餮饕。。。。。。餮饕餮。。。。。。。。。。。餮饕餮饕餮。。。。。。。。。。。。。。。。。。。。。。饕餮。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。饕餮饕。。。。。。。。。。。。。。。。。。。。餮饕餮饕。。。。。。。。。饕餮。。。。。。。。。餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕。。。。。。。。餮饕。。。。餮饕餮。。。餮饕餮。。。。。。。。饕餮饕。。。。餮饕餮。。。餮饕餮。。。。。。。。饕餮。。。。。餮饕餮。。。餮饕餮。。。。。。。餮饕餮饕餮。。。餮饕餮。。。餮饕。。。。。。。。餮饕餮饕。。。。餮饕餮。。饕餮饕。。。。。。。饕餮饕餮饕。。。。餮饕餮。。饕餮饕。饕餮饕。。。饕餮饕餮饕。。。。餮饕餮。。饕餮饕餮饕餮饕餮。餮饕。饕餮饕。。。。餮饕餮。。。。。。饕餮饕。饕餮饕。饕餮饕。。。。餮饕餮。。。。。。饕餮饕。。。。。饕餮饕。。。。餮饕。。。。。。。饕餮。。。。。。饕餮饕。。。饕餮饕。。。。。。。饕餮。。。。。。饕餮饕。。。饕餮饕。。。。。。餮饕餮。。。。。。饕餮饕。。。饕餮饕。。。。。。餮饕餮。。。。。。饕餮饕。。餮饕餮。。。。。。。餮饕餮。。。。。。饕餮饕。。餮饕餮。。。。。。。餮饕餮。。。。。。饕餮饕。饕餮饕。。。。餮饕。饕餮饕餮。。。。。。饕餮饕。饕餮。。。。。餮饕餮饕餮饕。。。。。。。饕餮饕餮饕。。。。。。。。餮饕餮。。。。。。。。。。饕餮。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。餮饕餮。。。。。餮饕餮。。。。。。。。。。。。。餮饕餮饕。。。。餮饕餮饕餮饕。。。。。。。。。。餮饕餮。。。。。餮饕餮。餮饕餮。。。。。。。。饕餮饕。。餮饕餮。餮饕餮。。饕餮饕。。。。。。。饕餮饕餮饕餮饕餮饕餮饕餮。。饕餮饕。。。。。。餮饕餮。。。餮饕餮。餮饕餮。。。。饕餮。。。。。餮饕餮饕餮。餮饕餮饕餮饕餮饕餮饕餮饕餮饕。。。饕餮饕。饕餮饕餮饕。。餮饕餮饕。。。。餮饕。。。饕餮饕餮饕餮饕餮饕。。餮饕餮饕餮。。。。。。。餮饕。饕餮饕。饕餮。。。餮饕。饕餮。。。。。。饕餮。。。餮饕餮饕餮。。饕餮饕。饕餮饕。。。。。。。。。。餮饕餮饕。。。饕餮饕。饕餮饕。。。。。。。。。。。饕餮饕。。餮饕餮。。。餮饕餮。。。。。。。。。餮饕餮。。饕餮饕。。。。餮饕餮饕。。。。。。。饕餮饕。。餮饕餮。。。。。。饕餮饕餮饕。。。饕餮饕。。餮饕餮。。。。。。。。。。。。。。。餮饕餮饕餮。餮饕。。。。餮。。。餮饕餮。。。。。。。。饕餮。餮饕餮。。。餮饕餮。。饕餮饕。。。。。。餮饕餮。。饕餮饕。。。饕餮饕。。餮饕餮。。。。饕餮饕餮。。饕餮饕。。。饕餮饕。。餮饕餮饕。。餮饕餮饕。。。。餮饕。。。饕餮饕。。。饕餮。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。餮饕。。。。。。。。。。。。。。。。。。餮饕餮饕餮饕。。。。。。。。。。。饕餮饕餮饕餮饕餮饕餮饕。饕餮。。。。。餮饕餮饕餮饕。饕餮。。。。。餮饕餮。。。。。。。。。。饕餮。。。餮饕餮。。饕餮饕餮。。。。。。。。。。饕餮饕。。餮饕餮。。饕餮。。。。。。。。。。。。。餮饕。。。饕餮。餮饕。。。。。。。。。。餮饕。。。。。。。。。。餮饕。。餮饕餮。。。。饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕。。。饕餮饕。。。。餮饕餮。。。。。。。餮饕。。。。餮饕餮。。。。。餮饕餮。。。。。。饕餮。。。。。。。。。。。。。餮饕。。。。。。餮饕餮饕。。。。。。餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮。餮饕。。。。。。。。。。。饕餮饕。。。。。。餮饕。。。。。。。。。。。。。饕餮饕餮饕餮饕餮饕餮饕餮。。。。。。。。。。。餮饕餮饕餮。。。餮饕餮饕。。。。。。。。。。。。餮饕。饕餮。。饕餮饕餮。。。。。。。。。。。。饕餮饕。。餮饕餮饕餮饕。。。。。。。。。。。。餮饕餮。。。。饕餮饕餮。。。。。。。。。。。。饕餮饕。。。。餮饕餮饕餮饕。。。。。。。。。。餮饕。。。。餮饕餮饕。。餮饕餮饕餮饕餮饕餮。餮饕餮饕餮饕餮饕餮。。。。。。。。饕餮饕餮。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。餮饕餮饕。。。。。。。。。。。。。。。。。。。。餮饕餮饕。。。。。。。。。。。。。。。。。。。。餮饕餮饕。。。。。。。。。。。。。。。。。。。。。饕餮饕。。。。。。。。。。。。。。。。。。。。。饕餮。。。。。。。。。。。。。。。。。。。。饕餮饕。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。餮饕。。。。。。。。餮饕餮。。。。。。。。。。。。饕餮饕。。。。。。。饕餮饕。。。。。。。。。。。饕餮饕。。。。。。。饕餮饕。。。饕餮。。。。。。。餮饕。。。。。。。。。。。。餮饕餮饕。。。。。。。。。饕餮饕餮饕餮饕餮饕餮饕餮饕。饕。。。。。。。。。。。。。饕餮饕餮。。。。。。。。。。。。。。。。。。。。饕餮饕。。餮饕餮。。。。。。。。饕餮饕。。。。餮饕餮。。。餮饕餮饕。。。。餮饕餮饕餮饕餮。。饕餮饕。。。饕餮饕餮。。。。。。。。饕餮饕。。餮饕餮饕餮饕餮饕餮饕。。。。。。。。。饕餮饕。。。饕餮。。。餮饕餮。。饕。。。。。。。饕餮饕。。。。。。。饕餮饕。。餮饕餮饕。。。。。饕餮饕。。。。。。。饕餮。。饕餮饕餮饕。。。。。饕餮饕。。。。。。餮饕。。。饕餮饕。。。。。。。饕餮饕。饕餮。餮饕餮。。。餮饕餮。。。。。。。。饕餮饕餮饕餮饕餮饕。。。饕餮饕。。。。。。。。。饕餮饕餮饕餮饕。。。。餮饕餮饕餮。。。。。。。。饕餮饕餮。。。。。。饕餮饕。。餮饕餮。。。。。。饕餮饕。。。。。饕餮饕。。。。餮饕餮饕。。。。。。餮饕。。。饕餮饕餮。。。。。。饕餮饕。。。。。。。。。饕餮饕餮。。。。。。。。。餮饕。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。餮饕餮。。。。。。。。。。。。。。。。。。。。。。饕餮饕。。。。。。。。。。。。。。餮饕。。。。。饕餮饕。。。。。饕餮饕。。。。。。餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮。餮饕餮。餮饕餮。。。餮饕餮饕。。。。。。。。。。。饕餮饕餮饕餮。。饕餮饕餮。。。。。。。。。。。。饕餮饕餮饕餮。。饕餮饕餮饕餮饕餮饕餮。。。。。。饕餮。餮饕餮。餮饕餮饕。。。饕餮饕餮。。。。。。。。。餮饕餮。餮饕餮饕餮。餮饕餮。。。。。。。。。。。餮饕餮饕餮。。饕餮饕餮饕。。。。。。。。。。餮饕餮饕餮饕。。。。餮饕餮。。。。。。。。。餮饕餮饕餮饕餮。。。。饕餮饕餮饕。。。。。。。。餮饕餮。餮饕。。。饕餮饕。。餮饕餮饕餮。。。。。。。。饕餮饕。饕餮饕餮。。。。。餮饕餮饕餮饕餮。。。。饕餮饕餮饕餮。。饕餮饕餮。。。。。。。。。。。。饕餮饕。。。。。。。饕餮饕。。。。。。。。。。。饕餮。。。。。。。。。餮饕。。。。。。。。。。餮饕餮。。。餮饕餮饕。。。。。。。。。。。。。饕餮饕。。。。。。。饕餮饕餮饕。。。。。。。。。饕餮。。。。。。。。。。。餮饕餮饕。。。。。。餮饕。。。。。。。。。。。。。饕餮饕。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。餮饕餮饕。。。。。饕餮饕。。。。。。。。。。。。餮饕餮。。。。。。饕餮饕餮。。。。。。。。。。。餮饕餮。。。。。餮饕餮。。。。。。。。。。。。。餮饕。。。。。。餮饕餮。。。。。。。。。。饕餮饕餮饕餮饕餮饕餮。餮饕。。。。餮饕餮。。。。饕餮饕。。。饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕。。。饕餮饕。。。饕餮饕。饕餮。。。。。餮饕餮。。。。饕餮饕。。。饕餮饕餮饕餮。。。。。餮饕餮。。。。饕餮饕。。。饕餮饕餮饕。。。。。。餮饕餮。。。。饕餮饕。。。饕餮饕餮饕餮饕。。。。餮饕餮。。。。饕餮饕。。。饕餮饕。。餮饕餮。。。餮饕餮。。。。饕餮饕餮饕餮饕餮饕。。。饕餮饕。。餮饕餮。。。。饕餮饕。。。饕餮饕。。。饕餮饕。。餮饕餮。。。。饕餮饕。。。饕餮饕。。。饕餮饕。。餮饕餮。。。。饕餮饕。。。饕餮饕。。。。。。。。餮饕餮。。。。饕餮饕。。。饕餮饕。。。。。。。。餮饕餮。。。。饕餮饕。。。饕餮饕。。。。。。。。餮饕餮。。。。饕餮饕。。。饕餮饕。。。。。。。。餮饕餮。。。。饕餮饕餮饕餮饕餮饕。。。饕餮。。饕餮饕。。。。。饕餮饕。。。饕餮饕。。。饕餮饕餮饕餮饕。。。。。饕餮。。。。饕餮。。。。。。。餮饕餮。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。饕餮。。。。。。。。。。。。。。。。。。。。。。饕餮饕餮。。饕餮饕。。。。。。。。。。。。。。。饕餮饕餮。餮饕餮饕。。。。。。。。。。。。。。餮饕餮。。。餮饕餮。。。。。。。。。。。。。。。餮饕餮。。。餮饕餮。。。。。。。。。。。。。。饕餮饕。。。饕餮饕。。。。。。餮饕餮饕。。。。。饕餮饕。。。饕餮饕餮饕餮饕餮饕餮饕餮饕。。。。餮饕餮饕餮。餮饕餮。。饕餮。。。餮饕。。。。。。餮饕餮饕餮。餮饕。。。饕餮饕。饕餮。。。。。。饕餮饕餮饕。饕餮。。。。饕餮饕。饕餮。。。。。。饕餮饕餮饕餮饕餮饕餮。。饕餮饕。。。。。。。。餮饕。饕餮饕。。。饕餮饕餮饕餮饕餮饕。。。。。饕餮饕。饕餮饕。。。饕餮饕。饕餮饕。饕餮。。。。。。。。饕餮饕。。。饕餮饕。饕餮饕。饕餮饕。。。。。。。饕餮饕。。餮饕餮。。饕餮饕。。餮饕餮。。。。。。饕餮饕。。餮饕。。。饕餮饕。。餮饕餮饕。。。。。饕餮饕。饕餮饕。。。饕餮饕。。。饕餮饕。。。。。饕餮饕。饕餮。。。。饕餮饕。。。饕餮饕。。。。。饕餮饕餮饕。。。。。饕餮饕。。。。餮饕。。。。。饕餮饕餮饕。。。。。饕餮饕。。。。。。。。。。。饕餮饕。。。。餮饕餮饕餮饕。。。。。。。。。。。饕餮饕。。。。。。餮饕餮。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。餮饕。饕餮饕。。。。。。。。。。。。。。。。餮饕餮饕餮饕餮饕餮饕餮。。。。。。。。。。饕餮饕餮饕。。餮饕餮饕。。餮饕餮。。。。。。饕餮饕。饕餮饕。。。饕餮饕。。餮饕餮饕。。。。。。。。。饕餮饕。。。饕餮饕。。。饕餮饕。。。。。。。。。饕餮饕。。。饕餮饕。。。。。。。。。。。。。。。饕餮饕。。。饕餮饕。。。。餮饕餮。。。餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮。餮饕。。。。。。。饕餮饕。。。饕餮饕。。。饕。。。。。。。。。。。饕餮饕。。。饕餮饕。。餮饕餮饕。。。。。。。。。饕餮饕。。。。餮饕。。餮饕餮饕。。。。。。。。。饕餮饕餮饕餮饕餮饕餮饕餮饕餮。。。。。。。。。餮饕餮饕餮。。。餮饕餮饕餮饕。。。。。。餮饕餮饕餮饕餮饕。。。。餮饕餮饕餮。。。。。。。餮饕餮饕。饕餮饕。。。。餮饕餮饕。。。。。。。。。。。。。饕餮饕。。。。餮饕餮饕。。。。餮饕。。。。。。。饕餮饕。。。饕餮饕餮饕餮。。。餮饕。。。。。。。饕餮饕。。餮饕餮。餮饕餮饕。。餮饕。。。。。。。饕餮饕餮饕餮。。。。饕餮饕餮。餮饕。。。。餮饕餮饕餮饕餮。。。。。。。餮饕餮饕餮饕。。。。。。餮饕餮。。。。。。。。。。。餮饕餮饕餮。。。。。。。。。。。。。。。。。。。。。。饕餮。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。餮饕餮。。。。饕餮饕。。。。。。。。。。。。。。餮饕餮饕。。。。餮饕餮。。。。。。。。。。。。。餮饕餮。。。。。餮饕餮。。。。饕。。。。。。。饕餮饕。。。。。。餮饕餮。。。餮饕餮。。。。。。饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮。餮饕。。。。。饕餮饕。。。。。饕餮饕。。。。。。。。。。。。餮饕餮饕。。。。。饕餮饕餮。。。。。。。。。。。餮饕餮饕。。。。餮饕餮饕餮。。。。。。。。。。饕餮饕餮饕。。。。餮饕。饕餮。。饕餮饕。。。。。饕餮饕餮饕。。。饕餮饕。饕餮。餮饕餮饕餮。。。餮饕。饕餮饕。。餮饕餮饕。饕餮。餮饕。。。。。。餮饕。饕餮饕。饕餮饕餮饕。饕餮饕餮。。。。。。。。。。饕餮饕餮饕餮饕餮饕。。餮饕。。。。。。。。。。。饕餮饕餮饕。饕餮饕。。餮饕餮。。。。。。。。。。饕餮饕餮。。饕餮饕。。餮饕餮。。。。。。。。。。饕餮饕。。。饕餮饕。。。饕餮饕。。。。。。。。。饕餮饕。。。饕餮饕。饕餮饕餮饕。。。。。。。。。饕餮饕。。。饕餮饕餮饕餮。餮饕餮饕。。。。。。。饕餮饕。。。饕餮饕餮。。。。饕餮饕餮。。。。。。饕餮饕。。餮饕餮饕。。。。。。餮饕餮饕。。。。。饕餮饕。。。饕餮。。。。。。。。。。。。。。。。饕餮。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。餮饕餮。。。。。餮饕餮。。。。。。。。。。。。。餮饕餮饕。。。。餮饕餮饕餮饕。。。。。。。。。。餮饕餮。。。。。餮饕餮。餮饕餮。。。。。。。。饕餮饕。。餮饕餮。餮饕餮。。饕餮饕。。。。。。。饕餮饕餮饕餮饕餮饕餮饕餮。。饕餮饕。。。。。。餮饕餮。。。餮饕餮。餮饕餮。。。。饕餮。。。。。餮饕餮饕餮。餮饕餮饕餮饕餮饕餮饕餮饕餮饕。。。饕餮饕。饕餮饕餮饕。。餮饕餮饕。。。。餮饕。。。饕餮饕餮饕餮饕餮饕。。餮饕餮饕餮。。。。。。。餮饕。饕餮饕。饕餮。。。餮饕。饕餮。。。。。。饕餮。。。餮饕餮饕餮。。饕餮饕。饕餮饕。。。。。。。。。。餮饕餮饕。。。饕餮饕。饕餮饕。。。。。。。。。。。饕餮饕。。餮饕餮。。。餮饕餮。。。。。。。。。餮饕餮。。饕餮饕。。。。餮饕餮饕。。。。。。。饕餮饕。。餮饕餮。。。。。。饕餮饕餮饕。。。饕餮饕。。餮饕餮。。。。。。。。。。。。。。。餮饕餮饕餮。餮饕。。。。餮。。。餮饕餮。。。。。。。。饕餮。餮饕餮。。。餮饕餮。。饕餮饕。。。。。。餮饕餮。。饕餮饕。。。饕餮饕。。餮饕餮。。。。饕餮饕餮。。饕餮饕。。。饕餮饕。。餮饕餮饕。。餮饕餮饕。。。。餮饕。。。饕餮饕。。。饕餮。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。餮饕餮。。。。。。。。。。。。。。。。。。。。。。饕餮饕。。。。。。。。。。。。。。餮饕。。。。。饕餮饕。。。。。饕餮饕。。。。。。餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮。餮饕餮。餮饕餮。。。餮饕餮饕。。。。。。。。。。。饕餮饕餮饕餮。。饕餮饕餮。。。。。。。。。。。。饕餮饕餮饕餮。。饕餮饕餮饕餮饕餮饕餮。。。。。。饕餮。餮饕餮。餮饕餮饕。。。饕餮饕餮。。。。。。。。。餮饕餮。餮饕餮饕餮。餮饕餮。。。。。。。。。。。餮饕餮饕餮。。饕餮饕餮饕。。。。。。。。。。餮饕餮饕餮饕。。。。餮饕餮。。。。。。。。。餮饕餮饕餮饕餮。。。。饕餮饕餮饕。。。。。。。。餮饕餮。餮饕。。。饕餮饕。。餮饕餮饕餮。。。。。。。。饕餮饕。饕餮饕餮。。。。。餮饕餮饕餮饕餮。。。。饕餮饕餮饕餮。。饕餮饕餮。。。。。。。。。。。。饕餮饕。。。。。。。饕餮饕。。。。。。。。。。。饕餮。。。。。。。。。餮饕。。。。。。。。。。餮饕餮。。。餮饕餮饕。。。。。。。。。。。。。饕餮饕。。。。。。。饕餮饕餮饕。。。。。。。。。饕餮。。。。。。。。。。。餮饕餮饕。。。。。。餮饕。。。。。。。。。。。。。饕餮饕。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。餮饕餮饕。。。。。。。。。。。。。。。。。。。。餮饕餮饕。。。。。。。。。。。。。。。。。。。。餮饕餮饕。。。。。。。。。。。。。。。。。。。。。饕餮饕。。。。。。。。。。。。。。。。。。。。。饕餮。。。。。。。。。。。。。。。。。。。。饕餮饕。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。餮饕。。。。。。。。餮饕餮。。。。。。。。。。。。饕餮饕。。。。。。。饕餮饕。。。。。。。。。。。饕餮饕。。。。。。。饕餮饕。。。饕餮。。。。。。。餮饕。。。。。。。。。。。。餮饕餮饕。。。。。。。。。饕餮饕餮饕餮饕餮饕餮饕餮饕。饕。。。。。。。。。。。。。饕餮饕餮。。。。。。。。。。。。。。。。。。。。饕餮饕。。餮饕餮。。。。。。。。饕餮饕。。。。餮饕餮。。。餮饕餮饕。。。。餮饕餮饕餮饕餮。。饕餮饕。。。饕餮饕餮。。。。。。。。饕餮饕。。餮饕餮饕餮饕餮饕餮饕。。。。。。。。。饕餮饕。。。饕餮。。。餮饕餮。。饕。。。。。。。饕餮饕。。。。。。。饕餮饕。。餮饕餮饕。。。。。饕餮饕。。。。。。。饕餮。。饕餮饕餮饕。。。。。饕餮饕。。。。。。餮饕。。。饕餮饕。。。。。。。饕餮饕。饕餮。餮饕餮。。。餮饕餮。。。。。。。。饕餮饕餮饕餮饕餮饕。。。饕餮饕。。。。。。。。。饕餮饕餮饕餮饕。。。。餮饕餮饕餮。。。。。。。。饕餮饕餮。。。。。。饕餮饕。。餮饕餮。。。。。。饕餮饕。。。。。饕餮饕。。。。餮饕餮饕。。。。。。餮饕。。。饕餮饕餮。。。。。。饕餮饕。。。。。。。。。饕餮饕餮。。。。。。。。。餮饕。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。饕餮饕。。餮饕餮。。饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕。饕餮。餮饕餮饕餮饕餮饕。。。。。。。。。饕餮饕。。。。餮饕餮。。饕餮。。。。。。。。。。饕餮饕。。。。餮饕餮。。饕餮。。。。。。。餮。。饕餮饕。。。。餮饕餮。。饕餮。餮饕餮饕餮饕餮饕。饕餮饕。。。。餮饕餮。。饕餮。餮饕餮。。饕餮饕。饕餮饕。。。。餮饕餮。。饕餮。餮饕餮。。饕餮饕。饕餮饕。。。。餮饕餮。。饕餮。餮饕餮。。饕餮饕。饕餮饕。。。。餮饕餮。。饕餮。餮饕餮。。饕餮饕。饕餮饕。。。。餮饕餮。。饕餮。餮饕餮。。饕餮饕。饕餮饕。。。。餮饕餮。。饕餮。餮饕餮。。饕餮饕。饕餮饕。。。。餮饕餮饕餮饕餮。餮饕餮饕餮饕餮饕。饕餮饕。。。。餮饕餮。。饕餮饕餮饕餮。。饕餮饕。饕餮饕。。。。餮饕餮。。饕。。餮饕。。。。。。。饕餮饕。。。。餮饕。。。。。。。。。。。。。。。饕餮饕。。。。。。。。。。。。。。。。。。。。。饕餮饕。。。。。。。。。。。。。。。。。。。。。饕餮饕。。。。。。。。。。。。。。。。。饕餮饕餮饕餮饕。。。。。。。。。。。。。。。。。。。。餮饕餮。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。餮饕餮。。。。。餮饕餮。。。。。。。。。。。。。餮饕。。。。。。。饕餮饕。。。。。。。。。。。。餮饕。。。。。。。饕餮饕餮。。。。。。。。。。。餮饕。。。饕餮。。。餮饕。。。饕餮。。。。。。。餮饕。饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕。。餮饕餮饕餮饕餮饕餮饕餮饕。。。。。。餮饕餮。。。。。。。餮饕。。。饕餮饕。。。。。。餮饕餮。。。。。。。餮饕。。。饕餮饕。。。。。。餮饕餮。。。。。。。餮饕。。。饕餮饕。。。。。。餮饕餮。。。。。。。餮饕餮饕餮饕餮饕。。。。。。餮饕餮。。。。。。饕餮饕餮饕。饕餮饕餮饕餮饕餮饕餮饕餮。。。餮饕餮饕餮饕。。。饕餮饕。。。。。。餮饕餮。。饕餮饕餮。餮饕。。。饕餮饕。。。。。。。。。。。。。。。。餮饕。。。饕餮饕。。。。。。。。。。。。。。。。餮饕。。。饕餮饕。。。。。。。。。。。。。。。。餮饕。。餮饕餮。。。。。。。。。。。。。。。。。餮饕。。餮饕餮。。。。。。。。。。。。。。。。。餮饕。。餮饕。。。。。。。。。。。。。。。。。。餮饕。饕餮饕。。。。。。。。。。。。。。餮饕餮饕餮饕餮饕餮。。。。。。。。。。。。。。。。。餮饕餮饕餮饕。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。餮饕餮饕。。。。。饕餮饕。。。。。。。。。。。。餮饕餮。。。。。。饕餮饕餮。。。。。。。。。。。餮饕餮。。。。。餮饕餮。。。。。。。。。。。。。餮饕。。。。。。餮饕餮。。。。。。。。。。饕餮饕餮饕餮饕餮饕餮。餮饕。。。。餮饕餮。。。。饕餮饕。。。饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕。。。饕餮饕。。。饕餮饕。饕餮。。。。。餮饕餮。。。。饕餮饕。。。饕餮饕餮饕餮。。。。。餮饕餮。。。。饕餮饕。。。饕餮饕餮饕。。。。。。餮饕餮。。。。饕餮饕。。。饕餮饕餮饕餮饕。。。。餮饕餮。。。。饕餮饕。。。饕餮饕。。餮饕餮。。。餮饕餮。。。。饕餮饕餮饕餮饕餮饕。。。饕餮饕。。餮饕餮。。。。饕餮饕。。。饕餮饕。。。饕餮饕。。餮饕餮。。。。饕餮饕。。。饕餮饕。。。饕餮饕。。餮饕餮。。。。饕餮饕。。。饕餮饕。。。。。。。。餮饕餮。。。。饕餮饕。。。饕餮饕。。。。。。。。餮饕餮。。。。饕餮饕。。。饕餮饕。。。。。。。。餮饕餮。。。。饕餮饕。。。饕餮饕。。。。。。。。餮饕餮。。。。饕餮饕餮饕餮饕餮饕。。。饕餮。。饕餮饕。。。。。饕餮饕。。。饕餮饕。。。饕餮饕餮饕餮饕。。。。。饕餮。。。。饕餮。。。。。。。餮饕餮。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。饕餮。。。。。。。。。。。。。。。。。。。。。。饕餮饕餮。。饕餮饕。。。。。。。。。。。。。。。饕餮饕餮。餮饕餮饕。。。。。。。。。。。。。。餮饕餮。。。餮饕餮。。。。。。。。。。。。。。。餮饕餮。。。餮饕餮。。。。。。。。。。。。。。饕餮饕。。。饕餮饕。。。。。。餮饕餮饕。。。。。饕餮饕。。。饕餮饕餮饕餮饕餮饕餮饕餮饕。。。。餮饕餮饕餮。餮饕餮。。饕餮。。。餮饕。。。。。。餮饕餮饕餮。餮饕。。。饕餮饕。饕餮。。。。。。饕餮饕餮饕。饕餮。。。。饕餮饕。饕餮。。。。。。饕餮饕餮饕餮饕餮饕餮。。饕餮饕。。。。。。。。餮饕。饕餮饕。。。饕餮饕餮饕餮饕餮饕。。。。。饕餮饕。饕餮饕。。。饕餮饕。饕餮饕。饕餮。。。。。。。。饕餮饕。。。饕餮饕。饕餮饕。饕餮饕。。。。。。。饕餮饕。。餮饕餮。。饕餮饕。。餮饕餮。。。。。。饕餮饕。。餮饕。。。饕餮饕。。餮饕餮饕。。。。。饕餮饕。饕餮饕。。。饕餮饕。。。饕餮饕。。。。。饕餮饕。饕餮。。。。饕餮饕。。。饕餮饕。。。。。饕餮饕餮饕。。。。。饕餮饕。。。。餮饕。。。。。饕餮饕餮饕。。。。。饕餮饕。。。。。。。。。。。饕餮饕。。。。餮饕餮饕餮饕。。。。。。。。。。。饕餮饕。。。。。。餮饕餮。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。餮饕。饕餮饕。。。。。。。。。。。。。。。。餮饕餮饕餮饕餮饕餮饕餮。。。。。。。。。。饕餮饕餮饕。。餮饕餮饕。。餮饕餮。。。。。。饕餮饕。饕餮饕。。。饕餮饕。。餮饕餮饕。。。。。。。。。饕餮饕。。。饕餮饕。。。饕餮饕。。。。。。。。。饕餮饕。。。饕餮饕。。。。。。。。。。。。。。。饕餮饕。。。饕餮饕。。。。餮饕餮。。。餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮。餮饕。。。。。。。饕餮饕。。。饕餮饕。。。饕。。。。。。。。。。。饕餮饕。。。饕餮饕。。餮饕餮饕。。。。。。。。。饕餮饕。。。。餮饕。。餮饕餮饕。。。。。。。。。饕餮饕餮饕餮饕餮饕餮饕餮饕餮。。。。。。。。。餮饕餮饕餮。。。餮饕餮饕餮饕。。。。。。餮饕餮饕餮饕餮饕。。。。餮饕餮饕餮。。。。。。。餮饕餮饕。饕餮饕。。。。餮饕餮饕。。。。。。。。。。。。。饕餮饕。。。。餮饕餮饕。。。。餮饕。。。。。。。饕餮饕。。。饕餮饕餮饕餮。。。餮饕。。。。。。。饕餮饕。。餮饕餮。餮饕餮饕。。餮饕。。。。。。。饕餮饕餮饕餮。。。。饕餮饕餮。餮饕。。。。餮饕餮饕餮饕餮。。。。。。。餮饕餮饕餮饕。。。。。。餮饕餮。。。。。。。。。。。餮饕餮饕餮。。。。。。。。。。。。。。。。。。。。。。饕餮。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。餮饕。。。。。。。。。。。。。。。。。。。。。。餮饕餮饕。。。。。。。。。。。。。。。。。。。。。。餮饕餮。。。。。。。。。。。。。。。。。。。。。餮饕餮。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。餮饕餮。。。。。。。。。。。。。。。餮饕餮饕餮饕餮饕餮。。。。饕餮。。。。。。。。。。。。。。。餮饕餮。。。餮饕餮饕。。。。。。。。。。。。。。餮饕餮。。饕餮饕。。。。。。。。。。。。餮饕餮。餮饕餮饕。饕餮。。。。。。。餮饕餮饕餮饕餮饕餮。餮饕餮饕餮饕。。。。。。。。。。。。。饕餮饕。。餮饕餮饕餮。。。。。。。。。。。。。。饕餮饕。。餮饕。饕餮。。。。。。。。。。。。。。饕餮饕。。餮饕。饕餮饕。。。。。。。。。。。。餮饕餮。。。餮饕。。餮饕餮。。。。。。。。。。。餮饕餮。。。餮饕。。餮饕餮。。。。。。。。。。饕餮饕。。。。餮饕。。。饕餮饕餮。。。。。。。餮饕餮。。。。。餮饕。。。。餮饕餮饕。。。。。。餮饕。。。。。。餮饕。。。。。饕餮饕餮饕。。。饕餮。。。。。。。餮饕。。。。。。餮饕餮饕餮。餮饕。。。。餮饕餮饕餮饕。。。。。。。。。。。饕餮。。。。。。。餮饕餮饕。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。餮饕。。。。。。。饕餮饕餮。。。。。。。。。。。餮饕餮。。。。。。。。饕餮饕。饕餮饕餮饕餮饕餮饕餮。餮饕。。。。。。。饕餮饕。。。。。。。。。。。。。。。。。。。。。饕餮饕。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。餮饕。。。。。。。。。。。。。。。。。。。。。饕餮饕餮。。。。。。。餮饕餮饕餮饕餮饕餮饕餮饕餮饕餮。餮饕。。。。。饕餮饕。。。。餮饕。。餮饕。。。。。。。饕餮饕餮饕餮饕餮。。饕餮饕。。餮饕。。。。。。。。。。。饕餮饕。。。饕餮饕。。餮饕。。。。。。。。。。。饕餮饕。。。饕餮饕。。餮饕。。。。。。。。。。。饕餮饕。。。饕餮。。。餮饕。。。饕。。。。。。。饕餮饕。。餮饕餮。。。餮饕。。餮饕餮。。。。。。饕餮饕。。餮饕。。。。餮饕。。餮饕餮。。。。。。饕餮饕。饕餮。。。。。餮饕餮。餮饕餮饕。。。。餮饕餮饕餮饕。。。。。。。饕餮饕餮饕。。。。餮饕餮饕。饕餮饕。。。。。。。。。。。。。。。饕餮饕餮。。。餮饕餮饕。。。。。。。。。。。饕餮。。。。。。。。。餮饕餮饕餮饕餮饕餮饕餮饕餮饕。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。饕餮饕。。餮饕餮。。饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕。饕餮。餮饕餮饕餮饕餮饕。。。。。。。。。饕餮饕。。。。餮饕餮。。饕餮。。。。。。。。。。饕餮饕。。。。餮饕餮。。饕餮。。。。。。。餮。。饕餮饕。。。。餮饕餮。。饕餮。餮饕餮饕餮饕餮饕。饕餮饕。。。。餮饕餮。。饕餮。餮饕餮。。饕餮饕。饕餮饕。。。。餮饕餮。。饕餮。餮饕餮。。饕餮饕。饕餮饕。。。。餮饕餮。。饕餮。餮饕餮。。饕餮饕。饕餮饕。。。。餮饕餮。。饕餮。餮饕餮。。饕餮饕。饕餮饕。。。。餮饕餮。。饕餮。餮饕餮。。饕餮饕。饕餮饕。。。。餮饕餮。。饕餮。餮饕餮。。饕餮饕。饕餮饕。。。。餮饕餮饕餮饕餮。餮饕餮饕餮饕餮饕。饕餮饕。。。。餮饕餮。。饕餮饕餮饕餮。。饕餮饕。饕餮饕。。。。餮饕餮。。饕。。餮饕。。。。。。。饕餮饕。。。。餮饕。。。。。。。。。。。。。。。饕餮饕。。。。。。。。。。。。。。。。。。。。。饕餮饕。。。。。。。。。。。。。。。。。。。。。饕餮饕。。。。。。。。。。。。。。。。。饕餮饕餮饕餮饕。。。。。。。。。。。。。。。。。。。。餮饕餮。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。餮饕餮。。。。。餮饕餮。。。。。。。。。。。。。餮饕。。。。。。。饕餮饕。。。。。。。。。。。。餮饕。。。。。。。饕餮饕餮。。。。。。。。。。。餮饕。。。饕餮。。。餮饕。。。饕餮。。。。。。。餮饕。饕餮饕餮饕餮饕餮饕餮饕餮饕餮饕。。餮饕餮饕餮饕餮饕餮饕餮饕。。。。。。餮饕餮。。。。。。。餮饕。。。饕餮饕。。。。。。餮饕餮。。。。。。。餮饕。。。饕餮饕。。。。。。餮饕餮。。。。。。。餮饕。。。饕餮饕。。。。。。餮饕餮。。。。。。。餮饕餮饕餮饕餮饕。。。。。。餮饕餮。。。。。。饕餮饕餮饕。饕餮饕餮饕餮饕餮饕餮饕餮。。。餮饕餮饕餮饕。。。饕餮饕。。。。。。餮饕餮。。饕餮饕餮。餮饕。。。饕餮饕。。。。。。。。。。。。。。。。餮饕。。。饕餮饕。。。。。。。。。。。。。。。。餮饕。。。饕餮饕。。。。。。。。。。。。。。。。餮饕。。餮饕餮。。。。。。。。。。。。。。。。。餮饕。。餮饕餮。。。。。。。。。。。。。。。。。餮饕。。餮饕。。。。。。。。。。。。。。。。。。餮饕。饕餮饕。。。。。。。。。。。。。。餮饕餮饕餮饕餮饕餮。。。。。。。。。。。。。。。。。餮饕餮饕餮饕。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。饕餮饕。。。。。。。。。。。。。。。。。。。。餮饕餮饕。。。。。。。。。。。。。。。。。。。。餮饕餮饕。。。。。。。。。。。。。。。。。。。。餮饕餮饕。。。。。。。。。。。。。。。。。。。。。饕餮饕。。。。。。。。。。。。。。。。。。。。。饕餮饕。。。。。。。。。。。。。。。。。。。。。饕餮饕。。。。。。。。。。。。。。。。。。。。。饕餮饕。。。。。。。。。。。。。。。。。。。。。饕餮饕。。。。。。。。。。。。。。。。。。。。。饕餮饕。。。。。。。。。。。。。。。。。。。。。饕餮。。。。。。。。。。。。。。。。。。。。。。。餮。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。餮饕餮饕。。。。。。。。。。。。。。。。。。。。餮饕餮饕餮。。。。。。。。。。。。。。。。。。。餮饕餮饕。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
是和同事们一起吃的。去年呢,忘了,应该是和她们一起吃的吧。 以前小思宇说,我们刚从学校出来,还跟学生差不多,所以可以像学校宿舍那样,后来慢慢地,每个人都有各自的交际圈,慢慢地对自己独立的空间的需求也越来越大了。也许是对的吧,可能放在这里说不是很切题。我只不过是有点恋旧,有点怀念以前的时光,虽然有时候也会不爽,但绝大多数时间是很开心的,三个很会闹的可爱的家伙。可是那样的时光一去不复返啦,大概有些事情就是命中注定的吧。虽然我的内心深处对于反抗命运的斗争本能还是依稀存在的,但是尘世间的灯红酒绿的诱惑对我来说,也几乎是致命地具有吸引力,唉! 这一年,回头看看,虽然生活得还算惬意,尽管中间有那么一段重大的打击,说实话应该是我给人的打击更大,但是我挺过来了,我换了另外一种方式生活。我自以为那是我有生以来最大的挫折,连续一星期,实在觉得笑是一种很奢侈很费体力的动作。不过我这样过来了,以后还怕什么呢!哈哈,祝小思宇、小玉玉和小妞幸福。祝所有在我周围的关心我的人幸福!2006年幸福,2006年以后更幸福!
当时正在公司的会议室里讨论问题,发现地在摇晃,同事们还开玩笑说,地震啦。当时还以为是开过什么大货车之类的,后来讨论结束后才知道是真的地震了 。看到网上的新闻,原来是台湾岛以南发生7.2级地震,影响到这里了,强!好像当年唐山大地震也就是7.3级。 这个笨猫猫,给我的账号是错的,怪不得转账n次都不成功,费了好多电话费,网上也转不了,还以为是软件系统哪里出问题了,气死! 每天要回来这么晚,实在懒得动脑筋了,郁闷!不知道是不是因为吃了火锅的缘故,肚子痛了一天。
88折也是折扣呀,比送券划算呀,送券就会鼓励消费,打折才实惠,也省了54块钱呢!! 花了一天多的时间把22集的《越狱》第一季给看完啦,看到15集我就开始不耐烦了,觉得他们是在拖延情节了,开始一边玩方块一边看片了,hoho~~~ eMule拖了个做电子贺卡的东东下来,唉,艺术细胞全部死完的下场就是这么惨,呜呜~~~
晚上睡少了,结果白天感到特别累,倒不是很困,晕! 看到一篇blog,比较不同的程序语言的,有点搞笑,倒不是像在bbs上的那种月经贴吵着不可开交的那种,是用女人来形容各种编程语言,回复也挺有趣的!
芳林来zte培训10天,我们几个在这儿的同学就打算一起见个面。周五下班,坐上391直奔华强北,xcc出差南京去了,就剩下afei了。然后三个人在漓江又一轩吃了一顿。芳林这猪,变这么肥,从肚子到脸,全都变胖好多,想当时在学校,多瘦小一个人呀!由于是晚上时间,也不是很想再去哪里玩,吃过饭,就随afei把芳林送上zte学院的车。然后我再把afei送到她回家的公交车上,我才自己去坐车回来。我觉得我很喜欢这种感觉,偶尔有同学过来,然后可以聚一下,了解一下别人的生活学习工作状况,不同于我们几个在这儿的人的状况。 回到家后看小说看到3点多,然后上床睡觉,结果第二天早上9点多就睡不着了,起床上网,无聊。洗了个澡,等到12点半过,去坐车,项目组活动,去梅林K歌。到那里已经是1点了,结果2个包间里只有3个人,晕,我还想我已经迟到1个小时了呢。起床开始一起没吃多少东西,看到有吃的,就把那些零食都消灭了。人陆续多起来了。因为用力在那里吼,哑了。大部分流行过的老歌都还是能唱的,至少高潮部分是会唱的,只是嗓音不好啊!尤其是女歌手的歌,唱不上去,晕!还逗了一下教授和疯丫头一会儿,哈哈,篡改歌词还挺好玩的,以前上中学的时候经常这样玩儿,大学里就很少了,因为大学里都只是安静地在电脑上听歌。 一直k到6点,然后老大说,一起去吃饭,果然,还是有点在预料之中的,在疯丫头的建议下,去吃韩国烧烤了。这边这桌的人个个是大食量的,上了就要抢,昏,呵呵!
所谓人不要脸,天下无敌,我为什么不让自己无敌呢? 白天和xcc还有他gf去爬小梧桐山了,像平常上班时候一样起了床,匆匆收拾了一下便出门,辗转到了莲塘,然后等了一会儿,等他们两个来了,一起走到小梧桐山,开始爬,人还真多。真是上山容易下山难,下山道开始一截好窄好陡,只敢扶着扶拦慢慢往下走。中午饭本来打算和阿菲一起吃的,结果她干其它事情去了,于是三个人就随便在路边找了个小馆子吃了一顿。然后去阿菲屋里,她回来了,四个人就在那里吃桔子、栗子,吹牛摆阵,一下午就这样过去了。阿菲原先打算去她舅舅家的,后来不知怎的,我说晚上去吧,晚饭和我们一起吃,居然答应了。四个人奔赴华强北民间瓦缸煨汤,大吃一顿,撑死了。 想想,我还真bt,自己不想要的却又想锁着人家。 得到当前所有榜单的源代码了,之前还想他是怎么调试的,原来留了这么一手的。
同事们都这么说,只不过才给了个B,加了2分。看评语是还不错的,还特地给我发了个cpptcl 1.1.2,呵呵,他不知道我早就研究过了。 顶级域名下来了,可以用http://www.llyfsoft.com/bbs/来直接访问三千无聊了。
终于决定在商务互联买个空间来整,把PHPWind挂上去。然后猛然发现,那个顶级域名呢? 晕!只好先用三级域名了:http://w36830.s7.freedns.name/bbs/
昨天down了一个Windows下用的Apache+MySQL+PHP集合包,今天装了后想试一下Discuz!,可惜总是有点问题,不知道是哪里出错了,于是又down来一个PHPWind,可以用,大概看了一下里面的设置选项,还算是挺简单的。设了个端口映射,就可以让别人从IP访问到了,hoho~~~ 得找一个稳定快速的ISP空间啊。
打算做一件无耻的事。一件有一点点技术含量,又包含了一点点社会工程学的事。 写一个注册表读写封装类,像VCL里的TRegistry那种。写一个SMTP模块,可以发邮件到指定的邮箱。写一个DLL Trojan,它被捆绑到某个版本的方块中,放到论坛里。DLL注入到explorer.exe,或作为svchost.exe里的共享服务。它搜索注册表中的用户名和密码,谁叫它是明文的!通过邮件发回来,这个不是重点,重点在于得知该台机器的主人是谁。搜索文件的打开方式注册的程序路径,分析路径,试图找到是否可能在该路径下的某个分支有源代码,把源代码文件一个一个通过邮件发回来。
头发实在长得难以打理,只好下决心去剪了,还洗了45分钟的头。本来还担心剪得很难看,现在看来,还没到很难看的地步,只是有点难看。 分析了一天的自动化设计,那用例颗粒也太粗了,分解出来的步骤越来越多,开始是几步,后来变十几步,再后来是三十几步,再再后来是五十几步,再再再后来,要七十几啦,我连忙停下,要不要把它拆成几个呢!还帮开发的写了个小脚本,不到100行,也花了1个多小时才算最后基本能用,我真是很粗心,做事不经过大脑的类型啊! 中午在食堂吃饭,完了去还餐具的时候,看到小妞在那边吃,远远地跟她打招呼。疯丫头问我在看谁呢,我说就那个黄衣服的,跟我穿情侣装的那个。晚上回来在QQ上,小妞说,今天看到我跟一个美女一起哦。然后两个人东拉西扯地又扯皮了一会儿。 我实在是没有自制力啊!而且是个很小心眼儿的人,几近变态的小心眼!呜呜,就因为去BBS上逛了一下,想起一些事,就让我觉得很不爽。不爽不爽不爽!
跑去对面小区里面买了张窗帘,没想到不够宽,唉,不知道是窗子上标的尺寸有问题,还是这窗帘本来就尺寸不对呢。买了张床单,呵呵,1.6米宽的,以前只有张1米宽的,搬了家之后一直垫席子,没什么机会用,床单买了也只是为了看起来更像样一点点,因为其实对于我个人来说,垫席子的话,只要有被子,过冬应该也是没问题的,因为还有睡袋和一张小垫子呢。还花了3.5元买了个很薄的塑料脸盆,终于有脸盆了,最终一直因为没有自己的脸盆,每天早上总是跑到厨房那边去用z3的脸盆,呵呵。 现在要慢慢学习自己照顾自己的生活起居,慢慢添置家用,慢慢学会享受生活。 从网上down了一百多张桌面,又打开WallpaperHelper来用了下,我自己都觉得难用,郁闷,还是重头再写一个好点的,总是有各种各样奇怪的问题,甚至连定时器都会有问题,总感觉是因为用了NeoWin的原因,这个NeoWin的实现方式有点不好,只好不用了。 我应该好好想一想,哪些应用可以使用嵌入式的脚本语言来扩展其功能。现在脚本语言太流行了,Python、Ruby是大红大紫,稍微弱势一点的Lua、Tcl等,也是各有各的用处。自从写了一遍TclSuck后,感觉一般的脚本语言的glue code轻量级实现我基本也会了,有了这样的glue code,做两边的实现很自然,可以各自用各自的思维习惯,但到底嵌入了脚本语言支持后可以用来做些什么,我还很迷茫,一点想法都没有。我的方块是唯一一个看起来可以用Lua的场合,其它的实在不知道了。比如WallpaperHelper,需要用脚本嵌入的支持么?我不知道。所以需要好好规划,考虑一下。公司的自动化体系将要全面从Tcl切换到Ruby,我觉得很诧异,这样的变革应该是不提倡的吧,实在看不出来目前公司的自动化系统把Tcl实现换成Ruby有什么好处,反倒是需要大量的重复开发,至少底层支撑是要全部从头来过了。不过我也不需要再想那么多,因为这跟我没多少关系了。我要做的是,先考虑一下TclSuck的实现,能否把Functor的支持加进去,然后分别实现一个LuaSuck、RubySuck乃至PythonSuck,因为我只要一个轻量级的,单纯STL依赖的库,我不想要一个还会对Boost有依赖的库。当然不是说我讨厌Boost,相反,我很喜欢Boost,这是个大宝藏,但Boost怎么说都是个第三方的库,要自行编译才能使用,更何况对于这样的glue code我不需要那么多的功能。
在沃尔玛买了个小小的折台,这下可以坐在地上打电脑了。 方块啊方块,重新写吧。 把《灌篮高手》剧场版看完了,虽然只有4集,而且每集只有20分钟左右,但还是让我看得很激动,毕竟是童年时候的回忆啊,况且这部动画片真的很能感染人的情绪,再次被它的主题曲和片尾曲感动。井上雄彦,真是做了件好事啊。一直以来《灌篮高手》没有出全国大赛的动画片,好在已有部分还是比较忠实于原著的,接着看漫画也不会觉得莫名其妙摸不着头脑,真是值得反复看的一部分漫画啊。
我愤怒地发现,我登录不进beta.blogger.com ,甚至ping都ping不通这个域名!为GFW的存在感到羞耻,更加的开始憎恨这个国家,这个社会,这个民族,这个统治阶级。防民之口,胜于防川?所谓上有政策,下有对策。你有GFW,我有Tor!这世界自从有了google,就有了让G.C.D忙的,有了google,你封不死我的BSP,我还是照样大摇大摆进来发blog,还不是用的FTP,也不是用的Email,而是用的Web在线编辑。 尽管速度是慢了很多很多,但这样的封锁只让我坚定了继续使用下去的决心。我不要使用国内的那些乱七八糟的稳定性奇差的BSP,我只想在这块全世界人都可以自由访问的天地占据一个小角落。 发现用http://missdeer.blogspot.com.nyud.net:8090/访问不太稳定,似乎用http://www.pkblogs.com/missdeer/就稳定多了,而且看它的界面,好像就是为了给我们这些身处于可怜境地的人儿提供一个快速稳定访问blogger.com的机会。 那些领导人应该都知道大禹治水吧,还不懂疏通优于围堵的道理吗? 不多说别的,将blogger.com进行到底!
唉!心寒啊!没有归宿感!使劲挖我的井吧!他们爱咋滴就咋滴了!自己想开点看开点好好活!
昨天晚上开始还可以访问我的页面的,还顺便发了个新志。过了一会儿再去,就打不开了,ping也ping不通,本来想是不是这边网络的缘故,就等一段时间看看。今天再来看,还是不行,跟昨天一样。GFW还真是不爽啊!赚点钱,移民算了…… 现在只有找办法访问我的页面了。目前找到两个办法,一个是在域名后面加个后缀,原来我的页面地址是http://missdeer.blogspot.com,现在改成http://missdeer.blogspot.com.nyud.net:8090/就可以访问啦,还有个办法,是通过http://flyproxy.com/这个代理服务器访问,直接在它的页面上输入http://missdeer.blogspot.com就能跳过去了。这两个办法其实都是通过代理转过去的,所以速度上明显不如以前直接可以访问的时候了! 今天好奇,用了一个http://search.blogger.com的blog搜索功能,自恋的偶搜索了一下missdeer,偶然发现了afei在半年前写的一篇blog,唉,一切都过去啦,再也不会有那样的时光了,都是偶的错啊! 最后再提醒一下,可以用http://missdeer.blogspot.com.nyud.net:8090/来访问这个页面哦!尽管速度慢了点,但blogger.com真的堪称世界第一的BSP了。
在公司网上看到有个哥们儿说,有FreeBSD、Debian、FC、Suse、Mandrake、Gentoo的光盘,只要一罐可乐就可以换。早上吃过早饭,顺便在小卖部刷了一罐,下午就发邮件打了个招呼过去了,换了18张碟,哈哈,虽然版本老了点,但装在家里那个老爷机上也没什么关系吧,自己从网上down的话,还要花好多时间,还要刻,要费些碟,所以这样还是值得的,啦啦啦…… 感觉好久没有好好练习方块了,虽然每天都会打一会儿,但最近都没有什么进步。真不知道那么3.0的速度是怎么练出来的,真是只是这样不停地打就能练出来的吗。现在只知道要尽量缩短思考的时间,尽量摆放到需要旋转次数少的形状和移动次数少的位置,其它的就不知道,只能这样摸黑练了。 突然觉得,要是我的方块可以装载JPEG格式的图片,skin的体积岂不是可以又小很多,再怎么样,JPEG这样专用的有损图片压缩方案压缩率就是比7z这样通用的无损压缩方案高得多。先看看GDI+或者libjpeg哪个方便点。
买了对周生生的耳环,还以为是黄色的,结果是白色的,不适合妈妈啦,只好以后再买其它的给妈妈啦! Firefox在我的机器上,启动时间超过10秒!估计跟我的机器的配置有比较大的关系,我猜即使在我老家那台Duron1G+384DDR的老机器上,也会在5秒钟内就启动吧!一点都没看出来2.0比1.5改进在哪里,唯一的印象的是,标签栏的外观改了,有两个扩展不能用了,其它的真的不知道了。不过最近一直在想,怎么能在Gecko内核的浏览器中“胡作非为”,像在IE中得到了IHTMLDocument2一样,也许用XPCOM可以吧,不过一堆的英文资料,看着头大。 挖了一会儿井,比前两天挖的都多,下面要做的是,消行处理、输入处理、配置对话框的实现。
糟了,我真的太没有自制力了。 好不容易上网最新时间down到Firefox 2.0正式版,试用一下,感觉打开网页的速度还不如1.5的呐!算了,先用一段时间看看,到底哪个版本好一点。有两个扩展也不能用了。
因为要缴房租了,去取了钱,顺便查了一下余额,天哪,我的钱都到哪里去了!唉,郁闷之极,这几个月来,一直为了这样的事情烦!心理总是不爽啊,不平衡啊! 每天下班回家,便挖一点,看心情好坏挖多挖少也不重要,最后能挖出一口属于自己的井就可以了。 给自己定了2大类目标,写在图片上,设为桌面。 技术目标:C++泛型编程、Lua及与C++集成、DX+Win32API游戏程序设计、编译原理。 产品目标:方块、Socket捕获、按键辅助、NES模拟器、音频播放器、桌面管理。
和尚挖水 有两个和尚住在隔壁,所谓隔壁就是隔壁那座山,他们分别住在相邻的两座山上的庙里。这两座山之间有一条溪,于是这两个和尚每天都会在同一时间下山去溪边挑水,久而久之他么变成为了好朋友。
就这样时间在每天挑水中不知不觉已经过了五年。突然有一天左边这座山的和尚没有下山挑水,右边那座山的和尚心想:“他大概睡过头了。”便不以为意。
哪知道第二天左边这座山的和尚还是没有下山挑水,第三天也一样。过了一个星期还是一样,直到过了一个月右边那座山的和尚终于受不了,他心想:“我的朋友可能生病了,我要过去拜访他,看看能帮上什么忙。”
于是他便爬上了左边这座山,去探望他的老朋友。
等他到了左边这座山的庙,看到他的老友之后大吃一惊,因为他的老友正在庙前打太极拳,一点也不像一个月没喝水的人。他很好奇地问:“你已经一个月没有下山挑水了,难道你可以不用喝水吗?”
左边这座山的和尚说:“来来来,我带你去看。”于是他带着右边那座山的和尚走到庙的后院,指着一口井说:“这五年来,我每天做完功课后都会抽空挖这口井,即使有时很忙,能挖多少就算多少。如今终于让我挖出井水,我就不用再下山挑水,我可以有更多时间练我喜欢的太极拳。”
我们在公司领的薪水再多,那都是挑水。而把握下班后的时间挖一口属于自己的井,未来当年纪大了,体力拚不过年轻人了,还是有水喝,而且喝得很悠闲。
11点半左右,彭彭突然给我打电话,我很惊讶,说这么远有什么事啊,他说我回来了。更惊讶,呵呵。然后他叫我中午出去一起吃饭,我说晚上行不行,他说晚上要去珠海,于是我说再等半个小时吧。接着我给小思宇发邮件,她还多得意的,我从文字中都似乎能看到她满脸的幸福,说每个人知道后都很surprise。 12点我便出来,说在金泉乐,拦住一辆小巴便冲过去了。4个人,吃得还算开心,我也奇怪,自己居然也努力想多说几句话,要是平时,我肯定只是一个人闷头不响的。
前言 这次去贵阳玩,是完全没有计划的,只是想到有个表哥在,可以不住什么旅馆之类的地方了。有小妞可以找来一起玩,呵呵,就直接冲过去了,真是头脑发热!10月2日 早上八点就被闹钟吵醒了,准备一下行李,其实也没什么东西,把几件换洗的T恤装进去,再塞进一个笔记本,就没什么东西了,收拾了一下,然后就出门去坐车了。只是听说华联大厦有机场大巴,可我以前一次都没去坐过,只知道华联大厦在深南路边上,却不清楚具体的位置。前一天晚上在网上问了一下同事,说可以在上海宾馆坐地铁过去。于是先坐391到了上海宾馆,然后去地铁站,看了一下指引,原来只是一个站就到了,出来一看,就在茂业深南店旁边啊,晕死,大巴就停在那里,20元一张票,40分钟到机场,那时才10点半,比我计划的早到了半个小时,然后换了登机牌,无所事事了,就在候机室里坐着打瞌睡了,醒过来正好快11点半了,刚好可以登机了。登机后就给afei,小妞,表哥还有lili都发了条短信。倒是小丫头还没等我发,就先发过来问了,呵呵,不知道这一天小丫头是怎么过的,说是有师兄要约出去吃饭什么的,具体的我也不问了,不想那么八卦啦。发了短信后就关机了。飞机起飞后,我就一直等着吃中饭,呵呵,好像我每次的飞机都是在吃饭时间的,而且我也很喜欢飞机上的饭菜的口味,这次我要了份鸡肉,一看那榨菜,还是浙江余姚产的,晕。 1点半就到了贵阳机场了,看了下短信,表哥说要晚一会儿才能到,于是在门口百无聊赖地等了近半个小时,才看到他过来。突然感觉怎么变这么高大了,好像身高也比以前更高了,人也壮了点了,走路动作都像个成熟男人了,晕死,才比我大半年的人啊,一段时间不见就这样了,看到他后边好多白头发。看来有生活压力还真是我暂时体会不到的。路上他跟我说,问他二爹借了五万块钱去搞装修,等等。其实很不错了,我的房子还不知道在哪里呢,这样漂泊不定的感觉,而且我买房子肯定没这么好的机会了,才一千多一平米。我还能说什么呢。一路辗转打的到了他住的地方,顺便看了一下他的房子,90多平米的,装修还才开始,这样他的人生基本就固定下来了吧。其实我一点都不羡慕,我还是想四处走走,在飞机上的时候看到一本杂志上介绍欧洲的一些地方,比如都柏林,罗马,维也纳等等,我好想有机会都去逛一下,要努力赚钱啊。虽说我还是想回老家找个运营商的工作蹲起,但我很清楚,靠这样的工作赚来点钱,是买不起房子,过不上小资的生活的。所以似乎我的想法有点理想主义了,我想的是赚钱是有另外的方法的,而那个蹲单位里的工作只是为了充实一下生活,满足一下精神需求! 然后两个人坐车去花溪公园逛了一下,吃了一碗正宗的花溪王记牛肉粉,味道比起深圳那家来,似乎要好很多。深圳那次跟小妞小玉玉一起去的,把我吃出心理阴影来了。她们也略带笑意得说,看来花溪王记把我伤很深。到5点半的时候,我们就开始折道回家。奔到他女朋友住的地方,看造型,有点像超女,晕!还好,看来人比较活泼外向的,两个人也比较喜欢搞笑,在厨房里做笑,做了两个小时吧,才开始吃。小妞还叫我一起去和她还有她妹去吃肥肠鱼呢,不过想到也只有这次晚饭是和他们一起吃的,第二天他们就要去女方家里,所以无论怎么样,还是和他们吃吧,之后两三天怎么样都可以。 想不到表哥也会坐菜了,做的土豆红烧肉还味道真不错呢!就是往成熟持家型男人发展了啊! 吃完饭,看了会儿电视,回到他住的地方,打了一会儿方块,看了成龙的《80天环游世界》,就睡了。10月3日 早上早早地被火车的鸣叫声和轰隆声吵醒了。七点半的时候,表哥就收拾了东西,去见岳丈大人了,剩下我一个人,好自由。洗漱了一下,就打开电脑玩方块,大概9点多一点,小妞发短信来问我起床没,然后两个人开始商量见面事宜,最后决定10点半出门,在火车站见。10点半出了门,先问了一下小区的保安,然后走到岔路口,又问了一下人,等到一辆直接到火车站的中巴,11点10分到了火车站,大概过了10多分钟,小妞和她妹妹就来了,小妞说怎么不穿红色的衣服了,都不好认,我说嘿嘿这次没带红衣服,都是这样浅颜色的,还有一件你这样颜色的呢,小妞就问哪一件啊,我说是新买的,呵呵。 随后,我们打的走了,中途放下她妹妹,我和小妞则去吃了烤肉。这烤肉是用细铁丝串起来的,有各种肉类,比如猪肉、羊肉、牛肉、脆皮肠、黄喉、烤螺、猪皮等等,跟吃火锅的菜式那样多,我因为没吃早饭,所以还叫了一碗炒饭,还和小妞人一叫一碗冰绿豆汤。吃完烤肉,喝下那碗冰绿豆汤好爽哦,一直从喉咙头开始凉下去到胃里为止。 然后去贵阳大剧院看电影,小妞的两个同学已经在那里等了,有一个是去过深圳的,所以见过,还有一个是第一次见。我都好久没进过电影院了,他们买了好多零食,电影是个成龙和古天乐演的新片,很搞笑很有趣,里面还有个娃娃,也很可爱,剧情也可以,一直看到2点多。 看完电影,决定去花溪吃小吃去,坐了中巴车,一路狂奔,到了花溪,直接走到“小吃一条街”,看到一家做小豆腐的便坐下开吃,吃好了多小豆腐,还有冰粉、土豆饼等,又吃撑吃爽了,冰粉直接灌下喉咙的感觉就像刚才喝冰绿豆汤一样。吃完小吃,他们又带我去看“黄金大道”,走了一段路后坐上一辆小小的三轮摩托,可以承载4个人。到了那边看到有马可以骑,不过里面人太多了,便一路走过去。小妞还去玩转的糖,还转到一个凤凰。走到陶艺吧,看到都是小朋友们在里面玩,我们就不好意思进去了。看到有卖“玫瑰糖”的,我也是第一次听说这个名字,只是小时候看到过这个的制作过程,我们那里叫“扯白糖”,因为最后的过程是那糖不停地在被撕扯,从红禢色最后被扯成白色为止,所以叫扯白糖。这里卖的是没有扯白的,而且据说是带有玫瑰香味的,所以叫玫瑰糖,不过我是怎么也闻不出香味了,但他们说这是只可意味不可言传的。我和小妞就一人一个在那里绞啊绞的,还因为太过专心,没看路,一脚踩到马粪上。一路走下去,终于看到一条石子和石板混合铺成的路,两边种着很高大的法国梧桐。听小妞介绍,是因为这里每到秋天,梧桐的落叶掉满了地,一片黄色,所以叫“黄金大道”。小妞玩腻了那玫瑰糖,我就把她的那个也吃了,嘿嘿,甜死我了。看到那里有汽枪射击的游戏,我便过去玩了一下,6块钱可以打10发子弹,前5发因为有一发是打了7环,把成绩拖累了。后5发打了3个8环,2个9环,达到42环可以奖2块钱,刚好10块钱的话还可以再打2轮,小妞就上去试了一下,这家伙还打到几次10环的呢。走到快尽头了,我们折回来,又坐小三轮摩托到花溪公园门口,那里有公车站。 折回到小妞同学的家里,因为我们都很饱,吃不下东西,便打起双扣来。手气很差啊,才打到3,小妞他们都打到10了。出了门去吃烧烤,一直走到小妞家楼下,吃起烙锅来。这个烙字还是询问了几次,思考了几次来认识到的,呵呵,就是那种似炸不是炸,似烤不是烤的。点了一条鱼,一些臭豆腐,还有些其它我都记不得名字的菜,又吃爽啦!吃完过后,去了小妞家里,范妈妈在家里,看起来跟我妈妈差不多的一个中年妇女。还又给我们做了绿豆汤来喝,这下真的是撑死了。小妞的房间好大哦,不过好像床比较小,小妞还在那里说,没整理床,呵呵。10点的时候,才从小妞家出来,她同学带我去坐11路公交车,1块钱坐到大转盘的地方,问了一下去三江口,只要4块钱,便上去了,到了那路口,我叫他开进去一点,他说要5块钱,而我关键是想去打开那整钱,便叫他开进去一点。开始买了支雪糕,还说没零钱,晕,没办法,只好去隔壁的一家店里买了包云烟,才有了零钱付车费。再一人走回小区,开始还担心这么晚了,会不会被门卫拦住,还好,没拦。10:50左右到了住处,小妞发短信来问我到了没,我说刚好到,要去洗澡了。 打开电视,洗了澡,打开电脑玩一会儿,睡!10月4日 早上照例先来了一次,然后继续睡,结果8点半就被xcc的短信吵了,于是起来打方块。9点半过的时候,小妞发短信说可以出门了,10:20在火车站出站口见。这次是轻车熟路了,走到那岔路口,直接一块二角钱坐到火车站。稍微等了一会儿,小妞和彭力就来了,到火车站对面坐2路公交车,到黔灵公园门口,可惜很遗憾的是,下雨了。 只好取消了爬山计划,打的到了一个地方吃起丝娃娃。小妞教我怎么用一张巴掌大小的皮子包起那些刮成丝丝的凉菜,然后浇上一些事先自己和好的辣椒油,再一口吞下这个包包,像春卷一样,但要小一些,而且听小妞说是因为包想来像人们给婴儿包起来一样,所以叫丝娃娃。我好像吃了16个吧,挺好玩挺有趣的。不由地感叹,贵阳人还想会研究吃的东西,我使劲想了一下我老家那边,似乎真的没什么特别的小吃之类的,我们那边的人好像对吃的不是很在乎,只是随便吃点炒菜就罢了。吃完丝娃娃,又走到旁边一家小吃店点了一笼灌汤包和一笼灌汤饺子,被我和彭力一下解决了。往旁边一走,又吃了一个烧卖,好能吃啊! 吃撑了,就要走走消化一下嘛,就去逛了一下电脑市场,随便看了一下DC,比起深圳来还真的贵不少,比香港的当然更贵一点。其实电脑市场也只是随便看看,我并没有什么想买的东西。去看了下D版碟,只有很少一点,更何况我现在什么东西都习惯从网上down,有了eMule真是好啊!从电脑市场出来,走进一家叫“昨日重现”的会所,里面可以喝茶,咖啡,点了壶茶,坐了好一会儿。后来无聊了,彭力就叫了一个人来一起打双扣,唉,手气像前一天一样的差。 一直打到5点多,就回小妞家去,范爸爸在厨房做菜,不一会儿就开饭了,菜很丰盛,莲藕炖龙骨、蚂蚁上树、肉沫蒸蛋、辣子鸡、香肠等等等等,范妈妈太好客了,我又吃撑了,足足吃了4碗!范爸爸好像是个不苟言笑的人,只吃了一碗饭就放下了。就我和彭力吃好多哦,把几盘菜都消灭干净,把饭也全部干掉了。吃完饭,我们又打起牌了,小妞在那里说笑,花了1400的路费,跑到贵阳打了两天牌,呵呵。直到10点,才出来,到了大转盘处,原来有那种mini巴可以乘坐,1块半就能到了,比三轮摩托还省呢!10月5日 今天不出去了,起床后打开电视,再开了方块来打,又写了一会儿代码,有点怪,1秒的interval的timer居然很不精确,想让它在60000ms的时候能触发一下,结果总是差好多,54000ms左右就会触发,很奇怪。到了中午,去买了包花生和小米花糖来吃。照彭力和小妞的说法,这半天可是值400块的哦! 然后等到3点半过后,下去1楼找表哥的同事,没在,打电话也关机了。再回到10楼,敲开对面屋的人家,把机票钱和钥匙放在那里便出门了。有点雨,昨天也是因为有雨才爬不成黔灵山的,郁闷,而且没有太阳,气温便下降了好多,我只有短袖T恤,还好比较不怕冷。 坐大巴到火车站,大概4点20的样子,问了一下有没有机场大巴,走去看到机场大巴,发现是自动投币的,只好去买了个烤红薯换了零钱。突然又想到,大巴会不会开很慢,不知道到机场要多久呢,于是还是打的了,50块钱。司机问我是哪里人,我说是重庆的,哈哈,操着很不地道的重庆话,他果然说我的重庆话不正宗,我说我长期呆在深圳的,来贵阳是有同学。到机场还不到5点,于是在候机厅里看起《西游记》来,看得津津有味。看过《西游记》又去看卖书的地方,发现有本小说《和空姐同居的日子》还挺符合我的口味的,一直看到登机为止。 在飞机上吃了晚饭,这次的榨菜是涪陵产的了,呵呵。主菜是鱼,还挺好吃的,飞机上的饭菜总是很好吃,至少我是都这么觉得。大概1个小时,就到深圳了,第一次在高空看到灯光点点的深圳,广播中播报,深圳的气温30摄氏度,强!又坐大巴到华联大厦,不知道为什么,才9点,华强北的那些电子市场、电脑市场都关门了。三下两下就转车回到了家,开机,上网!后记 贵阳还是多有趣的,给我感触最大的就是在吃的方面,有太多值得非贵阳本地人去试一下,而且如果是像我这样对自助游是文盲水平的人,最好能有个本地的人带去逛,像小妞这样好吃又爱玩的人,真是绝佳的导游,还有她的同学的全程陪玩下,觉得还是挺开心的,有些地方没去成有点遗憾,有机会应该再去一次,呵呵。
10月1日 昨晚就被告知今早上7点半要打电话去叫起床,虽然是后半夜3点钟才睡下的,但还是设了闹钟,7点半的时候就被闹醒了,拨了一下电话,然后发了两条短信,便再也不想睡了,起来玩方块,真是堕落啊!大概9点的时候,收到短信说到上梅林了,我估计了一下应该马上能到我家了,就开始刷牙洗脸刮脸,9点20的时候就到了,我顺便又用了一下洗面奶,然后就在那里闲聊,大概等到9点50的时候,出门去坐车。到了百草园,找到同事们,他们已经在那玩了一会儿了,我几乎是迟到了20分钟。然后上去互相介绍了一下,开始打起羽毛球来,好久没运动过了。在接下来的不到2个小时里,陆陆续续玩了几次,然后就说去吃饭吧,不想去食堂,想不到毛氏湘菜馆已经被关了,要么被迁走了,那里正在拆迁。于是我轻车熟路地带他们到金泉乐湘菜馆,点了个美味鱼头(失败),莲藕炖龙骨(还行),酸辣鸡杂(也可以),手撕包菜(获得好评)还有个小葱拌豆腐(不评论)。那些女孩儿们本来食量就小,随便吃了点就不动了,我和罗总想吃碗饭,结果等了好久,硬说饭还在做,气死,我放弃了!然后各自做各自的事去,同事们要去逛街,我就去百草园超市买东西,买了几本书,两盒月饼,要带一盒去给表哥,还有些小东西,就坐车回家,回家洗了个澡,好舒服哦,这样的生活才健康啊,好久没运动了,吃饭的时候右手拿筷子都是抖的,屁股走路的时候也是酸疼,晕!洗完澡,在那里看碟,想不到我down错了,不知道是哪里的一部什么乱七八糟的外国片子,也叫《夜宴》,晕死!幸好还有《百慕大三角》于是看到6点,虽然很困了,但还是坚持住了,谁到自己睡那么晚呢,才睡了4个半小时,真是自作孽不可活啊!去对面的小吃店吃了晚饭,想起来要是自己会做饭就好了。吃完饭,就打算回去了,送别人回去,天黑了嘛,还有那么些书,月饼,那么沉,送去的时候还好,车上人不多,送到楼下,我就折回来了,回来的车上挤满了人,郁闷,只能站着,还困死了! 就这样,一天是过去了。上网查了一下去哪里坐机场大巴,明天要买去见表哥,呵呵。 突然觉得郁闷,怎么我达不到1.2x以上了。要把自己调节到“无我境界”,才能在原有基础上加快速度吧!呵呵,从《网球王子》里看到的这个名字,不过听里面的描述跟我的要求是差不多,只有不经过大脑,直接的肌肉反射就能做到相应的动作,才能提升速度! 单机3.0终于在今天发布了,算是国庆献礼,我都已经玩了好多天了。在论坛里得到的灵感,可以带skin功能啊,还有就是直接从Lua脚本里定义游戏逻辑,这样可以在不修改主程序代码重新编译的情况下,就能添加新的游戏方式,比如前几天在论坛里听说到的Cascade模式。我觉得我的想法要是这样真的能实现的话,肯定是很cool的,至少现在好像很少有这样做的tetris game哦。
和同事切磋了一下方块,呵呵,好玩,悍超纯点大概1.0x的速度,居然也能打到总监级别,厉害! 不知道为什么,跟他们打了几盘后,再自己打单机,发现好像比以前快了一点点,超过1.1x的机会多了很多。
快半夜了,xcc还给我打电话,两个人就因为一些能让我们郁闷的事又为我们的客户贡献了大半个小时的话费!这样谈过,心里就很轻松,连像他们这样我看着都觉得艳羡的人,都有这样的困扰,那我还在乎啥呢?冥冥之中,自有安排,不用刻意追求,一切随缘吧。 ccal被我加了几行代码调试得差不多可以实用的阶段了,下次再来吧,be happy!
在实验室里,一个女同事和我旁边的男同事在调校一个仪表,仪表就放在我的电脑旁边,两个人就两个头都处在仪表前,我就开玩笑说,来,给你们拍大头照。突然,觉得心里隐隐一阵酸味,想起那个家伙。我还是挺小心眼的,就是很难过自己那关,我使劲劝自己那都是过去的事了,心情才稍稍平静了一点点。
xcc给我建议的出游计划因为另一方的不乐意而泡汤了,这个家伙! 只好另作打算,去哪里闲逛一圈,实在不想这么7天都呆在屋子里头,对着电脑,妈妈说要少打电脑,以后会生不了小孩的,郁闷,比起长期放在裤兜里的手机辐射来说,这个影响应该小很多吧。不过妈妈的话也是不无道理的,本来在公司就是超过8个小时对着电脑,每天下班回家做的第一件事还是打开电脑来上网,确实无聊啊,上次luolu问我平常做些什么,我就是压根儿想不出有什么值得说的,生活质量之低下啊!出去一趟要花些钱吧,不过钱总是要花的,攒了也没用,这点钱能买房子吗,能买车子吗,不能!那为什么不把它花在其它地方能让自己也稍微高兴一点的地方呢,生不带来,死不带去啊,应该像Linux消耗物理内存一样,不要让它闲在那里! 改了一下LLYF WallpaperHelper,能保存和装载配置了,不过还有一点是,要加上月历生成功能哦,估计不是很难吧。^_^其实我觉得这个程序的功能应该作为鱼鱼桌面秀的一个插件来实现,但是鱼鱼桌面秀总是要抢其它前台窗口的输入焦点,所以我只好很惋惜地放弃了这个想法!
今天晚上去SHOWGOOD的新家里蹭饭吃了。两口子租了套两室一厅,布置得挺温馨的,小伙子转变得挺快的,也不知道是不是以前我们就没有发现,他居然还会做菜,而且还做得有模有样的,味道也还可以,虽然稍微,我说是稍微哈,淡了那么一点点,幸好我们老家那边就是吃得清淡的比较习惯。那苦瓜花生汤,清蒸鱼味道都不错,呵呵。有家室的人,生活就是不一样哈。 这游戏,真的很容易让人堕落的。火拼俄罗斯我就玩了好久了,一个单机版的也能玩一天,真是堕落啊,我都鄙视我自己了。我的速度提高也太慢了,练了两星期多了吧,大概就提高了0.2,从0.8x提高到1.0x了,又一次证明,我的各方面素质,至少从天赋上来说,实在是算差的。偶尔看一下coolkuai的论坛,关心一下怎么传说中的单机3.0版还不发布出来,好些人在论坛里叫嚷着要公测,没想到今天被我意外地找到了下载的入口,真不知道他们是不是故意的,直接用域名访问的是另外一个直接指定的页面,排版设计还要好看一点的,就有更丰富的内容,可能是他们专门给自己圈子里的一群人设计的。被宣传得神乎其神的3.0并没有想象中的那么吸引人,也没有多加多少特性,不过有几点还是很明显能看出来很体贴很迫切的设计的,比如能保存设置,2.0的每次新打开,都是没有开键盘加速的,现在能保存这个设置了,不过没找到它是保存在哪里的。另一个是,对QQ火拼俄罗斯界面的实现,更好地有现场的感觉了。其它的,我倒是觉得对我影响不大,据说是改了加速的内核,只是觉得移动时就是没有Q块上的流畅,2.0也是,还增加了打榜等等其它一些小特性。反正其它的我倒是觉得都是不重要的,只是宣传得太夸张了,什么巨献啊,重磅推出啊。我要做的话,就做一个仿Q块的,至少是联机功能一定要有的,可以另外写个Server,今天又突然想到,还要有专门的训练模式支持,因为本来就不想跟Q块竞争,只是作为一个训练工具。 硬盘又一次出问题了,这次是在从一个分区向另一个分区移动大量文件的时候弄出问题的,所有的东西都又不见了,也懒得再恢复了,只是可惜了那些照片。还有很多动画片,好久才下下来的,那些文档资料,工具软件,都没有喽,有点郁闷的说,再一次得到的教训,对于比较重要的东西,就应该刻到光盘上备份的!
下午的时候xcc发短信来问我有没有空,晚上一起吃饭,我当然没事了,反正也正在郁闷现在每到周五都是凄凄凉凉的,就答应了。 到了下班时间,我就缠住一个同事,要蹭她的班车票,哈哈,一起坐车到了梅林,路上还堵了一小会儿。 去接xcc的女朋友的时候,雨下大了,等我和xcc回到他屋里的时候,鞋子已经是灌满水了,裤子也全湿了。衣服稍微好一点,只湿了肩膀上一点。 然后去那个小馆子,三个人点了一个鸡煲,一个水煮肉片,一个葱花炒蛋,还喝了两瓶啤酒,才54块钱,哈哈,真便宜!
但是以前被GFW封过,虽然现在暂时解封了,但是以后呢,谁也不知道会怎么样!不过,先也不管这么多了,被封了又怎么样,考察了几个BSP后,包括MSN、Blogsome这些非国内的,最后决定就迁移到这里吧,因为实在忍受不了CSDN的blog不稳定了。
Category Shareware
总共花了十几个小时用Qt写了一个简单的、具有图形用户界面的、CoreDNS配置文件生成工具,只有一个主窗口,传统widget比较丑:
前段时间突然心血来潮开通了一个微信公众号,虽然至今为止也才写了十几篇文章,但是用了官方文章编辑器和一票第三方文章编辑器后,我决定自己写一个。
这个app在2014年就上架过,除了一开始送出去一堆兑换码以外,以每月大约不到1个付费用户的速度卖出过几份。后来也就更新过1个版本,后来就懒得更新了,直到2017年10月因长期不更新被下架了。
这是好几年前就开的坑,当年是对标Launchy,后来推翻重写,想对标Alfred,到目前为止,也仅仅是完成了很少几个功能,很多精力和时间都花在UI上了。一开始是照Launchy的完全图片自绘,最近加上了Alfred风格的UI。
自从知道怀孕28周起要数胎动,我就花了几天时间写了个简单的app给老婆数胎动用。
大约一年半前因为感觉遇到解决不了的技术问题,于是imchenwen的坑就扔下不管了。上个月的时候突然意识到,妹子喜欢看网卡的视频,优酷腾讯芒果爱奇艺等等,但是因为身体原因捧着个手机或iPad看会觉得头疼,看电视就要好很多,所以就萌生了在电视机上看网络视频的想法。
老早就注册有赞云了,之前随便玩了一下,感觉可以用,加上自己对web开发并不了解,就放下了。
最近这段时间都在写一个叫UMLGen的GUI程序,从名字可以看出,就是一个用来画UML图的工具,与大多数现有的WYSIWYG(所见即所得)的UML画图工具(比如Visio,StarUML等等)不同的是,UMLGen使用代码的形式来描述UML图的呈现,与LaTeX的思想类似,即WYTIWYG(What You Think Is What You Get,所想即所得),我个人认为这种方式特别适合程序员使用。现在可用性已经很好了,主窗口截图如下:
最近又要在一个Qt程序中解压缩一些zip文件,以前用过QuaZIP,总觉得如果能不引入一个额外的第三方库会更舒服一些,于是上网搜了一下,还真有办法!
抓取网络小说的小程序断断续续有了不少更新,除了支持更多的小说网站外,还有一些值得一提的内容:
前些天突然心血来潮,写了个小程序,用于从网上抓取网络小说,然后生成content.html,content.opf和toc.ncx文件,再放入一个合适的字体文件,比如经过我几番比较,在我的Kindle4上使用方正准圆比较好,最后用kindlegen生成mobi文件,于是可以使用kindle来阅读网络小说了。
imchenwen的进展不快,这段时间主要在做两件事:
不知道怎么想的,突然开了个新坑,因为bilibili mac client并不能好好地工作,所以自己写一个也挺好玩的。
Avege开源后并没有太大的变化,除了收获了180多个star,大概也没什么人真正用上,别说PR了,连issue都没有,不过也收集了一些意见和建议。
昨天把Avege客户端部分的源代码单独取出来,放到github上了。然后在v2ex上发了个帖,在twitter上发了条推,在Telegram上的一些群里发了条消息。终于有了一个star数过100的repo了:P
经过大半个月的折腾,兼容SSR混淆和协议的坑终于填上了,目前混淆支持plain、http_simple、http_post、random_head、tls1.2_ticket_auth几种,协议支持origin、verify_sha1即原版SS的One Time Auth、auth_sha1_v4、auth_aes128_md5、auth_aes128_sha1几种。
之前写好的tls1.2_ticket_auth在接收到大量数据时会decode出错,后来发现auth_sha1_v4在接收大量数据时最后一块数据时会要等一段时间才能收到。由于tls1.2_ticket_auth的问题在前面那么多天的仔细排查定位后,仍然毫无头绪,我觉得auth_sha1_v4的问题应该会容易一些,就先尝试一下修正这个问题。
代码几天前就写完了,就是调试不通,昨天晚上偶然在github上看到从libev版分离出来的obfsplugin,都打算用CGO集成到avege去算了,今天上午甚至把编译、链接错误全都改完了,后来想想CGO还是不太好。
本来实现了tls1.2_ticket_auth混淆方法后,我觉得够用了,便想直接去做auth_sha1_v4协议了,但是调试了两天,没调通,很沮丧,还觉得没什么头绪。至少在调试混淆方法时,我用C#版做对比,通过抓包可以明确比较我的程序混淆结果是否正确,但协议就要麻烦些,协议是将加密前的数据预处理一遍,很难对比我的程序是否处理正确了。
虽然Go实现的代码是照着C#版的代码翻译过来了,但是引入了很多问题,经过几天的仔细排查,现在tls1.2_ticket_auth混淆功能终于完成了!稍微记录一点需要注意的点,以便日后翻阅。
这几天断断续续地移植着SSR的一个混淆插件tls1.2_ticket_auth,至今仍然没能正常工作起来,忧郁啊。稍微记录一点读ss-go和ssr-csharp/ssr-libev的代码所得,以便日后翻阅。
Avege最早的目标是成为一个redsocks的另一个实现,用Go做方便地跨平台,同时相比redsocks原版要多增加shadowsocks协议的支持。可是后来却只实现了shadowsocks协议,就只顾着做其他功能去了。
一直以来说微信公众号的阅读体验不满意,但是现在越来越多的高质量的文章都发到微信公众号上去了,再加上之前Google Reader关闭,这让我几乎放弃了之前每天坚持阅读高质量文章的习惯。
前些天看到有人移植了SSR Android版,我就顺便看了看代码,结合网上的一篇文章,觉得似乎挺简单的,它(官方也)用Java/Scala写了个外壳和启动VPN service,其他功能是几个用C写的程序共同完成,包括redsocks,tun2socks,ss-tunnel,ss-local,pdnsd。
之前在做的滚球推荐app只能在Android上分发,后来想想还是咬咬牙提交到Apple App Store试试,不过还是做好了被拒的心理准备的,因为照以前的经验,这个App有两个可能的原因很明显会被拒,一个是功能太简单,基本上只是浏览一个表格而已,另一个则是用户付费的功能,因为Android系统在国内收费不易的情况下,我就一直懒得做,只是放了个页面说明,让用户加我们的QQ/微信来通过微信或支付宝等国内流行的移动支付方式来收费。
原本avege就是有一个解决dns污染的方案的,是参照ChinaDNS的原理写的,简单说来就是同时请求国内和国外的DNS server,当收到结果的IP被认为是国外时,丢弃国内DNS server的结果,只取国外DNS server的结果,不然就取国内DNS server的结果。这是基于一些基本的假设,比如总是国内DNS server先返回结果,比如GFW不会使用国内IP来污染。
之前说过想做个类redsocks的实现,纠结了一些天看代码后,现在终于用Go做了个初步能工作的版本出来,名字叫Avege,依然是某女推友的id。
在高中同学的公司里兼了个职,原本只说是提供技术部发展等方面的咨询和顾问等事宜的,于是我要的兼职报酬也不高。后来他说要我写个程序,做债权匹配管理,我就觉得有点坑爹了,我顺势就提要求配一个笔记本,虽然是最低配的。一直拖拖拖,一方面是确实拖延症严重,另一方面也确实觉得这东西应该工作量不大。后来做的时候发现还是有些折腾的地方的。
前段时间用ss-redir实现了后端是shadowsocks的翻墙网关,虽然真的实现了全局域网自动翻墙,但仍然留下了各种不足。
前几天发现公司网络有个奇怪的问题,公司的DNS解析居然把花生壳(oray.com)和公云(pubyun.com)的域名给劫持了。
昨天晚上那两个合伙人跟我说他们打算先不上网站了,先考虑进驻诸如饿了么,美团糯米之类的外卖平台,也不做中饭和晚饭了,只做早点。
昨天打算提交一个istkani的新版本到app store,其实没什么更新的内容,前段时间在UI上微微调整了一下,其他原本想加的功能一直由于拖延症而没动手。只是因为iOS8发布了,Xcode也升级到了6.0.1而想试一下。结果遇到了不少问题。
昨天收到Apple AppStore的邮件,是八月份的Financial report,原来八月份居然卖出了两份istkani,真是太让我意外了。本来自五月份上架以来,除了兑换码送出几十份以外,我就没怎么指望能把它卖出去的,虽然也有过一些升级的计划,增加新特性以及提升UI设计等等,不过后来还是一直拖延着。
这两天看论坛,又想到两个对我来说比较有用的东西。其中一个是密码管理。
最近有很认真地在写一个Google Reader客户端,仍然是使用的Qt,一切为了跨平台嘛。之前Ninayan用QML写的UI,虽然能做出一些比较炫的效果,但没有一个优秀的美工,再炫的效果最后得到的都是不好的用户体验。于是这次使用了传统Widget来做UI,感觉还不错,中规中矩的,源代码也放在github上了。
到现在为止,Google Reader的客户端功能基本上实现了,可能还有些小细节需要修改。前两天因为工作上的关系,找了点资料在看怎么提高socket的效率,公司那个产品全部是用的select模型,貌似Qt的QNetworkAccessManager类也是用的select,这个东西的好处在于大多数的系统都直接支持,思路也简单,但是对于追求高吞吐率的情况下,就得用各个系统内核各有的一套东西了,比如Windows下得用完成端口,Linux下,2.6以后版本的内核得用epoll/AIO,BSD/Mac下又有kqueue等等,可谓是八仙过海各有神通啊。然后我就又找到了asio,这个库以前用过Boost里的那个版本,没用好,当时的感觉是资料太少了,性能太差了,后来也都是尽量避开自己写socket相关的代码,直到后来用Qt中的QNetworkAccessManager。这两天抑制不住地想把QNetworkAccessManager改成用asio实现,以达到各平台优化的尽量大吞吐率。忍住!
基本功能完成后,我就开始想着把程序改成插件架构,以插件的形式支持从不同的源获取信息,比如Twitter,Facebook,国内的微博等等,也以插件的形式支持把当前内容分享到不同的宿。其实从功能上来说,跟Ninayan是有很大重叠的,毕竟当时写Ninayan也是为了做一个信息获取工具,只不过从UI的设计上限制了操作方式,最终在用户体验上会有很大的差别。
最近Ainesmile的进展几乎停下来了,因为想到要让它支持像TextMate那样的bundles机制,但又为了避开版权问题而不能直接使用TextMate的bundles,所以就想把那些bundle的格式转换一下用就行了,于是就要写个小程序进行文件格式的转换。为了这个转换小程序更具有通用性和实用性,我就很是贪心地想让它支持在JSON、Apple PList、Windows INI、Java Properties和plain XML任意二者间进行相互转换。本来想想觉得只是个很小的任务,可实际做的时间还是有很多事情要做的,而且想来这样一个具有通用性和实用性的工具应该可以发布给别人使用,于是在包装上也做了更多点的工作,比如画图标,而且为了能在Windows和Mac OS X上都能使用,同时以为以前用过的一个Rapid XML封装更容易使用,结果陷入了无尽的跨平台的fixing中。
昨天发现一个新语言,Rust,据说是Mozilla开发来为了替代C++重写Firefox用的,现在才0.3版本,语言特性也还在快速变化中。看了半天的tutorial,发现语法上给我的感觉是很像Ruby,又有Erlang的一点点元素,而它自称是一种系统编程语言,所以从一开始就很注重与C的交互。它是一种编译型语言,有个叫rustc的编译器,现在还只能通过自己下载编译源代码来使用它。看tutorial的时候突然有个念头,这些年不断冒出来的声称解决了一大堆问题的编程语言,实际上也就是它声称的那些个领域上表现较好而已啊,C语言才是王道啊,哈哈。
在编译Rust的时候,发现它自动下载了最新的LLVM和Clang的源代码并编译好了,于是我就想再试下Mac OS X下用Clang编译下Qt,以前曾经尝试过但失败了。这次也遇到两个错误,就是返回值类型要去const修饰,gitorious上已经有patch的,但在4.8.2上没有合入,自己改一下整个Qt 4.8.2就能用Clang编译通过了。Clang在Mac OS X上基于上处于产品级的质量了,但不知道在Windows上什么时候才能达到近似的水平啊,叹气。貌似Clang对unix-like的系统都支持得挺不错的,甚至能用来编译FreeBSD内核。
最近正在编写一个文本编辑器,取名为Ainesmile。按照惯例,这个名字同样是一个妹汁的id。
这个文本编辑器的目标是成为超越Coda、Sublime Text和TextMate的存在,所以基本的定位是一个代码编辑器,也可以做为一个通用的纯文本编辑器。它使用Qt开发,所以目前可以确认的是它将可以在Windows和Mac上运行,如果移植代价不大,将也会在Linux或FreeBSD等其他Qt支持的桌面环境中运行。
写这么一个文本编辑器的出发点,首先,我觉得Mac OS X上的几个编辑器的功能都很炫目,很有现代感,而Windows平台上除了e,就没有其他类似产品了,而e的功能也似乎只是TextMate的一个子集。其次,我觉得Mac用户真是人傻钱多的存在啊。
功能方面,我觉得实现起来没有特别大的技术难点,只不过工作量有点大。当前一个主要的问题是,美工方面,缺少一套用于菜单、工具栏的图标,以及程序图标。求帮助。
看了cnsw上一位年入10w刀的小牛的经验之谈,对比我自己的现状,确实做得不好啊!
审视一下自己的产品和网站,产品太小众,而且在质量上讲,确实我自己都不满意,这得改。我看了一下原来的计划,做了些调整,重构IDE推出新版本,增加PHP、Python、Ruby的支持,增加TextMate Bundles支持。另外开辟另一条新的产品线,数据库相关的,分别是几种常见数据库产品的客户端,设计管理工具,比较工具和代码生成工具。我现在都不敢预估工作量和进展了,叹气。
网站的问题更多了,页面关系比较冗余零碎;排版不清晰,凌乱,字体太小;文字内容不丰富;截图粗糙,大小差别太大,内容不清爽。这得最先改,就参考OmniGroup的好了。
加油!
很偶然才知道这个工具——Balsamiq Mockups,因为完全是在另一个主题的论坛里看到的,当时在那个论坛里之所以提到它,不是因为它的功能多强大,也不是因为它的用户体验做得好,更不是因为它能帮助人们解决实际问题,而是因为它卖得好!
以前听说那些做快速软件界面原型设计的人,是用VB、Delphi之类的WYSIWYG的RAD工具,当时我就觉得与其已经用这RAD工具了,还不如直接就添加上各种事件响应函数,然后一个产品就做出来了。直到最近看到了Balsamiq Mockups,最在这两天简单试用之后,才发现这确实是个很不错的工具。
它是用Adobe AIR编写的,所以不但可以在Windows/Linux/Mac三大桌面环境中运行,还可以在网页上运行(貌似作者原来就是在Adobe工作的)。跨平台只是一个优点,另一个很重要的优点的,它的操作确实很傻瓜化,不得不承认的是软件的功能其实也很简单,就是一组图片,拖放堆叠在一个画布上。
这是个共享软件,桌面版要79美金,如果不注册,它会每隔几钟就弹出个消息框来,并且不能保存图像,但它有一些可以免费获得注册码的方法。其实我觉得这个软件的功能很简单,即使自己实现一个,可能也不用多少时间吧!
Source Insight有大半年没更新了,我觉得以前一个同事说的没错,Source Insight可算是最不思进取的软件了,最后的几次小版本更新,都不知道到底有什么变动,反正我们最关心的一些问题都在。包括缺少Tab,缺少代码折叠,中文支持极差。不过总的说来,Source Insight的完成度是很高了,除了这三个缺点外,其他确实很难找出明显的问题来了。
我想做一个类似的源代码浏览工具,有几点Source Insight做得不错的地方,很值得学习。比如快速打开文件,快速查找函数和符号,上下文敏感的代码浏览,以及调用关系图示。Source Insight内建支持C/C++、C#和JAVA代码分析,其他的语言是通过扩展定义的规则实现的,这种方式也值得学习。
想到实现Bundle,是个比较大的挑战,有些部分必然会跟编辑器核心结合得比较紧密,对于我这种直接使用Scintilla控件实现的方式,很有可能需要修改Scintilla的源代码提供必要的支持。今天一想,其实如果基于我现在的Code Snippet的思路做下去,是很难做到TextMate的地步的,因为Bundle能完成的功能很多,输入输出条件也有好几种,而code snippet只是其中的一种而已。如果只是沿着把Code Snippet强化这个方向发展,最多实现到TextMate中Tab trigger的那种地步,而这些正是我之前一直在考虑的以为是Bundle的东西。小瞧了啊!没办法了,一步一步来吧。
昨天在QQ上跟人交流,知道一个诺基亚的手机应用开发大赛,到6月10日截止提交作品,到9月评出结果。现在算来还有足足2个月,不过我并没有好的题材。他是做图像处理方向的,而且是用QT的,所以移植到Nokia的手机上应该工作量比其他人小多了吧。另外他还给我看了一个老外做的画图软件,那界面真是赞啊!如果不是做像IDE这种严肃型的软件,其他的大众类软件真的得好好设计一下界面。
前些天Firefox自动升级到3.6.2后,看到Firefox也用twitter/facebook/blog进行推广了,看来这是大势所趋啊。之前试过几次想创建一个组织型的Facebook账号,结果一直没成功,今天发现原来是创建错类型了,Facebook有专门的为产品/组织等非个人形式的个体创建页面的入口。于是今天就在网站上加了twitter和facebook的链接,至于blog嘛,众所周知世界上最成功的blog营销案例,在软件行业应该算Joel on Software,不过Joel在那篇宣布以后不再写blog的文章中提到过,要靠blog聚集人气,不光要写自己公司的产品,还要写关于软件开发的方方面面,这样才会吸引各种相关读者的讨论。可是,我现在的致命缺陷是,我当前的英文水平完全不够用来写blog,真郁闷啊!
这几天终于把两个软件都打了个包,上传到主机空间中去了。
花了近一天的时间,在100多个国外的软件下载站用PAD的方式提交了一下。纯粹的人肉提交,不过我对这个效果一点都不看好,但也仍然是不能放过的,据说有的人能找到500个提交站,不用工具还真是很吃力的一件事。也有人说,只要提交几个主要的站点就行了。当然,download.com,奶牛站,softpedia和BrotherSoft我也都提交了的。不过前两个现在已经太牛气了,不交钱的话,是要等几天十几天甚至几十天也是可能的,我当然是用免费的,等吧!
网站也改了很多,不交流不知道自己的问题。去JoelOnSoftware的论坛上自曝了一把,虽然没几个人回复,但回复的几个人确实都指出了一些问题,自己绝对想不到的问题,而且那些老外说话也真是直接,幸亏我对英文表达的语气和情绪不是很敏感,如果是中文说的,我可能就出离愤怒了。但不管怎么说,指出问题对我来说是好事,修改了一部分,有些东西我现在没条件改了,比如要做个醒目的logo,除非以后去找美工。
另外,又去cnsw的论坛上寻求友情链接了,可惜也是没几个人响应。
昨天还被人发现程序打包有问题,看来VC2008的Redist还是要自动安装的好,省事得多,安全得多啊。
今天突然想起来,在wikipedia上添加一个词条,应该有些作用吧。嗯,明天就去加两个页面去。
这两天整调试器,经过不怎样的努力,到现在为止,功能上基本算是具备了,不过就是剩下些bug,主要有:
从debuggee发送过来的信息有时候经过XML解析会出错。
从debuggee发送过来的信息,有时候没有调用栈信息。
断点工作不正常。
有时候刚启动debuggee,debuggee就崩溃。
明后天就集中精力修改这些问题了,哈哈!
前次说到,我觉得我把wxScintilla的代码合得有问题了,我的程序中使用了wxScintilla不能多选。其实是我毛躁了,没认真看Scintilla的文档。其实当时我也是浏览了一遍代码的,发现在wxScintilla中处理用户输入后,就直接转发到Scintilla的平台无关的代码中去了,而这部分平台无关代码我基本是严格复制了官方Scintilla的代码,所以照理是应该没问题的。昨天在整理《Free Software Collection》一文时,考虑到用什么软件来替代UltraEdit,结果发现SciTE的列编辑模式已经可以做得跟UltraEdit很接近了,看了看修改版的SciTE-Ru,也同样如此。当时我还有点怀疑是不是需要在容器应用程序中做单独的处理,想想又有点不太可能。看了一下SciTE-Ru的配置文件,发现是有这么个选项的,后来就去看Scintilla的文档了,看到在Multiple Selection & Virtual Space一节里,确实有相应的设置选项。
土了啊,代码合得没问题,哈哈!
这两天又用wxWidgets,不得不感叹一下,资料实在太少了,只有一个现成的manual,其他时候就只有看看CodeLite、Code::Blocks的源代码了! 到今天为止,修改了脚本扩展的功能,可以在一个描述文件中定义多个扩展的信息。对于主菜单来说,倒是勉强够用了,不过当时因为想让描述文件中对扩展的描述尽量通用,将其他的信息都写到脚本里去了,现在看来如果要对工具栏也使用脚本扩展,那么这种方式实在太不方便了点,还是应该把这种静态配置信息的都放在xml格式的描述文件中,脚本中应该只有动态的逻辑。所以还需要修改。 今天又忘了,wxWidgets的程序如果使用Lua扩展,而扩展又装载wxLua的话,wxLua的二进制文件不能用和wxWidgets程序相同的wxWidgets二进制动态链接库,不然会出现各种奇怪的问题。这是让我目前比较头痛的问题。我现在是用MinGW来编译wxWidgets和相关工程,那么一来wxLua就只能用VC或其他编译器编译了,但我今天试了OpenWatcom和Borland C++ 5.5,连wxWidgets都编译不过,郁闷!
这是这三天来忙碌的成果,其实实打实只有近一天的时间是花在这个上面了。前天差不多提交了50个,昨天休息了,今天则是差不多提交了90个左右。本来说是一个150的列表,其中有重复的,有需要back link的,有类型不合适的,还有其他一些原因的,最终没有提交成功的,所以估计最后的总数在140左右。 今天开始就新的内容了,嗯!
原本我提交的时候,都是老老实实一项一项地填写软件信息的,虽然也知道有PAD,还装过个自动生成软件,但一直没用上。今天突然觉得应该多提交些网站,于是从cnsw论坛里找了批下载站的地址,开始提交,猛然发现大多数站点是只接受PAD方式提交的,于是没办法咯,只好老老实实生成各个PAD,再提交。 不过这样下来,发现用PAD提交,既然没有软件自动提交,纯粹人肉也不是很费时间啊!
昨天跟一个以前的同事在QQ上聊天,说到他有朋友是卖电脑的,问有没有什么软件可以OEM的。想到要OEM,必然要大众,要傻瓜,要新潮。于是我随便想了想,倒也不是真想去OEM,只是最后想到AV类的软件,实在是极其巨大的市场! 于是我又发散思维地想了想,最后觉得这类型的产品是有利可图,而且网上代码和成品软件很多,开始涉足的技术难度应该不是非常大。 唉,为了快速圈地,只好先投身AV事业了!
我到现在还是没有掌握到Windows图形界面的真正规则,只能使用各种现成的类库、组(控)件、框架来做界面。很多效果如果默认的控件不能提供,需要自绘什么的,我就傻眼了。 昨天又花了不少时间在做界面上。本来是想在一个Pane上放在一个自绘的ListBox的,结果问题不断,困难重重。其实到最后发现所有的问题都是只要使用适当的窗口风格就可以解决,我大汗!
今天偶然发现在svn trunk中的wxWidgets已经支持Ribbon了。在更新了代码后,我还特地用VC2008编译了一遍体验了一下。总的说来,可以算是Ribbon了,但感觉没有像XTP、BCG或MFC v9.0中的那么舒服。我看的是它自带的那个sample,还带着Windows标准窗口的标题栏,没有左上角的按钮和下拉菜单,也没有右上角的按钮。不知道是sample中没实现,还是wxWidgets本身就不支持。不过我想么,用wxWidgets本身就说明是重点关注它的跨平台可移植性,就不要关注这种平台特定的东西了,包括那GDI+也是。它既然号称look and feel native,那么代价就是界面不容易做得很有个性,就只适合做些严肃题材的软件了,比如IDE。 今天又看了下MSDN中对VC 2008 Feature Pack中对MFC界面增强的介绍,让我有点儿小小的郁闷,之前是过分谨慎,或者说固步自封了,没早点尝试这个增强库,而一直盯着XTP不放。今天看来,绝大部分需要的特性,在这个Features Pack中是提供了的。只不过现在还没仔细看过它的各个sample的代码,不知道它到底可以实现怎样的效果。
升级程序中有一个热替换功能,呃,这个热替换,其实是我自己发明的词,意思是如果EXE、DLL之类的文件正在执行,文件是不能删除的,那么升级时也要能被替换成新版本的文件,而不需要相应的进程退出,这就是所谓的热替换。 之前也一直陆陆续续有bug报上来,说热替换不成功,但有时候又是成功的,于是也一直没放在心上,把它归结于Windows这个API可能有问题,当然更可能是自己用得不对。直到昨天自己再一次调试时,发现一个诡异的现象。升级程序的可执行文件叫updater.exe,其中加载了dbghelp.dll,当我升级这两个文件时,必然需要热替换了,结果发现,在文件下载完后,替换确实成功了,dbghelp.dll确实已经是新版本的了,可是当升级程序在弹出提示框,提示用户升级完成后,用户点击确定,提示框消失,那个dbghelp.dll文件又诡异地变回旧版本了!一连试了几次,都是如此,简直就是灵异事件了。 当然,不可能真是灵异,这种单线程的逻辑调试起来还是比较简单的,单步跟踪了一会儿,就发现,原来在在提示框消失后,会调用一个结束处理过程,这个过程中首先会判断当前是否正在升级,如果是,则中断升级过程,并把已经替换掉的文件还原回去。而刚好这段代码写得有问题,把是否正在升级的标志置位,放在调用这个结束处理过程后了,于是总是会发生回滚还原的操作。问题的解决很容易,只是调整一下两个过程的调用顺序就可以了。
这周开始投入环境组网绘图功能的Demo实现。说简单点,这就是一个图形编辑器,就像Visio之类的。以前也有过自己使用GDI画图形的经历,但那时更简单的一点,没有要求图形可以移动,所以实现时做的事更少些。虽然这次说是做Demo,但我为了以后能以这Demo为基础,继续实际项目的完全实现,在初期就做了不少事情,费了好些心思。 首先是程序架构上,基本上是按照实际项目的设计来做的,以后也不用做大的修改和调整。界面上会有的元素,都留出位置了。花了近2天的时候,才把主界面的框架搭好。昨天又花了1天,把输入的数据源那部分功能也差不多完成了。今天才开始实现真正的绘图功能。 这次Demo主要就是为了预研或显示绘图功能,所以这里需要投入的精力更多。项目使用MFC开发,不使用任何其他第三方的库,传统而显而易见的作法是在CView上进行绘制。本着尽量OO的原则,最先可以想到的是,每种图形元素,可以用一个独立的类来表示,而所有这些类,有一个公共的基类,在基类中声明接口。以前的设计中,我只是让每种图形类保存了各自的位置和类型信息,并实现一个绘图接口。这次我突然发现,如果把相应的响应用户操作也放到各个图形类中实现,才更合理。比如点住鼠标进行移动,这得让图形类自己决定自己该进行什么动作,像一般的矩形,就可以直接将整个矩形进行移动,像折线,则可能只是在中间的折点进行移动。于是一般说来,这些图形类应该能处理鼠标的按键按下,弹起,光标移动等事件。现在觉得这样的设计是理所当然的,可在以前,我是绝对想不到这点的,也确实曾经把这些操作都放到外面统一分类处理。而且自从知道了Loki::Factory这个模板类后,对于这种大批类的操作,我有种近乎执着的热情想让它们不被任何除了这工厂之外的其他模块知道,直至不知道它们的存在。有了这一批图形类后,就需要一个管理器来维护这些图形类实例化出来的对象。这个管理器完全将这些图形类实例的创建、销毁、任务分派等与界面(CView)隔离开来。对于界面来说,图形对象管理器可以完成所有功能。 再说代码实现方面。这次专门看了一遍GDI+的SDK,准备试用一番,嗯,不算试用,是实际用上了。MFC中使用GDI+没有任何限制,在CView的OnDraw方法中把所有图形绘制一遍即可。当然也有双缓冲以免闪烁。网上的用GDI+实现双缓冲的文章和代码都很多,但一般说来只分两种:1、标准的GDI+做法,临时创建一个Gdiplus::Bitmap,将所有内容都画到这个Bitmap上,再将这个Bitmap画到设备上去;2、GDI风格的做法,先创建一个内存DC,GDI+都向这个内存DC画内容,最后将这内存DC都BitBlt到设备上。经过我的实验,发现第1种方法的资源消耗比较大,速度感觉上似乎也慢一点,但没具体测过,没实际数据来证明。于是我换用第2种做法,网上有一个很流行的CMemDC类,使用非常方便。但等我这样实现完后,发现移动某个图形时,需要刷新整个绘图区,还是会闪烁。上网随便搜索一下,发现一个很简单的解决办法:处理WM_ERASEBKGND消息,直接返回TRUE就可以了。
昨晚坚持到1点多,做了两件事:1、验证GDI+在MinGW中的使用;2、编译wxWidgets中access这个sample。 GDI+在MinGW中的使用,在网上有不少方法,但绝大多数是不行的,至少都有点小小的问题需要自己修改一下。我本来是没想过有这方面的需求的,也是因为最近想用用GDI+,就顺便想试试MinGW是否也可以。很快就搞定了,先到这里下载一个包含GDI+的头文件和库文件的包,然后把所有头文件解压出来放到MinGw的include目录下面,再把库文件放到MinGW的lib目录下面,其实我没用这个包里的libgdiplus.a文件,而是用reimp.exe重新生成了一个。网上有篇文章说,reimp.exe后面的参数是GDIPlus.dll,其实是错的,看一下reimp.exe自带的命令行参数说明就知道,人家明明是接受一个IMPLIB嘛,所以要跟GDIPlus.lib,之后会生成libgdiplus.a和gdiplus.def文件。这些文件准备好后,可以试着写个小程序编译一下,我就没自己写,直接试着用MinGW编译wxWidgets,带GDIPlus编译,中间会报两个错,错误提示很明显,只要打开那两个文件,把它报错的地方,定义类成员函数的签名的地方,不用加类名作用域就可以了。 编译access则花了我不少时间,因为其中不少时间是在等待wxWidgets库的编译。如果使用默认的编译选项,最后可能也可以得到一个可执行程序,但在运行时会弹出消息框说要定义一个什么wxUSE_ACCESSIBLITY之类的宏。这时可以修改一下access的makefile,在编译命令行中加入这个宏定义。再编译时,可能到最后一步是说某些符号链接找不到。我当时的第一反应是,编译wxWidgets时没有定义这个宏,于是修改src/msw/setup.h中的定义,将这个宏的值设为1,再编译,到最后也是说找不到一些符号链接,这才意识到是没有链接相应的库,还是修改makefile,加上-loleacc,给wxWidgets和access的makefile都要加,就可以正常编译过了,运行access也可以正常工作了。
看到搜狗输入法网站上有那么多皮肤,想到哪里可以利用一下。最后想到,桌面时钟啊,以前为了弄些皮肤来,还找了不少其他的桌面日历桌面时钟之类的小程 序,把它们的皮肤里的图片都抠出来,然后转换成自己的程序可以用的格式,还真花了不少时间。输入法的皮肤与桌面时钟的布局有些微差别,于是只好只用来显示 一下数字了,不能显示那种模拟钟面的了又花了近8个小时吧,其中还有不少代码是直接复制的。好在搜狗皮肤文件是用ZIP打包的,这比较方便,原先写的那块 解压缩的功能是调用7z实现的,那接口太繁复了,不好用,还自己特地写了个小小的dll来简化,但还是怎么看怎么觉得不爽。这次就索性全部改成zip的, 从codeproject上找了个解压zip的代码。 刚弄得可以显示出来的时候,发现显示的字体有点问题。首先是字体很小,其次是字体显示部 分是透明的,颜色不明显。字体小我倒不是很关心,但颜色不明显就比较严重了,属于不可控问题了。后来乱试了一下,偶然发现用GDI+来写字时,字体不要从 HDC那里获取,而要直接从字体名称和大小创建一个,这样就可以了,两个问题都一起解决了。 演示如下:
本来想当成二进制数据一样把文本内容以Blob形式存入Sqlite3的,结果整了半天,虽然最后存是存进去了,好像不是像我预想中的那样写二进制的Blob,而是就是作为文本存入了。不过倒是知道了对于大块数据的操作,在简单的SQL语句中不能方便地实现时,可以用sqlite3_bind系列API,在SQL语句中可以用问号作为占位符,然后将数据bind到各个占位符上去。这样一来的SQL语句要用statement来执行。 存进去后,取出来也是一个问题,本来以为Blob么,二进制么,还专门从别处移植了一段代码过来,结果那段代码可能有点点问题。反正最后我也是看出来了,因为我是原样照搬地把数据存入的,那么还是原样取出来就行了,我大汗!真不知道如果哪天我真要存入一段二进制数据时,应该怎么办了!大概,存入的方式也要跟着改吧。
不知道什么原因,我的机器上什么VC2008命令行来编译项目,无论是devenv.com还是devenv.exe,都会占满CPU,而真正的编译进程cl.exe却一直慢吞吞地,几个文件的小项目,也不知要等上多少时间,在持续集成时实在忍无可忍。 不过因为之前有一段时间专门学习了一下如何使用bjam,所以我就决定在CI上,使用bjam来构建项目。统计了一下我的项目的情况,有用MFC的,有用WTL的,也有用wxWidgets的,有用VC编译的,也有用MinGW编译的,无论哪种情况,bjam都可以满足需求。 使用bjam的一个比较方便的特性是,它能比较智能地自动为不同的编译器套件使用各自的命令行编译选项,这样使得一个bjam脚本可以同时不同的编译器套件来编译。不过实际使用过程中,还是有些需要区别对待的地方,这可能是因为bjam主要用于boost的构建这个目的而产生吧。 比如对于VC和MinGW,可能链接的库文件是不同的,要么是文件名不同,要么是所在路径不同;链接选项可能不同,也许是boost的原因,bjam在构造exe时,默认是使用控制台子系统,所以需要自己在链接选项中自行指定使用Windows子系统,而该选项在VC和GCC中有细小的描述上的区别。 bjam的另一个比较方便的特性是,它能自动寻找编译器套件默认的头文件路径和库文件路径。这比使用makefile要方便太多了,比如在MinGW中编译一个C++,注意,是C++,不是C,的程序,需要仔细地设置引用路径,而bjam中完全不需要,只需要一行代码就能搞定:exe Hello : Hello.cpp ;这个特性对我的情况来说也是很有帮助的,比如使用MFC的项目,鬼知道它要引入多少头文件路径,还有就是有个工程设计成既可以用VC编译又可以用MinGW编译,所以这又省了不少事。 再扯一个跟bjam关系不是很大的东西,编译使用了wxWidgets的项目。有一个小工具程序,可以方便地得到指定路径中的wxWidgets在编译时使用的选项,那就是wx-config。通过这个小东西,在编写编译脚本时,又可以省掉不少事。在http://wxconfig.googlepages.com/上可以找到Windows的移植版本,不过在bjam中使用时,会有一点点小问题,就是它的输出内容都在最后添加了一个回车,而bjam并不能让用户方便地设定编译选项在命令行上的先后顺序,所以如果恰好它的输出结果被排在命令行的中间位置,那之后的那些选项就被断开了,shell则认为这是两条命令,所以会出错。好在这个Windows移植版本提供了源代码,下载下来,自己稍微修改一下,也就是在输出的那条语句中把最后的std::endl去掉就可以了。 VC在支持预编译头文件时,一般是指定stdafx.h文件,然后加个编译编译选项来实现。在bjam中不能这样直接加编译选项来达到这个目的,而是专门提供了一个叫cpp-pch的规则来实现。不过,对于只在CI上才执行的bjam命令,有没有这个功能都无关痛痒。 VC有个很好用的特性,auto-link,boost就使用这个特性,这也使得在VC上使用boost比在其他编译器套件中要方便,它默认链接的都是静态库,使得发布都省了一些事。在bjam中使用时,只要设定好boost库文件的路径,其他的就不用管了。 在使用了MFC的项目中,会有一些特定的选项,比如它需要再指定程序的入口,这些工作本来都是IDE默默地在后台完成了,使用bjam时就需要自己留心了,一般的做法就是直接看项目属性中的命令行一栏,把一些个性化的设置都提取出来写到bjam编译脚本中去。
回来整了几个小时,没搞出什么花样,只是把tab页对象换了个地方。本来是没想到要换的,只是今天突然想起,要截获tab页关闭的消息,于是折腾了那么久,发现在原来的那个类里搞不定,不知道是什么原因。开始我只是想试试直接用wxFlatNotebook对象的Connect方法,可是根本不知道那些参数要怎么写。后来我把那类从wxEvtHandler继承了啊,消息映射也加了,但就是不行。后来看到wxFlatNotebook官方的sample里是把这消息映射放在一个wxFrame里处理的,于是我也照样学样把它放到MainFrame里去了,果然能截获了,而且从设计角度讲,这也比之前那样好,因为这个wxFlatNotebook应该是全局使用的。只是没弄懂原因,有点不爽。
无论是软件,还是程序库,应该选定一个并不太旧的稳定版本,一段时间内,比如半年,一直使用该版本。 一个明显的例子是之前用4.3.2版的gcc编译好的wxMSW,后来年到4.3.3版的gcc了,就下载下来试用了一下,发现原来的工程死活链接有问题,报什么虚函数找不到云云,再换回4.3.2就又可以了。由此看来,4.3.2和4.3.3编译出来的.o文件可能在内存等方面有变化。我也不想再花时间去用4.3.3编译一遍wxMSW了,太浪费时间了,而且如果要换,就要把其他相关的库都换一遍,至少包括boost,Xerces-C++,wxLua,青春啊,不能就这么耗费掉啊!
半生不熟地用着wxWidgets,全是照着代码改的,勉强能运行起来,不过似乎用gcc编译出来的release版本有时候会报错,不知道是哪里出的问题!可能是哪里资源没正确释放什么的吧! 界面的框架算是搭起来了,排除掉那个报错的bug就比较完善了。接下来完成插件扩展机制,一大块功能就可以用脚本完成了。
这次回老家过春节,年前几天没事,就着手做那么个小东西。这个小东西的原始需求是从老大那里听来的,老大则是从其他同事那里收集来的,主要的需求是,能自动从指定的路径下找出所有可执行文件,并添加到菜单项上,点击菜单项便能运行这个可执行文件。 这个需求的意义不考虑,直接进到主题,如何实现。刚开始我以为从网上应该很容易找到一个免费或者开源的项目来满足需求,在网上逛了几圈后,只注意到两个有点关系的项目,分别是Launchy和TextBox。我想了想,决定整合这两个项目的特点来做,至于最原始的那个菜单项的需求,就变成一个次要特性了。 主要的设计和开发大概花掉我8天时间,而且每天投入时间应该超过8小时,所以还是比较可观的,尽管功能看起来确实简单,而且迄今还有些未实现的。 程序最终使用VS2008开发,界面用WTL写,VS2008没有WTL相关的向导,装个VisualFC插件可以简化一部分这种工作。其他用到了嵌入式数据库sqlite3,用于保存搜索到的文件信息;用到了msxml,基本是必备的配置文件解析和保存方式;用到了Lua,实现了一定程度上的外部脚本扩展;还有boost、STLPort等等。 总的说来,这个项目的最大几点收获是:一、熟悉了WTL的使用;二、熟悉了Sqlite3的嵌入;三、对用脚本语言实现C++程序的扩展,有了一点心得。还有一些与技术无关的收获:思维导图确实是一种辅助思考过程的好工具;在wiki中随时安排计划,记录进度,撰写文档是一种好的实践。
幸亏有Code::blocks和CodeLite两个的源代码可以参考,可以省事不少,不过还是发现,要像现在用MFC一样的比较熟练地使用wxWidgets仍需要先阅读一些基本的资料,当然wxWidgets的manual也是必不可少的。 学习一种新的GUI框架的使用方式,关键还是在于了解并掌握它的消息处理机制。通常见到的GUI系统都是消息驱动的,所有所有的编程框架都不可避免地要有一套自己的消息处理机制,而且这套机制的设计好处,直接影响到整个框架的运行效率和使用效率。 总的说来,我感觉目前wxWidgets已经有点庞杂,好处是有些问题可以有多种解决方案,坏处是增加了学习成本以及降低运行效率。总觉得它不但最终生成的可执行文件体积大,而且运行效率太低。不过似乎用gcc编译出来的代码,运行效率也不如用VC编译出来的。假设能用Intel编译器来编译,是不是运行效率能更高呢? 现在用wxWidgets来写程序,还有个比较麻烦的问题是,跟用MFC开发相比,缺少一个好用的开发工具。以目前凡事都追求效率的情况来讲,写程序早已不是随便找个文本编辑器就能写代码的时代了,不光要有基本的文本编辑能力,其他自动完成、重构、提示、引用跳转、向导等等,无不影响着程序员的心情,以及开发效率。从这方面讲,目前已经没有哪个环境能跟VC+MFC比了。用vc也能写wxWidgets程序,但跟开发MFC程序相比,它缺了各种向导,比如Property视图,可以直接为各种系统消息、命令ID生成对应的函数声明,还有常用类派生的虚函数实现。 不过,总算起步了!
一直沉迷于网络小说,完全属于玩物丧志的类型!今天无聊完,郁闷完,打开VS来,决定先把框架搭起来再说。 总的说来,这是一个需要用外部脚本和配置文件协同扩展才能让业务逻辑正常运行的系统,而C++部分纯粹是为了实现用脚本比较困难的核心功能。虽然想了很久很久了,但一直迟迟没动手,玩物丧志是主因。 另一个不太重要的借口是,没找到好用的开发工具。微软的一个很好的实践是dogfood,很早以前看《微软的秘密》一书时就知道这个了,前些天听那微软的专家交流时,又看到这个,觉得很有趣。像Code::Blocks和CodeLite都是典型的dogfood,使用自己来做为开发工具。而我目前还处于一片空白的阶段,被Visual Assist X惯坏了的我又受不了其他工具的弱智,于是一直停在那里。今天想通了,就用VS来作开发环境好了,先用VC编译一个debug的wxWidgets,要retail版本时,就写好makefile,用gcc来编译。 这次恢复系统后,只装了个VS2008,这一方面可以让我不至于为众多的选择而分心,同时也减少多版本并存而可能出现的各种奇怪问题。前两天把原本只能用VS2005打开的WIND工程尝试着用VS2008打开,居然没崩溃,高兴之余把用WTL封装了的Scintilla代码也精简了一把,删掉了几千行代码,这下应该更不会崩溃了吧!
昨天下班为止,也没把预定的版本发出去,因为预定的需求没有完全实现,一个大的特性不能正常工作。所以今天上午就跑去公司捣腾了一把,两个小时就搞定了,比较安慰的是架构没有错,只是几处很细微的细节上犯了迷糊,尽管调试到解决了花了近一个半小时。 我有点怀疑的是有人说TDD的最高境界是不用调试,但之前的经历已经证实,我尽管有单元测试,但单元不通过时,我还是需要调试来查找原因!难道就因为我TDD没到最高境界?我想狡辩,不全是我的原因,肯定是他们的业务逻辑太简单了。这样又扯到另外一个问题,为什么我的业务逻辑会复杂,照Martin Fowler大叔的说法,如果一处代码太复杂了就,就要分解成几个简单的。可是以我现在的水平和智商看来,这是个悖论,分解后还不是要再组合在一起,仍然是复杂的,仍然逃不过调试的命运。但我又怕万一有不幸的人看到这篇文字,会提出另一个观点是,如果组合在一起仍然是复杂,那是架构有问题。那刚好把问题的责任转移到另一处,哈,我争辩不过。不过还好,我一点都不排斥调试,因为不得不赞美几句MS,他们做的VS里的调试器太好用了,或者说他们已经做出了世界上最好的调试器,别拿那些啥gdb之类来的扯淡。 在公司的时候突然想起来,我要用MinGW+wxWidgets写GUI程序,是否可以用Eclipse+CDT呢,从此可以摆脱MS的诱惑了。下午回到家整蛊了一个小时,不得不说,我还是继续用VS+VA吧,我想到的也就是个自动补全、智能提示功能而已,可惜Eclipse+CDT还做不到那样。 总之,我是个深受MS毒害的代码民工。
说话那天还在抱怨嵌入Python真辛苦,后来突然灵光一闪,马上解决了那个执行外部脚本文件的问题!既然现在已经能做到这一步了,接下来就应该考虑,能利用这个能力做些什么事呢? 总的说来,现在我已经有了嵌入4个不同风格各有千秋的脚本语言解释器的经验:Lua、TCL、Ruby、Python。以后如果有需求,我估计TCL是不会再使用了,总觉得它的语法太枯燥了点。剩下三者,对Lua和Ruby的了解稍微多一点点,但也还没达到能用来做独立应用的程度。相比之下,Ruby的那种怪异变态的语法,还是比较吸引人的,还有就是它带了那么多稀奇古怪的库,可以大大减少重复劳动,这比Lua来说,省事不少。但Lua的轻巧,却一直让我觉得是嵌入的最佳语言。实在让人难以取舍呀! 想了想,WIND就只用Lua嵌入了,因为这是一个相对比较追求性能的应用。而WallpaperHelper其实用什么似乎没多少影响,而且照现在的趋势,WallpaperHelper的体积已经不成为主要关心的问题了,功能才是最重要的。另外还想过要写打谱程序的,也要嵌入扩展。StoneBase的功能让人比较满意,但从写代码的角度看,它的架构不行,可扩展已经成了继续发展的必经之路了。但我还没想好,是用MFC,还是WTL,或者wxWidgets来写呢?
昨天说干就干,打开尘封很久的工程,添加一个窗口,把那几张现成的图片抠过来,然后计算一下桌面工作区大小,把窗口放在桌面右侧,像是侧边栏的样子。结果一开始,什么都没有显示出来,这是相对比较麻烦的出错情况,因为根据之前使用GDI+创建异形窗体的经验,这时候任何地方都有可能是出错的地点,所以要找出原因就要费点工夫。仔细对照之前写的代码,一点点的修改,终于能让它显示出一个窗口了,但是窗口仍然是窗口,没有按照预想的那样把png图片显示出来,并按图片渲染窗口形状。最后发现是在创建窗口的时候,因为心急,直接把窗口设置为桌面的子窗口了,如果把那几行代码去掉,就都正常了。经过这次实践发现,用GDI+实现异形窗体可以随意缩放窗口大小的,一般说来,要把窗口调整到需要的尺寸,通常是大于或等于图片原始大小,这时再把图片按窗口大小画上去就可以了,这种特性在绘制侧边栏的时候有用,比如可以只有小小一张图片,但侧边栏可能很长,就直接这样拉伸了。 能显示出侧边栏的底座了,就要开始考虑接下去怎么做了。鱼鱼和雅虎是两套不同的方案。鱼鱼只是能计算一下各个widget的大小尺寸,根据当前侧边栏上停靠的widget计算出其他widget停靠的位置。雅虎的稍微复杂点,它的一个widget的可见内容分为两部分,一部分是在桌面上散布的体现真正内容的widget;另一个部分可算是widget图标,停靠在侧边栏上。这样对于widget开发者来说,刷新界面时需要刷新两部分的隐性要求比鱼鱼要大,鱼鱼的只要刷新widget主窗口就可以了。当然雅虎的也不是强制要求一定要同时刷新图标,只不过有这样的表现的机会,为什么不利用上呢! 今天又偶然发现,雅虎的widget也使用了跟chrome类似的sandbox技术,从任务管理器上看多显示一个widget,就会多一个YahooWidgetEngine.exe进程,数完widget数目后,还多一个进程,我猜应该是侧边栏的。自从见到chrome后,我就莫名地对这种sandbox做法很有认同感,据说我们部门在北京的分部做的一个测试用例开发执行工具也是用的这种方式。不过相比Unix-like系统,在Windows下创建进程的开销相比就大了点,随便开了十来个widget看看,有两个进程内存占用10MB多一点,其他的都是1MB多,我估计如果它若是使用单片式结构的话,同样开这么些widget,占用的内存数应该没有这些的总和多吧。再说说由此引出的进程间通信的问题,毫无疑问,进程间通信的开销明显要比进程内通信的大,在Windows上应该更突出,不过对于像widget这种应用,进程间通信的频率和数量应该都不大,影响也倒不会太大;其次是从程序开发的角度讲,进程间通信应该更难使用,尽管Windows确实也提供了不少机制,但终归是难用啊。最后还有另外一个问题,对于稍微有点常识的Windows用户来说,这种方式是否也能得到他们的认同呢,某一天打开任务管理器突然发现有这么多相同名字的进程,会不会觉得反感呢,至少我是看到有人这样非议过chrome的。 再说点WTL相关的问题。昨天发现一个用WTL写的应用,在VS2005下编译,Debug下好好的,到了Release下连编译都通不过,删了一些怀疑的代码,还是编译不过,最后从WTL的源代码看到,原来只要在工程设置里把是否使用ATL的最小CRT关掉,就没问题了,之前也有因为这个设置引起奇怪的编译不过的问题,缺少官方正式支持的东西就是累啊,这WTL光是这些头文件包含,宏定义,就让人头大了。 最后八卦一下Inno setup,发现有时居然会out of memory,这时把里面两个压缩级别选项都从ultra改成max就好了,不知道是不是Bug?
昨天好不容易咬咬牙,把捕获未处理异常的功能提取出来封装成一个dll了。这是一个很简单的功能,所有的代码都是现成的,我只不过是把它从源代码复用的方式改成了二进制复用。当时公司里的同事说我这源代码复用的方式太落后,想叫我改成一个COM组件。而我又恰恰对COM很反感,所以一直都没动手。这次在一体化平台中涉及到2个exe程序,而只在一个主程序中用到了这个功能,有一天收到一个报告,另一个exe程序也会崩溃了,所以就有了要分离出来的想法。 提取成dll我当然不会用COM来封装,而是学MinGW中的exchndl.dll的方式,移植的主要工作是把MFC中的CString类都替换掉。这花了不多的时间,然后放在WallpaperHelper中进行测试。 除了记录了系统简要信息和调用栈信息,我还另外加了几项也许有点用的内容,包括当前系统中所有的进程、环境变量、当前进程所有的模块、所有线程信息。本来还想加些其他内容的,比如当前系统的服务信息、系统设备驱动程序信息、当前进程的所有句柄、所有文件映射、所有窗口等等,不过想到暂时这些信息也不是很重要,而且这样会让生成崩溃报告的时间更长,先还是放一边吧。 最近我想我真的是工作压力大了点,昨天下午睡午觉,梦到了很多乱七八糟的事情。最让我觉得气愤的是,居然梦到有个老女人,对我的工作指手划脚的,然后旁边两个同事也不知道在干吗,跟现实中的很相似。真是日有所思,夜有所梦,愤慨啊,竟然我的梦都被人这样强加干涉了!
昨晚在整理硬盘上的电子书,顺便想到我零星收集的n多资料,一般就是一张网页,或者一个txt文件,里面可能是一篇文章,或者一小段代码,却很可能讲述了一个技术原理或一个小小的编程技巧,我没有计算过总共有多少个这样的文件,估摸着应该有几万个吧,这些只是平时上网,看到觉得有用才收藏下来的,不像那些电子书,很大一部分是去年从一个同事那里直接拿硬盘对拷过来,有些根本不是我关心的领域的,比如无线通信之类的。 这些文档散落在硬盘上,虽然我也大体上划分了一些分类,比如algorithme、crack等等,但当真要找某个比较细节的内容时,很可能要花很多时间,还不一定能找到。于是我就想,要是有一个适用于编程资料收集管理的工具就好了。我是懒得再去网上找了,先不说能不能找到真的完全符合我的要求的软件,即使有(这个可能性很小很小啊),也不一定是免费的。以前看过几个文档收集管理工具,要么是纯粹的通用工具,缺少对编程资料的倾向性适配,要么就是纯粹收集源代码的,又缺少对文字内容的支持。所以又回到原来我说过的一句话上来,最好用的软件是自己写的。 以前用BCB写过一个电子书管理的工具,花了些时间,但实际上并不好用,界面也其丑无比,太业余了,这是促使我后来义无反顾地投入VC阵营的重要原因之一,在像XTP、BCG之类的界面库帮助下,用MFC做界面其实并不比VCL麻烦,而且以我个人的经验看来,在同等工作量投入的情况下,反而更容易做出比较专业的界面来。又跑题了,那个电子书管理程序的功能太弱,虽然当时也想过不光要能管理电子书,还要能管理普通的文本资料,但后来由于对界面的极度不满意,直到完全失去了兴趣和信心,就放弃了。 现在想用MFC+XTP写一个,数据库就用SQLite好了,不光能管理文本资料,也能管理电子书,这是我比较希望的一种方式。管理文本资料时,需要特别关注,可能有两种不同类型的内容,一类是文字描述,一类是源代码,所以要同时有两个视图来表达一份资料的内容。资料的分类管理是必须的,而且更需要的是一种比较方便的搜索功能,不但要能搜索标题,还要能搜索内容。再有就是文本资料和电子书的管理要融合在一起,看起来没有特别明显的分界,但又留有余地可以完全分离开来。 这个工具不是通用目的的,是为程序员专用的,所以用户范围可能少了点,但这也算是围绕着我的整体规划目标了,developing for developers!
项目组把mantis换成了redmine,相比之下,redmine似乎提供了更多功能,也更符合我们目前的需要。redmine是一个ROR(Ruby On Rails)应用,于是简单起见,我们使用了InstantRails这个傻瓜包,但是,有一个问题是,我们总是在InstantRails的界面上使用Mongrel启动Redmine,于是会出现一个Ruby运行的黑窗口,一直到运行结束。 从网上找了一些资料,发现至少有两种办法可以解决这个问题。一种使用Apache之类的专业Web服务器,然后安装FastCGI,把ROR在后台运行,所有外部请求由Apache来转发。另一种是使用Mongrel_service,把mongrel注册成Windows服务,这样就可以在后台运行了。于是我想试一下第二种方案。 本来gem install mongrel_service这样一条命令似乎就可以把这个gem包安装到本地,但实际上我发现我根本不能安装任何一个远程服务器上的gem包,可能跟网络环境有关。于是我只好到它的官方网站下一个gem文件下来,用gem install mongrel_service -l命令进行本地安装。这时会提示需要win32-service包,于是到Rubyforge上去找到官方发布,也下载到本地安装,然后又提示说要windows-pr,下来安装以提示说要windows-api、继续下来安装,继续提示说要win32-api,再下来安装,然后反向这个顺序依次安装,到了后来,提示win32-service的版本要是≥0.5.2或<0.6.0的,而我装的是0.6.1的,于是只好反安装,rubyforge上又找不到0.5.2的,从其他地方搜了一个源代码包,解开后,执行命令ruby win32-service.gemspec,会生成gem包文件,再来安装,又提示要VC,而且经过试验,如果是用的InstantRails 2.0中的Ruby,则要用6.0版本的VC才能正常编译。终于mongrel_service也安装好了,可以注册一个Windows服务器,启动这个服务,则用ruby运行一个rails应用,我这里就是redmine了,当然redmine需要MySQL支持,不想直接使用Instantrails了,把MySQL也添加到服务中,Apache是不需要了,启动这2个服务,就能无界面运行redmine了,哈,开源的东西,还真是有点麻烦呢!
总觉得心事重重,走在路上焦躁不安,忍不住安慰自己“熬过这个六月就好了”,心里刚刚默念完,突然觉得这句话很熟悉,似乎以前自己说过。不过要说真的说过的,那肯定得是一年前才可能的事了,去年的六月我又在烦些什么呢!确实好像这一年多来,一直过得很不顺心,每次都劝自己说“熬过这段时间就好了”,结果这样的时间一段接着一段。 计划有点宏伟,但对于我这么一个懒散的人来说,着实有点困难:WallpaperHelper——VC/MFC;SourceCoding——MinGW/wxWidgets;DCoding——MinGW/wxWidgets;CppCoding——MinGW/wxWidgets;PHPCoding——MinGW/wxWidgets;RubyCoding——MinGW/wxWidgets;PyCoding——MinGW/wxWidgets;LuaCoding——MinGW/wxWidgets;TclCoding——MinGW/wxWidgets;PerlCoding——MinGW/wxWidgets;TeXCoding——MinGW/wxWidgets;XMLCoding——MinGW/wxWidgets;Flowchart——MinGW/wxWidgets;SoftwareDiagram——MinGW/wxWidgets;NetworkDiagram——MinGW/wxWidgets;Go——MinGW/wxWidgets;Chess——MinGW/wxWidgets。
今天又读了一点Scintilla的源代码,因为要达到现在比较流行的AutoCompletion的下拉列表,旁边还能显示一个tooltip描述选中项,那种效果,所以要先熟悉一下代码流程。 总结一下思路,要至少增加2个消息,用于显示或隐藏描述选中项的tooltip用。增加1个回送通知,用于告诉用户有机会对选中项进行额外操作,这里也就是显示这tooltip。修改listbox的显示方式,主要有效内容要加粗,其他的不加粗。修改选中项上屏函数,用于过滤出确实要上屏的内容。 总的说来,工作量似乎并不大,但实际上我却很懒得动手,而且为了以后发展的需要,最好这部分功能能合入官方源代码中,而确实Scintilla的原作者Neil Hudgson曾经说过,自己不会去做这个功能,并且并没有说,即使别人贡献了这样的代码,他一定会合入。 今天顺便看了一会儿notepad++的源代码,有几个小功能还值得学习,不过我个人认为这代码写得并不好,至少不如Scintilla的代码,但有些设计确实不错,而且它还能支持简单的插件。但我认为它最不好的是,似乎它使用自己修改的Scintilla,这样它的通用性就不好了。
今天突然有个想法,关于前段时间的用WTL写个围棋打谱程序的念头,是否可以把棋盘、棋子绘画动作也抽象出来,棋子的位置、走法规则都提取出来,有一组严谨的约束,而且这组约束可以通过配置文件,或者脚本来描述,最后,C/C++代码则只用来完成具体的绘画操作,对这些约束完全一无所知,比如它只知道在哪个坐标画一个什么样的图形,而为什么要画这个图形,这个图形有什么其他的含义,都不是它需要知道的。 如果确实能高度抽象地完成这个描述,那么带来的灵活性则是非常有用的。对于单纯是一个围棋打谱程序来说,也许带来的好处并不明显。但再换个角度考虑,在这一套架构下,很容易通过写少量脚本或配置文件,而不需要修改一行C++代码,一个围棋打谱程序立马摇身一变,成了一个象棋打谱程序,或者五子棋打谱程序了。这样的诱惑,对目前的我来说,实在是巨大呀! 这个想法的灵感,源于Eclipse的编辑器,《Contributing to Eclipse》中有一小段描述可以贡献一个编辑器,当时看到这段描述,甚是激动,差点想把那个IDE项目中的编辑器模块也这样做了。这次又联想到打谱程序,同样是画棋盘棋子的,只要合理设计,理应也可以达到类似的效果。 不过随便想想,以在世界范围最流行的4种棋类(围棋、中国象棋、国际象棋、五子棋)为目标,要想尽可能简单且灵活地实现,还有点困难。如何表示棋子的类型、如何表示行棋规则、如何定义精确的棋子位置以便程序绘制等等,都是摆在眼前最大的障碍。五子棋最容易表示,只有2种棋子,直接落子,虽也有像五手两打,三手交换之类的奇怪规则,但这些似乎都是在棋谱解析部分的工作。围棋则略为复杂,一个明显的问题是,要能计算出死子,并提出棋盘,这个工作如果纯粹交给外部脚本做,怕是会有心无力,但照现在的设计思想又不能让C/C++代码来做。两种象棋就更复杂了,棋子的类型就相比多了很多,每种棋子的合理行棋方式又都不一样,虽然从纯粹打谱的角度讲,比围棋、五子棋也复杂不了多少,但是在棋谱录入时,则很让我头痛了,如何表示一个棋子从一个位置移动到另一个位置,是否可以移动,移动后是否棋子的属性有变化(中国象棋中兵过河可横行,国际象棋中兵到底线可变身),移动后是否影响了其他棋子(吃掉了)等等,关键是一套界面和逻辑的交互协议,不能设计得太偏向于是为某种任务而特意为之,但又得有足够的信息在两者之间传递!
今天在公司网上看到一人发了个Komodo IDE,装来看了看,猛然发现它是基于Mozilla XUL技术实现的,有点诧异,居然还真有用XUL技术开发的商业软件。然后就跟公司里的另外一个人讨论了一下,那人比较了解XUL,在去年还做过技术选型工作。 从中我了解到,有一种叫Remote XUL的技术,可以使得通过Firefox浏览某个页面,界面效果跟通用的桌面软件差不多,但实际上却真真实实是部署在远程服务器上的。其他能达到类似的效果的有JAVA Applet,或者MS的ActiveX,好像Adobe现在在搞的AIR也差不多,有种让人惊艳的感觉。看来该是有必要学一点这方面的新技术了,一直以来觉得跟Web相关的,都不是很感冒,但现在看来,它混淆了B/S和C/S,即桌面和浏览器的概念,很有意思啊,比如,假设有一种能适应各种浏览器的这类技术,那么做一个Web版的IDE什么的也不是问题了。 除了这种远程部署的界面技术,还有其灵活的可扩展框架也是让我感兴趣的。那人的胶片中对Eclipse RCP和Mozilla XUL进行了简单的比较,结论是更看好XUL的,不过我个人的观点看来,两者单纯从可扩展性上讲,各有优缺点,不相上下吧。XUL体系使用C/C++实现具体的界面控件,然后用XML描述界面布局和事件响应,用JavaScript完成实际的业务逻辑,响应XML中定义的事件,调用C++代码作出具体的动作。XUL要创建出新的界面控件比较困难,只能用已有的控件组合成新控件,所以像Firefox就实际上提供了扩展和插件两种不同的机制,扩展就完成只使用XML和JavaScript实现,而插件就可以实现比较高级的像内嵌Flash播放器之类的功能。总之,简单看来,相比Eclipse的实现方案,XUL并没有哪里特别不如,或哪点特别突出,只能说也是一种不错的机制。倒是让我多了解了一种扩展方式,自己设计可扩展的软件架构时,倒是要好好考虑一下了。
写个围棋打谱程序,这个想法好多好多年前就有了,上高中的时候就有了。大概是因为当时对围棋有点点感兴趣,纯粹的叶公好龙型的,虽说感兴趣,却没有认真学过,只是知道大致的规则而已。这些年,看StoneBase的发展,觉得挺有趣的,不过它的实现不是我喜欢的方式,所以我突然又决定自己写一个,而且想了想打算用WTL来写。 开始是有点犹豫用MFC还是WTL的,因为MFC相对较熟悉一点,而且有Xtreme Toolkit Pro可以用,做炫酷的界面确实方便。但是后来想想用WTL就看中它生成的可执行文件体积小巧的优点,看看StoneBase当前最新的4.6.1版本,exe文件也就只有8.24MB,而假如用XTP的话,当是它的dll就有5.5MB,还要加上MFC的dll,大概是3.6MB,这样附属的文件体积就已经超过StoneBase主程序文件大小了。还有一个想法是,希望能借此机会好好学习一下WTL的使用。 至于要做得什么样的,从特性外部行为上看,可以模仿StoneBase和MultiGo。比如首先要能支持几种国内常见的棋谱文件格式,还要支持棋谱库,MultiGo没有,StoneBase 用了一个叫Absolute Database的嵌入式数据库,我猜大概因为StoneBase是用Delphi开发的缘故吧。我可以用SQLite来替代的,不过StoneBase有一个很庞大的棋谱库,所以也需要能以某种方式读取它的数据库。需要有良好的打印支持功能,肯定很多情况下,需要把棋谱打印出来,对着纸自己敲棋子,那种感观享受不是电脑程序能比的。要有方便的棋谱输入编辑功能,要有格式转换功能等等。 具体实现上,我想尝试一下纯插件框架,也即用C++实现一组核心的功能,其他高层的业务逻辑全都使用外部脚本扩展实现。这种框架有点像Eclipse,又有点像Mozilla的XUL方案,要扩展的地方包括主菜单、工具栏、弹出式右键菜单、棋谱格式读写等。
昨天突然下决心要搞一下月历显示部分。惰性总是我的最大困扰之一。慢慢调试,发现其实要实现这个功能代码并不需要多少,大概不到100行吧,之前实在是高估了困难以至于一直懒得,也是怕的去动手做了。不过虽然代码量不大,到最后可以基本稳定地用也是花了不少时间去慢慢修改的。 今天去驾校上了理论课,由于晚上睡得晚,早上起得早,加上中午还没午觉睡,于是上课时间都被我用来睡觉了,都不知道讲了些什么。 回到家大概5点左右吧,还算早的,于是又写了一会儿代码,把农历也显示出来了,哈哈,虽然原来打算能让农历显示在右边或下边,可以灵活配置,今天实现的时候发现如果要显示在右边,似乎比较麻烦,还让它只能显示在下边吧,嘻嘻。 这样就可以使用那些大块留白的皮肤了,真是happy呀! 再把配置模块做一下,就基本可以拿出去让人用一下了,只是GDI+输出文字时,有时候会输出不是预期的效果,原因至今不明,还待以后慢慢定位。
一直以来只用MSXML进行XML操作,在Windows平台上,确实是一个非常非常好的XML操作库。只是一直以来有点不爽的是,用它的save方法保存的东东,用记事本之类的纯文本编辑器打开看,是没有缩进格式的,就是直直的一行数据一直写完为止。想过一些办法,但最终还是放弃了,libxml2里有个叫xmllint的小程序,可以格式化一个xml文件,不过毕竟是第3方工具了,而且它依赖的是libxml,不是msxml。 下决心在google上搜了一番,英文的不知道搜什么关键字,中文的倒是找着几篇,最后觉得CSDN上的一种方法比较适合我目前的情况,因为我就是用MSXML DOM的。例子是用JavaScript写的,转换成VC还费我一点功夫,不过最后总算大体满足要求了,但是还是有个老问题,用它保存的东东,最后字符编码改成UTF-16了,而且强行插入不了Processing Instruction,晕。
自从用上了VC2008,用它来编译日历程序,就开始被Windows先进的Side by Side技术困扰着。其实说被它困扰有点过分了,毕竟是自己水平太臭,眼界太窄,见识太少。在开发机上怎么整都是好好的可以运行的,换个机器就不行了。盲人摸象般的整了几天,还是没能解决,代码是在家里写的编译的,拿着可执行文件到公司的机器就是不能正常运行。昨天晚上又在网上搜索了很久很久,终于在MSDN上看到一篇文章,虽然是以VC2005来讲的,但对VC2008是一样的原理,按照上面说的分好目标目录,做好安装包,今天拿到公司一试,果然没有原先那个什么应用程序配置错误的消息框了,终于解决这个让我郁闷了几天的问题。 不过今天偶然发现,我用GDI+实现异形窗体,在Win2003下不能显示,在公司网上找了个别人写的也是用GDI+画窗体的,也是不能显示。但装了个雪狐日历精灵的早期版本看了看,它也是用GDI+画的,却能好好地显示在上面,应该是那段代码有问题,唉,看来得用虚拟机装上2000/XP/2003,做好全面的测试才行了,不在实际的环境中运行还真不知道会出什么问题呢!
这个日历程序拖太久了,最早以为去年就能完成的,后来计划改到农历年前,以为春节几天假期里可以弄完,谁知生了场病,于是给了自己一个再次跳票的理由,回来后以为2月底前可以做好吧,可是还是不知不觉过完了2月,这个东东的进展却很小,最后就想,第1季度应该可以完工吧,现在很明显,已经是3月底了,马上就是第2季度了,前段时间只顾着看小说去了,呼呼。 实在是忍不下去了,先把桌面日历部分完成再说。 桌面日历大框架已经成形,还剩下带农历支持的月历、指针型时钟两个主要功能,先把目标放在这上面吧。 昨晚上网随便搜了一下,就找到几个看起来还可以的时钟软件。时钟软件在界面上的策略基本上跟日历软件差不多,都是可以支持换肤的,只不是可支持的灵活性有点差别。把其中两个附带的皮肤的图片抓出来,嘿嘿,我这里用一下下。
在网上看到一个英文博客,有一篇文章作者谈到他希望一个代码编辑器,或者一个IDE应该有什么样的功能。看了之后感觉还算比较客观,基本没有特别个性化的要求,对于要做这方面工作的人很有参考价值。
给江江写了一个小程序,用于自动从一些excel文件中复制数据到另一些excel文件。但江江说有问题,我也不知道到底哪里出问题了,于是想加入日志功能吧,这样至少可以看看代码执行的流程。可就在这里,遇到一件怪事,居然写文件写不进去内容!开始我是用C库里的fopen系函数来写文件的,但是什么都写不进去,单步调了一下,好像fopen就有问题,该函数返回的是一个FILE*,但看调试器里,该指针指向的内容是一堆0,好像就是打开失败,但它却确确实实返回一个有效的指针了,郁闷!于是我就试了一下用C++库里的fstream,开始看好像是可以的,于是我就把原来自己写的那个日志类拿过来用,反正里面写文件的代码就是用fstream的,不过这时又不正常了,只是零星写了点完全无用的数据进去,其它信息压根都没有,真是郁闷啊! 因为是用了那个日志类,所以OutputDebugString的输出还是有的,这就让我觉得很奇怪啊!因为下班了,于是也不想再继续深究下去了,反正用DebugCapture捕获这些输出,再导出到文件,也勉强是可以用了,呵呵。 不过这真是奇怪啊,完全没有任何头绪!
总的说来,GDI+的资料似乎还是少了点,用GDI+来实现异形窗体实在是太酷了,不过似乎用PNG这种支持透明色的图片格式最合适,如果是像BMP或JPEG这种没有透明色的,最好还是用关键色混合的方法,这种方法网上已经有n多代码了,纯API或MFC之类的封装都有。不过GDI+的用起来总会出现点莫名其妙的问题,比如我在家里用时,发现换成Win2000 Pro中文版或WinXP SP2 Pro中文版时,在窗体上用GDI+写出的文字有时候就是不正常,总是显示为透明的,一定要透过窗体下面的颜色跟背景色相同时,才会显示出正常的颜色。
跟去年一样,我又只请了年前的假,但只请了5天,2月1日开始,2月12日结束。幸亏是2月1日那天上午去的,飞机中午到了萧山国际机场,雪已经下大了,当天晚上机场就被封了。之后雪是不停地下,机场就封了好几天。爸跟我几乎是同时到家的,也是很幸运,反正如果错过了当时那个机会,就很难回去了。 之后几天都过得很清闲,每天就是写点儿代码,从早上起床,一直到晚上12点左右睡下,中间除掉吃饭的时间,其它时间差不多全坐在电脑前了。在写那个WallpaperHelper,这个东东被我搞得太大了点,粗粗分一下,有4大模块:墙纸管理、行程安排、图片处理、桌面日历。其实自己没写几行代码,全是抄的别的,像行程安排,Xtreme Toolkit Pro里就有现成的,完成度比较高的了,图片处理用的CxImage,不知道为什么,用UNICODE编译CxImage的库,就是不能正常地链接,最后很无奈,索性把整个CxImage的代码都放进工程里,于是一个很严重的副作用,每次Rebuild时,就要花多好多时间。另外还有个郁闷的问题是,在调试器里创建一个GDI+的Image对象总是会崩溃。中途还遇到了很笨的问题,我还花了好多时间去跟踪,以为CxImage的代码有问题,结果真是笨死了,居然总是想去打开一个不存在的文件,而没发觉这个文件路径是无效的,晕死。 大年三十那天晚上,吃得太油腻了,然后又喝了很多冰凉的饮料试图解渴,结果吃坏了,肚子也坏了,还感冒,有一天晚上起来后再躺下,全身发抖,却又不是因为冷,精神性(神经性?)痉挛了不知道多久,抖得人都累死了,还是停不下。一直病痷痷了4天,于是乎,连食量也被减下来了,不过倒是省了很多事。 昨天晚上7点多的飞机,这国肮,是我遇到过的服务质量最差的了,空姐的态度也不好,饭菜味道也不好,到10:20左右,顺利抵达。倒是下午我刚出家门,小丫头发了个短信来祝顺风,让我小小地感动了一把,我这人啊,真是太低贱了。
换墙纸的东东本来主业是为了能自动换墙纸,结果现在重心却移到了日历和时间显示上去了。关于界面方面的技术问题基本已经都解决了,主要是学那些日历软件的换肤功能,可以把PNG文件直接作为皮肤来加载,接下来就是要好好设计一下皮肤的机制。 早在做输入法时,就已经能实现换肤和异形窗体,那时只能支持BMP格式的图片文件,但所有代码全是用纯GDI完成,所以实现起来很简单,用API就能直接画出来,在窗口上写字什么的也很方便。但现在为了能使用PNG格式,就不得不用了GDI+,用PNG的好处在于,从图片上就能直接应用某些区域部分不同程度的透明化,BMP是很难达到这样的效果的。于是,从实现角度看,区别还是挺大的,而且不知道是不是我用得有问题,有时候它占用CPU有点多。不过暂时不管这些,毕竟能用了,先考虑一下如何有效地加载皮肤,并能比较灵活地定制和扩充窗体。 最先开始动手做这个东东的时候,原始的想法是时间显示是一个窗体的实现,日历显示是另一个窗体的实现,这样可以预见到的是对于界面部分的代码必定很大程度上是可以共用的,还甚至想过怎么把这部分抽象提取出来呢。到今天突然觉得,其实这个完全可以用同一个实现,至于显示什么内容,可以通过设计一个具有良好弹性可扩充性的皮肤机制来实现。初步想法是,一个皮肤至少包括一个图片文件和一个配置文件,图片文件用来最终描绘窗体,而配置文件则描述剩下的其它内容,比如在什么位置,使用什么字体,显示什么内容,这内容部分也是由主程序定义的一堆描述性的转义命令,例如当前日,月,年,小时,分等等。现在的困难就是配置文件要被定义成什么样,这个皮肤机制才能有足够的灵活性和后续可扩展性。比如显示内容,我可以让它是定义字体后再通过程序来输出文字,也可以是直接将另一个图片文件中的内容贴上去,我应该怎么选择呢?另外,因为想用一套程序代码实现时间和日历的显示功能,所以定义的转义命令也要考虑得周全一点,除了当前年月日,时分秒外,还需要星期、月历,也需要任意指定的某年某月某日的日历或月历,除了要有公历外,还要有农历和二十四节气、节日等等。 而这些,则还完全只限于实现一个时间和日历的功能,像现在的雪狐日历精灵,已经可以以皮肤的形式还实现计算器,游鱼等更实用或更娱乐化的内容。如果考虑到这些,这个皮肤配置文件就需要设计得更灵活强大才行。顺带还有另外一个待决策问题,这个配置文件用XML描述好呢,还是用Lua之类的脚本语言描述好?从我个人的熟悉程度来讲,XML明显好过Lua,从表达能力上讲,也许Lua更强一些,但ANT不也用XML实现了一套比较强悍的语法了么! 总之,这皮肤的机制得专门花时间认真设计一下了。
时间总是过得飞快,转眼间就三天过去了。今天放假政策跟往常不同,大概是顾及到为补放假其它加班的日子不能挤在一起吧。 三天只在昨天下午去华强北稍微逛了一会儿,还是觉得挺无聊的。今天就安分守己地又在屋里呆了一天,在整一个自动换墙纸的东东。 本来从网上已经找了一个很简单的,可以实现定时从列表中取出候选的文件作为墙纸。不过那东东真的是太简单了,除了可以换墙纸,其他什么都不能做。我的要求就多了点,光是换墙纸的要求就比较高。除了能定时换外,我还希望能分别指定每个文件作为墙纸的持续时间,过了这段时间再换,还要能分别指定每个文件作为墙纸的样式,是居中或是平铺还是拉伸。 另外,我还要它顺便能像那些日历软件一样,在桌面上显示月历,或日历,并能显示一个时钟。既然有了日历,我就希望它能进行日程管理,定时提醒了。所以日历功能要比较方便强大,最好能有中国农历,这样提醒设置可以按照农历来设,比如像爸妈的生日都只有农历的,老不记得。然后是能打印,支持年历、月历、日历3种形式,还要能自定义样式。再次是显示日历、时钟理所当然地要有skin功能,这是作为一款日历软件的必备需求。 再有,一些锦上添花的功能,比如支持用外部脚本扩展,定期执行一条命令啊,发送个Email啊,关机啊等等。不过我倒是觉得,如果这个东东想让其他普通用户接受的话,脚本扩展功能是多此一举了,因为我猜大部分的普通用户是不懂,反而会觉得这软件难用,晕!只是我最近是近乎疯狂地希望给所有程序都加上外部脚本扩展的能力,呵呵。 说实话,这里看起来似乎没多少内容,但实际做起来还真是颇费时间的呢,而且我总感觉在家里写代码,状态明显不行,很多时候大脑似乎是处理消极抵抗状态,不像在公司,在极其困顿疲倦的状态下,还能逛敲键盘,而且居然出错的地方并不多!
最近渐渐会用Boost.Bind和Boost.Lambda了,真是爽快啊。现在明白,要用Boost,就得尽量使用STL,配合它的容器、算法才能发挥功效。如果自己写了容器,也要看情况写些方法,适应它的需求。今天写了好久代码,挺累人的,到后来真的头昏脑胀了,郁闷。 回来继续搞SocketHelper,除了要有像Wireshark的抓包功能外,还要加上nmap似的扫描功能,以后有机会再搞个可以支持无线网卡的抓包功能,呵呵。 现在Wireshark和nmap都用lua来做扩展了呀,呵呵。
周末整了好久,想在程序里嵌入Ruby解释器,可是发现在MFC程序里,只要include了ruby.h,编译就会不过,说什么fd_set啥子啥子的,很是郁闷,今天在公司,同事说只要include一下WinSock2.h就行了,晕,我当时怎么没试试。 SWIG果然能一下生成一大片的代码,而且可以通过宏来比较灵活地进行配置。只是最后效果怎么样,还没有试。总的说来,自从改用VC以来,得到不少好处,主要是很多开源的东西都会主力支持VC这编译器,相对来讲对Borland的支持就要弱一些了。
没有解决,还是老样子,只知道它是要把那几个dll复制到系统目录下,把npf.sys文件复制到drivers目录下,然后安装系统服务。至于到底最后做了哪些处理,也不得而知,反正我是把网上找得到的说法都试过了,都没用。当然很多是针对3.x版本的处理,我用的是4.0版,也尝试过反编译它的安装文件,反汇编它里面一个dll文件里的导出的函数,但最后还是没有什么进展。暂时放弃了,郁闷。
一直想自己写一个计算hash的工具,而最无耻的是,我对各种密码学意义上的hash算法根本不了解,只知道有这么个东东。不过现在流行的hash算法网上有一些现成的代码,C和C++都有,比如著名的Crypto++、LibTomCrypt等等。 本来跟hash算法是完全没有交集的,平台根本用不到,最多也就是直接LoadLibrary系统自带的CryptDll.dll,里面有计算MD5的函数,这是在好些年前就知道了的,也一直丢在一边。现在因为要做一下文件共享的东东,其中避免不了的是唯一标识一个文件,而一个良好的消息摘要算法就是一种可行的方法。鉴于网上早就出现了一些针对MD5碰撞的实际例子,所以我就有点不甘心只使用MD5算法,于是把LibTomCrypt的代码抠出来封装成C++的样子。这样的消息摘要算法计算过程一般分为初始化,更新数据,得到结果3步,所以可以把每个算法都封装成一个单独的类,每个类都向外提供这3个方法,这样只要根据需要可以以相同的计算逻辑得到最后的结果。 封装好了各个算法后,再提供一个类,封装更高层次的功能,比如计算一个文件的hash值。文件需要打开,然后每次读出一部分数据来计算,最后才得到一个结果。这样的逻辑不需要为每个算法类都写一遍,写到单独的类里即可。至于该类与各算法实现类的关系,比较OO的做法是,用继承,所有的算法类都继承自该类,就自然而然地有该方法了,但似乎还需要增加3个虚函数,这样父类的方法才能调用到子类的方法,这样就多了点运行时间和空间上的开销,尽管不严重;另一个比较GP的方法是,把该类写成一个模板类,而各算法实现类做为模板参数,这样就可以省掉因虚函数引入而带来的开销了,当然带来的成本是用户使用这些类时,需要同时知道这个类的存在以及各个算法实现类的存在,而前面讲的偏OO的方法是只需要知道算法实现类就行了。 上面解决了一个向外提供接口的问题。接着又有一个新的问题来困扰了我两天。因为上面已经有一个类是对于每个算法实现类都知道其存在的,但我又发现其中有几个算法实现类中的更新数据方法逻辑是完全一样的,要把数据根据当前算法的实际需要拆分成多块进行压缩运算,所以只是其中调用的压缩算法不一样,数据长度不一样,这样的情况也是代码复用的一个场合。但是开始的时候,我不知道应该把这段看起来可以公用的代码放到什么地方。同样,比较OO的做法是写一个基类,让这些算法类继承过来,同样需要一个虚函数,因为会有一个压缩运算过程,不同的算法是不一样的,虽然函数名可以一样,所以也多了一点开销;另一个当时很不想用的办法是,像LibTomCrypt中一样,把这个过程定义成一个宏,在这些算法实现类里都写一句这个宏调用,就没有虚函数带来的开销了,但我觉得这是C的做法,而不是C++,这个场合这种做法很丑陋;后来偶然在QQ群里看到别人谈及模板应用的一种方法,得到灵感,就像WTL那样的静态多态就可以,仍然需要一个基类,但基类是个模板类,而模板参数就是自己这个算法实现类,这样通过基类中的方法仍然可以调用到子类中的方法,但又没有虚函数的开销。基本解决这个问题! 后来又遇到一个问题,不过没有解决。HAVAL算法,可以有3、4、5轮计算,不同轮数的计算中间的步骤也会有点小差别,每种计算最后的长度可以是128位、160位、192位、224位和256位。照理,前3轮或前4轮的计算通过宏定义等方法可以在某种层次上封装可相同的逻辑,这样3种算法就应该可以共用一部分代码,可是实际上,用宏定义的方法不行,第2次修改过的宏定义不能影响到上面的应用了宏调用的地方,所以实际上代码共享不了,只好重复写了,以后想想办法能不能改进。 Panama hash算法的资料好少,Crypto++的实现又比较复杂,看不懂哦!
每次看到按键精灵,心里总有种奇怪的感觉,这个东东,忽悠了好多菜鸟,也赚了不少钱吧,可我心里却觉得这不值,是忌妒吗? 最近想着,做什么程序可以集成脚本语言解释器呢! 有些情况是可以预见得到适用的,比如这些天突然想学学围棋,于是在网上找了下打谱的软件,这种软件就适用。有个叫StoneBase的打谱软件是国内做得比较好的,但它并没有第3方可扩展性,照我的想法是,对于要兼容多种格式的棋谱文件,就可以用脚本来解析,规定一种中间格式,假设是标准的SGF,把所有其它格式在主程序的主动触发下都用脚本转换成中间格式。我暂时也想不出其它更多的地方可以用脚本的了,偶然看到它的论坛上有人发了个可以自动下载TOM网站上公布的棋谱文件,于是我就想,是不是可以干脆直接支持外部工具,但是转念又一想,都已经是外部工具了,就不需要集成解释器了…… 另外还有种情况,最近因为要写Socket程序,所以想到如何方便地调试这类程序,特别是对于客户端和服务器端都还没写出来的情况下。于是我想写一个辅助调试socket程序的工具,大概的想法是,它可以做为一个主动去连接的客户端,或者是被动接受连接的服务器端,连接上后,可以看到接收到的内容,还可以由用户手动输入内容发送,这种情况下,脚本的应用就比较有实际意义了,比如可以把接收到的内容交给脚本处理一下,脚本再根据实际情况发送一些内容,这比较适用于调试协议,像http/ftp等协议用脚本就能实现一个简单的原型。这个工具我已经想了很久了,但只建了个工程,却还没开始做,如果做好了,一定是个很实用的东东。除了这样的客户端和服务器端功能外,还要有用Detours静态hook创建进程,动态注入attach到已有进程,用WinPCap或Raw Socket(其实有了WinPCap就不需要了)抓包这几项功能。静态hook和动态attach是为了看进程调用WinSock API的情况,而WinPCap抓包就是一个普通的抓包功能,因为如果光是做抓包功能,我想我是做不过那些专业的做了好多年的工具的,如IRIS、CommView以及开源的Wireshark等等,所以重要的是前几项。又扯远了,脚本在这个工具里还可以用于解析帧结构、协议等等。 当然还有种情况,就是用于像按键精灵这样的工具上。 现在有4种脚本语言是我比较感兴趣集成到程序中的,分别是Python、Ruby、Lua和TCL,但实际上TCL与前面3个放在一起并无多少作用了,它的应用面比较窄,又缺少现代语言的一些元素,而且没有什么特别有优势的特性。Python和Ruby这两个大而全,且语言特性丰富的脚本已经能满足大多数场合的要求,而Lua则完全是看中它小巧快速,特别适用对性能有点要求的场合。Boost中有Python的粘合库,Lua以前有LuaBind和LuaTinker,但好像没更新好久了,至于Ruby我还没有了解。但我想,我总有一天会自己来分别写一套简单的,自己够用的库的。
今天晚上加班无聊,就在看各个CMO团队的TeamRoom,看到介绍CVS的内容,突然想做一个GUI的front-end,可是,回来后看了看WinCVS,就想放弃了,我是不太可能做得比WinCVS还要好的!现在的软件好用的优秀真的是太多了,本来还想把ProcessHelper增强一下的,看了看Process Explorer,也放弃了,理由是一样的。还有Total Commander,直到前两天我还在想,为什么会有这么多人喜欢用这个东东,界面又丑陋,功能也不见得强到哪里去。现在才隐隐约约地感觉到,它的强悍之处在于极强的可自定义可扩展性上。它可以方便地对菜单,工具栏进行自定义配置,每一个菜单项或工具栏按钮的位置,标题,图标,快捷键关联等等全都可以自定义,并且可以以插件的形式扩展其功能。也许,它就强在这里。
这两天突然又想起按键精灵,去它的论坛逛了逛,看有什么新鲜的东西。发现多了个插件版,专注于插件发布、讨论的事宜。本来想看看是否有什么附加利润可以赚取的,但翻过几遍后才觉得,这东西现在留出来的空隙似乎很小了,大部分用户需要的功能,都有了。另外看看它的代码编辑部分,也还算完善了,再做也只能做得比它的好一点点,大多数只是脚本使用者,是不关注这部分的,另一些脚本开发者来说,原来的功能也基本够用了,不会再愿意去买个其它的软件。 暂时放弃!
这是一个总结,也是一个开端。所谓总结,即是到现在我已经发现并已尝试使用过这些东西,现在整理一下,罗列出来。所谓开端,即是从现在开始,我要好好使用这些东西,应用到实际中去,提高效率或减轻负担。 小作坊,适合于个人单干,或小型几人十几人的团队,如果对于大型的团队,我觉得我们公司那套其实挺不错的,毕竟人家花了我也不知道多少钱从IBM引进来的。所以小作坊有一点很明显的区别是,资源很有限,从硬件到软件,从资金到人力,都是很匮乏的。这里罗列出来的东东,全部都是开源的,而且是相对比较成熟的,就是为了应对上面提到的小作坊的各种可能面临的困难和不足。另外还要提到的是,这里讲的是“协助”软件开发,其实是针对整个软件开发周期中各阶段的活动,而不是单纯的在编码调试阶段的活动。最后一点,这是面向Windows环境下使用VC/Delphi等桌面应用开发人员的方案。1、建模——StarUML这个东东据说是个韩国人开发的,用Delphi写成,功能也许没有Rational Rose那么强悍霸道,但用来画个UML图、序列图什么的,已经足够了,而且安装包才20MB左右,快速轻巧。想想Rose需要多少钱,其实我也不知道,嘿嘿!2、版本控制——TortoiseSVN当然用SVN,传说中CVS的替代者,而Tortoise这个shell扩展真的方面。在Windows下用SVN如果不用命令行,就用它了,没啥好说的。不过说实话,VSS也不错,尤其是2005版文件传输效率较6.0提高了不少,而且和VC的IDE集成得很好。所以见仁见智了,对于不用VS工具的,就强烈推荐这个东东了。在单机上可以直接找个文件夹作为仓库就可以直接使用。3、项目管理——Open Workbench项目管理?我用得上吗,我自己也怀疑。但它号称可以和MS的Project匹敌,本来是一个公司开发的,后来捐献给开源社区,貌似他们也比较有钱的说,安装包还是用InstallShield做的。我大概最多也就是用来作作日程安排而已吧。4、持续集成——Cruise Control不用多说了,就用Cruise Control了,刚刚才学会,其实也没咋学,就是把同事那个脚本抄来改了改,真的挺好用挺喜欢的,现在最新版已经是2.7.1了,拿2.5上可用的脚本直接就能正常使用,而且比起2.5来,还少了乱码问题。5、Bug跟踪——MantisBug跟踪系统好像很多,商业的、开源的都有,比如FrogCreek,BugZilla、BugFree等等,选择Mantis只是因为我已经有点习惯它了,主页上有打包好的,直接运行一个批处理文件就能正常工作,特别提醒一下,要把config_default_inc.php和config_inc.php里的SMTP配置都改好,然后默认的账号administrator和它的密码root,这个我颇花了点时间去搞,开始没看明白帮助,晕!6、开发文档编写——doxygen也就是在写代码的时候插入一些规定格式的注释,然后运行一把doxygen,就能从中提取出内容生成多种格式的文档。不过似乎好像,我自己很少写注释的说,只有开源的项目才这样做得比较多。7、用户帮助文档编写——CTeX也没啥好多说的,用户帮助文档Windows上以chm/html格式的最为流行,很多大型软件公司的产品都会配上PDF格式的manual。如果想生成PDF格式的帮助文档,就用CTeX吧,这个东东还真的不错,相比Word来,完全相反的两种思想和作法。Word一开始会觉得上手很容易,所见即所得,但是内容格式一多,再进行修改什么的就很容易乱,而TeX则相反,一开始觉得很麻烦,所想即所得,但是一旦初稿已经形成,再进行修改什么的,就不容易乱了,呵呵。8、安装程序制作——Inno Setup以前用过Wise,感觉还不错,不过人家是商业软件。后来找到了Inno Setup,就喜欢上了。它用Pascal的脚本,可以调用Windows的API,可以完成很多高级的任务。其它还有NSIS之类的也应该不错,但没用过,暂不考虑了,而InstallShield一方面是商业软件,另一方面好像显得有点杀鸡用牛刀的感觉,嘿嘿。 就是这些了。
本来我也只是好奇在网上搜寻一些IDE,看看它们有哪些优缺点可以借鉴参考的,不经意间来到一个共享软件的官方站点。有些站点是很容易就看出来是一个做共享软件的,很可能就是一个人在做。这个站点卖几款编辑器,分别是针对HTML、Perl、PHP的,我都down下来大概看了一下,觉得还是比较粗糙的,所以我开始有点怀疑这个能卖出去多少,从定价上来看,Perl和PHP的编辑器要$59,HTML那个$24,但同类竞争应该是比较激烈的吧,各种免费、共享、商业软件都在抢夺这么块市场,应该有很多做得比这些好多了。不过这个作者倒是有点意思,只是一个文本编辑器,他就变出三个花样来。但我查看了一下三个编辑器的窗口类,却是不同的,有点奇怪,不知道是出于什么原因,或者说,三个产品开发的时间间隔比较大,导致作者在新开发一款产品时使用新的控件。 另外搜索到一个PHP Designer 2007,记得我大学毕业设计的时候就用过它的,当时好像还是免费的,不过现在这个要€39,它就要比前面提到的那个专业得多,记得两年前用它时就已经觉得很好用了,现在就更强了。它用的TSynEdit控件,应该是用Delphi开发的,About里很老实地把它用到的所有控件都罗列出来了,大部分是用Mozilla协议的,比较乖啊。看来善用开源成果也是做共享软件提高开发效率和产品质量的一种手段啊。
昨天为止,把输入法在注册表中的所有能找到的相关项都删除了,但输入法管理器中的图标还是好好的,输入法ime文件没被删除的话,也还可以切换过去正常使用。只有重启系统了才会消失,说明这样处理是不够的。 本来就知道有个小小的程序可以近乎完美地卸载输入法,不用启动就能使图标消失。今天上网把那个小东西找来,还真的挺小的,用PEiD看了一下说是用Delphi写的,没检测到压缩壳都只有20KB,应该是没用VCL了,本来还想用DeDe来反编译一把的,结果下了个DeDe来,好像不怎么会用啊,反正是反不出什么东西来。既然这么小,就用IDA试试喽,装入就分析完了。流程视图都只有一小点,从字符串表中顺藤摸瓜,找到一个叫UnloadKeyboardLayout的API调用,上Google随便一搜就看到有篇Blog写的如何用该API来卸载输入法,真是的,以前输入各种关键字都没有找到这篇Blog,还害得我大费周折地去反汇编,还好,也总算解决。 顺带还多了解一点内容,原来HKL就是输入法在Keyboard Layouts下面的子键的数值。
昨天今天翻看五笔爱好者论坛几年前讨论大熊猫输入法的老帖子,发现一些有趣的想法,比如词库用数据库来实现。 今天就动手把SQLite3.4版的代码下下来,并加入输入法的工程一起编译,看起来好像编译是没问题,不知道实际用的时候怎么样。 另外想到的是,要让输入法能直接使用sogou拼音输入法的皮肤,也就是ssf格式的文件,其实也是zip文件,只是后缀名改了,于是要加入unzip的代码,而既然加了zip格式的解压功能,索性把rar格式的解压也加进去算了。这两块的代码因为直接就测试使用了,还真出现了一些问题。首先是unrar的代码都是.hpp和.cpp后缀的,而整个输入法的工程原来一直只用C,所以要用extern "C"来修饰一下。然后发现unrar的文件包含关系还真是奇怪,它会直接include那些cpp文件,但如果直接把那些cpp文件加到工程里来编译是会出错的,这从它的makefile中也可以看出来,并不直接编译其中几个cpp文件,但也不能把它们直接删掉,真是奇怪啊!再后来的问题是,因为我想反正输入法最后生成的就是一个动态链接库嘛,让它多导出几个函数可以让辅助工具使用,所以加入RARDLL预定义宏,指示把rar代码编译成DLL,再把几个函数名写到def中去,这样就可以导出这些函数了。但还会有问题,再加个预定义宏SILENT,就能正常运行通过了。之后出问题的是unzip的代码,首先unzip的代码并不能自动覆盖已有的同名文件,所以只好在调用前先把目标文件夹内的文件都删掉。后来看起来好像运行得还算正常,但突然发现,release模式下,不能直接激活输入法,在激活时会调用unzip来解压文件,这时就直接崩溃了。但如果是先用rar或7z格式的皮肤,就不会崩溃,再切换到zip格式的文件,用unzip也不会崩溃,比较怪异。最怪异的是,这只有在release模式下直接运行会出错,如果是通过VC下的调试器,或OllyDbg这样的调试器里运行,就算是release也不会出错。这就导致问题很难定位了,本来就没有多少调试方面的措施在输入法里,而这又是第三方库的代码。想到debug模式的是没这问题的,于是又想到编译链接选项里动脑筋,经过少量的试验,最后发现,只要加上了缓冲区检查编译选项,release模式的也不会崩溃了。唉,VC的这些选项还真是大有学问啊! 今天一下加入了3个开源库,于是趁机把版权声明也整理了一下,呵呵,一个小小的输入法还用到了不少东西呢,现在就有7z、unzip、unrar、lua,还有从网上找来的一小段一小段的代码,以后辅助工具里估计还会加入Boost的东西。最后用debug模式生成的ime文件有1.9MB,用release模式生成的有1.04MB,用upx的--best选项压缩一下,最小也有近500KB,一个五笔输入法做到这种程度不容易啊,哈哈。而且还不是最终成品,成品应该还会再大点点。
昨天把输入法中的两个存在已久,但一直没引起重视的bug修正了。其中一个是,分号转英文或大写字母转英文的时候,不能混合输入数字;另一个是,大键盘输入数字后回车,紧接着输入句号或斜线都会变成英文标点。这两个标点都是在我引入分号转英文、大写字母转英文和大键盘输入数字转义时引入的,但因为其实这些场景自己用得很少,而且影响也不是非常大,所以一直没有很重视,昨天忍不下去了,就改了。 今天把分号选择第二个候选字的功能也修复好了,因为那段时间引入分号转英文,就直接把这选择第二候选的功能屏蔽掉了。这回看到要修复好像很容易,况且很多人好像都习惯使用这个来进行第二三候选,不像我只用左右shift,呵呵。 还要加入五笔加加那样的手动造词功能,嗯!其它bug也还很多,比如状态栏有时候出不来,状态栏的窗口跟随,保存词库时死循环。
今天发现有一个办法可以暂时让英文长度超长时宿主程序崩溃的问题,但也很无奈,不知道是什么原因。办法是在release的编译模式下让链接选项中选上生成调试信息的选项,这样最终生成的文件体积就会大一点,但确实不会有崩溃的现象了。真是奇怪啊!今天其它什么几乎都没做,想着开始给它进行优化了,主要是从速度方面。 在公司里的活儿也郁闷呢,VSS2005如果没有.NET的环境的话,连那两个DLL组件都注册不了啊!
终于又了了一块心病啊,把设置对话框改好了,终于可以显示成属性对话框了,看起来比原来的专业多了,原来的那个真的太难看了,所有的选项都放在一个对话框里,最开始的更夸张,所有的选项都是复选按钮,几十个复选按钮堆在一个对话框里,这个不爽啊! 之前也是试图改过几次的,但是能半途放弃了,因为总是遇到死机。也真是奇怪,一个输入法能引起死机,应该说一个属性对话框能引起死机,也太不可靠了吧。本来还以为是我的电脑的问题,今天去公司弄了一下,公司的电脑也死掉了。说明确实是我的代码的问题,仔细看了看另外一个可以正常工作的代码,发现有些消息我没有处理。加上后,果然在某些时候能弹出对话框来了,再然后就定位到肯定是我在填入实例句柄和父窗口句柄的时候引入的问题。回到家又经过少量实验,发现实例句柄用DLL创建时获得的那个就行了,父窗口句柄可以是NULL,也可以是宿主应用程序中接受输入焦点的那个窗口,不要是输入法自己的那些窗口就行了。 真是心情舒畅啊!不过好像状态栏换肤有问题,另外一个大心病是英文长度超过10个引起的崩溃问题。 小乖输入法渐渐地向可以发布的状态靠拢了!
突然发现在公司的那台机器上,开了我的输入法后,notes就会闪得很厉害,根本不能用了,郁闷,在其它的程序里敲入字符后,也会让整个屏幕闪烁,但是回家来看,发现重现不了,在我的本本上表现得很正常啊。 今天就只是改了一下,可以直接输出全角空格了,嘿嘿,努力努力往五笔加加Plus方向靠拢啊。不过五笔加加的稳定性,我只能说,真是佩服啊! 再加个手动造词的功能,以及状态栏换肤的功能,就不再新加功能了,程序弄得稳定点才是。再把辅助工具完成了,就可以正式对外发布了。
在网上无意间搜索到五笔爱好者论坛中的一个老旧的帖子,是五笔加加Plus的作者EasyCode提到的,他列出了几十行的反汇编代码,仔细看了一下,翻译成C代码后一试,居然真的能在Firefox中实现光标跟随了,真是太高兴了!这样,小乖输入法更具有实用性了,之前一直自己都怪它不能在Firefox中实现光标跟随,所以一直不用它,不过在其它环境下,比如公司里只用notes时,也已经慢慢改成只用小乖输入法了,呵呵。 现在还有些问题是,Release模式下,输入英文超过10个后,会崩溃。另外,缺少一个造词的功能。再有,状态窗口不会自动跟随主窗口。 辅助工具也整了一下,可以画出位图来了,设置对话框基本上可以用了。WTL就是没有文档不好,不过幸亏它的类名,方法名这些都有点模仿MFC的样子,还勉强可以猜一下,在猜不到的情况下,直接用API也是可以的,呵呵。
今天在整一个属性对话框,用WTL三四行代码就能整出一个来,不得不让我感叹类库对于开发效率提升的重大作用啊!想想曾经用纯C+SDK画过一个,费了好大的劲啊!以后没什么特殊要求的话,尽量用WTL了!
经过查看DDK中的IME源代码,学习了一下后,发现有一个办法可以算是避规那个在某些程序中显示不出候选窗口的问题。只要在接收到某个通知的时候,强制移动一下候选窗口就可以了,不过光标跟随问题没有解决,它只能固定地停在一个位置,不过也已经算是重大进步了,哈哈,真是开心啊。可以搞一下词库以及内部表示的问题了,不时地出现一下词库乱掉的问题,很恼火的!
“换肤论者”,呵呵,这个名词是在公司内部一个论坛上看到的,说的是一位同事说sogou输入法可以换成好多不同的外观,然后下面就有另外一位同事说,原来是个换肤论者。现在我发现,我也是个换肤论者,上sogou的网站看看,有好多比较漂漂的皮肤,然后又看到像极点中文之类的五笔输入法也是可以直接支持换肤的,想我用的五笔加加就不行,虽然当年它刚出来时用的组合框和候选框合一的界面新颖大气,可是这么多年过去了,也看腻了。无聊了,于是打算把我自己在整的那个输入法弄成可以换肤的,呵呵,大概的样子就像sogou那样,可以让候选框使用不规则形状,其实是用一张图片加掩码来合成一个region,再设成窗口的形状。用google在codoguru上搜到一段代码,可以把一个bmp转换成region,太好了,直接套上,真的可以直接显示不规则窗口呀,好开心!不过昨天发现问题,先是大红色(RGB(255,0,0))的掩码不起作用,但粉红色(RGB(255,0,255))的可以,单步跟踪到那段代码里面,发现是GetRValue等操作的时候在对一个色彩值取值时好像顺序错了,于是自己改了一下,改成大红色的也可以了,但其实没改对。后来又发现,对于超过一定高度的图片,窗口只能显示出上面一部分,又找了好久,把一些有用没用的代码都删掉,还是没找到原因,一直搞到后半夜2点,弄得心力交瘁啊。今天回来一下,原来在每次重画窗口时有一个MoveWindow操作,里面把高和宽都写死了,高只写了个90,所以只要超过90个像素高度的图片来操作,都会有问题。然后又发现,有一张淡蓝色掩码的,也没有正确的合成region,再跟踪了一会,又是那边取色彩值的地方的问题,又改了一下,现在也可以了,不知道是原本代码中的问题,还是其它什么问题,因为代码中提供的示例程序,是用黑色(RGB(0,0,0))这样特殊的值来演示的,可能并不能很好地测试到。 关于在Firefox中不能显示的原因,所说是因为自由拼音输入法并没有完全按照IME框架来写的,所以有问题,难道我要去找DDK中的那个例子来看看,然后重新写了一个。 不过说实话,自由拼音中的结构真的有点乱,而且效率也不行,特别是词库组织方面,比较土。尤其是后来被另一位作者加了五笔功能,代码更乱,连用UNICODE编译都会有问题。真要好的话,真的不如好好学一下IME框架,能支持UNICODE从头开始写一个。 目前已知问题:1、有些程序下弹不出候选窗口;2、有时候词库会乱,要重新打开一遍输入法才行;3、有时候会引起程序死掉,今天在公司里用Word就碰到过,所以不能用于重要场合;4、拼音的词组词库有问题;5、有时候状态窗口也显示不出来;6、还有很多其它小问题。
这两天在整那个输入法,很多是模仿五笔加加Plus来的,因为我的使用习惯已经深深地被五笔加加Plus影响了。把分号开头转英文,大写字母开头转英文弄了,把状态窗口也换了,不过真难看啊,呵呵。 只是有些程序中显示不了候选窗,一点头绪也没有。这个问题不解决,几乎可以说,这是个没用的输入法。
下午躺在床上突然想到,原来在TclSuck中是怎么做的,看了一下,这么简单,虽然不想给日志类加个模板参数,所以不能有模板成员变量,但一个作为回调的成员函数属于哪个类是未知的,所以一定要用模板,要把这个信息保存起来,只要先定义一个普通的非模板类作为基类,给这个基类添加一个虚函数,再从这个基类派生成一个模板类,就可以保存相应的类型信息了,而日志类中保存的是基类的指针,所以那个虚函数的作用也很明显了,狠一点的,可以把那个虚函数声明为纯虚函数,因为基类实在不需要让它做什么事,只是为了中间过渡一下而已! 傍晚去百草园见了一下hover,他进上研所了,来深圳大队培训,周四就走。吃完饭回到家,给afei打了个电话,她却告诉我belovedog也在大队培训,还说下午她们去见面的时候忘记叫我了,我当然要埋怨死afei了,于是给belovedog打电话,约时间见面。 熟识的人进公司越来越多了,从普通校友,到老乡,到同班同学,还有……
基本可以满足自己使用的功能上的需求,即使发现哪里不能满足了,也可以马上自己改。不过实现得真是很难看很丑陋啊,是拿不出去见人的!而且在写这个类的时候,暴露了我的一大能力缺失,我对标准库和Boost一点都不了解,一些常用的组件应该怎么用我都不知道,全靠看帮助翻手册才勉强搞定。 这个类开始是在VC2005下写的,然后拿到BCB2006下试了下,发现BCB连Boost::function库都不能好好地支持啊?真是受不了,而我写这个类时,有一部分功能是依赖于Boost的,比如支持回调,所以如果没有Boost,这部分功能就不能支持喽,当然其它的功能还是可以用的。目前可以将消息写到控件台、OutputDebugString(也就是调试器)、文件、系统日志。其实当时有个想法是,Windows下可以写到系统日志里,Unix-like的系统下应该用Syslog,不过这个就暂时不管了,哈哈!除了可以写消息外,还可以定制消息输出的内容格式,其实是不同内容在同一行中出现的顺序,呵呵。当然,如果编译器能支持Boost,就可以用回调,可以用全局函数,或仿函数(目前还不能支持类成员函数),就可以完全定制输出消息的格式了! 除了依赖的Boost库外,全部的代码只有一个头文件,而且其它的依赖都是标准库或系统支持的库,方便啊!
五一长假终于结束了,这是最省钱的一次长假了,只买了个双肩背包和一瓶15ml的眼部护理凝胶,呵呵。本来还跟小丫头说,每次长假是一次比一次花得多,小丫头就说我就是这样变穷的。 代码结构改掉,引出的问题还真的挺多的。因为希望能尽量减少对VCL的依赖,于是不用IntToHex,改用Boost::Format,突然发现有很严重的性能问题,调了好一会儿,甚至想过要放弃而改回VCL,最后发现,只要合理地整改程序结构,多余的操作不做,速度自然就提上去了。不过让我还是有点担心的是,Boost::Format是不是真有性能问题。暂时也不管了,反正能满足要求了,而且把AnsiString::Pos也换成用Boost::string_algo来实现。另外还有一个问题是,TCanvas还没能去掉,应该直接换用API画。 其实这次代码重构的一大目的是为了把原来写在MainForm类中的3000行代码精减,初步目标是控制在1000行以内,如果能更少就更好了。另外一个目的是要把不同类型的功能划分成不同的模块来实现,这样也是为了能更好更方便地支持多种类型的插件和协件。 再次,这回要把各种全局设置、协件、插件、外部工具等设置都做到同一个设置对话框里去,所以想要一个更好看点的界面,看到Foxmail里那个不错,观察了一下是用了TZlistbox控件,网上找了一下,好像是付费的。如果直接用TListBox就太土了点,又观察了一下VS2003里的向导,是用HTML做的,原来是没注意过的,也是因为MS用HTML做的界面经常做得像Native程序一样,所以也看不大出来,上次听同事说起过,今天看了一下,就是几个HTML文件在那里切换,自己实现几个接口就行了。当然,今天又得到一个教训是,在这种情况下,能让脚本做的事,就尽量让脚本做,放在C++里增加了不少复杂度,而且某群人说过比较极端却也不无道理的话,“一行脚本顶一百行C++代码”。比如原来我嵌入的WebBrowser里面没有XP风格,后来发现只要加一句HTML代码就行了。还有,一直没解决的屏蔽F5刷新的问题,在网上找了找,其实几行JavaScript代码就搞定了。 最后,看到有个叫ShowHTMLDialogEx的API,可以直接弹出个对话框浏览HTML文件哦,比较方便。
看着LLYF Spy中臃肿不堪的代码,实在惨不忍睹啊!于是下决心把LLYF Spy彻底重构一遍,原来已经算是1.8版的了,现在刚好来一个大版本升级,作为2.0吧!看看以前的升级版本历史记录,还是有点值得回味的,呵呵。最开始的几个版本都还是在学校的时候写的,从1.0到1.6都是,1.7是工作后买了电脑后做的第一次升级,并尝试用Inno Setup做了个安装程序,把几个其它小程序一起打包了。1.8是突然某一天在公司里想要一个抓任意形状区域的图像的功能,于是又改了一下,并且编译环境也从C++ Builder 6.0升级到BDS 2006。现在2.0的计划,不但要给它外形整容,还要给它内部调理,另外再把其它的几个小程序也清理掉,能整合的整合。看看新出炉的版本历史:2.0+增加主菜单+增加协件支持+增加Lua、Python、Tcl脚本插件支持、增加COM插件支持+增加外部工具配置支持+Website探测增加对Firefox的支持+增加全功能性的设置界面+支持英语和简体中文两种界面+添加到Office插件中+添加到Windows Bands、IE Bands中-移除了几个原来在主界面上的功能,转到协件或插件或外部工具来支持x重写了主要核心代码,用户可能体会不到,但对LLYF Spy的发展来讲具有重大意义 1.8+增加多种抓图方式x插件信息对话框中的WebBrowser增加XP风格x更小的可执行文件体积,使用BDS2006编译连接 1.7 + add some new plugins.+ add external tool integrated.+ add color pick dialog.+ auto records the form status...
作为一款输入法软件,有几点将会是致命伤:1、在某些环境中不能正常显示候选窗口,比如Firefox、Opera等程序中;2、不支持GBK字库或UNICODE字集;3、不能用UNICODE选项编译,因为编译了后运行不正常;4、有时候看不到状态窗口,或者没有方便的进行设置的方法。 以上几点按受影响严重程度依次排列,目前我正被这些问题困扰着,都不知道怎么解决啊!
前些天都说要做个LLYF Articles的,要能把指定目录下的网页文件都打包成chm文件。在公司里反正也无所事事,就用MinGW写了个命令行程序,基本可以实现这个功能了,只是有些方面不完善,当然如果用它来扫描Boost的目录,也是可以生成可用性比较高的HtmlHelp Workshop的工程文件了。但是,不知道为什么,用MinGW想写个GUI的程序,就总是有奇怪的问题,连对话框都弹不出来,几乎一样的代码用VC2005编译一把,就可以好好地弹出对话框来,晕倒!不过也随它去了,反正核心功能部分都已经完成了,哈哈。 今天下午快下班的时候,原来项目部的老大跑过来问我怎么没把计划发给他。我压根没想过这个东西要发给他,于是尽量把责任推到现在的老大的头上去了,其实我确实也写不出什么计划来,硬要我用SharePoint来做,以前没接触过,更不好做估计了,而且也一直没有好用的机器啊!今天把老大旁边那个PIII1G、20GB、256MB的老爷机搬过来,里面还装了个2.4内核的RedHat,呼呼。两个老大在那里扯皮,我在旁边只有偷偷地笑,现在的这个老大简直有点无赖啊! 下一站小乖,呵呵!学一下用WTL做界面吧。
突然决定做这个东东,主要功能是用来收集各种零散的文字,比如从网页上看到的有价值的文字片段等。不过让我决心做这东东的,却不是这个原因,而是想通过这玩意,能自动把分散在众多文件夹中的boost帮助文档打包成有序的,至少是能按照物理文件存放的分级打包成chm格式。 先要写一个能递归查找文件的功能,再按这种目录结构写成HtmlHelp的index文件。还要注意能剔除掉空的文件夹。
除了界面不好看之外,功能倒是绝大部分都完成了。先是把virtual listview多选不准确的问题解决了,用了一种很土的方法,遍历每一个记录,看是否被选中。把指定文件的打开方式部分也稍微修改了一下,先主动创建进程,如果不成功,再用ShellExecute指定程序打开或用ShellExecute让Windows来决定用什么打开。还在状态栏里加了个进度条,在导出列表的时候,如果记录比较多,就可能会花比较长的时候,如果中间没有什么提示还真会让人误解,所以这时候用进度条就最合适了。顺便发现了几个小错误。另外还可能会有问题的地方是,在TreeView中填入的文字,在用SQL语句写入Access时,可能会有单引号的问题。这也是个挺让我觉得奇怪的事情,为什么SQL语句中不能用单引号,写两个单引号就没有不会报错了,但写入的就是两个单引号了,这样读出来的时候还要自己在处理一遍,把两个单引号的地方改成一个单引号显示出来。 其余的顶多是加个Shell右键菜单项吧,这个也可考虑用比较简单的方法实现,给*.*类型的文件加个项,打开的时候因为会把路径传进来,所以就可以处理了。 另外就是,做个像CyberArticle样子能收集网页上文字的程序,本来这个功能想做在Ebookshelf里的,不过感觉两个东西的功能差别还是比较大的,合在一起感觉比较怪。所以还是单独拿出来好了,关键点是要能至少支持IE6/7和Firefox 1.5/2.0。
把设置对话框做得差不多了,就是从注册表中读取打开方式的时候稍微还有点点问题,另外把查找功能也做了,剩下就是把ListView多选的问题解决掉,以及其它一些小细节处理了就可以了。
这两天不知道怎么了,总是觉得眼睛花花的,其实就是想堕落一下,呵呵。回到家,坚持写了一会儿代码,又跟人QQ扯皮了一会儿。效率果然很低呀,这里改点那里改点的,还是没把设置对话框全部弄完。如果不是可以用Boost库里的一些东东的话,自己弄可能还要更慢些,当然为了用Boost库,也是要花时间在学习上的,Boost的文档可以说在开源领域里是做得算很好很好的了,不过里面的例子太少了,而且不知道是不是因为我对英文不习惯的原因,总觉得找不到全部我想知道的信息。说起来Borland的文档也是糟糕呀,BDS2006中的都不知道把原来的例子代码片段放到哪里去了。 这个小程序里,用到了Boost的Foreach和string_algo库,我猜其实我用到BOOST_FOREACH的地方是可以用Lambda和std::for_each来代替的,不过不熟啊,呵呵。已经搞得差不多了,设置对话框里只剩下搜索注册表中文件关联信息了。 白天在公司,看了一下Latex的相关资料,觉得还是多好玩的,回来把CTex装上,发现里面带的工具还真是全。以后得好好学一下,因为用这个可以做PDF格式的文档出来,可以不用D版的Word、PDFFactory这些软件了。
人又有点犯懒了,不是很想动了。画了个设置对话框,里面的代码就都留着不写了,查找对话框也不画了,直接用系统定义的那个了。白天在看Boost的文档时,偶然发现有个string algo库,可以对string进行一些诸如查找、替换、分割等操作,这样就方便了,可以把那块引号变换的代码省掉了,自己写的还指不定什么时候出现问题呢,现在就一行代码搞定喽。 鉴于人越来越懒,决定把设置对话框和查找功能完成,再把那个ListView多选的bug除掉,就算1.0版完成吧!
主窗体类的实现文件又变成有1000多行了,郁闷。能导入导出目录结构了,这样就方便很多了。基本上弄完了主菜单和工具栏了,但也更难看了。翻开以前的计划看了看,原来还要加IE/Shell右键菜单啊,要能收集了网页文件后再打包成chm格式啊。要做好一个程序真难啊,还有些bug没解决。还要加注册和设置的功能。
把ListView改成可以多选的virtual listview,有点问题,有时候不能获取到全部的被选中的项,在csdn上也看到有人有这样的问题,不过并没有提到解决办法,只是说用普通的ListView就没有这样的问题,难道我也改回去。改回去除了显示速度变慢这个缺点外,能得到另外一个好处,就是如果从后面添加了记录,不用全部刷新整个ListView。 原来那个OnEdited的事件是可以用的,它的参数中最后一个就指明了新的标题,而指向节点的那个参数里的标题属性还是老的,这样也好呢,可以决定是不是在某些时候不应该被修改。 另外想到,应该有个搜索功能,至少能按书名,或文件路径来搜索。其次是,有点想加个ListView和TreeView间的拖拽功能。拖拽以前都没做过,不知道麻烦不麻烦,其实我觉得这个小程序最麻烦的是数据库操作了。 今天从浏览器登录到Gmail中时,突然想到,如果邮件客户端的界面可以做成像这种,应该也很炫哦,把所有相同主题的列成一个,然后可以在一个浏览窗口中统一浏览。看了一个Foxmail、Dreammail、Koomail、Outlook、Notes都是没有这种界面的,其它的客户端程序也不了解,不过Gmail这样的可能也算得上是首创的了吧。然后我就又有点发神经了,想自己写个客户端了。
终于有点实用功能了,可以把磁盘上一整个文件夹下的所有符合要求的文件都导入到相应的节点下去了。在TreeView中用鼠标点击选择某个节点后,也能列出相应的记录。虽然效率是低了些,但是功能总算是完成了。突然想到,ListView应该可以多选,TreeView中右键中应该有个可以选择文件进入导入的选项,而不光是导入整个文件夹。还应该加个选项,可以校验磁盘文件的有效性,自动把失效的记录删掉。总觉得界面是太丑了,想让ListView中可以在每条记录前面添加一个对应在Explorer.exe中显示的图标,另外,如果让Toolbar中显示的图标是32bits的,会不会好一点。 再有,Access创建的文件实在太大了,添加了几条记录后,就变成900多KB了,用WinRAR压缩了一下,变成40多KB,原来压缩空间有这么大,就想是不是可以集成压缩和解压缩功能,这点用7z或zlib都可以实现,不过没研究过怎么在BCB中使用,而且以前也没研究过怎么使用压缩功能,只研究过在VC下来解压缩。
从数据库中读出数据并填充TreeView部分总算搞好了,用了一个递归的函数,还用了map之类的容器,把一些需要的数据保存起来,想起来,要是不知道STL这么好用的东东,还真是很麻烦呢。 之后要做的是仔细地控制TreeView。如果对TreeView进行了某个节点的改名,就应该update到数据库中去;如果TreeView中的节点少了一个,也应该把数据库中对应的那条记录delete掉;如果选择了TreeView中的某个节点,就应该把对应这个节点的所有书籍信息都select出来,并显示在ListView中,这依赖于把这些信息先保存到一个vector中,然后刷新ListView,如果信息量比较大,则对ListView的刷新速度有所要求了,因此,从一开始就应该设计好用virtual listview来实现,如果不算检索数据库的耗时,1秒钟插入显示10000条记录应该是没有问题的。 弄完了上面这些,就可以考虑其它的用户界面方面的问题了,比如加个选项,可以自动清除掉已经不存在磁盘文件的书籍记录;可以整个分类的书籍一起移动或拷贝到某个文件夹下;可以由用户配置合法的文件后缀名,并定义各自的打开方式等等。 不知不觉,又把所有的代码都写在主窗体类里去了,真是不爽,但是我又不知道如何可以把其中一些代码移出来,因为所有的代码都直接用到了一些VCL控件,控件是添加在主窗体上的,所以总是要在主窗体类里写才能找到。 在网上找到一个讲SQLite的中文网站,里面有一些中文的文档,还是挺有用的,比如知道怎么用VC来编译SQLite的dll文件了,估计Borland的编译器也是可以的,但最简单的方法还是直接用implib工具从dll文件生成lib文件,VC的编译器套件里也可以用lib工具从def文件来生成lib文件。Access生成的文件实在感觉大了些,不爽,说不定哪天我要把它换成用SQLite的数据库。有些开源的东东还真的很不错的说!
终于经过翻阅了手头能找到的所有关于VCL使用ADO连接数据库的资料,连猜带蒙,好不容易回忆起来怎么来用了。其实就是FieldByName()->AsXXXX的用法,后面的XXXX可以是Integer、String、Boolean等等。虽然这个用法是试出来了,不过还有不少的困难摆放在眼前,其中一个很大的拦路虎是,TreeView很难用啊!我那样的设计,要把TreeView中的每个节点对应到数据库中的一条记录,这就是比如繁琐的一件事情。还有一个原因是,我对ADO控件的了解,也仅限于直接写入SQL语句操作一下,甚至连SQL语句都是现学现卖的,临时需要了就临时看一下手册,什么select、delete、update、insert等等。这样一来,原本可能可以很简单的事情,被我弄得很麻烦了。 接下来要做的是,从数据库里读出所有TreeView所需要的数据记录,每条记录由3个字段组成,分别是节点ID、节点名称、父节点ID。强制规定第一条记录肯定是根节点,后面的记录肯定至少是根节点的孩子,在TreeView中添加了根节点后,再读出所有其它节点,并根据父节点ID依次添加上去。还有点很郁闷的是,TreeView的节点名称编辑完了,没有恰当的得到编辑后的名称的时机。有个OnEdited事件,还以为可以用,结果得到的还是编辑前的内容,有个OnEditing事件,也不能得到当前最新的内容,晕倒!以后没什么事能不用TreeView,千万别用这个这么难用的控件了。 最后想说的是,Access的数据库怎么体积这么大,只放了3张表,表里都没什么数据,那个mdb文件就有800多KB了。 唉,想想,一点技术含量都没有,不过能卖钱就好。
用ADO连接Access就先放下了,在公司里找了些资料看了看,还是没什么头绪。回来只是把其它的文件搜索、文件报表生成等功能完成了,剩下的主要就是怎么跟Access交互了。总是觉得TreeView有点难用,ListView倒是比较好用,以前用过比较多次了,而且没有什么特殊的要求。 倒是这次总想着怎么把Boost应用进来。Boost::foreach和Boost::lambda是最近才看过的东西,但是这种小程序没多少场合可以应用,很多时候都是不需要多少算法或是表达式的,只是简单的过程式的流程。还有一点就是,应该好好把STL的内容熟练使用,有些事情自己处理虽然也不是很费事,但如果直接使用STL中的算法来完成,不但更高效健壮,可读性可维护性也是更好。 luolu说,她可能要读博士了,还说,是因为没事情做,所以才想读书的。人和人的差别真是大呀!
今天经过半个小时的交通堵塞,终于比平常晚了半个小时到了家里。发明迅雷的人真不是人,这么抢带宽的东西也做得出来。 写了一会儿Ebookshelf,这个东西本来是自己用的,因为有了不知道多少本的电子书,却没有好的管理工具,只好先自己写一个。还为了用什么工具开发犹豫了好久,主要的当然是BCB和VC之间的抉择,不同的编译环境会涉及到不同的各种问题,比如打算用SQLite或Access来做数据存储,哪种接口在哪种环境中更容易使用,然后是WTL和VCL哪个更方便。最后的决定是在打开电脑后几分钟才下的,用BDS2006+Access,因为SQLite只提供了DLL和DEF文件,我又不知道怎么为VC的编译器从DLL和DEF文件生成导入文件(即lib文件),而Access的连接用VCL中的ADO控件是异常方便。另外一个原因是,本来BCB用的lib文件是可以生成了,但是直接include了sqlite.h编译都不过,也不想再研究了,就只好用这种组合了。不过比较郁闷的是,原来虽然也用过几次用ADO连接SQLServer或Access,但今天用起来时,发现很多东西都忘了,都不知道怎么从获取到的记录集中提取出指定字段的值了!原来的那个程序也找不到了,好像就是最近那种整理邮件的时候都删掉了。另外还有个问题是,总觉得我用VCL画出来的程序界面很不专业、很业余。主要大概是各种颜色搭配,以及控件的一些细节属性没设置好,这个角度讲,其实用VC的MFC或WTL就好多了,能一下就生成标准的Windows应用程序界面。先把涉及到数据库操作的部分放一放,接口都留出来,等哪天复习一下再补上吧! 部门又发了一本《读者》合订本,还是2003年下半年的,去年的还是2004年上半年的呢,真是抠呀!而且邮件一发,雨烟就说要罚那个知情不报的人,教授也真是可爱,居然还敢承认,呵呵。 下午又跟疯丫头一起看了一点数据特性的代码,那个新员工写的代码还真是有趣呢,虽然一个文件里面的函数只实现了1/3左右,还是被我们找出了几十个各种类型的问题,有些是压根就编译不过的。其实我觉得这种阶段就拿来让测试部做代码检视是不太合适的,至少也得能编译通过吧。尤其是在看了各种模板应用后,发现编译器在编译期间就能帮助找出不少错误的,所以没经过编译器的代码最多也他们开发内部互相检视一下算了,拿到测试部来有点形式主义或者说是小题大作。不过这样也好,至少疯丫头的PI值是提上去了,哈哈!
现在的新问题是,编译器不能编译显式特化泛化类的成员函数模板!从BDS的联机帮助上看到,这是编译器显式禁止的。郁闷!也就是说,LuaTinker中的代码,是不能直接用上来的!唉,真想不用BDS了,用VC不就行了。可是用VC的话,我只会用SDK,画界面真的太费时间了!其实还有个办法,就是好好学一下C++的模板元编程(template meta programming),再自己写一个好用的C++ Wrapper for Lua,呵呵。看几本书:《Modern C++ Design》、《C++ Templates》、《C++ Template metaprogramming》;研究几个源代码:Boost、Lua、LuaTinker、LuaBind。 有点多哟!
春节过年回家,因为上不了网,反而出乎意料地拿出不少时间来写SkinBuilder。一点一点地完善,总是觉得有很多地方要改进,呵呵。 现在已经实现方块池和预览框使用固定大小的矩形框,不再用进行确定;可以选择矩形的颜色、粗细、实心或空心;Lua脚本格式的配置文件生成,全是自己用iostream写的,因为要写的内容和格式都很简单;可以查看已有哪些生成;重新load已有的task和配置文件进行再次编辑;能用7z格式打包,这点是通过直接调用7z.exe来实现的;导出时,检查必需项是否齐全,包括背景图片和配置文件,导出后子窗体的标题作相应的修改;打包时,把背景图片和配置文件都改名,对于jpeg格式的图片能自动转换成bmp格式的;有了一个splash窗口,其实是用about窗口;重新load后能画出已有的矩形框,这个还费了点时间,原因是试验的时候总是使用黑色的,刚好不容易看出来,所以一直以为没作好,晕;文件关联,包括打开方式、图标、单一进程实例打开,不是很花时间,一部分代码还是在机场里等飞机的时候写的,呵呵;打开task文件能改变子窗体标题,这也是应该的;工具栏暂时被我屏蔽了,懒得写了,呼呼;本来打算做的无限次undo/redo的,后来想想,意义不大了,因为任何时候新画的都能把以前画的覆盖掉,还要undo干吗! LuaSuck写了一段,写不下去了,一来对C++泛型编程的了解远远不够深入,另一方面对Lua与C++的交互方法也不够了解,先整了些够用的功能。应该再好好研究一下LuaTinker和LuaBind,它们都是面向Lua 5.0的,直接放在5.1里好像会有些问题。 SkinBuilder就先这样告一段落了,接下来是连连看,然后是方块。晕!
终于能连上来了,老泪纵横啊!这个时代,越来越依赖网络的时候,越来越不喜欢本土服务的时代…… 好不容易啊,终于可以在TImage上画线条了,晕死!剩下要处理的是,怎么把文件中的图片装成背景。还有就是,对于方块池和预览框,是大小固定的,不是用拉矩形框的,而是要跟踪鼠标的坐标直接画固定大小的矩形框。 下午,小丫头给我发短信说我们公司给她发录用通知了。说实话,就像我自己被录用那样高兴,昏。不过她肯定会犹豫,我当时不也犹豫了一会儿吗,后来还是乖乖老实地来了,因为我懒得再去花心思在找工作上了。不过小丫头现的情况跟我有点不一样,她是有正经工作的,要一个人下决心跳槽也许不是那么容易吧,不过要是换作现在的我的话,哪里给钱多,就去哪里呗,还追求理想么,干自己感兴趣的事?有点可笑的幼稚,理想是随时间和经历变化的,现在的理想就是想办法怎么赚更多的钱,赚更多的钱就是现在自己感兴趣的事!小丫头要是过来了,拿的钱会比我还多,晕!由此可见我混得多么失败啊,唉!
其实SkinBuilder的功能还是很简单很简单的,只要能用鼠标拖出个矩形就行了,要是能加入7z的压缩功能就好了。现在只是实现了大部分的MDI界面的功能,很多东西都忘了,晕。要是Lua脚本可以能支持持久化就好了,说不定有什么扩展包是可以用的,只是我现在不知道吧。 我现在似乎又陷入了以前那样的困境……郁闷!唉,无奈啊!
把属性对话框界面的大部分功能都完成了, 该整Skin合成器和LuaSuck了。本来想试试用Delphi下的KOL和MCK的,结果稍微尝试了一下,编译Demo都通不过,不想研究了,直接cancel掉,还是拿出BDS来用C++Builder和VCL写一个。因为想写成MDI的,所以比SDI的麻烦了好多,界面部分就整了好些时间。 我的方块Todo list: 1、Skin和游戏逻辑脚本的ListBox要在创建的时候选中当前的项,不然会被改掉; 2、属性配置要映射到游戏中。 oneaddone居然是自己开的公司,牛,世界上就是不乏牛人啊!
先说段题外话哈,有点郁闷哦,昨天把QQ签名整了一下,今天叫教授去看,教授就去看了,我让他猜是啥意思,没想到他一下就看出来了。因为字数太少,所以这些讲到涉及到敏感话题的爱什么什么的特征就很明显,所以照教授的话来说,地球人都看得出来啦,我欲哭无泪丢人了要疯掉了。我就跟他说我没脸见他啦,不敢去公司啦,要立马辞职啦,不然会被算计的。然后跟小丫头去归隐山林啦,哈哈。教授说大家都想看你,还在那里使劲嘲笑我,说内裤也会有今天,我头都要炸了!气死人啦!不过再想想也没什么的,本来内心里就是想逗一下教授这个家伙,所以才这么做的,不然干吗要去叫教授去猜呀,哈哈。教授可有趣了,所以我就喜欢整出一些稀奇古怪的事情逗他,特别好玩,哈哈哈哈! 属性对话框画了好久了,真的是一边查MSDN一边写代码的,所有的消息,无论设置或查询都要自己处理,开发效率真是太低了,不过慢慢写代码也是一种享受,有种成就感,如果一直都要死要活地赶,不就跟给别人打工没区别了嘛。剩下还要做就是处理消息,如果设置被用户改动过了,就应该把Apply按钮设为Enable,这些消息全要自己截获呀,呜呜!
用PSDK写界面真是太太太麻烦了,每一个Windows Control的操作都要通过原始的Win32 API来进行,不方便啊!做完方块,应该考虑找一个现成的好用的库,或者自己写一个轻量级的。如果继续这样下去,大量的重复劳动时间耗费,太不划算啦!比如有个IP Address的Control,现在我有一个string形式的IP地址,要把它显示在这个Control里,要写好多代码呢! 要善于利用现有的库呀!不过我现在只信得过编译器自带的C/C++库和Boost呀,ACE还没试过好不好用呢,网上看到有人曾经抱怨过,有些奇怪的问题的,如果遇到了,又真的实在不好解决的话,就也真的只好另外找一个了,Boost不也要加一个网络应用的库吗,不知道进展怎么样了。重新发明轮子,这个真是说得太贴切了。比如这里我用到了一个文件搜索功能,以前都是直接用Win32 API来搜索的,要写个二三十行,现在用了C库里的函数,十行都不到就实现了我需要的功能。那些重复的代码就是C库的编写者已经帮忙写了呀! 中午跑到生产中心去自助了,有螃蟹呀,虾呀,扇贝呀,青口呀,呵呵,三个人吃到天下大雨回不去为止,本来还打算买伞的,后来雨小了点,后来又大了,便想叫教授送伞的,嘿嘿,结果最后还是坐了点对点回去的。 今天心情不错呀,原来我是这么容易被收买的!晕!!~
一边看MSDN,一边敲键盘,终于可以实现属性对话框的各种基本功能了。Apply、OK、Cancel都可以按标准Windows应用程序的样子做动作了。要吸引别人在某平台上做开发,详细的文档和丰富的例子是一大诱惑呀! 看到CSDN Blog上有人在讨论wxWidget、QT、GTK+,反正我觉得,在Windows平台,要省事就用VCL、如果想用MS技术,用就WTL、或者就纯手工打造SDK慢慢画吧,就像我现在写方块一样。游戏平台的丰富程度令人咋舌,手机、掌机、家用机等等等等,对于小游戏来说,手机和掌机应该是以后可以考虑开辟的一块市场,对于网络游戏,像QQ游戏那种,Linux版或许也可以吸引一部分用户,不太确定,可能国外的用Linux的人更多点吧。 把属性对话框的界面部分全部实现后,再弄LuaSuck吧,有了LuaSuck才能弄Skin和游戏逻辑脚本支持,不过Skin只要能读取Lua脚本中的几个变量的值就够了,只要确定了接口就行了,游戏逻辑脚本,其实也就是调用几个固定名字的Lua函数,不过LuaSuck还是要做的。另外就是,要写个Skin打包工具,可以比较直观地在现成的图片上定义相应的属性,生成Lua配置脚本,再用7z打包。完成了这些,才能再考虑联网的问题!晕!
实践是一种很好的学习方式。加了个类,也算是学习别人的样子,尽自己的力抽象一下,把配置模块提取出来了。属性对话框得花很多时间啊,这时就体现出一个好的GUI库的必要性了,可以大大地节省编码时间。那只给我一个念头:以后除了要用DX的游戏程序,其它的一定不再不用VCL了,VCL太好用了,其它的Framework也没试过,不喜欢MFC的结构,WTL不知道咋样。或者自己写一套简单的?看CSDN Blog上有个人一直在宣传自己做的一个基于WTL的GUI库嘛,我不需要非常齐全的功能,我只要一些常用控件就行了。 现在发现Singleton是种很有用的技巧。在使用过程中发现,如果一个类被实现为Singleton了,一定要顺便把析构函数也声明为非public的,这样就不会不小心把它delete掉了。Metaprogramming还是非常值得学习一下的!
在看LuaTinker代码的过程中,惊奇地发现,它居然用了可变数量的模板参数!!这个这个这个,对我来说,不啻于晴天霹雳,《Modern C++ Design》上可是写着“Variable template parameters simply don't exist.” 我打开VC2005又试了一下,明明白白,VC7.1到VC8,都是可以这样用的。到底是哪里出问题了,谁错了…… LuaTinker在处理C++ free function的时候,是把pointer to function当作light userdata压入了virtual stack,网上到处都流传着一份不知道从哪里散发出来的用proxy手法解决的方案,感觉不如LuaTinker的爽。
在好几天前对MSDN的一番研读后,终于把PropertySheet显示出来了,其实真的很容易,很简单,至少比想像中的简单多了。唉,用惯了VCL,再来用SDK,实在觉得吃力。要是以前,随便拖个Form,放个TPageControl,早就完事了。现在,里面的4页Dialog一个个描就不说了,在BCB里也是需要的,然后要写Dialog的消息处理函数,一个个标准的回调过程, VCL里就只需要对自己感兴趣的事件重写处理函数就行了。然后是注册表操作,VCL里的TRegistry也是多方便,多健壮的。自己写一个类似的封装吧,不但花了不少时间,还没有TRegistry好用,昏倒,不过现在勉强能满足当前的需要了。 之后要做的,要把各个Dialog消息处理函数填完,然后是LuaSuck。这几天也读了好几遍《Programming In Lua》,还有它的Reference Manual,对Lua的了解又进了一步。Lua为了屏蔽数据类型的差异以及编码风格的统一,*所有*的与C/C++交互的数据都是通过一个virtual stack来完成的。一定要记住这一点,所有的操作都是针对那个virtual stack来的。LuaSuck的目标和TclSuck类似,①可以使C++程序与Lua程序里的变量互通,②可以在C++程序里自由调用Lua的函数过程,③可能方便地用C++函数来扩展Lua。虽然SWIG应该能很好地完成①和③,但在上次写TclSuck的过程中,我深刻地体会到库的编写的乐趣,远远大于库的使用的乐趣(晕死,真的像Andrei Alexandrescu说的那样了)。
稍微打了一下交道,发现他写程序的经验好像还是挺丰富的,代码写得工工整整的,要么就是思维比较活跃,有些小技巧什么的,挺实用的。虽然之前看那程序的外在表现,觉得很多细节什么的都没考虑,看了一下代码结构,才觉得真是下了好多心思的。而且他说,如果要做网络联机的,要不卡的话,还得花些功夫。也许我是太低估了这事的难度了,我写程序从来不考虑什么架构之类的,上来就编码,遇到过不去了,才会停下来,然后发现很难再改了,这样下去,永远只能单干,只能做fans,做不到professional。 现在大概了解了一下,他是怎么实现录像功能了,原来每个动作他都是会保存一下的,每个动作有唯一的编号,以及可选的参数,估计在保存动作的时候也会保存一下时间偏移。hoho~~~ 要走的路很长啊,要学的东西很多啊!
总觉得现在的实现也很不好,说起来这么简单一个东西。只是把消行和左右移动处理了,对于出现新块前的时间空隙还没找到合适的解决办法,结束条件判断也是。 猫猫说我骗人,说了要写她的,结果没写,哈哈,因为昨天比较投入地去做我的方块去啦,所以就冷下了。今天也是,挖井还是挺有意思的。 雨烟和疯丫头去广州考试去喽,下班的时候,雨烟走得急急忙忙的,跟她说话都不怎么搭理,晕。真是有想法的人啊!自从上了大学,越来越怕考试,在这方面的能力也急剧下降。祝雨烟和疯丫头考好哦。
郁闷。本来以为有方便的算法了,应该很容易做好了,结果还是有N多问题。我的算法实现能力真是低啊。 经过比较耐心地检视代码和调试,纠正了那些严重的错误,不过还剩下很多事要做。首先,在一个方块到达底部后,要出现一个新的方块,这里会有一个时间间隔,要改。其次,方块满行了要消行。再有,要判断方块到达顶端,并结束出现新块。
方块以前写了那么多的垃圾代码终于被证明是有很多问题的。因为写得很垃圾,所以改都很难改,要想看出哪里出问题都很麻烦,所以我干脆把那些代码都删掉了,应该要重新写一遍,用简洁一点的算法 。 TclSuck就这样算完事了吧,不想弄了,能直接支持C风格函数和类成员函数的扩展了,并且参数个数限制也提高到了10个。其实说实话,那个实现,我自己都觉得很累赘,不过就为了写那个季度技术案例,能混过去了。估计也不会有什么好的结果,最多得很二级归档C吧,这个觉悟我还是有的。但是重要的是,我自己对C++泛型编程技术有了一定的认识,并且居然已经能实际做点事情了。而且TclSuck是真的可以实际应用的,假如哪一天真有需要在应用程序里嵌入TCL解释器,现在的成果就派上用场了。 有了TclSuck的经验,我想下一步,是做个LuaSuck。因为方块里是要用Lua的,而原来的在MspEmu里的实现只是最原始的方法,所以还是得自己写这“胶水”代码。LuaTinker似乎是可以用,但它基于5.0.2的版本,而LuaBind在提供强大功能的同时,粘附了对Boost的需求。因此最后的结论是,再自己重新造个轮子。
在实际写代码的时候,才突然发现解决不了的问题,原本还以为只要花几分钟或者十几分钟就能搞定的事,郁闷!只好放下,又看了一下C++/TCL的代码,仔细地想,为什么它就可以这样大摇大摆地做那些事情。真是实践出真知啊! 收到按键精灵的作者转来的300块钱了。好happy,简直像捡来一样,只是down了个国外的杀毒软件,扫了一下说有Adware,哈哈。有外快的感觉真好,真想再其它地方想想办法挣外快,谁叫工资这么低呢! 做完了TclSuck,要不先把LLYF Spy移植成一个按键精灵的DLL插件,看能不能赚点钱来。
今天去开通了招行的网上银行,虽然开始费了点事儿,没仔细认真地看帮助说明,最后还是可以了。很方便啊,把一卡通和信用卡都绑定了,可以直接在网上进行查询以及一些其它的操作。查了一下,钱真tmd少啊,郁闷,不jump不行啊,真是官逼民反啊!所以要使劲挖自己的井啊! coolkuai3.0大功能上的设计是很不错的,照oneaddone的说话,亮点是加了打榜功能。确实打榜功能是很不错,可以无限扩展新的玩法,不过似乎还是固定地依赖于它的核心,所以可定制程序不会很高。3.0在一些细节上,考虑得不是很周到。 我的方块,可以换肤,一大亮点;可以让用户定制游戏逻辑,比coolkuai3.0的可定制度高得多,而且coolkuai3.0不开放这部分功能,又是要用二进制dll形式实现,此之谓第二大亮点;可以联机对战,像Q块那样支持最多6人同时进行,还可以旁观,这是第三大亮点。另外就是,所有的skin下面,都提供了统一的操作界面,这点还是比较有用的,不用粗暴地要求用户要进行某些操作时,切换回原始界面了。 上面这些是计划内的,要一点点地实现,打算试试ACE这个framework。用VC除了画界面不方便外,其它的都很好用啊!
回家就写了两个函数,晕,4个小时哦,一边聊天,一边打方块,一边看网页,一边写代码,果然,只写了不到200行,呵呵!看明天或者什么时候把顺变逆变的写完了,就可以加上接受输入的代码了。还有就是,消行的处理,不能就这样,应该有个落块的动作之后的延时,这样让玩家知道是因为这个落块导致的消行。 要努力哦!《PIL》还是很值得反复看的,因为对于Lua方面的资料真是稀缺,除了《PIL》,再就只剩下官方manual值得看了。而对于它与C/C++的接口使用,LuaTinker是个比较值得学习的资源,因为代码很少,不会让人看到头昏。如果说,要能完整地看完C++的实现技法,参考三本书,应该就可以了,分别是《Modern C++ Design》、《C++ Templates》和《C++ Primer》。《C++ Primer》可算是一本完整的C++语言参考书,所有基本的知识几乎都讲到了,《C++ Templates》则可算是讲述了C++中template的完整使用参考吧,而《Modern C++ Design》是一种policy based的编程技术的完美演绎,对于如何使用template来产生代码生成器这样的任务,提供了极佳的范例。而LuaTinker的实现,正好是这几方面知识的一次良好体现。
晕死,我用的算法怎么这么麻烦!算了,不管这么多,最后能用就行了,谁管你里面用了多巧妙的算法呢! 现在要考虑的有:1、到顶了后,怎么让它停下来;2、随机程序不够啊,怎么总是连着出来好几个一样的块;3、消行的时候,活动块怎么处理。
哦呵,有动画了,但游戏逻辑还没实现好,看来真得慢慢想一下,幸好没有一开始就用Lua脚本来实现,不然我肯定疯掉了。定时器改用高精度的了,不用GetTickCount了,大致实现了在一个循环里做多个定时任务了,只是对于方块的速度,跟coolkuai3.0还有点区别。真的每天只能做一点点事情哦! 看了一下LuaTinker,刺激啊!给我最大的刺激便是,要好好学GP,好好学C++ Template,好好学《C++设计新思维》!短短不到1000行的代码,给Lua的C接口加上了一个很C++的轻量级wrapper,果然,Andrei Alexandrescu发现的和总结的技术对于实现库,是很有用的!好些语法,我都没看到过,每每让我顿悟,原来C++可以这样用!LuaTinker真是个有趣的东西,看看它的源代码,一来可以学习一下C++ Template的GP方法,二来可以学习Lua的与C的接口使用,真是一举两得!
昨天跑去和xcc还有他女朋友一起吃饭去了,那家梅林的小馆子,可以吃到比较正宗味道的川菜。3个人才吃了50块钱,3荤1素,外加2瓶啤酒。从小馆 子出来,才想起要给家里打电话,因为在馆子里,手机没信号。妈妈果然很着急,因为打不通我的电话。然后三个人走到一个住宅小区后面的小公园,有些公共的健 身器具。我想起疯丫头住这个小区里,就给她发短信说,我在她家阳台下,于是两个人在那里打电话,最后,她在她房间里朝着我挥小红手绢,那情景真是有趣,就 像xcc说的那样,完全一个童话里的人,可怜的小女孩被关在城堡里,朝着外面的小男孩呼救。回到家,发现z3回来了。 写游戏还是多好玩的,尤其是在写的过程中可以试验各种新学到的技术。现在想起来有点遗憾,当年在学习就应该做这些事的,不然现在就可以做更高级的事了,或者至少做这些事应该轻车熟路得多了。 我想还是先内嵌支持游戏逻辑吧,这样程序流程比较好调试,不然同时调试Lua脚本和C++宿主程序,会死人的。到时候可以设置个开关是否使用内嵌支持的标准方块逻辑,或者只使用外部Lua脚本定义的游戏逻辑。 7z格式的解压缩支持暂时也够用了,本来还想加入对rar和zip的解压缩支持的,后来想想,一来暂时不要放时间和精力在这个上面,应该先关注游戏功 能实现,二来为了保持程序文件体积不再为了些额外的trivial功能增加。其实可以在有空的时候,编译一个dll,同时支持这3种格式的解压缩。 游戏逻辑中有几点要注意的,是否贴边了,是否着地了,这两点是最关键的,贴边了就不能作某些方向的旋转和移动了,着地了,就应该返回一些统计数据,同时要把下一块丢出来。还有就是定时回调的支持,也是主要为了作些技术数据统计用的接口。
很奇怪,单独编译了7zDec.exe的时候,就好好的,只要是用VC7.1或VC8编译,都是可以好好地运行列表、测试和解压的,但是集成到我的方块里的时候,就出问题了,早早地便退出说OpenArchive出错了,幸亏有源代码,幸亏前些天刚刚学会在IDE里用debugger调试,经过N分钟的单步跟踪调试,发现最后到一处调用Windows的ReadFile时,总是会返回读取了0字节,这是出错的最终源头!经过几秒钟的思考,决定不用ReadFile这个API,因为源代码中通过预定义宏,来决定在Win32平台上使用依赖平台的文件操作API,而其它平台下都使用C的库函数,马上在前面把那个宏定义取消掉,果然编译通过了并正常运行解压了!加了些函数,可以把用7z格式打包好的skin文件解压到Temp目录下面,哈哈,安逸!不过很怪的是,我把画缓冲的代码注释掉了,但它还是大模大样把图都画出来了,为什么啊,撞鬼了!先不管它了,至少暂时这样可以用了,就先放着吧。 我把Lua的源代码都放进来一起编译,到luaopen_io的地方还是会崩溃,跟踪了一下是到一个sethvalue的地方,不明白为什么会这样,Lua的代码我没看懂,所以暂时只能把luaopen_io这句注释掉来拖延一下时间。好不容易从LuaTinker的官方网站上down到了0.2a版的源代码和二进制文件包,韩文还真一点点都看不懂哦!以前看到过Boost.Python的使用代码片段,发现这样的使用方式还真是独树一帜,之后大概就出现了为各种脚本语言提供粘合剂功能的库,都是使用的这种风格的,至少现在看到Lua就有Luabind和LuaTinker了,LuaTinker是个轻量级的封装,可以学习一下它的封装方法。 用SDK写程序,还是很有成就感di,嘿嘿,就是开发效率太低了。
堕落了。 写了几行就不想写了,去玩去了。可以画出方块池里的方块了,把Lua解释器也集成进来了,不过调用luaopen_io的时候就崩溃了,为什么呀,用的编译器是VC7.1的,自己拿Lua5.1.1的源代码来编译的lib和dll,无论静态链接还是动态链接,到这个地方调用都会崩溃。不知道如果拿源代码来一起编译,会有什么结果呢,呵呵。剩下就是很烦很杂的一些事了,游戏逻辑啊什么的,很多细节要处理。我还想到要写一个skin生成器,至少应该能在一张现有的图片上方便地定义各个元素的位置、大小这些信息,如果每次都是在图像编辑软件里慢慢画,浪费时间不说,人是要疯掉的。还有就是一定要支持压缩打包,不然光秃秃的bmp文件放在那里是很占用空间的,而且看起来很不专业的样子。试了试,一张24位色的1.38MB的bmp文件,用7z可以压缩到36KB!强悍啊,可以让它支持7z、zip和rar的解压,虽然程序启动的时候会慢点,但文件好组织啊。其实有个7z的支持就够好了,之后再考虑zip,最后考虑rar的。游戏逻辑放在Lua脚本里做,有些其它的东西就可能不好做了,比如速度检测等等。因为为了简单,Lua脚本知道的事情越少越好,所以嘛! 上网down了个Q块的外挂,不好用,呵呵。
把MoveWindow的问题改好了,也不知道是哪里出问题了,反正就是这样改了一下就好了,可以缩放成想要的大小了,还把画界面的位置也计算了一下,可以直接画在Client的左上角(0,0)的位置了,哈哈。另外一点就是,把Clipper也弄好了,本来是设置了Clipper,就画不出东西来,后来看了一下返回的错误码,说是BltFast不能Clip,换用Blt就好了,虽然说如果是用软件实现的Blt速度会没有BltFast快,但MSDN上说也只是快了10%而已,更何况它说在硬件Blt的条件下,两者是没有区别的。其实速度不速度现在来看,根本不重要,因为一个小小的方块游戏,对动画要求实在不高,完全用GDI做也可以比较流畅地实现的,要是我开始就是在BDS下用VCL的TImage来写,估计已经快到了可以玩的程度的,呵呵,不过这样也好,学一下C SDK和DX。看了一下DX8里的samples,里面的代码写得真是整齐啊!顺便加了个图标,不过还不清楚为什么没能在窗口左上角显示出来。 本来打算把画方块池的功能完成的,但是人懒了,动了一下就不想动了,呵呵,慢慢来吧。 在看maillist的时候,偶然看到有人提到什么时候用Lua,突然得到提示,为什么不用Lua来做配置文件呢。我还老老实实地用ini文件或者xml文件,要解析也得再研究一下用Win32 API直接怎么解析,以前都是用VCL里封装好的类,唉!这样也好,只要写好一个Lua的交互模块,就可以既用作配置文件解析,又用作游戏逻辑定义了,一举两得啊! 想了想,skin里要定义的数据还是有点多哦,包括主界面图片大小,方块池位置,预览框位置,道具池位置,系统按钮位置,功能按钮位置。 白天考虑了Lua脚本中需要定义的游戏逻辑,包括move_left、move_right、move_down、speed_down、rotate_next、rotate_prev、on_timer、on_cycle、game_start、game_init等。在初始化的时候需要提供一些基本的信息,比如游戏等级等,另外就是对脚本应该有校验,MD5算法比较合适。
用C++ SDK和DX7,还真是烦,什么都要自己处理,郁闷啊!花了好多冤枉时间啊,先是图片压根就显示不出来,后来终于跟踪到原来是在IDE里调试的时候,根据可执行文件的路径来得到图片文件的路径下是没有这个文件的。把它放进去,再看看,发现可以显示一些乱七八糟的颜色了,再设置断点,跟踪到装载位图文件的函数里,发现总是试图去delete一个不知道哪里的值,才明白过来,原来这个结构在使用前应该先清零的,郁闷啊! 现在图片终于能显示出来了,但还有个问题,就是因为没计算好,总是画到(0,0)的位置上去了,另外就是不知道为什么,用了AjustWindowRectEx和MoveWindow后,窗口总是会消失……把这问题解决后,就剩下实时画方块池的任务了! 另外再好好规划一下,跟Lua怎么交互!
现在真的越来越懒了,只写了几行代码就不想动了。似乎DDraw在Normal模式时不能用FLIP?不确定,想不到有这么多未知问题,代码产出率太低了。白天在公司的时候,用VC6编译了unzip、7z这些,似乎还行,回到家,用VC7.1来编译,全都通过了。可以集成unzip和7z的解压缩功能了。 看来还是得好好学习一下怎么使用DX,也不用最新的技术,只要DX7的接口就行了,D3D也暂时先放下吧,DDraw和DSound最先要紧。 首先,只考虑矩形的界面,把主界面画出来,定期调用Lua脚本中的游戏逻辑,再根据Lua脚本返回的结果把方块池、预览框和道具池中的内容画出来。这样看来,似乎没有多少事,就是用DX画个界面,把Lua集成进来。还有一点要考虑的是,怎么做键盘加速和游戏录像功能,同时再考虑一下联机功能。今天在公司看到一段高精度计时器的代码,对于键盘加速,似乎有点帮助,就是定期检测按键状态,按一定速度发送WM_KEYDOWN,用IDA反汇编了kbace.dll,大概看到就是这样做的,也许具体的细节需要再研究。联机从技术上似乎也不是很有问题了,唯一需要的就是时间和毅力了。 好好学习《Windows游戏编程大师技巧》!
诱惑真是让人难受,总是忍不住去做些很费时间很不上进的事情,比如打俄罗斯方块! 打了一段时间的俄罗斯方块,进步很慢,好像现在很不稳定在1.1x的样子,不知道那些3.5以上的人是怎么练出来的。原来,是因为确实缺少一些必要的知识,所以可能很不现实达到那样的高速,尤其是要平移。现在知道是因为键盘加速了,但还有一些小技巧,比如手指的动作应该尽可能地灵活,并且幅度小,这样可以高速地击打按键。另外就是要尽量缩短思考的时间,一方面,应该在完成一件事的时候可以同时进行思考,比如在移动的时候可以思考下一块的动作,另外一方面,应该对一些常见的形状形成条件反射,看到那样的形状几乎不经过思考而直接由肌肉反射进行移动摆块。现在只能想到这几点,但这几点要做好就已经很不容易了,大概剩下的能做的就是不断地练习练习再练习了! 修改了一下tracetcp.dll中的一些代码,再在SocketCapture里对接收到的消息进行解析,其实也就是把字符串截断成几个,分别显示在ListView的几个列里。只是还是没找到正常关闭completion port的办法,郁闷,会把程序弄崩溃。 在微软的网站上看到Vista RC1的下载,32位版本大概有3GB,填了几张表格,回答了几个问题,终于可以下载了,先下一个再说。
今天听到一个同事说,他觉得电视的《红楼梦》比书要好看,然后被我们几个周围的人一起狠狠嘲笑了一把。晚上2点多睡觉,早上8点不到就起床,身体还真有点吃不消,白天的时候就觉得又累又困。zzz终于也辞职了,他的动作还真快,比起我那个同事来快多了,他今天就没去公司了,因为昨天下午6点开始,他的所有权限都已经没有了。我那个总是一起吃中饭,讨论一些编程问题的同事,应该也是再也用去公司了,今天另外一个同事买了一些零食,就说是他剩下的一点钱买的。人员流动就是这么快,倒是我,还暂时只能窝在这个地方,我没那么洒脱,没那么大胆,得找好后路了才敢动。 大概想了一下SocketCapture,在WinSock监视部分要把API的名字单独列出来,至于进程名,可以在宿主程序中通过PID计算得到,而且为了能获得比较快速的响应,我在想,是不是应该把计算得到的进程名保存起来,下次得到PID就直接查表了。还有一点要记住的是,在工作线程里操作ListView时,记得要用临界区包起来。另外有一点要考虑的是,ListView的显示性能问题,是不是应该改成Virtual ListView呢,看到LLYF DebugCapture的速度,真是太慢了,当时不知道是怎么想的,居然没考虑到?倒是LLYF Spy中的那部分功能是用Virtual ListView来实现的,响应速度还算可以了,15K条记录大概要全部删除的话,不到1s就可以了,添加记录倒不知道需求有多快。做完这些,还剩下过滤功能,数据显示功能这两大块。之后,再考虑其它的周边需求小特性。不过最近我总是在为界面的事儿郁闷,总感觉为什么我用BCB画出来的界面看起来非常业余呢! 我现在都还像个学生一样,总想学点自己感兴趣的东西,而且还很多。今天在公司里就看了很久的编译原理的东西,想着怎么做一个所谓的“按键语”的解释器。另外要学的是,基础算法,这方面我最薄弱了,因为一直以来数学都学得不好。看了一本写棋类游戏的书,就对那些算法感兴趣了,可以写个象棋和五子棋的程序,集打谱、人机对弈、联机对弈功能。还有音频开发和简单的图像处理算法,因为打算要写一个音频播放器,要给那CaptureHelper加上简单的图像处理功能,要写模拟器。甚至有点想写一个像QQ火拼俄罗斯的东东,但是要有加速功能,更强的娱乐性(用coolkuai上的人的话说),我是真的疯了,我确定,一个人有这么多精力吗?我似乎全是兴趣驱动的,而且目的除了希望能获得经济利益,还为了多学点知识,hoho~~~
早早地回到家,把Detours里的代码copy过来试了试,用Complete Port和Named Pipe协作完成的IPC机制看起来对高吞吐量的需求是可以很好地满足,有时候就是不得不佩服那样的人,可以把程序写得那么好。剩下要做的是,把数据分解成不同的字段,可以方便地提取并显示到ListView中去,另外就是把dll改一下,可以用global hook注入到其它的进程中去,或者用remote thread,对于没有消息循环的进程,消息hook就不起作用了,只能用remote thread来解决吧。 看了千千静听的论坛,突然想自己也写一个这样的程序,我真是疯了,总是想着自己把所有的东西都做了,主要是看不惯用不惯,但别个又不能照着我的意见来修改实现我的需求,只好自己操刀动手。不过这个难度也大了点吧。 从论坛上down到一个叫Volume Logic的音效插件,有for WMP、for Real和for Winamp的,就是没有for foobar2000的,有点不爽,换上WMP一听,惊人的效果,立马给人不想再用其它播放器的念头!就是可惜了没有foobar2000的版本,还有,似乎是有iTune的版本的,不知道什么时候能把它集成到iPod里,这样,用随身听也能听到高品质的音乐了,人类的智慧真让人佩服!
Category Software
CoreDNS有一个官方的prometheus插件,可以暴露一个http接口给prometheus使用。通过观察度量数据,可以了解到自己网络使用情况,有些比较有趣。
前些天突然发现家里台式机(Windows 10)上的Firefox不能工作了,具体表现是:
自从给blog换了个theme,一直断断续续在调整一些细节,于是不免要用到jekyll,不过前些天手贱给公司的iMac升级所有gems,结果升坏啦,一运行jekyll serve就会报错:
自从知道nginx后,就再也不愿意用Apache了,总觉得Apache配置复杂、体积笨重、运行缓慢,当然这些只是我的无根据臆想。原本用nginx只是用来做静态站,做反向代理,今天zhangh说想要个Wordpress做产品展示页面,于是只好弄一下。顺便感叹一下他的执行力。
发现FreeBSD上的LXterminal很容易在输入长命令时换行错位,于是胡乱覆盖掉前面的内容,就很难好好地输入完一整条长命令。这事在Debian上没遇到过,我也只在Debian上装过LXDE并使用LXTerminal。其他在Linux上用过的Terminal也只有GNOME Terminal和Mate Terminal,感觉吧每种Terminal都是配合自家的DE的,虽然可以混用但心里总是有点疙瘩。
买硬盘有一段时间了,当时的想法是可能要做Linux平台的开发,所有自己家里的机器上也得正儿八经地装个Linux某个发行版,于是纠结了很久,终于在京东上花了总共780块大洋买了个WD的绿盘2T。结果把硬盘装入机器后,只是分了十几个分区,就再也没动静了。
后来过了大概2、3周吧,实在对自己鄙视得受不了了,翻出两个8G的U盘来,一个是花了20块大洋从淘宝买的,谁料想过了没多久公司(已经是前公司了)又因为十周年纪念每人发了一个8G的U盘。于是从网上找资料看了一下,在Windows系统下用一个叫Win32Image Writer的程序把Linux发行版的ISO镜像写到U盘里,就可以从U盘启动安装了。
先是装了个Debian 6,用的GNOME,装好后发现屏幕闪得厉害,估摸着是显卡驱动的问题,据说ATI的显卡Linux就是支持不怎么好,我的是Radeon HD 4540,从网上找了一圈各种解决方案,试了各种配置和开源闭源驱动,都没效果,很失落。本来对Debian的印象很好的,就是一种运行速度快,而且稳定的发行版,因为曾经在公司用VirtualBox装了LinuxMint和Debian同时编译clang,发现在Debian下要快不少。可是现在的闪屏问题使得这个系统处于基本不可用的状态。后来我还试了换GNOME为KDE,果然没用。于是知彻底绝望了。
因为Debian的闪屏问题搞不定,于是只好试着装装Ubuntu12.04这种小白发行版,它果然一装上就所有驱动都搞定了,不光是我那块显卡,连在10.04时需要自己找相同芯片其他牌子无线网卡的驱动源代码来自己编译安装才能使用的Fast无线网卡都直接驱动了。真是让人感叹果然是个适合我等小白使用的发行版。本以为问题就这样搞定了,于是下载了qt呀,qt creator呀,clang呀之类的源代码,都编译了使用。可是好景不长,不到两个星期,就出现各种问题。比如启动特别慢,在红黑屏要停留很久,一开始都以为是启动不了了,后来才发现是因为需要时间很长。再后来,各种已有的分区不能自动挂载了。虽然可以自己敲命令挂载,但终归让人心里极其不爽。到现在,居然不能关机了,一直停在关机logo界面里了。失望透顶,Ubuntu是从7.x以来,各个版本都装过的,窃以为最不稳定的Linux发行版,没有之一。
今天实在对Debian和Ubuntu失望之极,打算再换个发行版试试。之前在VirtualBox中用过不短时间的Arch,Fedora,openSUSE和Mandriva,对于Arch和Gentoo,我就担心显卡问题搞不定。对于后三者,不是很喜欢它们的包管理机制。于是最后打算看看Mint吧。以前在VirtualBox中也装过Mint,现在公司里还装着用呢,它默认不使用GNOME或KDE,而是使用Mate或Cinnamon,感觉挺精致的。在装Mint还是LMDE之间犹豫了一会儿,后来看LMDE用的是Debian的testing源,在我看来相当于放弃了Debian的稳定性这一大优势,所以还是用Mint吧。安装过程仍然一样,写入U盘可以当Live盘启动,然后安装,很快很傻瓜。而且我之前装Debian和Ubuntu把它们的/home都放到同一个分区,而且两个系统中都用相同的用户名,在Mint中也这样做,就可以直接使用以前做好的一些把配置写到/home目录的软件的配置了。
Mint用了近一天了,感觉不错,就看它能用多久吧。
前两天才知道GDIPP是LGPL的,放在googlecode上。昨天把它所有的源代码clone下来了,然后编译了一下,倒是全部编译出来了,不过运行后貌似没什么效果,囧了,有空读一下它的源代码。众所周知Windows的字体渲染效果不怎么样,所以对于自己有一套效果良好的字体渲染手段是很有吸引力的,我就是想试一下把GDIPP集成到自己的程序中去。
看到推友@davidx_me说有个叫WBIM的for Mac的五笔输入法,马上去下载了来试用一番。之前一直用系统自带的那个五笔型输入法,相当不好用,不但字符小,应该是GB2312的吧,而且连候选提示都没有,其他的常用选项更不用说了。试用了WBIM后,就爱不释手了,虽然跟小鸭、极点神马的在可配置选项上有所差距,但总体来说,已经可以说是鸟枪换炮了。
它有着大部分常用的输入需求的选项,比如繁简切换、中英文标点、全角半角、空格,还可以自定义翻页的快捷键,可以自定义用户词库,比较遗憾的是貌似不能自定义选择候选的第二三项的快捷键,不过好在五笔输入绝大多数是选择第一项的,所以也可以忍受。
再有一个还算满意的是上屏速度不慢,虽然偶尔还是有点呆滞,不过也在可以忍受的范围内。
最后要说一下,这个软件目前貌似是免费的,这对于混迹于人傻钱又多的Mac用户群中偶尔几个穷人来说,实在是个福音。
看到有人晒他用的Firefox扩展,想想自从我走出学校以来,就开始用Firefox,已经4个年头了,也晒下我用的扩展,Firefox如果不用扩展,还真是连IE都不如呢!
Adblock Plus,这个几乎是所有装了Firefox后都会装的扩展吧,我当年是过了好久才反应过来,用Firefox确实很少弹出各种广告窗口哦,全靠它了。
接上,有个同事后来跟我说,有个小NoScipt的东东,很霸道,我试了,果然把每个页面上的一堆脚本都禁了,确实从事实上到心理上,都更安全了。
AutoPager这是个国人做的扩展,可以自动把下一页的内容接到本页下方,造福了我这种懒人,看论坛可以一滚到底,当然我最开心的是用它来在线看小说,几百章也可以拼成一页,好壮观!
AutoProxy翻墙利器,不想花钱用VPN,只能用Tor之类的免费方案,但又难忍它的龟速,当然要把白名单里的网站剔除掉了。
Echofon似乎是个不翻墙也可以用twitter的方案,功能一般吧,有时候还自动登录不了,界面也不好看,还不能自动缩短网址。
FireGesture好像是Firefox中最流行的鼠标手势扩展吧,其中有一个版本用着很不顺手,好在过了没多久升级后,又顺手起来了。现在用鼠标手势操作浏览器大概是非菜鸟的必备技能吧。
接着是一组扩展合用,为了让Firefox的界面像Chrome那样,主要是先装个第三方Theme叫Chromifox Extreme,然后是扩展Chromifox Companion,这样可以让Firefox的Tab,工具栏,地址栏的背景色,位置等跟Chrome比较想像,然后是装Hide Caption和Hide Menubar把标题栏和菜单栏都隐藏起来,这样至少跟Chrome有九分像了!
比较有意思的是Google Redesigned扩展,可以把Google Reader、GMail、Google Calendar的默认界面替换掉,嗯,我就是个换肤论者,就是想试试不同的界面!还有个Integrated Gmail,可以在Gmail的web界面中又同时显示当前账号的Google Reader以及Google Calendar内容,对于gfan来说也是值得试用的,一个入口多种服务嘛!
Weave Sync可以将书签、浏览历史、密码和Tab信息保存到远程服务器上,不过我是没什么大用,因为我基本上只在我自己的机器上用,而且Firefox也被我用命令行的方式重新指定了用户数据的目录,所以直接备份也不麻烦。
除了这些,还有什么QuickDrag呀,Tab Mix Plus呀,UnMht呀,CoolPreviews呀,Coral IE Tab呀,Flagfox呀,Shorten URL这些扩展,平时装着也是装着,用得不多,但偶然想到时若没有这些功能,又会觉得有点儿不舒服,姑且留着吧!
今天在安装程序中添加了2个网页快捷方式,因为用的是ISTool编辑的,所以就直接用它来编译了,结果试了几次,都发现没正确添加上快捷方式,连原来应该有的其他的快捷方式都没有了,甚至发现我本来让它在所有文件复制完后,应该有个选项可以让用户选择是否运行程序的,连选项都没有了。 真是奇怪的问题,于是在CruiseControl的历史记录中翻出最近的历史,发现还是正确的。想到这个安装脚本的区别基本没有,主要在于使用的是不同的编译工具。于是用命令行ISCC.exe编译了一下,居然是正确的! 这ISTool原来还是自己做了一套编译功能的说?
前些天才知道,tor也是会被封的,要用tor bridge才行,至于bridge的ip从哪来,网上到处有说,也就是给某邮箱发个邮件索取来的。 这两天发现,这些bridges也是时好时坏的,于是笨办法是不停地索取新的bridges来用,今天发现得到的ip有的是之前得到过的,也就是说可能是不好用的,只能试试之前没用过了。 唉,封得越来越死了,无语!
昨天一时好奇,从网上下载了CTeX 2.8 Beta1来,安装好后,尝试着编译原来的一个纯英文的文档和一个Beamer做的幻灯片,结果发现全都有问题。首先是编译速度非常非常慢,CPU占满。然后是原来用grphicx的地方,直接插入png的语句编译不过。最后是发现Beamer包的应用和bibtex联用的地方,最后一次pdflatex编译时,编译不过。 速度慢倒暂时也忍了。至于插入png的语句编译不过,通过网上找到的资料,下载了个ImageMagick,里面有个convert.exe,可以将png转换成eps,而实际上这eps也只有在普通文档中是可用的,在Beamer中仍然要用png,这是让人很郁闷的地方,几方处理方式不一致,是让写程序的人很头疼的事。 好吧,这些都是可以放一边的。最最关键的是,那个幻灯片编译不过呀!如果不编译最后一次,那参考文献就不行了。于是继续上网找办法,发现一会儿工夫有了CTeX 2.8 Beta2,嗯,实际上我是很有心理准备的,这么一个小Beta号的变更,是不会有大变动的,但仍然不死心地尝试了一下,果然不出所料还是不行的。于是在CTeX的网站上看到正式发布的2.7.1.42版本CTeX,仍然不行。期间还试过有个CTeXLive2008的集成包,呃,也是不行的! 我相当的郁闷!于是上CTeX的论坛上发帖求助,直到今天有个管理员给了个2.4的CTeX下载路径,才算最终搞定!对于这种不了解的东西,不能随便升级了,要升级前也得对能正常工作的旧版本做好备份工作,以便及时回滚啊! 昨天差不多搞了整整一天,幸亏现在网速快了,不然还得花更多的时间呢。被LaTeX折腾了,教训啊!
本来计划是明天才开始做这个功能的,不过因为着急着要尽快走流程办手续,只好把这最主要的任务尽早实现了。 总的说来,基本算法是完成了,不过还是有些小bug。大体的算法是这样的:三类连接线,包括折线,样本曲线和贝塞尔曲线,其中两种曲线要都Flatten一下,最后变成一组前后相连的线段,然后将这组线段分别与矩形的4条边计算交点,把离交点最近的跟踪点作为新的连接线的一个端点。 这里要注意的是计算交点的顺序问题。也就是说,如果是从连在矩形上的端点开始遍历那组线段来计算交点,那么应该以最后一次的交点作为最终结果。而如果是从另一个端点开始遍历计算交点,那么应该以第一次的交点作为最终结果。 其次是中间点的调整。像折线,一个比较简单的做法,把交点与端点间的所有连接点都删掉就可以了。而样本曲线则应该调整中间的切点位置,贝塞尔曲线则是调整两个控制点的位置,以免新生成的曲线因为中间那些点的牵引而仍然横穿矩形。
今天大概花了两个小时吧,加了右键菜单添加子对象的功能。这个功能的实现,有几个部分需要关注。 首先是图形绘制部分。这是需要修改最少的部分,因为之前的工作已经实现了子图,子对象就是在子图中添加的对象,只需要在相应的响应函数中实现添加子图,在对应的图中添加对象即可。 其次是右键菜单动态生成。这部分也不是很麻烦,只要识别出当前点击位置是什么图形,该图形在业务意义上可以拥有哪些子对象,就可以拼装出一个完整的右键菜单。 最后是花了不少精神的配置信息读取部分。本来配置信息都是从配置文件中读取的,因为并没有对配置文件与配置项的对应关系做严格的限制,所以原先的设计中,把配置项的信息基本上都是做成实时读取的,今天又要拿来用一次,就显得原来的设计似乎不是很方便。不过我还是没做更多的改进,仍然沿用原来的做法,实时读取某个对象可以拥有的子对象的类型信息和其他描述信息,以便于添加到右键菜单和后面的创建子对象 。 今天的任务基本完成。数了一下代码量,这个项目总共才4.7Kloc,挺少的,很出乎我自己的意料之外。这么算来,假设我在这个项目中已经投入20天,那么有效产量大约是230行每天,比自己订的目的500行每天少了一半多啊!
这次的需求中提到,能为一个图形关联一个子图,用该子图来描述该图形的内部结构信息。展现给用户的语意是,当双击一个图形时,则展示该图形关联的子图。 今天投入去实现该特性,基本没有遇到什么阻碍,因为原来的架构设计可以满足这个需要。当初把用户界面视图绘画层,图形管理器,图形对象三部分独立开来实现,所有用户操作都从视图绘画层接受,将操作信息传递给图形管理器,再由图形管理器转发给各个图形对象进行响应。在那之后,我曾经考虑过,这么做是不是有点儿过度设计,这个图形管理器的操作响应转发功能是不是多余的。现在却发现,这样的实现才刚刚好,一个子图,对应一个图形管理器,视图绘画层要始终跟踪当前起作用的图形管理器对象,任何时刻都只跟一个图形管理器进行交互。这样,没花费多少力气,只是增加了创建图形管理器,维护图形对象与图形管理器的对应关系以及销毁图形对象和图形管理器的功能,就可以实现子图功能了。 在实现这个功能时,有一个小心得,及早加入dump文件捕获功能很有用的,因为即使是开发阶段,也不是每次都在调试器中运行,所以当在自测试时偶然出现的崩溃现象,可以及早通过dump文件进行定位,而且因为是Debug版本,所以通过dump文件分析出的结果往往比较精准和明确。 除此之外,还发现一个以前没想到的现象,原来MFC中,CDocument类的OnCloseDocument方法,居然会销毁自己,及其派生类对象,如果要做些扫尾功能,放在派生类的OnCloseDocument方法中时,一定要把调用CDocument的OnCloseDocument方法放在最后。
昨天熬到快后半夜,从Embarcadero官网上把Delphi/C++Builder 2010的ISO安装镜像下载了下来,并从网上找了个一年试用的license,装好了来体验一把。 在4年的大学本科生活中,可算得上用了3年半的C++Builder,在毕业后从事测试工作的那近2年的时间里,也断断续续地用着,所以总以为自己对C++Builder的感情可能是不容易割舍的。但是经过昨天晚上和今天晚上短暂的试用后,嗯,只是把一个C++Builder2007的工程转换为C++Builder2010,编译有不少通不过的。我放弃了,我想说:Byebye,C++Builder!编译不过的地方,我看了一下,都是因为Unicode这个编译选项引起的,我粗略地找了一遍工程设置,似乎没有可以修改这个选项的。说实话,我感觉最好的版本是C++Builder6,后面跟Delphi合并使用一个IDE后的版本,差不多每个大版本都装过,但都没有让我继续用下去的念头。 出2009时,我曾自己安慰自己,彻底放弃它了,这回有了2010,还是忍不住弄来装了装,真的彻底放弃了,没有一点亮点!一款C++开发工具,我关注的是三方面:IDE、编译器、类库(框架)。曾经在BCB6.0和VC6.0的年代,这三方面BCB都是占据优势的,可是这之后的7、8年来,VC在大幅进步,而BCB却是裹足不前,VC现在都已经精进到几乎没事可做的地步了! 就让它,活在回忆中好了!
图形编辑功能已经做了两周了,到现在为止,也只能画出矩形框,在矩形框之间用白线、样本曲线,或贝塞尔曲线进行连接。又一次发现,只有在编码实现的时候,才会遇到很多之前没有想到的各种问题,而且有些问题要解决,也是要花费不少功夫的。 要考虑图层的问题,如何定义每个图形所在的图层,在绘制时,才得比较方便快速,而且需要可以随时修改图形所在的图层。图层的影响是多方面的,例如在绘制整张画布及图形对象时,要从底层开始绘制,而对于在某个点上点击选中一个图形对象时,却要从上到下进行遍历查找。 还考虑随时可以修改画布的大小,因为在添加图形,或修改图形位置时,是随时都可能把图形放在一个走出当前画布大小的位置上的,这时程序应该可以自动检测出需要扩大多少。对于向右、向下方向的扩大处理很方便,直接将画布大小重新定义即可。而对于向左、向上方向的扩展,则除了重新定义画布大小外,还得把超出部分归整到(0,0)这个坐标上,也就是说,要把所有已存在的图形对象的位置都调整一遍。 再要考虑子图的问题。也就是说,一张完整的图片,在某一时刻,只是显示了其中一部分图形对象,这部分当前被显示的可以作为一个子图来对象,而没有被显示,则是属于其他的子图。每个子图之间应该没有多少强相关的关系,最多是一个图形,与一个子图可以有包含(从属)关系,一个子图用来解释一个图形。常见的一种应用场景就是,双击了某个图形,就展示另外一张图片。这就同样要求设计一种灵活高效的数据结构来保存这些信息。 从当前的实现情况看,每个图形对象中,都有不少成员变量,保存了一些中间数据,这些中间数据不属于图形对象的本质属性,却对于图形在特定时刻进行动作起着重要作用,从代码美观角度讲,感觉很冗余,所以要考虑如何优化,减少这种成员变量。例如对于一些状态变量,或许可以用位域的标识。
开始做那个图形编辑程序1周多了,现在遇到了瓶颈,因为原来的设计考虑得太不全面,很多很明显的问题都没有有顾及到,结果到实际编码实现到一定程度时,发现原来的程序结构有点不行了,不够用了。 主要的矛盾在于,原本我的设计上是,每种图形,都各自响应用户操作,互相不知道其他同类的存在。而实际上这是不对的,或者说不合适的,比如连接线,在端点确定前就是要知道那个位置是否贴到某个图形上了。另一方面,当某个图形上的连接点移动时,同样得通知所有跟这连接点连着的连接线,或者是某个图形被删除时,得同时删除连接在它上面的所有连接线。 本来所有图形对象都在一个管理器进行任务分派,现在看来,至少有得有一个类,可能还是这个图形对象管理器,做更多的事情,可以查询它所管理的图形对象一些特殊的状态,还要维护图形对象间的关系,可以是一个邻接矩阵,或一个邻接链表,反正就是一个图的表示法。这些不是我现在的主要困扰,我的困扰在于,图形对象怎么来调用这些查询状态的操作。本来图形对象被那个管理器对象包含了,另一方面那些查询状态的操作得知道所有这些对象,这样的循环依赖,让我感觉不爽!
话说,我并不是计算机科班出身,因此很多基础的知识都是不知道的。这不,发现SQL真是有必要要好好学习一下了。最近在很多地方用到了数据库来存储东西,于是不可避免地需要写些SQL,最最基本的SELECT、INSERT、UPDATE还是会点的,不过也仅限于在单表中进行操作。 前两天发现一个可以显著提高在Sqlite3中SELECT性能的方法,那就是建索引。因为IDE需要AutoCompletion和Calltip功能,而用于这两个功能的数据都是存在一个sqlite3数据库中,该数据库目前已经有不少数据了,光是一张记录了方法的表,就有1万多条记录,从中SELECT是经常要做的操作,所以能提高点性能是很有意义的事。自从给该表建了索引后,至少感觉上非常明显,AutoCompletion几乎没有任何停顿就提示出来了,而以前的话,有个明显的停顿,虽然这个停顿的时间并不长,但已经能让人感觉出来了。这只是一点,让我觉得学习一下SQL有好处的地方,就让我尝到了莫大的甜头。还有一点就是,有不少地方的SELECT的条件,是从这次其他的SELECT中取得的数据,而我全部都是分成一条SELECT一次操作来进行的,我想,如果能把这些SELECT合并成一条语句,应该还是能再提高点运行速度吧。
嗯,一直以来都以为UTF-8和Unicode是一类的,今天才明白过来,UTF-8确实明明是多字节一类的才对啊,我的理解能力实在是太差了,唉! 不过今天倒是也知道了,如果只是要在ANSI、Unicode、UTF-8之间进行转换,使用两个Win32 API就可以全部搞定了,不需要用什么iconv和ICU了。总是觉得微软做的东西易用性真的很好,通用软件产品很适合普通用户使用,而那些开发工具、库、API对于开发者来说,也很好用啊! 唉,我也就只用玩一下这些容易的东西了。
看《Windows高级调试》猛然发现一个问题,书中的例子都是对exe进行调试的,而且几乎都是知道问题重现步骤的。这跟我现在的情况可差得很远了,我只有一个core dump文件,不知道问题出现时的操作。看书上都是一直操作,直到问题出现,然后在调试器中断下来,查看寄存器,堆栈,句柄等信息,再抽丝剥茧一点点推测出问题的根本原因。我不行啊,我在源代码中加入了一个自定义的UnhandledExceptionHandler,在问题出现后,就转到那里去执行了,连最后现场都被破坏了的! 晕!
无意中在一个讨论组中看到Chrome的新differential算法Courgette(http://dev.chromium.org/developers/design-documents/software-updates-courgette)的讨论,其中提到一个Develper Channel从190.1到190.4的升级例子:完整升级包:10,385,920字节,一般bsdiff算法:704,512字节,而Courgette算法:78,848字节,近十倍的空间效率提升啊!真是太恐怖了,直到今天我才知道,原来对于二进制补丁,也是有这种优化算法的,汗啊!http://neugierig.org/software/chromium/notes/2009/05/courgette.html 这篇文章也对这个算法进行了介绍。大体上,Courgette算法目前是基于x86体系的,适用于exe、dll等可执行文件补丁,它会将这些新旧版本二进制码进行反汇编,在反汇编的基础上进行比较,据说是将二进制文件中所有的internal pointer/reference的地址重新符号化, 然后再计算differential,得到补丁。 另外一个博客中也有一篇讲优化二进制补丁算法的,http://blog.csdn.net/housisong/archive/2006/04/11/658863.aspx。 由此我想到我们现在的自动升级程序,都是完整文件下载替换的,土了啊!
啊,非SHFileOperation莫属!今天要实现个文件夹复制的特性,于是就想到这个API,可是很不幸,无论我怎么整,都报个1026错误!从网上找了一圈,发现代码根本一模一样的,人品问题啊! 后来在花费了不知道多少时间后,也许是1小时,也许更多,等不及了,花了10分钟自己用递归写了个函数来实现文件夹复制,我吐血三升!
今天看到一篇文章,讲鼠标手势算法,觉得有点意思。现在不少软件都有了鼠标手势支持,尤其是浏览器,几乎成了高级用户的标准配置了。 这算法分为4步。 一、过滤鼠标移动动作。如下图所示,这步过程把一连串的鼠标移动动作中幅度过小的动作过滤掉。这跟系统配置也有点关系,不同的配置下,记录鼠标移动的速率等量纲有所不同。
二、限制鼠标移动方向。如下图所示,对于简单的鼠标手势支持,只支持上下左右4个方向,就把其他方向的动作都归并到这4个方向中。一般就是比较一下上下方向和左右方向的差值,取大的那个作为最后的方向。
三、简化移动方向序列。如下图所示,这步非常简单,原本是右右上上右上上的方向序列,简化后变成右上右上了。
四、匹配和推演。这步是最困难的,表面是把夹杂在长距离移动动作中的短距离动作过滤掉。大概的做法是先把整个动作序列与一组预定义的序列匹配比较,如果匹配失败,就把这序列中最短幅度的动作过滤掉,再进行匹配,如此循环往复,直到最后匹配到为止。
提高软件生产力,意味着可以在更短的时间内交付质量更好的软件产品。软件生命周期的各个环节都对此有着极大的影响,而从开发人员的角度讲,有几件事是力所能及的。 一、提高代码产能。单纯的代码生产力,比如一个开发人员原本一天能写100行代码,经过一段时间的学习和锻炼,相同规模相同难度相同质量的代码,只需要半天就可以完成了。 二、提高代码质量。这个质量指代狭义的稳定性、鲁棒性,代码bug少。这一方面也是通过学习、锻炼可以获得此类能力和经验,另一方向,引入合适的工程方法,比如TDD等良好的实践,也有一定的效果。 三、发扬“拿来主义”。现在可以从各种渠道获得并使用的代码片段、函数库、类库、框架、组件、中间件、软件等等不计其数,并不是所有特性和功能都要自己着手开发实现。只要代码功能满足实际需要,质量在可承受的范围内,可维护性也过得去,以及license没问题,就拿来直接用吧。可重用的,不光是代码,还有架构、设计思想等。形式上,无论是源代码复用,还是二进制组件,都可接受,甚至可执行程序也可以。 四、提高代码复用性。自己写过一遍的代码,尽量不要写第二遍,复用吧!代码重构一种使得代码得以提高复用性的不错的办法。 五、提高架构可扩展性。为了更快更好地实现后续新增需求,高可扩展性的架构是一个良好的基础。可扩展性的对面是可裁减性,假如有一天突然要求去掉其中的一些特性,这种情况也是存在的。这点对经验的要求和依赖比较高。 六、提高架构和代码的可修改性。需求发生了变更,或者原本对需求的理解就有问题,或者发现了bug,这些情况都需要对代码进行修改,别因为一个功能上的小改动而引发代码上的大改动。 七、使用先进的工具、方法和流程。比如眼下流行的敏捷,使开发流程减少僵化。使用优秀的IDE,智能感知、重构、自动代码生成等等。使用版本管理工具,定期对一些代码进行指标度量。 八、宽松、舒适的环境。环境好,对开发人员的身心都有好处,长期收益极大。 九、快捷、方便的求助渠道。向人请教是一种很省事的方法,但很可能影响其中一方的状态。上网搜索则是另一条有效途径。 当眼下软件生产力严重不足的情况下,这是仅剩的几件我能做的事了。
老雷说,画图功能可以让Excel来做,我曾经还抱着试试看的心理在网上找有没有免费的代码可以方便地生成各种柱状图、饼图的,没找到,也实现懒得自己去画了,于是硬着头皮去用Excel了。 VC的程序操作Excel,而且不光是为了存取数据,所以用COM是最正规最有效最理想的方法。如果是用MFC,可以让IDE自动生成其中的某几个接口的封装类,这样的好处是封装得比较高层,使用起来更方便简单一点。如果直接导入类型库,会生成整个类型库内所有的接口和类型的封装,不过是底层一点,最多是用一下COM智能指针封装的接口,可以少处理一些引用计数的问题。 先可以录一个宏,查看VBA代码,就基本知道要用哪些接口的哪些方法了,但实际上如果用VC通过COM来操作,会发现跟VBA的结果经常有些出入。这让我有点纳闷。不过今天整了一天,总算勉强完成任务了。
今天把一个用了wxWidgets、Xerces-C++、luabind的工程用bjam写了个构建脚本,可以用MinGW来编译,也可以用VC来编译,这就是bjam的好处,很少需要关心不同编译器的命令行参数。 经过这次实践,还发现alternative的选择原来是要跟它的属性完全对应上才行。比如一个目标,写了toolset和variant以及threading,则在命令行中要把这三个全都设置上,不然它就说找不到匹配的目标。这让我有点头痛,假如我只想在命令行上选择toolset,而让其他两个属性固定死,那怎么办。 不过还算可以了,目前基本能满足实际需求了。
bjam编译Windows下的rc文件不用特别指定,就像其他C/C++代码文件一样,直接放个文件名就行了,它能自动认出来,并调用相应的资源编译器来,只不过生成的二进制文件后缀还是跟代码文件编译出来的一样,不过并不影响最后的链接过程。 对于debug或release下使用不同配置的情况,需要至少每一种情况写一遍目标,同样如果是不同的toolset也这么处理。 今天把一个使用WTL写的工程用bjam系统编译了一把,果然也不是很麻烦,不过需要写不少特定的参数,bjam的默认配置不够用了,所以这样的情况还是不适合用bjam的。简单地说来,适合用bjam的场合,至少是没有一个好用的IDE的情况下。 想起直接在bjam里用wx-config来生成的编译选项,居然会出错,因为wx-config的输出后面多了个回车,用make就没影响,而链接选项在bjam中也没影响。没办法,去网上找到wx-config的源代码,只有一个文件,不过有几千行,稍微找了一下输出的代码,把末尾的回车换行去掉,再试了下,果然可以了。
要在工程的根目录下放一个Jamroot文件,可以没有扩展名,也可以加.jam为扩展名,这样其他子目录下的可以命名为Jamfile了。 基本上是个大小写敏感的系统。 还没找到怎么让它来自己编译Windows的资源文件。 用path.glob-tree可以指定目录来进行glob-tree,如果光用glob-tree,是只能从当前Jamfile所在目录开始全部搜索的。
在编译Luabind成独立的库时,顺便学了一下bjam。bjam在某些场合下挺有用的,如果之前用的是make,再来用bjam,感觉就是用过汇编之后来用高级脚本语言。 折腾了一阵子后,我的感觉就是bjam几乎是完全给boost设计的。其中最突出的特点是,编译器无关。它在这方面做不了少工作,只要指定一个toolset,它就能自动查找编译器所在的路径,而且不用关心编译命令行,因为大部分常用的选项它都提供自己的抽象方式来表达。还有就是它似乎有良好的可扩展性,在boost的源代码目录下有几bjam的工作目录,下面有几个子目录,里面分别存放着一些jam文件,在写jamfile时,可以import模块进来用。 我捣鼓了一阵,把自己一个工程,里面有几十个C++源文件,从GNU make转成了bjam工程。感觉有点新鲜,但总的说来,它应该是适用于这样的场合:工程是可移植的,即要跨操作系统,跨编译器。
主要的内容生成功能基本完成90%了,于是就研究一下怎么把这html内容通过SMTP发送出去。原来有一个从CodeProject上找的SMTP类,直接用WinSock写的,倒是也可以正常工作,接口也很简单,而且当时沾沾自喜经过自己修改,是可以支持中文的,其实是自己土了。现在只是想把这个类再修改一下,可以直接发送html内容,不过看起来似乎有点儿复杂。 用Outlook Express发了几个邮件,用Wireshark抓来看了看,看得云里雾里。后来找到另外一个示例程序,有源代码,也可以发送html,用Wireshark看了看,发现差别还真大。最后看到一个说明里提到,RFC2110里就是讲这个的,于是马上找来瞄了几眼,终于有点儿理解了。原来Outlook Express在一封邮件里包含了2封邮件的内容,分别是html和plain text的,这样无论对方的客户端能不能支持html阅读,都可以方便地看到真正的邮件内容,当然html中的链接嵌入对象除外。
老雷要一个自动发汇报邮件的程序,这个任务落到我的头上,于是我这周开始整这玩意儿。所有的数据几乎都是存放在MySQL里的,一个是RedMine的内容,另一个是组里自己开发应用程序使用情况统计工具,服务器端也使用的MySQL。今天我发感叹地跟开发那应用程序使用情况统计工具的同事说,幸亏你们当时选用了MySQL,不然还要更麻烦一点,比如万一选了个Access或者Sqlite3,还不能方面地远程访问。如果是SQL Server,还得使用一套不同的数据库访问方法。 通过这两天使用mysql++来访问MySQL的经历,我感觉无论是MySQL引擎,还是暴露的API,都挺不错的。大概是因为ADO访问SQL Server用得有点反胃了。那段经历让我觉得最为不爽的是,如果SQL写得有点问题,就会抛异常,而且这异常就是catch不了,因此很难排错。这次用mysql++在这方面就做得不错,异常可能catch到,而且给出的出错信息很准确,定位很方便。另外有点值得一提的是,mysql++里有一个重载了很多类型转换符的String类,呵呵,这也是一种办法啊,不过使用operator+时却遇到了点小麻烦。 开发这个程序最大的收获大概就是这个了,大部分情况下,可以用MySQL来代替MS SQL Server了。再扯远点,Access也有点不好的,打开的时候特别慢,用Sqlite就挺快的,而且Sqlite3还是是弱类型的,呵呵。
之前说到,用多了chrome,竟然不知不觉地想着firefox的界面也想跟chrome一样,说干就干,先去找theme,要能尽量模仿chrome的,还真找到一个chromize extreme,不过它只能支持3.1b1以上版本,没办法了,我现在是3.0.6,只好去重新down了一个3.1的装上,还是像以前一样,用命令行参数,将配置目录指向3.0.6的目录下,这样就可以使用3.0.6中已经有的一些东西,不过有些扩展不兼容,暂时不管了。装了chromize extreme后,挺像chrome了,除了多了个标题栏。找到一个hide caption扩展,不过发现它不能用在3.1版本中,于是另外想办法。最后只好用custom button扩展,加上一段脚本,叫max的脚本,会自动将firefox弄成最大化并隐藏标题栏。 搞定!界面看起来真的像chrome,感觉舒服多了,哈哈,就是不能用3.0中的一些扩展了有点遗憾!
突然发现,怎么Firefox有标题栏,怎么有菜单栏,怎么这theme就不正常了呢!使劲点了几下菜单,也没变化,切换了一下theme,重启firefox,菜单栏不见了,再切换回去,怎么标题还在! 突然想起来,这标题栏似乎一直都在的!是chrome用多了吧,傻掉了,汗!
还是搞不定,郁闷! 首先我用vc2008编译从svn中取出的boost代码,总是有问题,只能生成一些libxxx.lib,没有生成动态链接版本,这个问题在boost正式发布的版本中是不存在的,真奇怪。
其次,无论是正式发布的还是从svn中取出的代码,编译的boost::program_options,在与STLPort一起用时,是必定出错的。debug模式编译基本能过,但链接死活不行。release模式则索性编译不过,这个问题在取消STLPort时,就不会存在。但是如果不用STLPort,在链接时,会报符号冲突。
如果实在不行,也没办法了,只好不用boost的需要编译的库了。boost中大部分的库是header only,这总算让我觉得比较欣慰。不过昨天看到Boost.Log以提交review了,而且看了一下它的文档,需要依赖了boost中的好多库,其中好几个需要编译的,比如boost::filesystem、boost::system、boost::date_time等等,郁闷,一直在等着boost出一个log库,准备工作还那么麻烦啊!
在复杂的Internet环境中,用惯了firefox,用惯了它的扩展后,再也不想用其他浏览器了。这两天又装了几个扩展,太好用了。 noscript,自动禁止了一些无用的页面脚本。Coolpreviews可以在鼠标指针移到超链接上时,自动弹出页面预览窗口。FireGestures,就是现在在很多软件中流行的鼠标手势。 像chrome这样的实验品,我最多只是在局域网环境中用一下,一来忽略了外网环境中特有的复杂性对它的过高要求,二来它的超快速度在局域网中也能更好地体现。
前不久为了使得MSXML输出到文件的内容有良好的缩进格式,在网上又转了一圈,最后终于在一个老外的论坛里看到一段代码,使用SAX的方法,果然可以几乎完美运行。再也不用以前找到的使用xslt的方法了,使用xslt的方法是很久以前在国内哪个网站上找的一段javascript代码,自己翻译成了C++的,最后效果不是很令人满意,主要有两个缺点。一是文档开头的处理指令没了,要在额外添加,二是对于没有文本内容的节点,它还是会添加一个结束标记,累赘冗余。 这两天在写WIND时突然遇到的问题,本来只是使用STLPort替换了VC9自带的STL实现,用着也没什么问题,后来想试试boost::program_options,结果在编译时,报boost::program_options的lib跟WIND编译时使用的标准库不一致,一猜就晓得是因为当初编译boost::program_options没有使用STLPort编译,于是想重新编译一把。翻了好几遍boost自带的文档,也没找到具体的方法,在网上又转了几圈,还是没发现有效的方法。今天又是偶然在一个老外的论坛上,看到一个回复,简单试了试bjam果然可以正常运行下去了,唉! 又靠了次老外。
这两天才发现,用msys运行configure生成的makefile是直接编译链接有问题的,最后链接的时候总是报找不到一个什么sqlite3Backup函数。今天在源代码文件中查找了一下,发现这个函数是在backup.c文件中定义了的,所以代码有问题的可能性不大。于是看了一下生成的makefile文件,赫然发现没有编译backup.c的动作,加上后,再make一把,果然通过了。 看来sqlite3的configure脚本没有跟着更新啊!
今天终于解决了向SQLServer2005存xml时使用的字符集的问题了。 年后第一天上班,看到年前一个邮件,说是有个文件导不进去。拆下来跟踪了一下,发现是中间生成的xml文件不完整,通过简单的试验,直觉告诉我是字符集的问题,因为我将这xml文档的字符编码设成gb2312了,而鬼知道别人会写些什么特殊字符进来。把文本粘贴到UltraEdit中看了一下,果然有一个非gb2312范围的字节。我想,这种情况都出现了,无论如何都不能再继续用gb2312了,只能往utf-8之类的方向去考虑了。实验证明,以utf-8编码的xml文档是完整的,可是又回到一年前的问题,utf-8编码的xml文档写不到SQLServer 2005中xml类型的字段中,只能写gb2312的。 实在没办法,这方面没有人可以提供相关的经验指导,只好去看SQLServer2005的online help,好在是中文的,随便翻了一会儿。中间联想到,会不会是MSXML保存时并没有真正转换编码,实际上当然不是。又联想到,该不会是因为没有BOM吧,结果我没有去试。后来偶然看到其中一段说明,可以用utf-16,而且不在乎有没有BOM,如临大赦啊! 用ADO写回去时,先读出整个文件,因为开头的BOM的原因,需要再用SysAllocStringByteLen生成一个BSTR,不能直接用_bstr_t,再填回数据库,就可以了!
今天在公司网上看到有人在发Chrome的绿色可执行包,于是又好奇心起,下载下来玩了一下。以前也装来玩过,不过当时的版本还没有足够的稳定,时不时崩溃或挂起,于是摆弄了三两下就不玩了。这次下载下来的似乎则要稳定得多,毕竟是经过好久的beta测试了。
这次给我最大的震憾是chrome的速度真的很快,比IE和Firefox不是快一点两点,而是快很多!也许在外网环境还没有这种体会,因为等待的时间全耗在网络延时上了,在局域网环境下,网络延时极小,浏览器的渲染速度差异就很明显了。
本来在公司里,我也只是用3.0版的Firefox,因为用它来浏览redmine比用IE快多了,其他的应用场合主要是写wiki,用的mediawiki程序,以及看CruiseControl的报告,还有一些静态页面,比如用doxygen生成的html文档。换用chrome后,只能用震惊来形容,除开网络延时不说,真的是一点链接即出来整张页面!
不过总的说来,以chrome目前的状态,我也只能在公司里用用,写写wiki,看看报告,换到外网复杂的网络环境,chrome还不能胜任。首先,firefox有Adblock plus扩展,对广告的拦截效果非常好,用过它的人已经离不开它,chrome就没有类似的东东。其次,firefox下的鼠标手势,增强标签浏览,内嵌IE等,都是日常需要的功能,chrome也不行。再还有,似乎chrome的稳定性还是有待提高,偶尔还是会出现阻死在那儿的现象。
要是哪天firefox能弄得这么快就好咯!
最近几次在网上看到有人提到xmind这个东东,今天偶然看到有安装包,也不用上网下载了,就装来试了试,是一个基于Eclipse RCP开发的,简单看了下,快捷键的使用习惯上跟MindManager是一样的,其他的常用功能也基本都有,而且还有官方的中文版本,又是免费的,实在是最佳的思维导图绘制工具。 之前试过FreeMind、MindMapper和MindManager,最终觉得MindManager最好用,但这三个只有FreeMind是免费的,用盗版的MindManager心里总有点疙瘩。现在好了,换xmind了,哈哈!
今天稀里糊涂地试了一下,把线程里的run_reactor_loop给try了一下,居然有用,欣喜若狂。现在想想真是糊涂啊,这也太扯了吧! 不过话说回来,那块的代码在上次写完后,一直心有余悸,不敢再去动它,也不愿意再看它,有点反胃的感觉。今天下决定看了看,还真发现几处bug,有没关闭句柄的,有没有添加消息映射的而处理代码却是写好了的。今天这么一整,至少崩溃问题又要少一些吧! 虽然现在用ACE已经勉强能够运行了,可我还是有点想再换回用boost::asio去。当年用boost::asio也不知道是哪里出错了,死活不能好好地连接上再互相发点数据,现在有了这点儿用ACE的基础,而且比起当初boost::asio也是正式release的版本很久了,也许一方面是我用得不对,也有可能另一方面是因为我用的从svn里直接check out出来的代码确实有点儿问题呢!
因为考虑到要跨平台,所以不能用MSXML了,而且对于MinGW能不能直接使用MSXML我都不抱希望,于是在几个开源的可跨平台的XML解析器中进行选择,并且只能是用于C/C++的。候选项包括expat、TinyXML、libxml/libxml++、Xerces-C++。我不喜欢expat的实现方式,也不习惯TinyXML的只有DOM的解析方式,而libxml/libxml++则是因为捣腾了一阵子还是没能用MinGW正确编译,最后的选择只剩下Xerces-C++。而实际上编译Xerces-C++也花了我一些时间。网站上最新的是3.0.0,倒是有VC7、VC8、VC9的编译好的包,不过我要MinGW的,所以下载下来源代码,看了一下网站上的说明,先装好msys,选好参数运行./configrue,就会生成makefile。而这生成的makefile似乎并不能直接用MinGW的make过,需要稍微修改下,也就是把其中所有的什么dirstamp目录的创建和依赖都删掉,方能编译。 编译wxLua稍微好过一点,不过一开始绕了点远路。从CVS下下来的源代码,到build/msw下找makefile.gcc文件,这个文件少了写了两个编译选项,以致于在生成库时在链接时总是去找WinMain,开始不明所以,硬是把LDFLAGS设为-shared,在编译库时是没问题了,但编译出来的.exe文件就不行了。后来发现只要添加LINK_DLL_FLAGS := -shared和LINK_MODULE_FLAGS := -shared就可以一切正常了。当然wxLua依赖于wxWidgets,所以事先要设置好WXWIN和WXCFG环境变量,而且最后面不能有反斜杠。只要设好了这两个环境变量,用VC9倒是可以很顺利地编译过。 有些时候不免要抱怨一下,开源的东西,易用性可能确实差了点。
昨天遇到一个问题,用MSXML操作XML时,删除一个子节点,可是死活删不掉。后来想到一个变通的办法,把这个子节点的标志性属性值改掉,这样其他处理过程就认不出这个节点了,就相当于删除了,很黄很暴力。 今天再去定位这个问题时,发现原来那子节点真的被删掉了。进一点试验发现,只要在删除该子节点前,先随便改一下这个子节点的一个属性值,下面的删除操作就正常了,但如果没有那个修改操作,就删不掉,真是怪事! 我当时还以为是不是因为子节点下面还有其他孙子节点,还想是不是要修改一下删除子节点的封装方法,递归地删除掉所有子孙节点呢!看来不必了!
今天在公司看到一个同学在用e,有点好奇,早听闻它有“Windows下的TextMate”之称,以前也下载来装过,只看到界面很简单,功能也很简单,于是就没下文了。今天又有点兴趣,就让同事共享给我再试用一下。 还是老样子,界面上没什么改进,也许比之前我试用时功能上有所增强,但以我目前的眼光看来,它还是太简单了。总的说来,只有一个特色功能,就是bundles。不过可能TextMate赖以成名的就是bundles了,e就是全盘照抄了,从网上看到,说e的作者和TextMate的作者是老乡,两人协商过,让e可以直接使用TextMate的bundles。所有的人都说,e只有TextMate的一小部分功能,这我也是相信。但是最让人受不了的是,e运行极其不稳定,随便点几下就是挂起,或者崩溃。这么烂的程序居然也来卖,而且听同事说可能卖得还不错,我想这全沾了TextMate的光啊!因为说,它的一切思想,无论是从程序开发的角度,还是用户体验的角度讲,都是很好的,但这一切都是TextMate赐予的,e里唯一有点自己特色的是,用类似异步可插入协议的方式来修改配置。我没用过TextMate,不晓得它在这方面是怎么做的。 看了e后,另外一个同事就说,我们现在的Impeller应该也好卖吧,有语法结构树,有自动完成,有调试执行,我笑!
今天做另外一个工具的一点维护工作,需求是通过用户输入的宏名,宏值,类名,函数名以有函数返回值,工具要能自动到指定的文件中找到指定的位置,自动插入生成代码。本来这个需求是上个版本就已经实现了的,今天只是对需求有略微一点修改。可是最大的问题是,今天发现以前实现的这个根本不能用啊,文件是能找到,可是位置却是错的,根本毫无联系。 调试了很久,实现过程是首先利用MSR的greta来找到参考标记,取得标记的位置,然后插入生成的代码。一开始怀疑是取得标记的位置不对,其实冷静地想想,这种可能性几乎不存在。不过我还是傻傻地加入代码,看标记位置取回的字符串内容,毫无疑问,肯定是对的。接着怀疑是Scintilla的插入方法有问题,同样事后想想,这种可能性也微乎其微。不过我也不死心地,加入代码,看该位置的Scintilla文本,果然已经是不正常的内容了。 正在束手无策之时,突然不知怎的,灵光一闪,可能是因为看到其他一个项目中使用多字节编码的greta,觉得可能是这里引起的问题。greta在匹配文本时,在unicode情况下,一个中文字符和一个英文字符都是一占一个长度,而此时Scintilla还是以多字节方式处理,一个中文字符占两个长度,所以greta算出的位置对scintilla来说并不能对应上。想通了这一点,立即将工程编译选项切换到多字节方式编译,果然就正常了。 这次遇到这个问题,也能为以后实现相关需求,或者解决类似问题,提供了极大的参考价值。
从学校出来后,重装系统的次数大大减少,自从买了个本本,只是恢复过一次,今天是第二次,当然不算帮别人装的。 为了减少工作量,有些小小的算不上技巧的伎俩。记得第一次恢复是用的光盘,今天拿出光盘,发现读不出来了,大概是光驱的问题,于是直接选择恢复到出厂设置,反正我的恢复光盘中的内容跟出厂设置差不了多少。 选好后,可以去干点别的事,比如我就出去边吃饭边看电视去了,这样不知道总共花了多少时间,最后一直到设置机器名和用户名密码的地方,这时才需要人工介入。首先需要安装中文支持的MUI包,装完跑到控制面板里设置一下语言,使得界面上可以正常显示那些能完善支持中文的软件。 然后是安装那些必备的软件。 对于那些绿色版、免安装版、安装后更改文件夹后仍然可用的软件,则应该放在非系统分区中。这样下次恢复系统了,使用可以直接使用。比较典型的是Foxmail、QQ、Firefox(它要通过命令行参数实现)等等。 对于必须要运行安装程序才能使用的软件,则根据一般建议安装在系统分区,这样在恢复系统时,也能自动清理掉。这样软件包括Visual Studio、Office(虽然现在实际上不装这个了)等等。 接着是安装系统补丁。有个比较省事的办法,是装个360安全卫士,用它一扫描,发现所有的hotfix,自动下载自动安装,又可以去做些其他事情了。我就打了一会儿游戏,还去洗碗,整理床被等等,哈哈。 做完这些,基本上可算是恢复系统了,但实际上要花很多时间,对于我来说,似乎需要6、7个小时才能搞定!
还是因为贪心啊,想用盗版软件啊,这下好了,中毒了,不幸中的万幸,不是一个后果很严重的,照赛门铁克的说法,是个误导性的病毒,老说你的机器有风险,还自作主张地把网络给拦截了,有的程序都不能正常使用了,比如foxmail,每次都说打不开socket,暴汗,IE则根本不能打开网页了,幸好一直用的Firefox,不过很多页面上方加了一条腥红的字“Warning! Your system is in danger. You need a full scan of your computer.”,还把很多的超链接的颜色也改成了腥红色,真恶心啊! 盗版软件害死人啊!
要做一个配置界面,用户通过该界面可以修改一些系统配置项。本来配置项是一直都有的,不过不需要用户修改,都写死在配置文件中,这次有了新需求。大体上分成两个部分,一部分用于操作配置文件,另一部分当然是用户界面! 配置文件是XML格式的,用MSXML组件的CString封装版本来操作,用这样封装版本的好处主要有三点:一、所有接口都用CString而不用BSTR,方便与MFC程序交互;二、封装的方法中有一些简单的出错处理;三、有一种简单的用于跟STL中算法适配的迭代器,方便操作节点列表。 问题出现了,图省事,我直接在界面类中获取配置操作类中的DOM数据结构,想直接在界面类中遍历XML,结果发现每个节点想取属性时都会异常。开始怀疑是迭代器封装有bug,于是换了几种访问元素的方法,还是异常。后来猜测难道是不同线程使用COM的原因,想想也没有多线程啊,加上CoInitialize和CoUninitialize,还是异常!于是病急乱投医,想会不会把操作XML的代码全都放在配置操作类中,就好了呢。说干就干,因为要根据读出的配置信息操作界面,所以需要一个通知界面类的方式,我选择了callback,又因为callback是个界面类中的一个成员函数,所以越弄越复杂,最后为了能少写点代码,或者说看起来直观点,动用了boost.function,其实不用它也不会麻烦多少。好不容易全都改过来了,还是异常!我已经接近崩溃的边缘了,再异常就是我神经要异常了! 所谓柳暗花明,最后无意间看了看配置文件的内容,猛然发现根节点下的第一个子节点是条注释!用DOM解析时,注释也是一种节点啊,昏,耗费掉我差不多2个小时,又被XML摆了一道。
周末无聊,就尝试着用VS以外的工具来写代码,都决定用MinGW+makefile了,所以不存在编译器的问题,不过最后还是放弃了,因为代码编写的原因。 尝试了Eclipse3.4、Netbeans6.5,Nightly Build的Code::Blocks和CVS snapshot的CodeLite,总之一句话,写C++程序,VS+VA的王道!确切地说,其实我是离不开VA了。 今天在公司的论坛看到别人在讨论代码编辑器要怎么做,有一个老员工列举了他用编辑器的需求,我都觉得那已经不是编辑器了,而是一个IDE了。 看来,如果要有好用的IDE,除了VA,只有自己做了……
今天听同事讲了rdoc的处理流程,他完全是通过阅读rdoc的源代码来理解的,而且似乎他根本没有多少编译原理的基础的,汗! 总的说来,通过他的讲解,我了解到,rdoc的处理流程基本也是分为词法分析和语法分析阶段。首先,应该说有一个词法分析器生成器,叫SLex,然后由RubyLex提供规则,其实是一组正则表达式,SLex可以说是有一个正则表达式引擎,根据这些规则,生成token,提供给RubyParser使用,基本上是lex/flex做的事情。然后RubyParser根据这些token解析出class和model,建立起相关的实例,解析出相关的注释信息,通过yaml写到文件中。这里有点虎头蛇尾了,不过大体上也能表达清楚想要的意思了。 比较佩服的就是同事仅凭这些ruby源代码,就看到流程来,我怀疑要我上的话,如果没有这些编译原理的知识作铺垫,应该达不到他这样的程度吧!
今天把CruiseControl上的label改成svn的revision号了,在公司发现个问题,有一个项目里总是不能正确取到svn的revision号,虽然构建了,但从web上看不到结果,没有日志,晕!回到家,也改了一下,又发现另外一个限制,其实这个可能要算是svn的限制,当时我把源代码从vss迁移到svn时,所有项目都是放在一个目录下的,所以现在svn里各个项目的源代码commit后revision号是累加的,并不是各个项目独立的,于是在CruiseControl上显示的就是几个项目用了相同的revision号了,晕!不过第二个问题应该影响不大,因为照我现在的应用场景,一个时刻只会对某个项目的源代码修改,只要CruiseControl是一直开着的,出现这种冲突的机会也不多。
可测试性设计,即所谓的DFT,今天又一次重重地感觉了一次它的重要性。 系统中有一个权限管理模块,同一个物理用户可以不同的逻辑角色登录系统,系统中以各个逻辑角色为最小管理单元进行权限管理。一般情况下,用户可选择的逻辑角色范围是极有限的,绝大多数用户应该有只一个逻辑角色,当然在测试情况下,情况刚好反过了,基本上每个物理用户会有几个逻辑角色,容易暴露出问题。主要集中在,角色拥有的权限不正常,比如看到了不该看的,看不到该看的,可以做不该做的,做不到该做的。 一直以来,对这块的调试/测试都是很困扰我的问题,主要就是DFT没做好。最开始,把所有业务逻辑和界面绑定在一起,差不多每一条规则都要在界面上点来点去,构造很多与真实环境类似的数据去测试,非常麻烦,不容易遍历到各种情况。 后来将这模块重构了,把业务逻辑和界面分离,用单元测试来保障逻辑的正确性。从DFT的角度讲,这种代码架构方式,就是一种改进,对DFT的改进。 有了单元测试,还不能保证程序能完全正确地运作,因为除了逻辑正确,还有可能其他地方出错,比如输入数据就有问题。在前些天他们测试的一个版本中,依然发现了一些权限相关的问题,让我觉得比较郁闷,因为我一直以为应该是万无一失了的。不过事实摆在眼前,也逃不掉,今天老老实实地在那里定位,不过开始的时候还是异常困难,因为测试场景的千奇百怪,我的开发环境下,有些场景很难模拟。 后来突然灵光一闪,我应该为了方便测试,多写一点代码,多加点功能,比如当前这个问题,我可以加一个特性,能在某种特定条件下,使我可以以任意角色登录系统。说干就干,果然很容易地定位到了测试发现的几个问题的原因。 今天的经历告诉我,在软件可测试性设计方面,有很多值得研究的东西的,天呐!
项目里要有发送邮件的功能,想法非常简单,公司有个SMTP服务器,通过它直接就可以发送到notes中了。网上SMTP的源代码也是一堆一堆的,找了一个CodeProject上的,加上base64编解码也只有4个文件,接口非常简单,于是稍微改了一下,base64本来我就有,就只需要加入2个文件就可以了,附件也能正常发送,很是满意。不过上周五的时候突然发现,主题和内容中的所有中文都变成乱码了,有点气馁,随便又找了几个其他的代码,也是一样。 今天闲起无事,就想改一下。只知道在哪里看到过说要用base64,就能解决这个问题。尝试着先把主题编码了,发现收到后就是编码后的字符串了,这也是预料之中的。上公司的论坛发了个帖,没人回复。后来自己忍不住了,用Outlook Express写了个邮件,主题和内容都是中文,然后打开Wireshark,抓包,比较了一下CodeProject上那个代码发送的,看出区别了,原来也就是加上个charset="gb2312",再base64,就搞定啦!
早就想在保存文件时,能让用户顺便多输入点信息了,于是自定义保存文件对话框的需求就提上来了。在网上搜了一遍,各种方法倒是不少,不过都跟我想像中的有点区别,我想在MFC中做,就希望能尽量的简单方便。于是就搁下了,直到前天,在公司里想起这件事,问了问同事,同事给我一个例子,VC6写的工程,看了觉得很简单,但是回家自己弄还是不行。昨天又跟同事交流了一下,再加上晚上在网上找资料,结合着弄,终于成功了。 首先,添加一个对话框资源,加上需要的各种控件,最重要的是要加一个ID为stc32的控件,可以是Static,至于大小、位置,可以之后慢慢调整,以及对话框的风格要加上WS_CHILD。 然后,给该对话框添加类,基类就选CDialog好了,生成代码后,把基类从CDialog改为CFileDialog,尤其要注意,CFileDialog的构造函数需要更多的参数。 再之后,要给m_ofn成员初始化一下,先是dwFlags要有OFN_ENABLETEMPLATE,再lpTempate要指定到刚才活到的对话框资源。 最后,就是看情况,重载几个虚函数,比如OnFileNameOk,OnFileNameChange等等。 搞定!
昨天心血来潮,装上了鱼鱼桌面秀看了看,以前也是装过的,有乱码,现在经过几个版本的更新升级,软件名称也已经换过了,但是乱码问题还是没有解决,原来用Delphi开发的就这么郁闷啊!我用的是英文的XP,打了中文语言包,照理显示中文是没有问题了的,不过这个软件在安装路径中如果有中文的话,就不能正常启动。另外,界面上也不全是乱码,某些地方的中文还是能显示出来的。还有,装的2.1.1纯净版,运行非常不稳定,经常出错崩溃。如此看来,这个软件也就是界面上比较出色了。 说完了缺点,来看看它的技术特点。现在这个软件也算是一个widget工具了,可以有一个侧边栏,依靠在桌面的右侧,在该侧边栏上的可以安放一些widget,一般就是显示当前时间,当前CPU占用率,内存使用率,某个城市的天气情况等等,翻来翻去就是这么固定的几个内容,主要体现在界面上的设计有所不同。看了一下它的SDK,终于基本搞明白,原来是程序内部固定了只提供这些服务,外部每个widget有一个脚本文件,可以是vbs或js,调用程序提供的那些对象、方法,然后绘制界面。除了一个描述逻辑用的脚本文件外,widget还会有一个配置文件,记录一些最基本的信息,比如图片文件路径等。widget可以通过鼠标拖拽,拖到桌面上任意位置,也可以停放在侧边栏上。稍微想了一下,觉得这个应该不难实现,也就是侧边栏是一个单独的窗口,在拖拽widget的时候,检测当前widget的位置,如果进入侧边栏窗口区域,则自动调整widget的位置,看起来像是多个widget贴在侧边栏上一样,实际上还是各个窗口各自管理。如果拖出了侧边栏,则拖到哪算哪。后来看了一下窗口类信息,果然跟我猜想的一样,说起来我的LLYFSpy都不能正常使用了,抽时间也得好好整一下,就作为WIND的一个插件好了。 看完鱼鱼桌面秀,我又想起盛大的widget和雅虎的widget,于是上它们的网站看了看。盛大的是能放到游戏中去的,这是一大特色,但目前似乎还不能放到桌面上。雅虎的看起来则要比鱼鱼的专业得多,widget能做的事也多一点,界面响应和交互能力也要强些。雅虎也是给每个widget一个配置文件,但是XML格式的,而且把逻辑处理的代码也放到这个配置文件里,说起来,单纯从用户角度讲,雅虎的方案更好一点,但如果能把一个widget的所有文件都打包的话,这个优点就不存在了。如果从widget开发者的角度讲,可能鱼鱼的方案稍微好一点点,因为不同的格式放在不同的文件中,用支持syntax highlight、auto-completion的编辑器来方便得多,现在还很少有编辑器能同时支持混合的语言。 看了这些之后,我就想,我是不是能把WallpaperHelper里的桌面时钟日历功能扩展一下,不就也有一个widget功能了嘛!看它们用来扩展的都是vbs或js,鱼鱼似乎是直接用的MS的那个WSH组件,这有一个很大的好处,直接用WSH的强大功能,它内置了不少接口,像FSO之类的,还可以直接调用ActiveX,实在强大!雅虎的倒是看到一个js32.dll,可能是mozilla的那个js引擎。盛大的没看。但是我现在对于要嵌入的脚本语言,只能Lua感兴趣,公司里也曾经有人讨论过对于嵌入的语言使用Lua好还是js好,当时我的观点是看应用场景,希望脚本做些什么事,再来分辨做这些事用哪种语言方便。
今天断断续续写了几行代码,再次感叹,在这VS中配合VAX写代码给人那种酣畅淋漓的感觉,任何其他地方都是体会不到了。网上有不少人不少文章在说,使用IDE有很多坏处,让人不知道背后的机制原理云云,对于此种言论,我很不屑。不是说,懒惰是程序员的美德吗,既然有工具能帮人完成一部分工作,为什么不放手,而去追求那虚无缥缈的所谓“高手”的虚名。 从csdn上看到新闻谈及VS的下个版本,这MS的动作也太快了点吧,VS 2008才出来不到一年呢,CodeGear真的彻底完蛋了!再没有哪家公司能像以前的Borland那样生产IDE,跟MS抗衡了。 今天写代码时,发现需要记录一些想法,或者是计划,但我找不到合适好用的工具。之前也看到一个群组里有人开话题讨论用什么来记录想法,有人提到evernote,这个工具我也看过,是个共享软件,而且对中文的支持不行,仅这两个问题让我就望而却步了。之后再也没有其他的类似的好工具了,平时如果只是为了记录下问题、需求这种跟软件开发强相关的信息,我倒是搭建了一个Redmine服务器,它也有一点项目管理的功能,但还是太弱。在公司里,流行的做法是用MS Project来做项目管理,用Excel来记录需求,用notes上的CMM库来记录问题,不过我因为所在部门的不规范性,所以更自由一点,或者说其实是没有机会使用那么高级的东西,只好还是在redmine中折腾。 寻找好用的全流程软件生命周期管理工具!
这两天还是照平常一样,在网上看小说,因为看的都是盗链,看到后面的章节一般都是截图的。昨天偶然开了一个Opera 9.51,猛然发现在它这里图片出来的速度比Firefox里快多了,很明显的现象。不得不承认,Opera在这方面的努力真的很有成效。而Firefox对现在的我来说,最大的让人不满之处就是它速度实在慢了点。如果换作以为,我肯定还会再加一点内存占用过大,不过现在1.5GB物理内存使得我不再特别关注这个缺点了。不过速度慢这个缺点却是没有明显的可以弥补的办法。 都说Chrome的V8引擎已经作了极速优化,但是总的看来chrome还是个半成品,我已经太过习惯于添加了各种扩展的Firefox了,所以Opera也还是没能正式作为我的主用浏览器。而我就只能希望Chrome的出现能刺激一下Firefox开发团队,好好优化一下代码,提高点效率。
今天偶然看到一篇blog,讲述了chrome用到的各种开源代码库,至少有25种之多,让我不禁感叹,开源真是个好东西啊,真是软件界的共产主义啊。我内心是很认同这种做法的,觉得理所当然,而且自己平常也有这么做的倾向,只不过限于自己视野和认知,很多时候并不知道有合适的方案可供选择使用。 以后要多多了解这方面的内容并在现实中加以应用啊!
几个月前,就想从公司图书馆去借本《Lex与Yacc》了,可是从在线服务中可以查到确实有一本没有借出去,但到了图书馆就是找不到那本书放在什么地方了,图书馆的人说他们也没有办法找到,因为书要么就是照着编号放在书架上的,如果在指定的书架上没有,那就没办法了。我还为此去了几次图书馆,希望碰碰运气万一某一天他们整理的时候能发现那本没有找到的书,但是一次一次都失望而归。也想过自己买一本,但逛过深圳的几处大型书城,都没有找到过,从网上倒是能看到介绍,可是都是断货了,太郁闷了! 昨天觉得该去还那本《Windows技术内幕》了,虽然借了三个月,但没看几页。到图书馆一看,惊喜地发现有一本《Lex与Yacc》静静地躺在柜台面上,看来是刚刚有人还回来的,连忙抢到手中。 实在觉得这词法分析和语法分析在处理模式化文本时太有用了。说起来虽然现在在做那个劳什子一体化平台,可是我心里却一直想回去完善编辑器,简直有种生不逢时,壮志未酬的感觉。本来同事是有一种语法解析组件的,大概浏览过那代码,其实是从ruby源代码里抠出来,在某一阶段直接把语法分析树dump出来。不过不知道为什么在源代码超过8000行时,分析出来的行号总是过绕接,从头开始。我也没仔细定位过这个问题到底是哪里出了错,主要是那代码全是别人写的,而且用了一些我个人极不喜欢的处理方式,我就懒得再去查错和修正了。我宁可自己再写一个解析器,因为我知道用lex和yacc可以做到。当时简单地看过ruby的源代码,发现它的词法分析器并不是用lex生成的,并且里里有一段代码是用gperf生成的,于是以为gperf也是一种词法分析器生成器,后来自己用了gperf才明白过来,原来ruby的词法分析器是手写的,其中gperf生成的那段代码只是为了识别出其中的保留字而已。而语法分析器确实像是用yacc生成的,不过由于ruby的语法太过于魔幻,所以语法分析器似乎复杂得超出我的想像。如果我回头再去做编辑器,这个语法解析器势在必行,不关是为了解析出语法树显示出来,另外还有些用途。其中之一是,其中有一个另外的需求是将表格化的描述与脚本来回转换,如果没有可靠的语法解析器支持,这个需求要实现就实在太过困难了点。另外还有个需求,是前两天才提出来的,说是要能跳转到方法定义处,于是当然要知道方法定义的位置,而这位置当然需要事先准备好。本来还以为rdoc从源代码中提取文件时可以顺便提取出来,后来同事一说,yaml中并没有保留文件名和行号,所以还得想办法提出来。我一想这个就太不可靠了点,万一某些方法就是没有注释文档呢。所以一定要另外有个模块来提取方法定义,我当时想到了ctags。今天试了试,发现用ctags还是有些缺憾,它只能提取出方法名称,以及匹配该名称的正则表达式,而并没有行号。另外,看了看ctags的源代码,发现另外更严重的问题,ruby并没有说定义方法时def关键字和方法名一定要在同一行中,如果是不同行中,ctags就不行了,所以还是得实实在在的语法解析器出马啊! 当然,像ruby这种比较复杂的语法解析,我不需求全部自己从头开始写起,可以抄袭一部分它的代码,至少词法分析器大部分可以直接使用,而那语法解析里把BNF留下,把动作换掉, 这样虽然还是要读懂那部分代码,但总比全部自己来轻松多了,而且也可靠得多。 得稍微系统点地学习一下lex与yacc了。
今天在公司就发现有人传了个chrome的完整安装包上来,都没有安装过程,直接双击,过n秒钟的后,窗口就弹出来了,很简洁,简洁得让人感觉像是个玩具。只玩了两下,就没了新鲜感,就凭它现在的状态,它是吸引不了我的,我还是继续用回Firefox,那些使用习惯设置,插件,都已经成为我暂时离不开Firefox的理由。 回家打开Google Reader一看,n多blog和discussion在描述chrome,顺便让我有那么一点点惊喜地发现这还能直接从svn里下到源代码!不过就像其他的各种开源源代码一样,不到真的要用时,我是决计不会去看这些源代码的,尽管我确实已经下了不少源代码了,包括Code::Blocks、CodeLite、notepad++等等,都是因为在某些时刻突然觉得这些源代码有一定的参考价值,而且update这些源代码也成为我每次打开电脑后几乎必做的一件事。但实际上,我却还是没有真正能从这些源代码中获取过多少有用有价值的东西,这不怪这些源代码,而要怪我自己。公司里有个牛人,看部门似乎是个做硬件的,却好像看过n多开源项目的源代码,包括那些BSD系统、Linux系统的,实在佩服这种人的毅力和恒心。 Google出浏览器了,对最终用户来说,也许是件好事,这样激烈的市场竞争,能促进产品进步。当然可能就苦了Web开发者,不同的浏览器之间必定有些不兼容的情况存在,而Web开发者则必然需要为了兼容几大主流浏览器而煞费苦心。 对于我来说,暂时影响不大,继续留守Firefox 3观望中。
发现机器上装的几个VS出问题了。6.0不说,因为压根没想过要用它。2003出问题似乎是最早的,大概是因为最早用得最多,就出问题也早,发现问题也早,现象是时不时弹出个消息框说什么GDIPLUS怎么出错了,而且一弹就会连续地弹好几次,让人受不了。2005本来还没怎么发现问题的,因为不常用,要用也是2003或2008,当时只是发现它的菜单怎么变中英文夹杂了,也没怎么在意,反正看得懂,最近一段时间想用它来创建个工程,发现这个wizard不能用了,估计也是因为这本地化引起的,老是去不存在的目录下查找那些html文件!最后说2008,2008是今年开始用的,春节回家的时候用它来写WallpaperHelper,当时安装的时候也费了些力气,新建个MFC工程来编译,发现还缺几个.exe文件,抱着侥幸心理从2005那里照着文件名拷贝过来,发现勉强也能用,结果今年上半年堕落颓废了,看小说去了,几乎写过代码,现在发现2008里的资源编辑器不能用了,资源视图里都打不开资源,只是报个RC多少号的错,我也懒得再去查这是什么错了,反正这个资源文件是肯定没错的,郁闷死! 没耐心继续跟它们耗了,直接卸载,重装!
最近这段时间,SVN和VSS混用,有些工程是放在SVN里的,有些是放在VSS里的,但总的说来,感觉SVN更好用些,也许VSS 2005已经提供了各种现代化的特性,但直到现在,我还只是以VSS 6.0的眼光看待。 SVN在编辑前不需要check out,这点我就很喜欢,在VS 2005中,可以设置得让IDE自动check out出来,但离开了IDE,还是得自己去做这点操作。现在我用的VS 2003,就会自行弹出个check out确认对话框,这让用过SVN的人觉得很不耐烦。尤其是在某些情况下一个操作会要求先后对多个文件进行编辑,这时VS 2003就会不厌其烦地一次又一次地提醒要check out每一个文件,比如要编辑资源,就会要改.rc文件和resource .h文件,如果是添加一个新的类,就会要求编辑.h和.cpp文件等等。 但是SVN也有很让人头痛的问题,比如它完全依靠文件夹下的.svn文件夹工作,而且似乎很容易出错,出错了还不容易修复,VSS就很少这类问题。还有就是似乎代码仓库也有类似的毛病,容易出错,出错也也不容易修复。 今天得到一个经验,如果一次性要添加很多文件夹和文件到仓库中,最好不要用add和commit操作,而是用import。前者需要2步人为的操作,所以感觉要花费更多的时间。今天我就是需要添加4个文件,总共有130MB左右的数据量吧,n多个文件,用add还正常,commit时还会执行adding操作,然后是send content,到中途不知为何就阻塞在那里了,等了一会儿耐不住性子就x了窗口,到仓库里delete掉看到的几个文件夹,却有一个文件夹之后总是add不了了。后来改用import,就全加上去了,汗! 但是如果是一点一点来的话,我更愿意接受SVN这种工作方式。
今天偶然发现有时候会出现内存泄漏,于是照老样子打开那个编译开关,打印出所有内存分配的记录,但是却发现又不出现泄漏了,或者说可能是没有跟踪到。这样整了一个小时,毫无进展,只好放弃了,要多掌握几种比较可靠的内存泄漏定位方法才行啊!
昨天就想把其中一段代码,一堆if...else比较字符串的代码替换成用gperf生成的hash来进行分派,但是昨天想了想我根本不会用gperf呀,晕死,于是想着回家上网找点资源。结果回到家还是什么都忘了,光顾着看小说和聊天了。 今天到公司里看到那段代码才想起来,昨天晚上堕落去了,于是有点儿沮丧。后来偶然发现,嘿嘿,在资料共享区有几篇关于gperf的文章,看来是我跟同事的唠叨发挥作用了。看了一下,发现它的输入格式虽然有点学了lex/yacc的样子,却比它们简单多了,而且我的需求也是非常简单,就是可能会有6种不同的字符串,我现在想让它能自动映射到一个枚举值。gperf的秉承了开源命令行软件的一贯作风,虽然只是那么小小一个功能,也提供了好几个命令行选项,幸亏有比较详细的中文说明,再加上功能实在不复杂,试了几次,就可以了。跟最新的flex/bison一样,我用了cygwin中版本号3.0.3的gperf,它也支持输出C++代码,这是我比较喜欢的一点,毕竟C代码混在C++中还是感觉有点别扭的。 另外一点说不上技巧的小提示,如果对生成的hash函数不放心,可以写个单元测试用例,跑一遍就安心啦,而且这种hash函数一般的应用场合下不会有太多的映射关系,看人家ruby用在识别关键字上,也就是几十个而已,单元测试遍历一个所有的映射关系,写一遍就一劳永逸,不错不错,哈哈。 这个小工具值得推广,以后凡是遇到3个或以上字符串需要比较时,就可以考虑用gperf来做这种工作,不但代码运行效率高,而且代码可维护性也上去了,一举两得。
好不容易等到可以公开获取的修改版Cruise Control,装上来试了试,问题多多啊,还没有文档,这才是让人郁闷的,现在的我已经越来越习惯看文档行事了。 这个修改版的Cruise Control有一个好处是,集成了多种工具,比如代码行统计、代码风格检视、代码静态检查、代码复杂度度量、重复代码检查等等,如果光是执行一遍这些工具,用官方发布的Cruise Control也可以做到,只不过这个修改版可以对每种工具的运行结果生成一个xml格式报告,最后将这个报告merge到Cruise Control的log里去,然后又扩展了对log的解析,可以以统一的报表格式查看各种工具的运行结果。 但是这个Cruise Control集成的这些工具运行得并不稳定,首先代码行统计的好像没一次正常运行的,总是阻塞在那里,要手动杀掉进程才行,然后是复杂度度量的生成的日志因为太大,然后merge的时候老是有问题,还有就是这个改过后的Cruise Control不时地会出现运行不下去的情况,真是郁闷,当然最不爽的还数没有完整的文档,我发邮件给该项目的接口人,结果回了个邮件说还在某些产品线试用,等试点结束后让我去问各产品线的负责人,靠!
公司内部的论坛里看到coLinux的介绍,于是从论坛里随手下载了一个装上试了试,只有最基本的一个可用的系统,这个系统作为Windows上的一个应用程序来运行,但表现上看,又是一个Linux,在shell下可以运行各种命令,查看各种系统状态数据。可如果仅仅是这些东西,对我还没什么用处,我至少也要在Linux下写几行代码吧,不过这些都需要自己额外安装,在公司不通外网的苛刻条件下,几乎没有了继续下去的兴趣。 另外有个比较完整的发行版,叫andLinux的,还在beta阶段,这也是开源软件常有的现象,WINE不就beta了十几年嘛。andLinux似乎直接提供了大部分需要的软件,特别是那些GUI的是我比较关心的。但是后来想起来,其实我即使装了,现在也没多少用途,主要目标还是Windows下写写代码,最多最多以后,可能会需要在其他平台上,比如Linux,很可能也有Mac,也有可能一些嵌入式设备上,但这不是目前要关心的了。所以这个coLinux对我来说,没啥用哈!
从David I的blog上看到,C++ Builder 2009会附带Boost 1.35.0一起发布。想起当初,我弃C++ Builder不用转向VC,其中一个原因就是Boost对编译器的支持上,VC远远好于C++ Builder,虽然几年前,都号称C++ Builder对C++标准的支持远远好于VC,但那也是2002年前的事了,当时就已经泛滥的VC6,虽然对标准的支持差了点,但还是很多人用,而C++ Builder对标准的良好支持只是作为广告的谈资,实际上可能并没有为它带来多少用户。后来随着VC2002、VC2003的发布,VC的进步也是突飞猛进,而且从那时起,很多第三方C++库也把支持VC作为优先考虑的事项,从此Borland的C++编译器就更没落了。 其实以我个人狭隘的眼光看来,C++ Builder也没达到预期中的好的效果,有一个原因是,它使用了以Object Pascal写成的VCL库,而不是用C++写成,这样为它配合使用其他C++库,造成了一定的阻碍。虽然因为C++ Builder提供了一定的Object Pascal的支持,使得很多为Delphi设计的第三方组件,可以在C++ Builder上使用,但这并不是它使用VCL带来的好处。 这次附带Boost库的行为,我以为,并不会为C++ Builder带来多少市场占有率,就好像其他编译套件都没有默认附带Boost,但它们的用户如果确实需要肯定会去自行下载、配置、使用,而从编译器角度来讲,其实最需要做的是改进编译器,提高编译速度、改善最优化能力、增强兼容性,使其尽最大可能地支持Boost。 以后,在Windows平台上,会不会只有一个叫VC的主流C++编译套件了呢?
这几天看google reader上Codegear blogs一栏上,不时地贴出Tiburon这个词,开始还没留意,直到过了两天,目光稍作停留,才发现,原来是Delphi 2009/C++ Builder 2009的开发代号!上wikipedia查了一下Tiburon,似乎是一个加州小镇的名字,也不知是不是说的同一个。软件以地名作为开发代号的例子数不胜数,Borland系的产品更是如此。 这两年是Delphi/C++ Builder的多事之秋,先是从Borland分离出CodeGear子公司,出了个Codegear RAD Studio 2007,之后就是将整条IDE产品线以两千多万美金的跳楼价甩卖给Embarcadero,一代传奇,以这样的方式终结,让人唏嘘。 Tiburon最大的改进是对Unicode的支持,说是所有的都是基于Unicode实现的,包括编译器、RTL、VCL、IDE、COM、dbExpress等等等等。我也不知道到底用户对这个特性的需求有多强烈,只是感觉这太晚了点,如果早5~8年就有这个特性,也许情况会好一些。除此之外,增加了一些新的VCL控件,不过说实话官方VCL控件的个数多少其实影响并不是太大,好多第三方控件库,各种酷炫的控件都有。另外还有些其他的改进之处,比如对Delphi语言的修改,使其支持泛型、匿名方法等,还有IDE的增强。比较炫的是C++ Builder集成了UML建模工具,可以使代码和UML模型同步,来回在两边编辑,这个特性我比较感兴趣,一定程度上说,Borland系不愧是最会做开发工具的。 然而,我现在已经不用C++ Builder了,转用VC一年多,也只是工作需要,以后会慢慢转向那些开源免费的开发工具上去,或者自己做。现在或许只是因为身上有那么一丁点自己也不太愿意承认的Borland情结,关注一下最新的发展动态罢了。
今天看了一段CodeLite的源代码,很小一段,从app开始看,到Frame。因为想学习使用wxWidgets,阅读现成产品的代码一种比较有效的方法。我并不知道到底有哪些程序是用wxWidgets的,到目前为止了解到的有FileZilla和Code::Blocks,以及这个CodeLite。 学习的主要目标是掌握如何创建各种类型的窗体,如果为窗体设置消息响应。如果在绝大多数情况下,都能比较快速熟练地解决这两个问题,那么基本上可以认为算是会用这个库了。 wxWidgets的处理形式跟MFC比较相似,都是有一个app类,代表当前程序,然后有frame类,表示主窗体,在frame类中再衍生出菜单、工具栏、状态栏等元素,也包括其他一些子窗体,比如CodeLite中,用到各种Pane,这些Pane通过wxAuiManager来管理,可在主窗体上依靠,或脱离主窗体浮动在外。CodeLite和Code::Blocks都用标签页(Tab)的形式作为主界面,也用标签页的形式做Pane,但两者在实现标签页时略有区别。Code::Blocks用了wxFlatNoteBook这个组件,而CodeLite则似乎是自己创建的一种组件,该组件将标签页头和页内容分成两个wxPanel来实现,标签页头部分又在这个wxPanel上使用Tab来展现出页头的效果。这样的好处是标签页头相比wxFlatNoteBook有更多的可控制选项,坏处则是需要自己写不少代码。 现在我最大的困难就在于,还是没有完全搞明白,这个界面是怎么创建起来的,一旦这个框架建立起来了,那剩下的业务逻辑部分都是比较清晰明了的,至少知道大方向上应该怎么走了。
虽然打算使用MinGW+wxWidgets来写程序,似乎是可以抛弃VC+MFC或者BCB+VCL这类商业软件了,但是,实际上我发现我根本离不了VC,主要是离不了VAX,这个超级好用超级变态强悍的VC助手。 早先的时候,只用到VAX的智能联想提示功能和跳转到定义或声明的功能,自从看了Martin Fowler的《重构》,VAX的诸多重构功能也成了我目前最常用的功能,日常工作写代码,离了它简直痛不欲生。 写代码最好用的是VC+VAX,但看代码最好用的,个人感觉还是Source Insight这个虽然不思进取,但基础确实不错的东西。Source Insight也可以用来编辑代码,不过比起VC+VAX来还是弱太多了,而且它也是要买license的,最关键的一点易用性方面不足是,多少个版本推出来,还是不支持标签页浏览,真是不可理喻,而且对中文的支持也是一直都没任何改进。 所以最好的工具是能集VC+VAX代码编辑功能和Source Insight代码浏览功能于一身的。但是目前还没有找到能达到这种效果的软件,从免费到商业的,都没有。回到最开始提出来的,要用MinGW+wxWidgets来做开发,还是比较困难的,比较折中一点的办法是,先在VC里做debug版进行开发和调试,定期用MinGW生成release版本进行测试,先打造一个好用的CppCoding工具。
昨天随口给一个同事讲了一下怎么部署用VC2005生成的应用程序,才能解决因为先进的Side by Side技术引起的应用程序配置问题。其实我自己也是半生不熟,没有掌握到真正的精髓。今天那个同事就给我打电话,说还是没有解决这个问题。于是我就亲自出马,上午搞了半个小时,还是没搞定。于是看我原来用VC2008写的WallpaperHelper怎么弄的,以及人家的Edraw是怎么弄的。一点一点凑,最后发现那个么临界点,只要先到VC安装目录下有个redist目录,里面能找到发布用的dll和配套的manifest文件,复制出来,然后把manifest中的内容复制出来,自己填写一个新的manifest文件,作为RT_MANIFEST类型添加到exe的资源中,这样就基本解决了。而且从中看到,manifest中的版本号可能比dll的实际版本号要低,但是没关系,反而如果自己强行把manifest中的版本号改了,程序反而不能正常运行,反正照着redist目录里的那样填就行了。
话说本来6月17日就是FF3发布的日子,不过由于时差等因素,昨天一直没等到它的发布,于是只好等到今天。回到家迫不及待地下载安装,然后把需要的扩展也跟着升级,对于一些没有对应版本的扩展,只好再上mozilla的网站找替代器,忙乎了一阵子。 媒体传闻得沸沸扬扬,说得悬乎神技地,但我用了一个多小时后,感觉也没多少值得表扬的。比较明显的改进是,内存占用确实比以前小了,可能只有原来的2/3或1/2吧。另外一个比较明显的修改是所谓的Awesome bar,就那花里糊哨的地址栏,也许是我还没用出来吧,反正觉得原来FF2里的也没有不好用到哪里去,这个也没有方便到哪里去,所以这个特性算不算得上是改进,我保留意见。再有,就是启动速度似乎是比FF2快了一点,不过对于我这样已经习惯于龟速电脑的人来说,吸引力也不是特别大。 倒是一些原本在FF2里用得好好的扩展,到FF3里不能用了,这让我觉得很郁闷,比如Tab Mix,还有能将网页保存成mht格式的Mozilla Archive Format,都找不到够格的替代品。还有,号称的15000项改进在哪里,仅仅是我这一个半小时的使用,就崩溃了2、3次,这个品质不行啊! 好了,牢骚发完了,要不是因为不想用IE,要不是看中它扩展多,升级方便,我才不这么啰嗦哩。
如果在goolge(不是“谷歌”)中搜索关键字“音乐播放器”,排在第一位的,赫然是千千静听,第二位提QQ音乐,第四位是Kugoo,如果搜索关键字“音频播放器”,则出现的是foobar2000,而前3位则连影都没有。这一方面似乎可以看出,中国大陆用户对此类软件的偏好和定位。 因为前些天看到Kademlia的介绍,想到可以结合着做一个不需要服务器的P2P音频共享播放软件,于是偶然关注了一下现在国内流行的此类翘楚。就个人感觉,最专业的还是foobar2000,虽然它的默认界面非常简陋,没有歌词显示,没有文件搜索等诸多目前国内用户用得最多的功能,但是它做为一个音频播放软件,在纯粹的音频播放功能上可是一点儿都不马虎,尤其是它的插件机制,从效果上看,远远强于其它的竞争对手。目前最新版本0.9.x的频谱显示功能,比起前几位,也是强得不行,就比较流行的狭小范围看来,大概只有WMP能跟它匹敌吧。不过由此带来的负作用是,新手上路困难,难以获得菜鸟用户的青睐。另外随便看了一个曾经的老大Winamp,现在是5.5.x版本了,不过在我的机器上极不稳定,立马就卸载掉了,而且似乎没有做好市场调查啊,亦或是老外的使用习惯上就是那样的? 中国市场的大半江山应该是被千千、QQ、Kugoo三巨头控制了,这三个软件互相之间做得很相似,唯一大点的区别是Kugoo是以文件共享起家的,经过几年的经营,可以极其方便地以P2P的形式直接下载歌曲文件,而服务器上只需要保存些索引即可,负载压力顿时少了。千千则是以纯粹的音频播放器出身的,注重音质音效等是它早些年发展的重点,然而国内用户似乎并不特别在乎这点,当年的在线搜索歌词功能为它短时间内赢得了大量忠实用户。 其中一个重要的现象是,音乐网络化。三个软件都可以打开一个小窗口,显示一个网页,通过该网页可以查看当前的音乐流行趋势,在线试听,甚至下载(中国不像美国那么注重音乐版权,中国人真幸福)。其它的功能特点,就都很普通了,无非是换下皮肤啦(这皮肤机制也都很土,就是换一下窗口边框,这点WMP就强太多了),有个播放列表啦,搜索显示歌词啦(foobar/WMP/winamp默认的都不行,至少得装插件才能支持),支持插件啦(似乎都没公开的SDK,foobar/WMP/winamp都有,这似乎又说明了两地用户的使用习惯和素质上的差别)等等。就这些明显的特点看来,中国用户跟欧美用户的使用习惯上应该有不少的差别,本土三巨头也算是依仗本地优势,因地制宜,殊途同归啊!
为了用上比较新版本的flex和bison,又不想额外装个啥Linux,于是只好走旁门左道了,在Windows上装个cygwin暂解燃眉之急。这个cygwin也是个小气的东西,只提供一个大小只有几百KB的在线安装程序,这个程序从远程服务器上下载了文件列表,根据用户选择,下载需要的文件到本地再进行安装。无奈的是我贪心了一点,想把所有的软件包都下载下来,结果昨天晚上开了一晚上,卡在一个包上,后面的都没动静了。 今天回来看了一下这个软件包列表,提取出所有软件包的远程地址,导入到FlashGet中进行批量下载,可是这个1.9.x版本的FlashGet有不小的问题,平常还看不出来,在下载项很多时,总是不时地卡住下载不下来,而要暂停一下再开始,才能继续下载。当时用它来下载那几千个sogou的皮肤,也把我弄烦死了。今天又是这个状况,偶然兴起,上网看了一下最新的版本,已经到了2.0了,于是索性装一个来试试,哈哈,似乎没有这个问题了哦,而且界面上也改得面目全非了呢!软件该升级的时候还得升啊,呵呵! 再扯些其它的,这东东放了一堆的广告上去,这也是没办法的,谁叫它是个免费软件呢,人家也要吃饭的。好久之前就听说它是能下BT的东西,不过我已经久不用BT了,改用eMule了。另外又看到它也用到了DHT技术,大概是为了下BT下载才用的吧。前些天看到一篇blog,讲了eMule的Kademlia相关内容,让我有点热血沸腾,这个技术再搭上一个音频播放器,只要用户足够多,就不用什么Kugoo了嘛!
几天无聊中,又拿起TeX来玩,这东东用来做PDF真不错,可用来写软件的user guide或manual,也不用做htm或chm了。 编译器用gcc,界面库用wxWidgets,多语言和国际化用gettext和iconv…… 今天偶然发现cygwin中的flex已经是2.5.35版本了,而gnuwin32中的才是2.5.4,bison在cygwin中是2.3,而gnuwin32的是2.1,差了不少了啊,看来得装个简装版的cygwin才行。 也不单是为了不用盗版,而是这些开源产品确实质量已经足够了,尤其是在开发方面。
偶然看到一则消息,遨游将自主开发浏览器内核,真是让我觉得有点不可理喻。当今世界,IE、Firefox、Opera、Safari几大流行浏览器正拼了个你死我活,遨游从MyIE开始,多少年来一直使用IE内核的外壳程序突然从中插一脚,在我看来,实在是前途困难重重,希望渺茫啊! 先不说遨游是否有这个技术实力,就算有了水平堪与一流产品比肩的成品,最后的宣传推广,以及后续维护发展,也是前景相当不乐观的!
鉴于编辑器模块的重构任务已完成大部分,从两个View中提取出了一个基类View,这样总的说来大概减少了近2000行代码吧,中途也遇到些小麻烦,不过最后都没花什么大力气解决了。 今天就又看了一天的lex和yacc的资料,真是犯贱呀,在学校的时候这么大把的时间不好好学习,现在却要临时抱佛脚。回来看了几篇blog,难道最近流行学习编译原理?从理论到实践,都有人在搞。以前还是很不在乎的,因为再怎么样,也很少有可能需要自己去写一个编译器出来。其实现在若不是要整编辑器,也很可能再也不会去碰这玩意儿了。 昨天看到网上提到一个软件CodeLite,于是好奇心起,装了一个来试试,使用wxWidgets开发,所以横跨Windows、Linux、Mac三大桌面系统。它只是一个编辑环境,编译器还是使用其他的解决方案,比如MinGW,不过除开编译器因素不谈,它是个自消费系统,跟Code::Blocks一样,在自己的环境下开发自己,如果下载了它的源代码想自己编译一把的话,除了要装必要的编译器和程序库外,还得先装一个它的Release安装包,这个过程很明显又给自己打了一把广告。 突然我有个大胆的想法,这似乎是给我一个完全抛弃盗版软件的机会。在Windows平台上软件的丰富程序,确实很大程度上影响了我们的日常生活。记得还在大学的时候,就很雄心壮志地想所有的软件都不用盗版的,如果遇到找不到开源免费的,就自己写一个。但很严重的一个问题是,我当时只会用C++ Builder,所以开发工具只能用盗版的。现在也没好过到哪里去,只不过从C++ Builder换成了VC而已。可目前,就似乎有另外一种选择,使用MinGW+wxWidgets,从CodeLite和Code::Blocks的表现看来,完全可以满足我目前绝大多数的需求,而且还带来另外一个意外的好处,就是跨平台!虽然都没怎么想过在其他平台发展,但现在有这样的低成本扩张机会,何不放手一试呢!从此可以不用商业化的开发工具啦,哇哈哈哈哈!
偶然看到这篇文章,Delphi for PHP已经升级到2.0了,不愧为曾经最强大的IDE生产商,把PHP的开发工具都做得这么神! Code insight,也就是auto completion、call tips等功能的集合,想当年,第一次用Borland C++ Builder 5.0的时候,就很诧异它的auto completion,不过那个版本并不稳定,后来没多久就出了6.0,发现稳定好多,不过以现在的眼光看来,它的速度就慢了点,还看到国内有个牛人自己写了个增强插件CodeFast,速度,内容上都有很大提升,但极其不稳定,几乎处于不可用状态。当时用得多开心的,而且以VCL出色的设计,开发GUI程序,尤其对于初学者,有极大的鼓励作用。由此,我也就以为,Borland出的IDE是世界上最好的IDE,这个原因,也一定程度上让我不再愿意去费力气转向其他工具,包括VC。 后来用上了装了Visual Assist.X的VC,发现VAX的能力太过惊人,再后来就是工作中,直接使用VC作为开发工具,就已经离不开VAX了,VAX的智能提示功能实在是太好用了。 工作中,负责的也是一个IDE的编辑模块,其中的auto completion和call tips则是重头戏,前段时间计划着增强该功能,但一直没有动手。曾经考察过几种当前甚为流行的IDE的这个功能,包括VC(其实是VAX)、C++Builder/Delphi、Netbeans、Eclipse、Visual SlickEdit,当时的比较结果看来,C++ Builder/Delphi的似乎是其中最弱的,Netbeans的则看起来比较炫,太显得啰嗦,VAX的比较适中(可能也是因为看习惯了)。但有一条明显的需求是,当光标在下拉候选列表项中移动时,旁边应该可以弹出一个tooltip来详细描述当前被选中的项。但是项目中使用的Scintilla控件似乎并不直接提供此类支持,因此需要修改控件的源代码,而这是我最不愿意做的事情,我希望这个支持应该由官方来做。 而今看到这篇blog,则提供了一个可以学习的范例,同样是脚本语言开发环境,别个是当前业界最先进的,当然应该取其所长,补我所短了。
其实学的是flex,从公司网上找的,大概也是gnuwin32中的某个版本。顺便在公司网上又找了些资料来学,纯粹只是看的话,是跨不过那道坎的,所以要自己写几行来玩。生成的C代码倒是能直接用MinGW中的gcc编译,这让人觉得很舒心。开始的时候不明白,为什么写的正则表达式好像不起作用,总是把该扫描分析的文本全都打印出来了,而我明明只是想让它打印被匹配上的那些内容就行了啊,经过仔细观察,最后发现,其实是flex生成的C代码中,自动把不匹配任何自定义正则表达的内容也输出到控制台上去了。所以有两个办法可以解决此问题,一是把匹配内容输出到文件中,另一是修改下flex生成的C代码,把默认输出的那个ECHO修改了。 让它分析一个3万行的rb文件,匹配几种常见的token,如常量、变量、数字等等,速度奇快无比,可能不到1秒吧,想想我原来用Greta写的全文匹配5种模式,不知道要多久,不过幸好在不是很晚的时候发现了这个解决方案。从中已经可以看到曙光,原来我的猜想、直觉应该是正确的。flex可以解析出token,因为我需要的是其中的子模式,所以光是flex还不够,需要借助yacc(现在用bison的比较正常吧)进行语法分析。我猜即使加上了bison生成的语法分析过程,扫描那个3万行的rb文件,得到需要的结果,应该也不会超过3秒钟吧。不过另外有个问题需要注意,flex和bison生成的代码里都有一些全局变量,如果在多线程环境中使用,需要非常小心地进行同步,不过也许,自己也是可以对生成的代码略作修改的吧,尽管这些代码的可读性在我看来真的十分糟糕。
因为我是一个半路出家的coder,除了会写几行C/C++代码外,所有其他计算机科班出身的人会做的事我都不会,这也是我的一大劣势。 其实前段时间就想过,要学一下lex和yacc的用法。有这个想法,主要还在于看到不少开源项目,比如doxygen、source highlight、swig等等,全都用到了相关的东西,而正是因为我对这方面一无所知,所以即使能获取到它们的源代码,我也不知道如何自己编译。 这两天在公司里,遇到一个问题。编辑器里需要auto completion,为了尽可能实现地进行联想,于是以project方式组织时,需要扫描单独文件的上级文件内容,把符合要求的几种模式都识别出来,其实也只有5种。于是我就用了一个比较简单,可以说是笨的方法,用正则表达式去全文匹配一下,5种模式就匹配了5次,当文件内容少的时候,问题不明显,可说是没有问题。当文件有几万行时,就不行了,CPU占用率一下就99%以上了,而且匹配一次就会持续十来秒,5次就可能要1分钟去了。而且这个动作是在打开文件的时候进行,所以如果连续打开多个文件,机器就假死了。这个问题一直在存在,存在大半年了,只不过没人提出来,我也没意识到其严重性。这次跟同事讨论起来,我才觉得不改不行了,但我又想不出好的办法,缺少必要的理论支持,绞尽脑汁也是无济于事的。我的直觉告诉我,用编译原理方面的知识可以解决这个问题,所以学习编译原理也将提上议程。 编译原理一直以来是我最怕学的东西之一,记得很久以前,高中时的某个假期吧,但毫无进展,不了了之。后来大学时考高程,其中有一部分就是编译原理的内容,全靠考前死记硬背,考时胡乱蒙猜。可能其他还欠缺些理论知识的支撑,也是一部分原因吧。 因为想做好编辑器,所以对代码编辑的支持是必不可少的,因此从现在开始,订个计划,学编译原理,lex、yacc使用。
今天一时兴起,修改了一会儿自动升级程序。这个自动升级程序半年前就做了,当时用的boost::asio来实现http下载文件,可是问题就在于下载时,CPU占用99%,而且下载速度并不快,这让我很郁闷,在网上也没有找到确实可行的解决方法。后来觉得功能基本可用了,就一直丢在那里不管了。 前些日子,另一个同事也开始为Impeller做了一个自动升级程序。那个程序的实现我不喜欢,它在升级时没有一个可见的需要升级的文件列表,进度条也只有一个总的,总之至少从界面上看,是个很土的程序。不过它除了能升级本地应用程序的必要文件外,还能进行Gems包的升级。另外,似乎它还可以在文件被替换的前后,执行一些额外的操作,比如一个COM组件可能需要注册,这时这个功能就很有价值了。不过,有时候我又觉得,有必要那么复杂吗,它还想内嵌一个Ruby解释器,能执行Ruby脚本,晕死! 在我心中,一个比较理想的升级程序应该是这样的:1、每次都是从一个指定的地方获取一个文件列表,文件列表中记录了可升级的文件的相关信息,如文件名、相对路径、大小、hash值、日期、版本号等,每次都是将本地的文件跟文件列表中的信息进行比较,才得出是否需要升级的决定;2、一般下载文件都是通过http的方式(比较简单)实现,这样可以实现多线程及断点续传;3、下载时,有针对当前下载文件的进度以及所有文件的总进度;4、允许用户中断升级过程;5、能自动替换文件,包括被打开的文件;6、能最小化到托盘图标;7、能通过配置就可以直接适应其他升级需求(配置可以放在文件中、注册表中,或直接通过命令行得到);8、在替换文件前后,可以执行简单的命令行,不需要执行什么脚本程序那么复杂;9、升级程序自身文件体积应该比较小;10、有良好的出错保护机制;11、可自动生成第一步需要的文件列表;12、支持子目录中的文件升级。 暂时就只想到这些,呵呵,抽空用WTL写一个。
话说我已经通过抠早期版本FileZilla的代码,能让程序在崩溃那一刻进行dump,但是却只是知道,dump时,如果有相应的pdb文件在搜索路径下,是可以直接得到详尽的信息的,如果当时没有pdb文件,就只能得到一些看似无用的东东。 其实我错了,大大地错了!也不怪中间各种各样的原因,关键是现在知道只要能保留下可执行文件相配套的pdb和源代码在本地就可以了。当初从别人那里拿来dump文件来分析,是因为搜索路径下的pdb和源代码都是跟那个可执行文件不匹配的! 我居然还想着通过什么策略把pdb分发出去,哈哈,太可爱太幼稚了!现在终于可以安心地发放可执行文件出去了,只是崩溃报告机制需要好好设计一下,如何能及时地把报告从用户处取回,考虑到公司的网络环境和使用政策,还是要费点劲的。 另外又引出一个新问题,配置管理怎么做?嗯嗯,越来越复杂哈!
这些天为了看一部网络小说,很是堕落啊,还熬过一个通宵,之后就一直没恢复过来,整天昏昏沉沉的。 开源里好东西还真是不少,前些天在公司网上看到有人提到一个libEtPan的库,原来是一个mail库,提供了pop3、imap、smtp、nntp等协议的支持,简单看看觉得还是挺有用的一个东东,可以放在程序里,结合程序崩溃报告,提供一个比较友好的用户体验。
今天突发奇想,看到Edraw的一个软件包里有个CrashReport程序,觉得这个功能真是很值得放到自己的工程中去。想想大概原理就是使用dbghelp.dll库中的Debug API来实现,不过具体细节我是一点都不懂。记起以前在公司网上看到有人提到过FileZilla就有这样的功能,可以在程序崩溃的那一刻记下程序堆栈,函数调用栈,寄存器等有用信息。于是我马上找来FileZilla代码,运气也好,刚好找到2.x版本的,因为3.0以上版本的源代码包中是不带这部分代码了。这部分代码模块独立性做得相当好,只要把那几个文件抠出来加入自己的工程,几乎不用怎么修改就可以工作了。要做试验的话,可以来个除0错误,或者向空指针写入值,然后运行,就会弹出消息框,并生成2个文件,一个是文本格式的简要信息,另一个是二进制格式的core dump。又在公司网上找到一篇用Windbg分析core dump文件的简要介绍,马上拿来试试,还真是好用,设置好symbol目录和source目录,它能自动从网上下载缺少的symbol文件,并能自动打开源代码文件跳转到引起崩溃的那行代码上,真是太爽啦。以后再定位程序莫名崩溃问题,要方便简单多啦。
这次是真的想学一下Python和Ruby这样的脚本语言了,主要是它们的开发效率都似乎比较高,有大而全的库,很适合写些小程序,完成些小功能。几次去书店和小卖部,看到几本相关的书,都想买下来,但最后都还是忍住了,想想我买了来很可能还是束之高阁了,而且网上一般都能找到英文电子版的。 对于这两个语言,我不期望能很精通,只要有点熟悉主要功用就行了,顺便自己用MFC做个IDE,当然目的不单纯,呵呵。
昨天感冒就比较严重了,流鼻涕不说,连嗓音都变了。人也有点昏昏沉沉的,不想干活。 无所事事了快一天,下午的时候终于下决心用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值,但我想,这个算法应该能自动切换,不同的时间自动使用不同的算法,这样就用户就可能很难猜出用什么了。
跑去华强北买了个TP-Link的无线路由器,只是觉得好玩,其实完全是多余和浪费。最多只是少了一根线插到电脑上而已。 以前在学校的时候,还以为路由器是好大一个机器,后来见到过一个同学拿来一个小盒子,才觉得好笑。不过再想想,更早些的时候不也认为交换机是好大一个设备嘛,后来去电脑城跟同学装电脑时,看到8口的交换机也才200多块钱,而且那都是快5年前的事了。昨天去帮公司一同事MM搬家,偶然间谈起说她有个无线路由器,当时觉得她好高档哦,呵呵。 买回来后,飞快看了一遍它那薄薄4页的说明,很简单,然后就把原本插在电脑上的网线插到路由器上,打开无线网卡的网络连接属性,搜索一下,再通过Web登录上去设置一下。因为本来就是一个交换网络里了,再设置时,选静态地址分配,并把默认的路由器IP改掉,不跟交换网络的同一网段就行了。因为要用eMule,所以还要设一个转发选项。另外就是,一切正常了,可以加个密码,免得让其它人家的人偷偷使用我们的带宽,呼呼。
这东东早就从eMule上down下来了,只不过当时看到它的建议配置是1GB内存,我估量了一下自己本本上可怜的512MB的内存,最后放弃了,只是跑去把公司里那个台式机装上了,虽然那个台式机也是512MB的,不过我总觉得自己把那台式机调校地比较好,呵呵。 今天不知是无聊至极了,还是禁不住诱惑了,还是决定要装上试试。因为本本的系统盘有70GB大,即使已经装了一堆的东西上去,还是空了50GB左右,所以不用像在公司里那么麻烦,一路next下去即可。想想那天公司里装的时候,先是报空间不够,删了一票东西后再装,好不容易装上了,系统盘就只剩下13MB空间,又删掉一票东西,最后好不容易弄出200MB左右剩余空间,还不时地会被notes、IE等东东写点临时文件进去,Windows就会弹出个气球来提示一下。 装上后,先想编译一下Xtreme Toolkit Pro来试试,静态库还好说,基本上顺序地编译链接过去了。到了动态库的时候,报rc.exe执行出错。后来搜了一下,发现根本没有这个程序,把.NET 2.0 SDK里的拷过来试试,发现可以用,接着是缺mt.exe,再拷过来,顺序pass,呵呵。 不过这个比起VS 2003来,还是嫌它占用资源多了点,平时还是不用了。VS 2003英文版好不容易从eMule上找来的呢。
自从大致了解了Scintilla后,就喜欢上了这个控件,一般的用法照它文档和代码中写的,只要LoadLibrary那个dll,就可以直接使用"Scintilla"为类名创建窗口了。这两天发现XML Spy也用了Scintilla,并且没有看到那个dll文件,猜想应该是静态链接进去了,所以我也想试试。 首先,当然是下载源代码,现在最新的是1.7.5版了。然后有个VC的工程文件,其实是编译出dll来的,用makefile也只能编译出dll来。要用VC自己新建一个lib静态库工程,把include、src、win32三个文件夹下的所有.h、.cxx、.rc、.cur文件都添加进来。再到项目属性里设置一下,使用多线程库。这样就能编译出一个.lib文件来了,Debug版有4MB多,Release版是3MB多。 试用一下这个新建出来的lib文件,正常创建一个工程,用的时候不用LoadLibrary了,要调用Scintilla_RegisterClasses函数,看ScintillaWin.cxx文件最后的DllMain就知道了,当然这个函数并没有在公司的头文件里声明,所以调用前自己声明一下。然后强制链接前面生成的那个lib文件,假设Release版的名为SciLexerS.lib,对应Debug版的名为SciLexerSD.lib,这时就可以编译了,在链接的时候可能会报一堆Imm打头的函数没法链接,很easy了,强制链接imm32.lib文件就可以了。 其实相比动态链接,静态链接除了发布的文件少了一个之外,没有任何优势,反正dll倒是可以由用户任意更换,有了新版本,只要替换一下dll文件就可以了,即使如果是个通用的代码编辑器,假如新版中增加了对新的语言的支持,除了替换dll文件,再更新一下配置文件就可以了。
今天偶然看到XML Spy的代码编辑器是用Scintilla做的,这么说来,Scintilla的品质已经达到很高的级别了,以前也知道Adobe的Flash ActionScript for Mac的编辑器是用Scintilla的,而且Adobe还贡献了一点代码的。在Windows平台上两大开源可用的代码编辑控件除了Scintilla外就是TSynEdit,不过TSynEdit只适用于Delphi或C++Builder,而Scintilla是用C++写成,通过消息机制来进行各种操作,如此看来,适用于各种编程语言,而且它从本身设计上就能支持Windows和Mac以及支持Gtk+的环境。不过这些对我来说,现在看来都不重要,反而那个候选列表框不如TSynEdit的好,因为TSynEdit可以在关键字的前面和后面都加上描述性的修饰,而Scintilla加上的都会做为内容。 另外,我从一本几年前出版的翻译书上看到XMLSpy以前v2.5版的界面,好土啊,就是一个标准的MFC MDI界面,现在后来看到的2005,实际上是v7.0,就用了BCG ControlBar,2006、2007版的都是差不多界面。 从XMLSpy中,可以看到XML这是一种很强大的工具,当然XMLSpy也做得很好,很多针对XML的功能,或者从XML衍生出来的功能都做出来了。比如Boost里广泛使用的DocBook,就是用XML来描述的,我觉得是种不错的东东,值得学习使用一下。
今天发现有些内容(比如针对某文档的评论内容)显示,是一条一条的,用表格是种不错的选择。如果在MFC写的程序里,比较方便的做法是用ListView来显示,不过随后到实际要动手的时候发现,用ListView并不能够满足需求,因为一般的ListView只能显示一行内容,而我需要的是在固定列宽的限制下显示一条内有多行的内容。这时如果霸道点的做法是,自己扩展写一个新的控件,可以显示多行内容在一条记录内,大概这算是一个VC程序员的风格。不过我并不懂怎么做,或许网上有例子或代码,但我暂时也懒得去找了。后来一想,就想到HTML中的表格不就可以嘛!而刚好我要显示的数据从来源处得到的就是以XML格式组织的形式,说干就干,只要在前面加个头,指定一个XSL,保存成文件,再用内嵌的IE控件显示这个XML文件就可以了。 从图书馆找了两本XML大全之类的书,翻出里面XSL的章节照猫画虎整了一下,就整出大概的样子出来了。不禁再次感叹,XML这真是个好东东!以后即使显示的界面要改,也不用改程序,只要改外面的XSL文件即可,还可以带CSS,想要表现成什么样子,就表现成什么样子! 幸亏前些天刚刚看过我以前写的一个程序里有导出成XML文件,并用XSL转换显示的功能,不然说不定这次还不会想到这个上面去,说不定真会绞尽脑汁去写个控件,也说不定会去手动写个HTML格式的文件再来显示,哈哈! XML,很好,很强大!
在开始决定使用doxygen后,一直有种隐形的强迫之力,促使我为自己写的代码作好注释。今天经过一番小小的努力后,到晚上加班时,终于可以warning free地用doxygen为我那个工程生成暂时令自己还比较满意的文档了。心里不免有些小小的成就感,心想这样的场合下写的代码,就是应该这样作好注释,为文件、类、变量、函数等等各种元素进行标记。 现在我用doxygen的方式还是比较落后的。先用doxywizard生成一个doxfile,然后把这个doxfile添加到VC的解决方案里,注意保存路径也是要和解决方案一起的,这样以后方便。再在VS的IDE里有个外部工具菜单项,添加一条指向doxygen.exe,参数当然是doxfile,路径是和解决方案的一样,运行目录也是和解决方案的一样,这样就在菜单上多出一项doxygen来。为图方便,可以写几个自动添加注释的宏,并把它们绑定到快捷键上去。目前我自己用的有为文件、类、函数以及普通目的几种定制了宏,定制宏的目的是一方面可以生成符合doxygen要求的格式注释,另一方面有些内容是可以自动填好的,比如文件名、作者、日期等等,当然这样的宏还是很低级很落后的,最好是能把这样的功能跟Visual Assist X之类的插件集成在一起,可以自动识别出函数名、类名等更高级的信息,并生成相应的注释,不过现在在还没找到更好的办法之前,就先这样将就一下吧。最后就是点击那个菜单项,运行doxygen,生成文档。 doxygen提供了很多选项,也支持非常多的关键字。在使用的时候,我也是一边摸索一边尝试,唯一的资料就是它自带的文档,在开源的项目中算是很不错的了。不过始终让我觉得郁闷的是,为什么中文的老有问题,好在现在有一个别人的自编译版本,1.5.1的能比较完整地支持中文了,先暂时这么用着。 另外有些经验。对于同一项目中不同目录下的同名文件,可以通过写路径来让doxygen区分出两个文件的不同,而且要注意的是,这个路径它是大小写敏感的。对于文件名唯一的文件,只要写出文件名即可。 注释写在头文件中比写在实现文件中要好,而且最好声明和实现完全一致,比如函数参数列表。注释中标识参数时,只要写参数变量名即可,不用写定义的类型,而且变量名要和声明时的完全一致。 doxygen支持todo list,它会把它单独列出来,比较方便,当然现在的MS和CodeGear的IDE也有对todo list支持。 最好对每个有点作用的变量、函数、文件、类(结构、枚举)、宏定义等都作注释,这样看起来比较舒服。 对于ATL中使用STDMETHOD(xxx)(yy,zz)这类形式的声明,如果doxygen认不出来,可以改成STDMETHODIMPL xxx(yy,zz)这样的形式,就可以了,不过我没试过其它选项,说不定哪里设置一下,前面的那种形式就能很好地识别出来了。 最好装上Graphviz,让doxygen使用它来生成类图、被调用图,很好,很强大。 还有就是要坚持,要循序渐进,在新定义一个变量,一个类,一个函数时,就给它添加注释,嗯,这样就能写出一份well documented code了!
跟TextPro的负责人交流了一下,发现分歧还是挺大的。他们只想做一个普通的处理中文文本,有正则表达式支持查找替换,还有一些简单的转换处理功能的小程序就可以了。而我原本还以为要做一个通用的文本编辑工具,至少类似UltraEdit、EmEditor之类的,只不过对中文处理增强了。分歧很大,我只好放弃了,不如自己玩自己的。 看了一下鱼鱼桌面秀,存在字符编码问题,我的系统上如果安装路径里包括了中文,就运行出错,处于不可用状态。其实我只是想看看它的插件编写环境,原来它用的SynEdit,还是比较完善了。晕!
doxygen真是个不错的东东,现在都有点爱上它了,特别是对于现在我这样的情况,我还是随时准备着要把手头的代码交接给后来的人的,所以为了减少沟通交流的时间,比较详细的文档是很重要的一步,而对于缺少设计文档的项目来说,源代码即是最好的文档。这时doxygen的作用就很明显了,在它的帮助下,可以很方便地扫描出当前项目下所有源代码中类的依赖关系,文件依赖关系,类说明,文件说明,方法说明等等等等!我现在用的办法是,先生成一个doxyfile,添加到项目中,在VC的外部工具中添加一项,调用doxygen生成该项目的文档,还是比较方便的。不过也遇到些问题,最奇怪的莫过于中文的支持了。我从官方网站上找来的1.5.x对中文支持都有问题,但从公司网上找的一个人家自己编译好的却没问题。另外一个问题是,对于不同工程中同名的类,它会只留下一个,丢掉了另外的,这就不好了。对于不同工程中的同名的文件,倒是可以通过指针建子目录来解决。不过也许是我还没用好,说不定是哪里的设置问题。
刚刚看到同事在用酷我音乐盒听歌,可以在线听,又有歌词,专辑封面等信息,觉得挺有意思的,于是下了一个1.3.0Beta的来试试,发现怎么都不能让它发声,于是经过短暂的尝试后,毅然决定要把它卸载了。可是,就在我卸载之时,猛然发现,我只是在设置里把下载的cache目录设到我的存放了几个GB的mp3目录下去了,而它却自作主张地把该目录整个地删除了,连招呼都不打一声,关都关不了,看进程一时间又没找到是哪个,于是,眼睁睁地看着那几GB的mp3全没了!
前些天因为那论坛上用gcc来做编译器,所以又翻出很久没动过的MinGW来。没有像VC那么强大好用的IDE,而且VC的debugger真的很强。开始很笨,用printf来debugging,后来觉得这样也太傻了太不专业了,决定要用一下gdb。看了一点资料,其实只要了解很少几条命令就可以用了,查看源代码,打断点,运行,单步,继续运行,基本就可以了。 今天发现,在emacs里,可以直接用gdb,都不用到外面的shell里,太强大了! 还发现,好像STLPort用-g选项编译,cout就可能有问题,不知道是不是我自己哪里弄错了。
今天突然又觉得自己的墙纸已经用了好久了,一直一成不变挺单调的,自己收藏的那么多pp的图片深居冷宫那么久,真是浪费了。想起自己一年前(还真的是一年前,去年十一的时候还在整呢)还用C++Builder来写一个呢,结果当时遇到一些问题,比如定时器没正常工作,晕,然后就丢下了。 上网搜索了一下,没发现什么好用的,总是有这样那样的问题。而且今天突然发现,好多好多软件的界面在我的机器上显示有问题,总的说来就是界面上的汉字显示不出来,全是问号,晕倒!另外就是,其实我希望的是,像ADC这样的东东加上一个定时自动更换墙纸的功能,可惜我找了几款日历软件,都没有这个功能,遗憾啊! 大概没有几个人觉得自动更换墙纸有多有用吧,所以随便下了几个更换墙纸的软件,也都做得很差劲。 没办法了,只好自己动手,丰衣足食了。用MFC写一个吧,以后有精力的时候,再考虑加上日历,反其道行之,呵呵!
相比MFC,我果然还是更熟悉VCL的使用。不过我不想再用回C++Builder了,我要用VC,就冲着Boost库对于VC的编译器的极佳的支持。今天又写了一点点代码,要把asio的库都好好体验一把了,UDP、TCP都要有,Client、Server也全都有。现在还吊死在C++上,只是因为我确实还不怎么会用其它的语言,在项目进度的压力下,我不敢贸然地尝试完全不同的概念和思维方式。今天只是稍微做了一点html页面生成的部分,还有很多要做,尤其是要能做成带不同的链接地址的,唉,走一步算一步了,问题总有解决的一天,先把最有把握的部分解决掉。后半个月看来是要晚上加几天班了,呼呼,原来那个项目还有一些遗留问题也要解决,真是郁闷。上午突然想起来,我那东东得有一个自动升级功能,想了好一会儿,构思着再加一个updater.exe,每次系统启动的时候运行一下,把该升级的都升级了,后来突然又想到,干吗不把这个功能作为客户端程序中的一个模块呢,不需要单独的一个project了。 还有就是,我还是想做一个流程文件编辑器的,因为用Excel也真的太傻了。但是今天粗略地想了想,这个编辑器其实还是有点复杂的,要求比较灵活呢!其实如果是用VCL来做的话,我觉得应该几乎没多少障碍,可是现在可能是MFC,或者其它的,很多事情我都不知道怎么实现。
今天开始搞新项目了,这个项目需求好久好久前就出来了,一直拖着,大概的设计思路我也已经有了,但从工作的角度讲,今天才是真正的开始,从需求分析开始。其实我觉得需求已经比较明确了,只是那些人到时候估计会不停地改口,这是很让人郁闷和气愤的,但也是不可避免的。 鉴于打算用类似Google桌面搜索那样的界面技术,所以得先研究下本地建一个http服务器有困难,看了看asio的例子程序,估计所有代码加起来不到100KB吧,但确实已经是一个可用的http服务器了,我都用bjam编译运行过来,效果很让我欣喜若狂,本来这样的只是为了本地建一个给本机用的服务器,足够了啊!所以不禁要感叹一下,asio真是牛x啊! 老大一直很担心到时候拿不出东西来,总是叫我好好讨论一下需求。我自己的想法,这个东西要是把所有支撑模块都做好了,业务逻辑其实是很简单的一块,随便怎么改都行,应该很灵活,即使到时候发现他们的要求变了,我应该也能快速作出响应。 中午没睡着,下午就虚了,晚上就又累又困了。
今天只进了一次系统蓝屏后,就再也进不了系统了,每次在登录界面等待输入密码就会蓝屏然后自动重启,开始还以为是哪个外接的外设引起的硬件不兼容,于是依次把网线、音箱、USB Hub、硬盘全都拔了,依然蓝屏。于是怀疑是电脑附近有什么磁场之类的影响,先把手机拿开,故障依旧,再把本本放到床上去,仍然蓝屏。真是把我郁闷坏了,于是打算进行系统还原,但我把所有重要的东西全都放在系统盘上啊,晕!先进入恢复还原的工作界面,试图把重要的东西刻到光盘上,结果不知道是哪里有问题,就是不能备份啊!退出来侥幸心理想看看还会蓝屏么,果然还蓝屏,最后想起有个安全模式。重启时狂按一票Fx键,终于要进入到安全模式了,偶然看到它居然提示要不要装载某个.sys文件,这倒提醒了我可能是哪个驱动搞鬼。进入安全模式后,先把系统盘上的重要的东西备份到外接硬盘上,再看了看,把360安全卫士和Kaspersky卸载了,再重启,可以进入了。似乎问题就这样解决了。 怎么办呢!没有杀毒防木马软件,还真是有点不习惯,心里不踏实啊!
下午正在睡觉,小妞打电话来把我吵醒了。打完电话,穷极无聊,想想怎么弄一下我的T43让它可以和我的N73通过蓝牙连接。一直都知道T43可以用蓝牙,但一直没用成功过。上网找了一下相关的资料,原来只要Fn+F5打开蓝牙功能就可以了。这样用N73就能搜索到了,但在连接的时候提示需要什么通讯码,就像识别标识一样。还以为是固定的,所以上网搜索了一下,没什么实际有用的信息。后来偶然发现,在T43上搜索蓝牙设备,可以找到N73,这里设一下PIN码,然后在N73里连接时要求通讯码输入那个自己设的PIN码就可以了,呵呵。这样就基本解决了T43与N73蓝牙通信的问题。不过试了一下,连接很不稳定,经常马上就断了,而且传输速率只有8Kbps左右。
话说同事那任务把他整得精疲力竭,昨天加班又是继续攻关这个遗留问题。老大的看法是RichEdit在显示的时候占用太多时间是主要原因,于是同事把RichEdit换成用Scintilla控件来进行显示,结果效率并不比RichEdit好,估计因为Scintilla是一个通用的文本编辑器,为了进行着色、词法分析等任务,在这种特殊场合下,并不是最优的方案。还是换回RichEdit,只好从提高字符串操作效率着手。把其中一部分操作原本使用CString的,全部改换成用C运行时库重写了一遍,尽量减少字符串复制操作,用原始的指针,同时也避免了原本非常频繁的CString对象的创建和销毁,再加上一点点从CPU优化的角度的编码技巧。最后发现似乎效果还是挺明显的,不过RichEdit内的数据如果一多,显示速度也会降下来,这个问题照我的看法,如果坚持要使用RichEdit的话,只能开个定时器,每一个固定的时间周期,把RichEdit中的数据减少一点,保证RichEdit中最多只存储一定数量,该数量应该还不至于明显影响显示速度的内容,否则就完全摒弃使用RichEdit,采用自己画的方案,因为每次只是画出显示的那一部分内容,速度应该很快,而难点是,要把所有内容缓冲到文件中,如何能在文件不断增长的情况下,快速准确地定位到需要进行显示的那部分内容。 这个事件,让我对现成库的效率都产生了怀疑的心理,MFC库的慢是为众人诟病的,但不知我更习惯使用的STL效率如果,它的string类,它的各种算法不知道应用到这种场合会是什么样的效果。必要的时候还是得靠自己手动解决,看了《软件优化技术》中的一点内容,编译器优化会帮我们做不少事情,但很多时候还得程序员帮助编译器创建更优化的条件和机会。
同事为了能快速地打印输出格式化的字符串,已经被弄得精疲力竭了,呵呵。这些字符串来源于Ruby解释器的输出,包括各种复杂的信息,所以需要在显示前进行相关的处理,比如提取出放在行首的颜色信息,把字符串断行等等。目前的问题是,输出显示很慢,要么就是闪烁,要么就是脚本执行已经被中断了,它还在那里慢吞吞地输出,其实确实字符串已经送到了,但进行字符串处理的过程太慢,导致脚本执行中断时,还堆积了很多没处理的字符串。 看一下我们这个项目的代码,一般都是只求功能的实现,几乎从来不关心代码运行效率的问题。我一直也是这样的毛病,以前也没怎么想过特意去怎么优化。现在这个事情突然让我对这方面很是关注。 一般说来,以这个例子来说,要解决,首先就是要使用更高效的算法,看到同事写的那一段代码,确实是很低效的,大量的字符串重复拷贝、对象创建和销毁、字符串匹配等等都是很耗费时间的操作,又不注意稍微节省点用,照老大的说法,一个CString被复制了几次,用个引用效率也能高一些啊!然后可以考虑从CPU层面的优化,当然当前都是调试版本处理,也许效果还不是很明显。 我想了一下,如果是我来做那部分东西,我会怎么办。首先,我可能会把所有的CString都用C++标准库里的string/wstring来代替。其次,我应该尽量会避免每次收到一个字符串时就new一个结构体,里面还有个CString成员,这样的分配内存和创建对象操作在这种场合都太费时间了。然后是,开一个合适大小的内存池,这样一边可以追加,一边可以取出处理。再就是尽量提高匹配的效率,选择一些比较高效的算法以及好好改写程序逻辑和代码结构。最后是,RichEdit似乎也有一部分问题,可以考虑自己画,把所有接收到的内容先写入一个文件,或某块内存,每次自己处理滚动条消息,然后计算比例,画出相应的部分内容,如果用双缓冲画几行字,即使用GDI应该也还可以吧。不过这样纯粹是我的空想,基本没有实践支持,所以具体效果如何,以及复杂度如何,我也不得而知。
今天用WTL写一个输入法的辅助工具,到了后来,又发现Release模式下链接不了了,看来不是个别现象了,最后排查到,到了C++标准库,就会有问题,报符号定义冲突的错误。这次忍不住了,上google搜了一下,发现msdn论坛上一个帖子说,只要在设置工程属性的地方,把链接ATL为最小化CRT改成no就解决了,试了下,果然ok了。亏我当时还郁闷了一天就放弃了,看来在Windows下开发不上msdn不行啊,尤其是用VC了,就更应该上msdn的论坛了,难得有英文的这种Web形式的技术论坛,呵呵,都已经有点思维惯性了,以为老外只喜欢maillist或newsgroup的。 用WTL写了两个小程序后(都还没写完),觉得WTL真的不错,不过编译速度感觉有点慢了,不知道是不是因为这些天只是用来编译C程序,对速度的感觉已经被影响。但是生成的文件小巧啊,我到现在还没弄明白,到底什么时候,会链接进来那个msvc**71.dll之类名字的文件进来,反正这两个程序里都没链接进来,也许是因为太简单吧。 WTL形式上有点像MFC,一个窗口会有View类,一个对话框会有对话框类,然后有消息映射宏,宏里写上了对应的消息名字和消息处理函数名,再在处理函数里填上相应代码就行了。不过实质上,我也知道是极大不同的。
真可怜,虽然是周末,明明是个让人睡懒觉的日子,可是每到那个时间点,就会自动醒来,然后睡不着,然后翻来覆去也睡不着,然后躺着觉得狠狠的无聊,然后起来开电脑! 昨晚睡下之前,发现了让日志类的表现像标准流一样的方法,其实很简单,就是加个成员变量,是一个标准流的对象,然后用一个方法把它的引用返回出去,外部用户就可以用标准流提供的各种设施了。不过这样有一个东西我还没搞明白,怎么知道人家一次IO完成了呢,我只是希望能通过它来接受用户的输出,之后我要把这些输出处理一下再用我的方式输出,这个时机我就不知道了。现在的办法是,到下一次再输出上一次保存的内容,很不爽啊,很不可靠啊!估计方法还是有的,只是我不知道而已。 于是可以不用一个特定的结束符了。还加了个过滤功能,比较有趣。用了一堆编译开关的代码调试起来还真是麻烦的呢,因为很可能写的某段代码是从来没被编译到的,所以错误一直都不会暴露出来。比如这个日志类,涉及到是否是Win32平台、是否是UNICODE编译、是否带有Boost库,几个分支一混合,就是n多种情况,哪那么容易都覆盖到啊!
今天终于是睡到闹钟响才醒来的! 还是觉得挺累的,在公司里没怎么做事,昏昏地过了一天,接到一个新任务,做跟VSS交互的模块,当前的主要问题在于需求尚不明确,而且可能会有些比较麻烦的需求。也懒得去仔细研究需求,就先看些文档和代码,VSS提供的一个ssapi.dll就暴露了所有接口,不过比较怪的是,在VC.NET2003中import时,6.0版的saapi.dll里IVSSDatabase接口居然没有Close方法,而8.0版的是有的!这也不合理啊,难道是真的没提供,亦或是VC的bug? 回到家后,就不怎么想动了,脑子接近处于停滞状态了。这些天越来越不喜欢用BCB了,感觉VC挺好用的,其实一大原因是得意于它的编译器对标准的支持程度好,还有一大原因是对Boost支持好!WTL也还算好用啊,VCL用Object Pascal写成就是感觉不爽了。MFC除了要带比较大的库外,用起来也不怎么不好用的,呵呵。
昨天审视了一下那些概念,猛然发现一个严重的Bug的原因,原来一直是因为我对BSTR等的概念不了解,才造成了这样的问题,哈哈,纠正一个严重bug的感觉真爽啊!现在也许真的是可以把那个任务搁一会儿了!除非到时候又有什么新的需求,或者要对某一块内容重构,对,有一块,现在的设计很傻很笨,缺少灵活性和弹性,如果要扩充新的内容,就比较麻烦,而且如果那个结构内容一多,就看起来特别怪异。 突然很想自己写一个简单的日志系统,那个胖子曾经还跟我吹牛他们设计日志系统的时候参考了ACE的很多东西,我看了一下,只不过是每天新建个文件,把文件名、行号和消息内容写进去而已啊,只能说它真的是个日志,根本没有所谓的系统的概念! 要日志系统,就看ACE、Pantheios、log4cxx、log4cpp、log4cplus、Boost.log(没被Boost接受)。其中log4cxx、log4cpp、log4cplus都是从log4j派生来的,后两个都好久没有更新了,log4cxx最后的发布版也是好久以前的了,svn里倒是可以取出最新的版本,不过对于Windows平台来说,它没了直接的VC的工程文件了,需要用ANT才能编译了,看过它的文档,功能还是很强大的,大概是得益于log4j的强大吧,而且它可以支持配置文件。ACE里的日志功能,设计得也是很强大,它还能自动缩进输出消息,这点比较有趣,但是使用时需要链接整个ACE库,这就比较不爽了,要是能单独把日志部分提取出来,或许用的人还多一点。Pantheios基于STLSoft这个库,功能也很不错,它使用Syslog协议,这个协议在RFC3164有描述,甚至自己在Windows平台上实现了这个协议。不过我除了Boost,很不习惯再用其它的非标准通用库了,所以这个Pantheios就这样被我cancel掉了。大概看了一个Boost.log的文档,发现大部分需要的功能,它确实也都有了,或许不如ACE的强大,但之后也存在着不小的提升空间,不知道当时Boost怎么没有接受它,现在它好像被搁置下来了,也没在maillist里提起过了,而我看boost-consult的vault上那个,照那个样子,应该不会被接受的,看来要让Boost加入一个日志库,还得等待一段时间了! 所以近期一段时间内自己写个小巧适用的,还是有点必要的哈!不过有一点很重要的是,需要能同时让VC7.1/VC8/BCB5.6.4/BCB5.81编译,最好还能在Unix-like的系统上用Syslog协议。
Inno Setup真的挺容易用的,小巧轻便,又免费。本来还专门整了个安装输入法的程序,把ime文件复制到系统目录下,再写一下注册表,调用一个API,最后把所有文件用WinRAR打包成自解压文件。其实这样的方案也不是不行,只是觉得自解压的界面丑了点,看起来更业余了点。于是抽空用Inno Setup整了个,ISTool才是其中的大功臣,把本来全部要用代码完成的功能分解到各个GUI窗口中进行设置。它可以完成复制文件,操作注册表,调用简单API等功能,实在太方便了。现在我这个安装程序还可以自动寻找上一次的安装路径,可以根据用户选择写入不同的内容到注册表中,用户体验应该说还是不错的,哈哈。 生成的安装程序在系统菜单上显示的“关于”选项,会弹出一个版权信息消息框,如果要改这个消息,应该改setup.e32文件中对应的信息。我开始用UltraEdit来改,但改了总是出错,于是把源代码弄来自己编译一个setup.e32,不过有一个问题是,我自己编译的体积要大好多,不知道哪里的问题,而且界面显示上有一点点问题。另外,安装程序文件查看版本的时候,在“备注”一项里,也会有固定的标识,也是可以用改资源的方法处理的,如果有代码的话,先修改一个SetupLdrVersion.rc文件,再编译成res,最后编译一把SetupLdr.e32就行了。在编译Setup.e32时,会要求有RemObjects的Pascal Script控件,下一个装上就行了。最后还有一点是,它居然不能用Delphi7来编译,看代码中的注意说,用小于7的版本,或者9都可以,9应该是2005吧,反正我在2007下面是编译过了的。
用cnsw.org论坛上某位据说是mm的话说,VCL打从娘胎里就不支持UNICODE。这让我觉得很痛苦,自从在VC2005下用API写了几天代码后,就不知不觉习惯了想用_UNICODE选项来进行编译了。唉,可惜的是,我现在是严重依赖VCL画界面了,不用它我还真的不知道怎么实现一些界面效果,比如我经常用到的PageControl。 Boost sandbox已经从sf.net的CVS迁移到SVN上去了,待Boost 1.34.0正式release后,Boost的主库也会从sf.net的CVS迁出。Boost是个好东西啊,不过跟VCL一起用的话……
在上网的时候,小丫头突然打电话来,出乎意料地。然后两个人聊了大半个小时,照小丫头的说法,都从公司里聊到家里了。还是照原来一样,小丫头在那里抱怨了一通,呵呵。五一要不要去成都呢,犹豫ing…… 写程序总是遇到些奇怪的问题。这两天在研究直接用PSDK写一个能支持在2个TreeView中进行节点拖放的窗口,昨天还一直很奇怪的,只有一个 TreeView能作为拖放的宿,另一个则怎么也不行,但两个TreeView的代码明显是相同的,因为都是从同一个类中的方法啊!今天给窗口加了个拆分 条,可以让鼠标拖动TreeView之间的拆分条来调整两个TreeView的大小,结果稀里糊涂的居然发现两个TreeView都能作为拖放的宿了,真 是奇怪呀,明明我一点都没改动TreeView的代码啊! 从别人那里要来了一个通过COM接口跟GT3K交互的Demo,这个Demo是在Excel中用VBA写的,不知道如果在VC中用,还有多少困难,看来得学一下COM的知识了,比较麻烦呀! 另外一边的人打电话来说,要讨论一下单板软件的相关计划等,呵呵,要做嵌入式开发去了,这让我觉得有点兴奋,因为从来没有接触过这方面的东西,只是别人写的代码倒是看过不少,虽然也从来不看代码流程,只是为了PI值发现些很低级的语法错误。 SharePoint总算第一次被我调得可以显示一点东西出来了,不过还没有研究怎么使用,因为那台老爷机实在太慢了,我无法忍受在这样蜗牛的速度中 进行操作学习。SharePoint的资料是少了点,没办法的时候,只能跟别人交流交流了。而且,才发现目前只要装Windows SharePoint Service 3.0就够用了,不用装Server了,哈哈。 把输入法的界面改了一下,Comp窗口和Cand窗口合在一起了,就像现在流行的输入法一样,不再是传统界面啦,这有一个好处——可以方便地让它支持 Skin,或者不规格窗口。不过老问题还是存在:Firefox中还是出不来。而且一直想把设置窗口改成用PropertySheet样式,但总是要么不 出来,要么弄死机,郁闷,只好暂时就要原来的了。还有个问题,也是这两天才遇到的,在用UNICODE编译的时候,为什么stprintf总是得到乱码?
输入法最后的文件后缀虽说一般是ime,但它是个地地道道的dll文件。有过几年地狱般的调试经历,好不容易从MessageBox升级到OutputDebugString,最后终于进化到用IDE里集成的debugger。不过一直以来都是只对完整的可执行文件进行调试跟踪,对dll还没有相关的经验,尽管也写过几个,但那都太简单了,基本不用跟踪就可以正常工作啦。现在的输入法就复杂了,开始没想通怎样可以进行源码级调试,还是退回到OutputDebugString,编译连接一把,在记事本中试一下。后来想想,它应该可以attach相关进程进行调试吧,白天在公司也看到过一个文档,讲的是怎么在VC的IDE里进行相应的设置。其实非常简单,在项目属性里,把调试一页中的命令设为notepad.exe就行了。随便在源代码中打个断点,启动调试,VC会弹出消息框说notepad.exe没有调试信息,不用管,继续,notepad.exe运行后,切换输入法到这个被调试的输入法,如果程序走到断点这里了,就会被断下来了,变量窗口、输出窗口都跟调试exe文件时一模一样,哈哈。有一点需要追加说明一下,这个dll文件一定要放到能被load的地方,像普通的dll的话,放在和exe文件相同的目录就行,输入法就需要先安装一遍,这时ime文件是需要放在系统目录下的,所以方便起见可以直接在项目属性里把最终的输出文件指定到系统目录下就行了。 另外再说一点和UNICODE相关的事。为了和国际接轨,程序使用UNICODE似乎是最好的方法,我就先在输入法安装程序中做试验,一个百来行的小程序,用UNICODE选项进行编译,结果还真发现了问题,有个字符串在写入注册表时总是写不全,这让我很奇怪。同样的代码改用多字符集编译连接就没有问题。看看代码我已经都尽量用各种字符操作的宏了,最后发现原因,_tcslen在UNICODE的情况下,2个字节只算为1,在写入注册表REG_SZ类型的键值时,需要指定字符串长度,所以其实只指定为实际占用空间的一半了,这种情况就需要特别处理。虽然发现了这个问题,在这么个小程序里还影响不是很大,而且很容易暴露问题,但要是输入法程序是用UNICODE编译的不知道还会有什么问题呢!怪不得极U被炒得这么火!
一直以来,基本上是用着加加系列过来的。以前的拼音加加,以及现在的五笔加加。现在拼音输入法市场可谓战火四起啊,原来的拼音加加已经失去了王者之风,蛋糕被微软、搜狗、google、紫光几个分食了。五笔输入都全是些个人的作品,也许真是因为使用五笔的人比用拼音的少太多吧,大厂商怎么都不原意做个好用的五笔呢。不过现在的极点、加加、小鸭都是很好用,又稳定了。 相对来讲,大概五笔做起来比拼音要简单一点,也可能是因为没有什么创意或技术上的突破吧。五笔是只要能打出字,稳定就行了,命中率什么的基本还不用考虑。而拼音就很大一部分精力可以放在命中率上,微软拼音在这方面就做得很不错,google也是朝这个方面发展,但两家东西都有个很明显的缺陷——响应速度慢。 要做好一个输入法也不容易呢,Windows定的框架就太复杂了,而且Windows平台上各种各样的软件,要全部兼容谈何容易啊!
想起要写些关于Boost源代码的东西,要把代码贴到blog上来,不免想要弄稍微好看点,虽然有个Boost中自带的演示Boost::regex的cpp2html工具,不过觉得太单调了点。上Google搜索了一下,还是能搜索不少来,其中一个放在GNU上的source-highlight引起了我的注意,这是一个由Lorenzo Bettini编写的命令行程序,能支持好多种语言的源代码输入,同时又支持包括Html、XML、LaTeX、DocBook等格式的输出。看到最新版本已经是2.6了,不过作者已经不屑于发布Windows下的可执行文件了,只好去sf.net的GnuWin32工程里找了一个2.1.2版本用用。这个小程序做得挺灵活的,作为输入的源文件规则和作为输出的目标格式都是通过外部的配置文件来说明的,这样如果要添加支持新的语言,只要添加新的配置文件就可以了,不需要修改重新编译程序。这是个很棒的小程序! 小丫头现在都知道怎么骗我了哦,真让我感动得想哭,突然觉得这种感觉就像《Hunter X Hunter》里奇犽的哥哥说他妈妈哭了,因为奇犽现在都会砍她了,她好感动的。
早上虽然醒过来了几次,但还是坚持睡到了11点半才起来,这对于我来说,从工作以来是很少见的,而且居然做了个美梦。经常有人说,梦里发生的事和现实中的正好相反,仔细想想,其实好像没什么道理,倒是这样被说了后,有心理暗示罢了。 也不吃中午饭,又想起前些天在玩TeX,下午就把CSDN上的Blog的内容全用LaTeX做成了PDF格式,虽然很多想要的功能没有找到实现方法,但也已经很有趣很好玩了。现在才知道怎么在CCT的环境下做书签,先要使用hyperref宏包,加几个选项后,只能用dvipdfm来转换,而且开始先得用latex编译一把,再用gbk2uni转换一把,再用latex编译一把,最后用dvipdfm来转换成PDF文件,这样就可以做出中文的书签了。 再来说csdn上的blog,那是我第2个blog,第1个是放在blogdriver上的,因为当时csdn上好像还没有,而看到有个当时在csdn社区很有点名气的gigix在blogdriver上建了blog,我也就去建了个,写过十几二十来篇的样子吧,开始出现了一次问题,打不开我的页面,跟网站维护人员反映了一下后就弄好了。过了些日子,又打不开了,这次再给他们反馈,他们却没像第一次那样马上弄好,而是拖了好多好多天,也不知道是什么时候弄好的,反正没等它恢复,我决定把blog迁移到csdn上,因为当时对csdn还是很抱有好感的。没想到csdn的blog系统太太太不稳定了,我写了100多篇后,持续了两年,主要是在学校期间使用,工作后,也用了快半年,实在忍受不了了,刚好遇到这个blogger.com被解封。blogger.com上的空间是早就开了的,只是当时只觉得老是打不开,还不知道有GFW这回事,所以一直用csdn的,而这里刚好情形反过来了,当然也是考察了一些其它的BSP的,比如MSN的,Blogsome的,国内的ChinaUnix的,最后还是决定放这里了。所以正式点的说法,这是我的第3个blog,虽然也遇到了再次被GFW,但只要还能通过某些不正当手段访问或发文,我是不会搬了。 把csdn上的blog内容copy下来,也当是个纪念吧!只是blogdriver好像访问不了了。
几乎又是玩了一天TeX/LaTeX,我觉得最大的障碍还在于文档系统的不完善,大概是被MSDN惯坏了,什么事情都希望有个大而全的文档可以随时查阅。它相当于一个编程语言,但它只能描述相关信息,却没有能力进行复杂的逻辑运算。其实要用它很简单,只要能找到完整的参考手册就行了。 遥祝小玉玉生日快乐,去年跟她说如果明年还可以帮她庆祝生日……这是不是就意味着某种暗示是不能了呢?世事无常啊!
在公司里,新版本的文档管理都切换到CVS系统了。今天,几个同事说要配置一下怎么使用,他们不知道CVS原本是一个命令行工具,都照着宣传胶片上的开始装上WinCvs和CvsNT,然后一步一步地设置各个选项,而最终目的只是为了从服务器上checkout出文档来。用命令行的话,登录一条命令,checkout一条命令,最多再加上登出一条命令,多方便!由衷地感叹,来自UNIX体系的命令行文化的简洁和强大!不禁想起那个Rational ClearCase,曾经安装卸载了n次,还是不能使用,真是郁闷。 再说回来CVS,现在看sf.net上,好像是CVS和SVN并存的,但感觉CVS的存在只是为了兼容原来的老存档,SVN取代CVS是迟早的事情,公司到现在这种时候还只是把VSS改换成CVS而不是SVN,就有点让人觉得土气了。不过公司向来对开源世界的东西比较反感,以及人员的技能素质整体也呈下降趋势,靠着一流的市场、二流的用服来销售和维护三流的研发做出来的东东,这样的情况是持续不了多久吧。
LLYF ToolBox里除了LLYF Spy,其它的都是使用BDS2006来编译的,相比BCB6,2006版本的编译器最明显最直观的改进是编译速度的巨大提升。另外,传说中的VCL改进使得更好的内存管理,导致的更佳的内存占用情况,也是值得升级过来的。另外就是,IDE界面和其它工具的改进,比如debugger,都说明,从BCB6把工程移植到BDS2006是多么应该呀!LLYF Spy一直没移植过来,是因为BDS2006中一直安装Flash的ocx控件没成功,而LLYF Spy中有个Splash窗体,尽管一直都在配置文件中把它屏蔽掉了,但当时是为了演示Flash跟本地应用的集成而添加上去的。昨天下决心去找了一下解决方法,要在BDS2006中添加ocx控件,应该先new一个package,然后再import type library,试了一下果然可以,对于有些函数说连接错误的,就把原型改一下,比如__fastcall改成__stdcall,还有就是加inline,设好obj文件的搜索路径,终于可以编译LLYF Spy了。 除了移植过去,还试图给嵌入的WebBrowser控件添加XP风格。这点当时我郁闷了很久也没想通,以为整个程序有了XP manifest就应该把它嵌入的WebBrowser也有XP风格。前几天看了一篇文章,才知道,原来是要另外作些处理。要调用InitCommonControlsEx,设置一个标记,再把shell32.dll和explorer.exe装载进来。还有种方法说是改写WebBrowser的接口,返回一个标记就可以,可是我试了不行,不知道是哪里出错了。
突然想到的,把一些本来设置成手动的服务改成自动,或许会加快系统启动速度。果然有用,大概是因为有些服务设置成手动后,本来是需要的,在系统启动时,却还需要花时间去检测,或是在启动的后期进行启动服务,所以速度变慢了。 好不容易下到个官方命令行版的svn,上去把CodeBlocks的源代码取下来。唉,如果不是因为可执行安装包下不下来,我才懒得弄呢!不过刚好试用一下svn也好,起码比起CVS要先进,比起VSS它是免费的,比起ClearCase它小巧。 射手网真是个好网站,一般流行的片子,都能找到字幕,哈哈,现在才大致知道应该怎么找字幕。 网上很难找make和gdb的文档!有还是有的,但我想要的是用chm或pdf格式的整理好的,却很少很少。如果以后都像写我的方块那样写游戏,可以先考虑用MinGW是否可行,代价是否很大。一般说来,需要一个好的代码编辑器,所以试试CodeBlocks,需要一个强悍的调试器,就用gdb,还需要良好的工程管理,就用GNU make。不过说实话,VC加上VAX插件,绝对是在Windows环境下最牛x的开发环境,但毕竟,都是要n多money的,而前面提到的那些工具,全是GPL的。可以试一下,也许还需要一个GUI开发库,比如Delphi/BCB中的VCL、VC中的MFC,免费的有wxWidget、Fox、QT等等,但都会拖一个大大的链接库,我不需要跨平台可移植,所以,看winx的表现,似乎是可以把WTL单独剥离出来,给MinGW用的,到时候再看看,说不定,只写DirectX游戏的话,对这方面的要求不多呢!
很早以前就尝试过用MinGW,总是因为遇到奇怪的问题解决不了而马上放弃。写个小程序,它硬是不照着人想的那样来,资料又奇少无比。但再想想,连MAME这么大的工程都能用它来编译,为什么呢! 配置好了编译环境,整了个makefile,写个小程序,用来生成HTML格式的文件列表的。遇到好多问题,最怪的就是,它生成的程序居然会自动解决命令行参数,比如*.*,它就自动把当前目录下的所有文件名作为参数传进去了,除非用引号包住。开始不知道原因,硬是以为它调用的库函数有bug-_-b 放弃bjam了,白天看了一下它的文档,跟Boost的耦合太强了,似乎不太适合作为通用的工程管理工具,还是用make算了,文档也多,基本上绝大部分的工作都能完成。
用VC7.1写榜单,榜单一般就是一个cpp文件就搞定了。因为有很多个榜单,所以一个一个建工程似乎稍微麻烦了点,后来想想用make能搞定不,可是我又不熟悉make,只好看看能不能写个批处理文件,用命令行来解决。看了一下LUA发布包里的编译用的批处理文件,再看看IDE里的工程属性,照着写了一个,舒服啊,可以一下把所有的都马上全编译连接了。
照着写单机的榜单,突然发现从某个修改开始,总是会把C运行时库也连接进来,真麻烦,仔细看看自己的代码,实在没必要拖个DLL呀,何况VC7.1的C库是msvcrt71.dll,是不由Windows携带的,所以要发布这个榜单的同时,就要背负需要同时发布这个dll的负担。在工程属性中把可能想到的所有的编译选项都关掉了,用depends看还是连接进来了。仔细想想,应该跟代码有关系。因为把我的代码贴到其它以前编译过不用连接C库的工程里,最后也会有C库被连接进来的。于是心一狠,在工程属性中设置连接时强制不连接C库,看它最后有什么提示。可以看到有浮点数的应用,就要求连接C库了。刚好这时浮点数的应用很简单,可以转换为整形的计算。然后再编译连接,发现是有要连接另外2个函数了,看看函数名,猜想大概跟程序运行安全相关,再到工程属性中把异常和缓冲区检测都关掉,果然可以编译连接通过了。再一步步试,最后发现是因为打开了缓冲区检测,每当程序中用到了数组的操作,就会有连接C库中的一些函数的要求。 终于搞定!
其实好久以前我就是这么想的了,我不想当一个职业程序员,我写程序的目的只是为了能帮助日常生活中的一些小的事情得以更方便的方式来实现。以前还在读大学的时候就经常写一个程序不是为了写程序而去写程序,而是因为在某方面有这个需求。比如阿菲连连看,完全是因为受不了阿达连连看的非注册版的限制同时又找不到好用的破解,像IPKeeper,就是因为受不了在校园网上BBS打魔兽的时候被人冲IP,还有一些其它的也是。当时最年少轻狂的时候,还曾经想过,除了Windows,除了BCB和VC ,其它我要什么软件,都自己写,呵呵! 晚上加班了,因为突然冒出一些事情来没做完,郁闷!后来有点烦了,也没多少心情做这些没做完的事,写了一会儿VBA脚本,以前在进公司前,几乎只会一点点Word,到了公司没办法,开始使用Excel,发现Excel的功能挺强大了,尤其是它集成的VBA可以帮助用户极大地提高工作效率,好多机械重复的事情写几行脚本,就可以人出去逛了,让电脑自己在那里干活,人就省心了安逸了舒服了。高中的时候学过的QBASIC现在派上用场了,VBA的语法基本上跟QBASIC一样,连Lotus Script也是用的这种语法,哈哈。而且VBA集成开发环境里的调试器也还算好用,呵呵。现在还有一个可以用脚本的场合,用例被调整结构后,很多可能是重复的,把重复的那些找出来,然后该删掉,或者怎么着,就可以整几行脚本来跑,哈哈,人又可以出去骚扰了。 此之谓程序改善生活,程序帮我偷懒,hoho~~
在VeryCD论坛里看到有Office Pro 2007 Plus的下载,马上down一个下来,等装的时候才发现要sn,而帖子已经不见了,只好找到另外一个帖子,里面有个截图,有sn,试了试,可以用。有D版用的日子真是爽啊!尽管在家里,真的很少会用到Office,但为了尝鲜啊。 打算去买个国内的空间,开个论坛,但论坛主题做什么好呢,才能吸引人气呢,嗯,得好好想想。
自从blogger.com被伟大的GFW前段时间封住开始,一直都是用Tor来发贴的,而同时又把pkblogs.com或nyud.net:8090的地址告诉别人,让别人也可以浏览到网页的内容,但是留言是不行了。昨天突然发现,居然又被解封了,真happy呀,可以暂时不用Tor了,blogger.com直接访问的速度还是挺快的,就像在自己家门口一样呢,呵呵。 昨天半夜的时候上coolkuai论坛,发现coolkuai作者还是给我回了信息的,只是很粗心啊,我明明写了我的邮箱地址的,他还叫我给个邮箱,发点资料给我。我无奈,只好又回了信息,但他又不睬我了。他说coolkuai可以实现很多榜单,有兴趣可以先做一下榜单。coolkuai3.0的榜单实现方法我以前了解过,其实原理很简单,根据用户选择的不同榜单到coolkuai的网站上下站对应的动态链接库到temp文件夹,该动态链接库导出几个定义好的函数,分别用于在不同时刻被主程序调用完成不同的处理。说实话,这个coolkuai单机版大功能上还是实现得比较算是有亮点的,比如录像,比如键盘软加速,比如打榜,但在细节上,说是不敢恭维都不为过吧。作者提到以后的发展,是想添加联机功能,呵呵。
给coolkuai的作者发了信息,但不回我,看来对我的加盟请求是不屑了。 没办法了,只能专心我的方块了。我的方块进度也着实慢了,以前是因为算法没弄好,所以花了很多冤枉时间。现在有算法了,却提不起精神了。其实我的方块需求也不是很多啊,就一个skin功能(基本已经可以工作了),外部脚本实现游戏逻辑(突然想把接口做得再通用点,可以任意添加新的脚本语言支持,比如加个Tcl模块,就可以直接支持用Tcl语言来编写游戏逻辑,而主程序是不用修改的),键盘软加速(大致方案已经有了,但怕是会效果不好),录像(这点还是没想通,觉得可能是用键盘录像钩子),联机对打(类似QQ火拼俄罗斯,有大厅可以看桌数,一桌最多6人,可以旁观)。 看了下Google AdSense好像200次显示才$0.05啊?比原来预计的又低了一半,晕。看来仅靠Google AdSense是不现实的,得有其它的注册来源。 WallpaperHelper、CaptureHelper、SocketCapture都是可以做为shareware的,另外还可以做一下按键精灵的插件,可以让它自动弹出我的网页,或者也作为shareware。 小丫头发短信来抱怨说要辞职了,仅有的自尊心都被剥削光了。唉,心里很多话,说不出口的。
看了一下csdn的blog访问量,发布在首页后,果然比以前多很多了。不过再看一下google adsense的账户里,增加得好慢啊,好像是100次显示得$0.05,hoho~~~现在累计都没有100次,要累积到$50的话,要100000次显示啊!得想想办法怎么吸引别人。我把Google AdSense放在了主页和blog上,blog就只能通过多写些文字来提高访问量,主页只能靠宣传我的软件了。目前只想到这些。Blog上要写有点新意,有点价值的东西,才能吸引别人访问。可以先写一下C++与Tcl/Lua等的交互,因为有TclSuck的基础嘛,然后可以写一下C++ template的学习心得,再然后,我希望可以参加coolkuai的开发,就可以吸引那些关心coolkuai的游戏玩家来访问,写coolkuai开发的WIP,本来方块要做也是做得出来的,但是coolkuai现在已经聚集了一些人气了,如果能好好地利用这种人气,就好了。 大概想了一下WallpaperHelper,应该左边有一个TreeView,右边分上下两块,一块是个ListView,另一块是预览框。这样可以组织多种主题,主界面可以朴素一点。另外要加日历、月历、年历和时间框的功能,这些就最好能有skin功能。感觉WallpaperHelper是实现难度最低的,等完成了之后,再好好考虑SocketCapture和CaptureHelper,还有我的方块呀!
昨天晚上去华侨城吃晚上去了。那个叫爱西华温泉的地方,吃了饭后,去里面的酒吧玩,到12点才走,结果结账搞了大半个小时,打的回到家都1点多了。 Inno setup是个不错的东东,现在越来越多的软件使用它来做安装程序了。很久很久以前,大概是三四年前吧,也试过,觉得难用,样子也土,就放弃了,转向Wise了。昨天搞了下,今天又研究了一下,真的已经是很好用了,做出来的安装程序也比较好看。把googlepages里的页面改了下,把LLYF ToolBox传上去了,还提交到了华军、csdn和upload上去了,不知道有几个会收录。其实要好的话,要把英文的那个页面好好做一下。 下午突然停电了,晕死了,实在无聊,就想出去逛一下了。结果就逛到电子市场去了,结果看到nano就不想走了,结果最后还是买了个2G的。然后就逛上去买了个USB Hub,就为了能同时接摄像头,鼠标和MP3。最后又逛到茂业,还买了双PUMA的鞋子,去抽了2次奖,真tmd的衰啊,这个我觉得不正常啊,凭什么啊,只中了2瓶水,后又顺便办了张茂业会员卡。晚上去交房租了,唉,钱啊!
几天前申请的Google AdSense,还以为不会下来了呢,因为我当时只是把csdn的blog地址提交了上去,那个blog已经一段时间不更新了,就是从搬到这里来开始吧。不过那里也是有近百篇的文章,总访问量也有1w多近2w了。终于收下来了,放了一个图片和一串文字的在上面,看了看美观效果影响不大。就打算放在这里来,不过有点郁闷的是,因为我是用Tor+Vidalia+Privoxy+ TorButton+Firefox这种奇怪的组合才能访问到blogger.com的,所以在定制我的blog模板时,添加Adsense总是失败。最后看到有一个添加HTML/JavaScript的,就加上去了。看了看效果,用Tor的话,会被Privoxy拦截的。用www.pkblogs.com来访问的话,就压根不显示。用.nyud.net:8090的话,可以显示,但是网页中的所有的链接都失效的。唉!看来只好首推csdn的那个blog了,以后多写点有点技术含量的blog,然后就发布到csdn blog的首页去,增加几个点击量。其它的生活娱乐方面的,都还写这里吧。 关于luaopen_io调用失败的问题,在Lua的maillist里问了一下,有人说是因为io库里有些函数的运行是依赖于Lua建立的特定的环境,所以要用lua_call来调用,要么,就直接用luaL_openlibs来引入所有标准库。看了看帮助文档,还有Lua的源代码,似乎好像就是这么回事啊! 现在看到我的方块里那一堆7z的源代码文件,就感到不爽,太多文件,充斥着我的方块的project,应该把它分离出去,对于7z、zip和rar专门做一个lib或dll,在需要的时候可以直接链接进来,而不需要添加这些源代码文件!
刚回到家就像以前的每天下班回到家一样,拿出电脑,连上电线网线USB线音频输出线,开机,开eMule,不料却连不上网。去整了一下Router,重启了也没用,于是无所事事地看完了《黑社会2》,总算是又解决一件事情。看完之后再看网络状况,可以上网了,又要重新设置一遍端口映射。唉,为什么动画片总是很少人下载呢! 然后和同事聊了一会儿天,又打乱了计划,只是添加了连接变量的功能。
下班后吃完饭,先坐车到九鼎皇,那里有个文体用品批发商店,进去买了个28块钱的飞镖盘,顺便买了三支镖,8块钱。回家丢了几个,看来便宜的东西质量是不好哈,那针眼很明显,而且镖尾不正 ,容易飞歪了。 把afei的blog从头到尾翻了一遍,还有几处零星地提到我的,呼呼。 TclSuck差不多已经把C++调用Tcl函数部分都封装完成了。接下来可以加入变量访问控制部分了。好在发现了,原来Tcl调用C++函数时,会把第一个函数名当作第0个参数传入,就像就像就像(好几处好几个文档提到的)C程序main函数的参数那样。这部分要分成两部分,一部分是调用全局函数(类静态函数也属于这类),另外一部分是调用类成员函数。对于已经完成的部分,真的是很难看的一种实现,而且完全失去了运行期效率。不过在外部表现上看来,它真的能让client application以一种比较优雅而且方便的方式来调用Tcl中的函数,呵呵。
都不晓得出什么问题了,慢得很啊,打开网页都很慢! 白天想了想,凭现在对Tcl的掌握,我是写不出这样的封装库的,因为只知道要写一个固定原型的C函数,再调用注册。但当时的直觉是,理论上应该是可以实现的,只是我不知道而已,就像Lua那样,有LuaTinker这样的封装。果然,上google搜了一把,找到个C++/Tcl库,看样子是实现得很好,它的说明文档里也说,是得益于Boost.Python的灵感。本来我都想,只实现Tcl的嵌入算了,现在好了,可以研究一下,把Tcl扩展了实现了。不过时间有点紧了啊!!
装了个IE7。在网上看到文章说到,装IE7的时候会进行正版验证,现在终于我也可以理直气壮地直接安装了。要是以前,肯定还要先去验证一下我的破解版是否是“完美”破解等等诸如此类的事情。相比之下,对于我来说,可以体验到的,就是多了个tab浏览功能,而且说实话,这个tab浏览操作习惯还不适应。其它的,也没看到什么特别之处,照“他们”的说法,就增加了很多特性,提高了安全性等等等等,我一个普通用户,是完全体会不出来的。 照Borland Blogs上某篇blog上说的那样,我用IE的时候,都是在Firefox里用IE Tab来进行的。不过似乎好像,IE Tab对IE7的兼容性……郁闷! 中午去笨笨家里吃饭了,虽然在同一间公司里,但却好久没见到她了,还有老板。阿菲也过来了,倒是阿菲,似乎反而要多见到一点。 小丫头找到房子了,我说我感动死了,我认识的人中居然有这样辛苦地工作生活的人,还比我小,还是个女的。哭ing!不是经常有那样的电影吗,哪个小孩子,生活艰辛,还很努力……下面的观众感动死了,哭得稀里花拉的! 打算学习LuaTinker的样子,做个Tcl嵌入和扩展的C++泛型封装库,其中使用的封装技术可以作为这个季度的案例来写。不过这次时间有点紧了,15号之前就要提交,没多久了。要达成这个目标,所需要的工作量似乎不大,只要能:1、在C/C++里调用Tcl函数,2、C/C++变量与Tcl变量绑定,3、Tcl脚本调用C/C++可调用体。可以趁此机会练习一下C++ template的应用,刚好做出来的胶水代码也有点实际使用价值,而且想在我的方块实现里不用LuaTinker,自己写一个类似的,更符合实际需求的。
好奇,看了一下coolkuai3.0的打榜功能,从网站上看到有几个trc文件,从文件名看,就是支持各种不同类型的打榜功能的,再打开coolkuai3.0,随便打一种榜,查看一下该进程的模块信息,果然发现它装载了一个在临时文件夹中的trc文件,再看一下这个trc文件的PE信息,没有导入信息,只有几个导出函数 Core/GetCore/OnAfterAction/OnBeforeAction/OnGameStart,用PEiD看也看不出是用什么编译的,反正体积很小,都只有3、4KB,也不像是用ASPack处理过的。oneaddone在这点上做得挺好的,用户根本不用管要下载什么文件来支持新的玩法,只需要知道在那里点选一下,就可以了。
和江江她们打方块去了,呵呵,速度也没啥提高,一直在1.2x,有点气愤,为什么我就练不快呢! 白天在公司,看了好久的《Programming In Lua》,还遇到一个C++ new的没见过的用法,去公司内部的支撑论坛问了下,好菜啊,没看过《C++ Primer》就这样水啊!我大概是从大学里开始养成的坏习惯吧,静不下心来仔细看书,总希望有个速成式的学习快餐,可以随便翻一下就能学会一些东西。大部分时候,都是看一下目录、前言、序就当是看过一本书了,到时候知道去哪里查阅就行了。 在看LuaTinker的代码的时候,还学到一招,创建匿名的对象,并直接调用返回值为该类对象引用的成员函数。有趣,这种匿名对象的生命周期好像只在当前代码行内有效。 又看了一点点LuaBind的代码,原来以前在Boost.Python的examples里看到的那种奇怪的语法,只是重载了操作符operator,和operator[],呵呵。从云风的书上看到,如果不是忙于各种各样的日常事务,大多数的程序员一定会迷上博大精深的C++。说得一点都没错啊,现在看来C++ template的运用,对我来说就是一个很大的诱惑。 要看懂LuaTinker的代码,还是很依赖于对Lua的深入掌握,尤其是Lua提供的C API,如何让Lua脚本能调用C++里的类方法,这样的技术是LuaTinker提供的重要功能。Lua与C之间通过一个virtual stack来实现通信,所以virtual stack的操作很迷惑人了。看来还是得再多看几遍PIL,再试着自己写些代码。另外,云风的书里也有提到过怎么进行这样的封装,不过我更倾向于LuaTinker这样的方案,因为目前我是彻底被C++ template技术迷倒了!
在ccrun上看到用GDI+来实现的skin功能,拿出用BCB6编译了一下,果然可行,效果也不错,然后想给LLYF WallpaperHelper里加一个类似的功能,看代码挺简单的,但就是编译不过去,说两个函数间搞混了,ambigous了,真是郁闷,后来没办法,想到看一下那个工程里有没有定义什么特别的宏,打开工程属性一看,比平常多了个STRICT的宏,加到自己的工程里一试,果然可以编译了,真是奇怪。想到这样的界面效果,最适合像鱼鱼日历秀那样功能的程序了,所以就可以加个日历、月历、时间的显示,突然想可以试试NeoWin那样的窗体继承,试了试还可以,右键菜单也能正常弹出来,只是在父窗体中实现的窗口风格改变似乎对继承下来的子窗体没什么效果。又稍微看了一下ccal的代码,基本是可以实用了,传入指定的参数可以生成特定年份月份的月历,包括阴历哦,这一点才是迫使我使用ccal的原因。突然发现一个软件要做好,真的要考虑很多方面的因素,现在我写程序完全是随着自己的性子来的,基本上只是大概估计一下要弄成什么样子,就开始动手了,计划根本不够严谨,说白一点,是缺乏设计能力,唉! 又跟江江他们打了一会儿火拼俄罗斯,现在打单机速度基本上可以稳定在1.1x,但是打Q块就不稳定了,不过打一下江江还是够了,大牛更水一点,悍超猛一点,不过那天看他截的单机的图上速度才1.1左右,感觉应该不止这个速度才对。如果只是这个速度,我也差不多啊。不过我现在发现我的摆法真是全无章法,一点都不好,很不整齐,垒不高!还是得多练习啊,速度的提高是首要的,其次是摆法。
今天一天写了几行脚本,为什么效率这么低呢,只是添加了个生成chm文件的功能,就花了8个小时!如果是用C/C++这样的语言来表达的话,我会不会更快一点?我怀疑,不确定,算了,随它去了,反正勉强能符合我自己的要求了。 一个好用的debugger还真是重要哈,以前在Lotus Notes上用Lotus Script写Agent的时候, 就已经发现了这一点,但当时也只是觉得大概这样的debugger只适合这样的脚本语言,这两天突然发现在BDS中的debugger也是很好用的,我真是土,用BCB那么久,一直没用过它的debugger,自己汗一个先,知道我以前调程序有多复杂多麻烦多痛苦了吧。最早在DOS下用QBasic或TC写程序时,调程序都是通过打印语句输出变量的值来做的,后来大概过了2年左右迁移到Windows上时,居然...居然是用MessageBox来显示变量值来调试的-_-b主要是VCL里的字符串和数值之间相互转换很方便,所以...唉,闻道有先后,术业有专攻嘛(又想起那个家伙)。用MessageBox有一个不好,就是会打断程序的执行,要人为介入使它继续。后来发现了OutputDebugString,其实是先发现了一个它的捕获程序DebugTrack,才知道有这个函数的存在,还依样写了个简单的版本,这个方法跟我在DOS下调程序几乎是一样了,输出一些变量的值,来跟踪程序的执行,好就好在不用打断程序,而且又用stdarg.h的一些宏,把它封装得像printf一样,可以方便地用一个接口来输出不同类型的值!直到前两天,才发现集成在IDE那个debugger,用起来就像调Lotus Script和VBA程序一样简单方便,还可以用CodeGuard,居然能自己检测出内存泄漏,哈哈,太好了,在日志文件中甚至能指出是哪一行分配的内存没被释放。啊,我真是太土了! 今天买了2号中午12点的机票了,计划5号下午回来,最晚6号上午吧,要回来要回来要回来,过中秋,呵呵。
今天看到某论坛上一张比较好看的CG MM图片,突然想起Dead Or Alive里的那帮MM,于是上google搜了一下,down下来好多图片,多了图片就是为了当桌面用的,想起我那个只是做出显示界面的LLYF WallpaperHelper来,用来后台自动更换桌面是绰绰有余了。不过这个程序只能用简陋来形容,真的只能用来更换桌面,界面实现地也不太友好,我的审美细胞实在不行。稍微改了一下,也治标不治本,有些实用的特性都没实现。还突然想到,要是能把桌面做成月历就好了,于是去搜了ccal的代码来,代码实现并不多,但我的代码阅读能力确实也差,晕。 在外面闲逛的时候,就想要做哪些东东,回到家对着电脑,却怎么也提不起劲来。Yuyuamp,这个名字还真有点别扭,YuyuNES稍微好看一点点,YuyuTetris呢,也比较怪,还有Yuyu Entertainment呢,哈哈! 我根本没有利用上键盘加速的优势,因为我一直都是一下一下点的,不是用的平移,郁闷,习惯改起来很痛苦!
昨天把WinSock捕获部分的代码封闭到一个类里面了,看起来似乎要舒服一点,维护起来或者有新的需求了,也应该更方便一点。不过现在,从Detours里copy过来的代码用起来还有一点点小问题,因为原来它是被用于一个单一功能的控制台程序的,而我现在这里每一次开始都是一个新的线程,所以结束的时候,应该发送消息让complete port自己结束工作线程,不然程序就可能崩溃。 今天在公司,花了几乎所有工作时间,至少有6、7个小时吧,写了几行VBA代码,可以把写好的手工用例自动导入到自动化分析的模板里面,并分成各个步骤和预期结果。虽然说花了那么多时间,但回去看一下所有的代码,并没有多少行,这里可以大致看出,用这样的语言开发效率在某些领域某些场合是比C/C++之类的语言高,我花这么多时间来实现这么简单的一点功能,完全是因为我以前基本没用过VBA,很多时间都是花在查找MSDN等帮助文档上了,想到一个需求,就想应该已经有相应的函数封装好了,于是翻来翻去看msdn和online help。中途也产生一点想法,或者说抱怨,这种语言还是比较麻烦,比如不能随时随地定义新的变量,觉得不爽。因为一开始都没有什么计划,上来卷起袖子就写代码,所以什么变量名啊,程序组织结构啊,都是乱来了,还好想要的功能大体上都实现了。 还有点不爽的是,VBA的编辑器居然不支持鼠标滚轮,晕死!不过虽然今天花了这么多时间,以后就可以少做很多机械的重复劳动了,只是不知道自动化组的人没有没做这方面的事,不然我的时间就是白费了!
今天旁边那个女同事从网上学来的看相功夫,要给我看手相,还说得有模有样的。首先说我,是个比较花心的人,嗯,我心想原来我真是这样的人啊。然后说我的钱可能不会多,再说什么健康啊智慧啊事业啊什么的,最后说到我的婚姻线,说我的老婆是个很有钱的人,晕,我的钱不多,就让我老婆钱多啊,真是有趣,还说这个老婆对我很好啊,是个很不错的人啊等等,反正最后的总结是,我的手相整体看来是不咋的,唯一好的就是那个老婆不错,又有钱人又好,昏倒,然后我就说对啊,我老婆有钱得很,是xx的首富,哈哈。梦吧! 想了一天,怎么实现键盘加速的呢,去公司那个论坛上问了一下,有人说等KeyDown时只要没有KeyUp,就一直发字符消息,这想法似乎有点可行,但是要是其它游戏程序里不是通过字符消息来进行响应的该怎么办呢! 另外一个还没有想通的是,录像功能是怎么实现的,看它的录像文件都很小,一般2.0版的录像文件是10几KB,而到了3.0版,则降到了5KB左右,查看一下2.0的录像文件原始内容,似乎是有不少的冗余信息。但不知道它到底是怎么实现的!
Category Plugin Framework
Qt Creator有个很风骚的插件管理器PluginManager,还有个很骚包的插件说明PluginSpec。基本上,所有的Qt程序的入口都是传统的C程序一样,代码流程从main()函数开始。
在main()中,先初始化用于国际化的translator,然后获取程序配置settings,接着就在栈上创建了PluginManager对象,之后为PluginManager设置搜索用的文件扩展名pluginspec,设置配置,再设置插件搜索路径。
设置好插件搜索路径后,PluginManager会从配置中读出被忽略的插件列表和需要强制使能的插件列表,然后开始在插件搜索路径中查找*.pluginspec文件,这类文件中记录了插件的名称,版本号,依赖插件等信息。找出所有.pluginspec文件后,就检查一下每个插件所依赖的插件的名称和版本号信息是否匹配。
接着再返回main()中,找出Core插件,该插件是整个Qt Creator的主框架,甚至实现了主窗口。如果Core插件有问题,Qt Creator就会打印出错信息后主动退出。
最后便是调用PluginManager::loadPlugins()载入所有插件。loadPlugins()首先调用PluginManager::loadQueue()以确定插件载入的先后顺序,该过程做了两件事,一是检测是否存在循环依赖的情况,这里用了一个很简单的方法,将当前的插件放入一个队列中,然后检测它所依赖的插件的依赖插件,如果新检查的插件所依赖的插件在队列中,那么说明存在循环依赖。另一件事便是安排载入顺序,同一个函数内通过递归,先递推将最被依赖的插件放入队列,然后回归将最后的插件放入队列,这样生成的便是解决了载入顺序问题的队列。得到载入顺序的队列后,便依次调用PluginSpec的loadPlugin()方法,这里它将插件状态定义为Invalid、Read、Resolved、Loaded、Initialized、Running、Stopped、Deleted共8种,loadPlugin()方法根据传入的要求的状态,进行相应的操作。Loaded时通过Qt本身支持的插件机制,装入动态链接库,之后是Initialized状态,调用每个插件的initializePlugin()方法,最后是Running状态,调用每个插件的initializeExtensions()方法。其中initializePlugin()和initializeExtensions()并没有多少区别,调用的时机也是挨着的,中间没有其他的操作。一般可以简单地这样区分,initializePlugin()中完成最最基本的插件初始化工作,包括创建插件内部的一些对象等,而initializeExtensions()中则完成那些内部对象的初始化工作。当然也可以不用严格遵守这种规则。
到此为止,整个Qt Creator就运行起来了,消息循环启动后,用户就可以进行操作了。
在app::OnInit()中,插件管理器先设置了一个安全模式,安全模式只是影响后续插件是否被激活。
在MainFrame的构造函数中,调用MainFrame::ScanForPlugins(),该函数根据配置又调用插件管理器PluginManager中的方法ScanForPlugins()扫描指定目录下的文件,该方法在指定的目录下查找dll(Windows系统)或so文件(UNIX系统),同时,需要确认当前是否以BatchBuild模式运行。所谓BatchBuild模式,可以这样理解,Code::Blocks启动后只是用于编译工程,不进行其他诸如代码编写之类的操作,所以除了编译器插件,其他的插件都不需要载入。每找到一个dll或so文件,PluginManager又会去找同名的zip文件,从zip文件中提取出manifest,manifest文件中保存了插件相关的版本号,作者,联系方式等无关紧要的信息。之后PluginManager::LoadPlugin()方法被调用,在该方法中实现了系统层面的动态链接库load并创建插件实例对象的工作。而且从这里可以看出,一个dll文件中可以有多个插件,PluginManager会依次将该dll中所有插件都创建实例对象。
接着MainFrame::ScanForPlugins()又调用PluginManager::LoadAllPlugins()方法,这个方法做的事情跟它的名字有点不对应,因为照我们传统的理解,之前PluginManager::LoadPlugin()已经完成了插件载入的工作。而这个LoadAllPlugins()方法只是调用了每个插件的Attach()方法,该方法做的事情可以归类为插件初始化工作,每个插件都可以有自己的独立的OnAttach()方法被PluginManager间接调用。并且每个插件类都从wxEvtHandler继承下来,可以让自己处理一些事件,比如响应菜单项点击或工具栏按钮点击等等。在Attach()中会将自己这个新创建的实例对象插入到MainFrame的event handler chain中,这样才能将事件响应流向插件实例对象。实际上Attach()就做的有意义的事只有使能了事件处理响应。
最后,便是做些插件在界面上的处理。比如在创建主菜单时,会让有需要的插件自己添加菜单项,并绑定事件处理函数。到此为止,插件就基本上可算是能正常工作了。
首先,之前我说过,现在的CodeLite没有一个很大的包罗万象的dll了,这个说法不是很准确了。因为确实仍然有一个叫libcodeliteu.dll的文件,只不过里面包含的内容确实不介Code::Blocks的那个dll是包含了完整的几乎所有的功能,而是只包含了一些跟IDE业务关系不大,却是比较底层而又基础的通用功能。
其次,CodeLite的插件使用C链接的方式导出几个知名函数,用于创建插件对象,查询插件信息等。而Code::Blocks的插件则不然,它们没有这样的知名函数,而只是从几个规定的插件基类中选择一个进行派生,而这个派生类又声明成dll导出,同时,又在定义插件的cpp开头处定义一个全局对象,用于注册本插件。该全局变量接受两个参数,分别是字符串类型的插件名字,以及泛型的插件类类型(也就是说,是个模板参数)。注册插件的那个全局对象保存了插件类类型,在需要的时候可以生成一个插件对象。所以这样可以省掉那几个知名函数,代价是需要导出插件类,容易暴露过多实现细节。感觉CodeLite的方法比较传统,但应该适用于多种编译器,而Code::Blocks的方法就Quick & Dirty一点,跟C++编译器的绑定就比较紧密了。从软件工程的角度讲,我倾向于CodeLite的方案,从项目进展的角度讲,我倾向于Code::Blocks的方案。
最后提一下,Qt Creator的插件也没有知名函数,但具体是怎么载入的,我还没仔细看过。Qt Creator的插件拥有多种状态,这点太完备了。
Qt Creator的插件机制比起CodeLite和Code::Blocks来要强大得多。每个插件至少有一个dll文件(以Windows平台为例),还有一个必须的.pluginspec文件。插件的基本信息在.pluginspec文件中描述,包括插件的名称、版本、版权、作者、基本信息、分类、网站等,最重要的一点是有依赖的插件信息。支持插件依赖可以获取得大的灵活性和可扩展能力,这点CodeLite和Code::Blocks都没做到,因为单靠一个动态链接库很难实现这种依赖关系的描述。
插件的实现同CodeLite和Code::Blocks类似,都放在dll中,但它的实现有点像是糅合了两者的作法,但又有所改进。Qt Creator应用程序本身的exe基本上只是实现了一个插件管理器,其他的IDE相关的业务逻辑全是由插件实现,甚至于主窗口也是放在一个叫Core的插件中实现。Qt Creator又定义了一组组的接口让插件实现,这点看来跟CodeLite比较像;但是它又基本上将接口的实现,至少是头文件全暴露了,插件在实现这些接口的时候可以直接调用它依赖的插件的服务,而不是通过接口调用,这点上看又有点像Code::Blocks的做法,我个人不是很喜欢这种暴露过多信息的做法,尤其是如果作为一个商业项目,应该尽量少地提供各种内部信息,当然Qt Creator本身作为一个开源项目,大概在这方面就比较随意了,如果全部用接口的形式交互的话,大概工作量会增多,跟实现一遍COM差不多了。
另外说一下,Qt提供了几个宏,用于定义插件类和使用插件,而且Qt框架本身的一部分特性也是通过这种插件机制实现的。只不过这种支持实在太过简陋,只能说了胜于无吧。
昨天查看了一下CodeLite和Code::Blocks的源代码,了解了一下它们的插件机制的实现情况,还是非常简单的。
CodeLite宿主程序是一个单独的exe文件(Windows平台下),插件都是单独的dll文件。宿主程序首先声明了一组接口,这组接口定义了宿主程序可以提供给插件使用的各种服务,比如访问当前编辑器等,然后宿主程序实现这组接口。接着再声明一组接口,这组接口需要每个插件都提供自己的实现,另外,插件还需要提供几个dll标准的导出函数,用于查询插件的基本信息,比如返回版本号,返回接口创建后的实例等,这跟Windows的COM很像,只不过COM规范更完善得多。插件要实现的接口包括在菜单中添加自己的菜单项,添加工具栏等。CodeLite启动后,扫描文件夹,取出各个插件dll,查询出接口实例指针,调用插件实现的接口,并将宿主程序自己实现的服务接口指针传递给插件,这样插件就可以反过来访问宿主中的数据。
Code::Blocks的实现跟CodeLite差别不大。Code::Blocks的宿主程序是一个很小的exe文件加一个很大的dll文件,所有的核心功能都在dll中实现,exe只是一个外壳。插件实现跟CodeLite类似,都是dll,区别在于Code::Blocks定义的插件接口类型有好几种,比如普通插件,编译套件插件,调试器插件等等,另外的区别就是,由于Code::Blocks宿主并没有采用接口的形式提供服务,而是将服务封装在核心dll中,所以插件要访问核心服务都是通过链接这个核心dll来实现的。
从开发者的角度看,Code::Blocks需要的代码量相对小一点,因为少了宿主接口声明,以及接口实现的衔接部分。但CodeLite的接口形式提供服务封装性更好一点,更类型无关。Code::Blocks的插件开发需要核心dll的那些头文件以及链接库文件,这难免有种暴露了过多细节的嫌疑,而CodeLite则只需要接口声明就行了。所以我个人更倾向于使用CodeLite的方案。
今天看到推友@liancheng说Mozilla/WPF/QT/GNOME3都同质化了,大体的意思是指这几种方案都把表现层和逻辑层分离得很独立,复杂的,高度重用的,平台相关的部分,用C/C++之类的语言实现成组件,表现层用XML描述界面,用CSS之类的样式描述skin,再用如JS之类的脚本语言描述运算逻辑粘合组件和界面。
我最早了解到这种架构是几年前Firefox开始大肆流行,网上这类技术文章也大量涌现。当时也是很惊叹于Firefox的扩展机制如此灵活,却对它的开发环境很是鄙视,而且用于表述逻辑的脚本语言是用JS这个我完全没了解过的东西,所以看过介绍后,就丢到一边了。后来也偶尔听说WPF、XAML之类的东西,但对.NET一直没啥好感,于是也没研究。最近几个月跟个网友讨论,提到QT的界面方案,大体上也是知道QT也采用这种架构了,而且也确实一直计划着做完眼前的这组东西后,以后全面转向QT了,但仍一直没抽出时间来研究。
今天看到@liancheng的讨论后,让我有点儿沮丧。我现在用C++/wxWidgets做主框架,好不容易设计并实现了一个并不精巧的插件机制,用Lua来编写逻辑,还总是有这样那样的限制,这不就是典型的重新发明轮子么,而且发明的是个不咋样的轮子。唉!
前几天,把所有的插件以插件为单位打包成zip了。不过不知道wxWidgets中的zip虚拟文件系统如何支持密码,至少是没找到相关的选项。现在的情况是验证了方案可行性,可以确认功能上的不缺失以及性能上的损耗在可接受的范围内,但真正实用是一定要有密码的,也就是为了保护插件中的源代码。以前还以为带了密码就不方便第三方开发插件了,现在想通了,其实只要我提供一个插件开发环境,其中自带插件打包功能,这样就可以用同一个密码了。既然wxWidgets没有简单方便的接口来支持密码zip,那就只好自己写一个这样的功能了,好在zip实在是一个很大众化的格式,源代码很容易找到。
宿主程序提供了界面国际化,那么插件不能提供国际化就说不过去了,至少得有这样的机制以供支撑该种需求嘛。 得益于wxWidgets对国际化的良好支持,要让嵌入的Lua解释执行的Lua脚本也能根据宿主程序的本地化信息进行正确的处理非常简单。wxWidgets中对要进行国际化的字符串用_()进行包裹,其实这是一个宏,用于调用真正的翻译功能,比如wxGetTranslation。所以在嵌入的Lua中将wxGetTranslation函数注册到Lua中即可,然后在Lua脚本的最开始处将该函数换个更简单的名字,比如_,这是最好的名字了,哈哈。这样就可以在Lua脚本中对需要进行国际化的字符串也用_()进行包裹,它会调用wxGetTranslation函数。 GNU的国际化方案套餐中,提供一个叫xgettext的工具,可以从众多编程语言的源代码文件中提取出字符串,生成po文件以供翻译生成mo文件。比较不幸的是,xgettext不能支持Lua语言,同时由于我这个项目中使用的插件描述信息中有一部分界面信息是在xml文件中的,这也是一种自定义的格式,所在很不幸地xgettext更是不能处理啊!所以我在想,我是否要先写个可以支持Lua和我这种xml格式的类似xgettext的工具呢?Poedit太扯蛋了,居然只能认它自己生成的那种po格式的文件,稍微改一点就报错了!
到昨天为止,基本完成Code Snippet的框架,剩下的都是些体力活。该特性要求在点击菜单项时,根据当前光标所在位置的字符串,替换成对应的代码片段。由于菜单项是通过插件添加实现的,而且Code Snippet又根据当前编辑的源代码对应的编程语言不同,也会有不同的处理,所以也是通过不同的插件实现的,这就要求插件可以再次调用插件。好在当初设计插件扩展框架时,已经考虑到这一点,所以虽然有实现过程中有需要慢慢调试的地方,但没有特别大的障碍。 完成Code Snippet后,应该开始Auto Completion特性的开发。该特性是本项目中可算是难度最高的特性之一,同时又有比较高的准确性和运行效率等要求。还有点比较头痛的是,针对不同的编程语言,可复用的东西不多。 此外,还有个功能应该尽早加入,就是处理文件的不同编码。比如通常,尤其是早期的代码,都是直接使用ANSI编码保存。而现在已经比较常用的是保存成UTF-8等编码方式,特别是像LaTeX的一些处理器直接要求输入文件是UTF-8编码。所以应该能在文件的装入和保存时,可以自动处理文件的编码问题,这可以通过iconv或ICU实现,不过问题就在于有了选择,才是苦恼啊!目前我倾向于使用iconv,因为相比之下更轻量,而且够用。 这些天发现,Lua的字符串连接符..效率还真低,怪不得Lua要提供*all和table.concat等设施。 本来Lua中操作XML有几种不同的选择,这跟在C++中情况差不多,我选择的是比较轻量的ltxml。而昨天在Code Snippet特性的开发过程中发现,我把所有的信息都保存在xml中,而每次完成snippet时都从xml中读取,开始几次还是正常的,但只要过一会儿,在调用xml.open时就会报什么试图index一个function值中一个number值,还真是诡异,但调试发现这时无论xml.open还是传入的参数都是正确的,很是纳闷啊。于是只好规避一下,只在开始时读一次,全部都装入到内存中,以后就直接读内存了。 一直以来,都是通过print来进行Lua脚本调试,真是应了那句“一夜回到解放前”。前两天才在界面上加了一个专门的输出窗口用于从Lua脚本打印字符串过来。好比是当年写Windows GUI程序时,用MessageBox调试进化到用OutputDebugStrng进行调试。昨天记起来有LuaLogging这么个第三方库,于是仔细看了看,很简单的功能,只有几个lua文件,可以记录日志到文件、控制台、socket、email或数据库中。于是我参照这些appender的实现,加了一个新的appender,用于将日志打印到宿主的插件输出窗口中,感觉不错。 接着是使用luabind的问题。在网上看到有人说luabind的各个版本都存在指针的double deleting问题,这让我有点惶恐。好在今天看邮件列表时,看到luabind的作者说,这种问题只出现在使用智能指针或类继承时切片的情况,而且要求是Lua的state先于这些对象被销毁,现在没有好的办法来修正这个问题。我想了想,这几种情况我现在都不会遇到,我只有最最简单的嵌入和扩展交互。之后,又发现有人在邮件列表中写了一个luabind和SWIG的性能比较,SWIG的封装比luabind的快一倍。看到这个结果,我觉得是意料之中,SWIG的封装方式比较底层,调用快也是正常的。不过luabind的作者说,他写了些benchmark的测试,在未发布的luabind 0.9中已经有不小的改进,虽然仍然不比SWIG快,但相比0.8.1版本,差距缩小了约一半,期待0.9的发布。 昨天无意中看到云风blog上一篇老文章提到有Lua Ring这么个库,可以在Lua代码中再创建个新的Lua state,让某些代码在这个新的state中运行,从而保护比较重要的核心state。我潜意识中认为,像我现在这个项目使用嵌入Lua来作为插件扩展的运行环境,确实要用一个比较安全的环境,即所谓的沙盒,但这个Lua Ring怎么应用上去,以及能有多少效果,仍然有待考察。 前些天,从SVN上更新的了wxPropertyGrid的代码后,发现用GCC编译不过了,直到昨天仍然不行,实在忍无可忍,真要骂娘了。上它的sf项目见面看了一下,自11月25日更新代码后,估计作者就压根没发现这个问题,于是在上面提了个单。今天发现作者已经回复那个单,并在svn trunk中已经修正了该问题,总算松了口气。 今天仔细学了一下如何让wxWidgets支持国际化,发现非常简单。只要在程序初始化时,自己创建一个wxLocale对象,把mo文件的搜索路径加进去,设置好当前要使用的语言。其他想要被翻译的字符串用_()宏替换wxT()和_T(),如果是个wxString对象,就用wxGetTranslation(),这样在这些字符串会自动从mo文件中读出相应的翻译后的文本,感觉比ini等配置文件,或是国际化资源dll的方案方便很多。不过为了让插件支持国际化,也可以使用类似的方案,但是我有poEdit时发现它只能从源代码中提取出需要翻译的字符串,不能全新的创建一个,这太土了,以后一定要自己写个好用的。 最后的一个问题是,现在的插件扩展机制,容易出现重复代码,比如相同的功能会在菜单中写一遍,在工具栏中也写一遍,这该怎么修改一下呢,呃,得仔细考虑考虑
昨天偶然发现一个超级严重的问题,程序运行一小会儿就会自动退出,什么提示都没有。至于没提示,这已经有一段时间了,照理说,内部状态、逻辑不正常么,可以给个Windows的崩溃报告嘛,可是它偏偏没有,弄得我要跟着崩溃了。 后来在代码中加入一些跟踪语句,发现出错的原因跟我的猜测一致,内嵌的Lua解释器栈溢出了。这是个很头痛的问题,以前听人说过,如果没有sandbox,插件运行环境是不可靠的,呃,最出名的是chrome的架构,经典的sandbox。但是我这个程序跟它的情况有点不同,在主窗口和子窗口上都有大量的用户交互操作,以及主窗口和子窗口之间大量的交互,子进程间的通信会很复杂。而且现在引起崩溃的,都是主窗口中的逻辑,所以还是会导致整个程序的不可用。 昨天晚上调试了好久,发现只要更新工具栏按钮或主菜单项的界面状态的响应函数打开后,过一会儿就会退出。所以最后可以把范围缩小在C++调用Lua函数的那一块代码上。我不怀疑Lua的代码有问题,凭我现在对Lua的了解,即使真有问题,估计我也是束手无策的。既然是栈溢出,而且时间不长就可以重现。我仔细地看了那块代码,又看了Lua manual和PIL,以及Luabind Documentation,发现我一直忽略的一个问题,在调用Lua的C API出错后,Lua经常会把出错信息压入栈中,而Luabind可能会直接将其封装为luabind::error类型的异常抛出,然后我就只是看一下那个字符串内容,却没其他处理了。这是一处错误,应该在提取字符串后,将其弹出。另一处错误是,我这里调用Lua中的函数,都是存放在一个表中的,所以中间无论哪个步骤出错,都应该把先前压入栈中的东西弹出。还有一处错误是,最后我从Lua栈中获取到函数后,用luabind::object封装了一把,然后luabind::call_function来调用,这时我又直接返回了,却没把这个放在栈中的函数弹出。 昨晚解决了这三个问题后,还以为所有问题都已经修正了。今天又测试了一遍,发现过了约半个小时后,程序还是自动退出了,而且连那exe文件都没了!我要疯了! 唉,这什么都是从零开始的,风险实在太大了。使用wxWidgets是第一次,复杂的内嵌Lua扩展框架是第一次,使用Luabind是第一次,使用wxLua是第一次,把所有东西混在一起用更是第一次!而且很不爽的是,已经用惯了MS的解决方案的我,没有像MSDN这样的大而全的文档极不适应,那些说使用开源的东西成本低的人,不知是真的短视,还是别有用心呢。
这几天似乎渐渐进入了正轨,发现并解决了一堆的问题。 从github上下载的0.9版Luabind可能不稳定,毕竟是没有正式发布,之前没有经过仔细的试用,后来实际用的时候总是这也不行那也不行,万般无奈之下退回到正式发布的0.8.1版。两个版本确实有不少区别,至少源文件个数都不一样。在实际使用的过程中发现,0.8.1中如果注册一个类时,无论有没有注册它的构造函数和析构函数,都要求它们是public可见的,而0.9似乎没这个限制。 比较郁闷的是,没找到一个可靠的办法,把一个类中的STL的容器类型的成员变量传给Lua。Luabind中有个return_stl_iterator策略,似乎是可以把它传给Lua,也能在Lua进行迭代,但是在应用程序退出时,就会报未处理异常。我想以后如果真的一定有传容器的需求,可以试一下SWIG。 在Lua和C++之间传递字符串是个很头痛的问题。C++中的字符串类型太多了,几乎每种框架或大规模类库,都会有至少一种自己的字符串实现类。在wxWidgets中用的是wxString,但跟Lua交互的最好就是C的字符数组。如果是只读的访问,那还是比较容易处理的,Luabind默认处理了std::string类型的转换,SWIG中只要包含了std_string.i,也是差不多透明地处理了。但是如果要把字符串作为输出参数,那就头痛了,Luabind中是有out_value策略和pure_out_value策略,但实际上我发现在Lua中用的时候程序就崩溃了。暂时也不想再深究这个问题了,顶多在必要的时候考虑修改一下接口了。 又是才发现,SWIG和Luabind中注册的类型是不能互相混用的。比如SWIG中注册的某个函数,返回一个类的实例,而Luabind中又注册了这个类的话,是不能作为那个返回值的类型的。所以有时候可能需要在两边都注册一遍某个类型。比较安慰的是,基本数据类型还是能混用的,呵呵。 对于有缺省值参数的函数,SWIG会自动封装成多个函数,每个函数使用相同的名字,只是参数列表不同。而Luabind一次只能注册一个函数,那个完整参数列表的函数,如果想要达到SWIG那样的效果,大概只能自己老老实实一个一个注册上。 再有是Luabind中,不能随便注册char*类型参数的函数,要注册得指定out_value策略,不过说到这里我就有点疑惑,Luabind好像不支持多个策略的啊,如果有多个参数要指定策略怎么办?而且虽然我没经过测试,但我想除了char *外,其他的自定义类型作为参数的,都有这个问题吧!
今天整理了一下项目中使用的第三方框架、库的列表,很多,有C++的,有Lua的,突然面临一个迫切需要解决的问题:怎么决定某个功能应该由C++实现还是由Lua实现? 最早决定让项目成为一个由C++构建主体框架,由Lua脚本扩展实现其他的业务逻辑时,只是单纯得想让C++完成一部分最核心的功能。但现在的问题是,怎么判定一个功能是否够核心,以及即使够核心了,还得考虑其他一些因素,包括实现难度,安全保护,代码架构合理性,代码和逻辑共享等。 众所周知,用不同的语言实现相同的功能,难度和工作量可能差别很大。以前听同事和领导不止一次说起过,一行脚本顶得上一百行C++代码。这也许有点夸张的成分,但正好说明差异巨大这个事实。引起这种差异的主要原因就我自身角度出发来看,在于对语言的掌握程度,不同的语言风格就对不同开发任务的适应度,以及可利用的现成的库和代码的丰富度和成熟度。 说起安全保护,是今天看到Lua的maillist上讨论LuaJIT时Mike Pall说起源代码保护时才提醒了我。一般说来,用C++编写的代码,经过编译生成二进制代码,比起用脚本语言写的代码生成的字节码(中间码)反编译要困难得多。而我本来考虑让众多功能都通过脚本实现,这就面临一个问题,如何保护自己觉得重要的代码。最早的时候想用Lua的官方编译器编译一把就行了,现在看来这个保护弱得可以。而最近又面临另外一个短期内不可能解决的问题是,我打算嵌入LuaJIT 2.0的解释器,而刚刚才知道LuaJIT 2.0不兼容Lua官方的字节码,只提供源代码级的兼容,似乎LuaJIT也没提供一个自己的编译器,同时即使有这样的编译器,万一某种情况下需要用Lua官方编译的文件,那么处理就不一致了!Mike Pall的意见是,用个zip之类的东西打包加密就行了,呃,怎么说,确实是个方案,但使得本方案只能自己使用的了,不能让第三方的开发者参与了!所以除非有其他比较完善的解决方案,不然那样的代码只能用C++实现了。 再说架构合理性,总的说来,到目前为止的进度,自我感觉这样的架构还是比较满意的,当然现在只是一个空壳,只能支持让主菜单、工具栏按钮和右键弹出式菜单的构建和触发都是由脚本插件扩展而成,接着就而对的问题是,像配置选项功能要由谁来做,这种功能有一定的复杂性,又有GUI界面,又有后台处理逻辑,是全部让C++做,还是全部让Lua做,或者是各做一点,那又是各做哪些和各做多少呢?几乎所有同时涉及界面和后台逻辑的功能点,都有这样的问题,究其原因在于,用C++实现了主界面,而在Lua中目前并不能很方便地操作这些界面。原本天真地以为,C++用了wxWidgets做界面,那么Lua中用wxLua就可以实现无阻碍互通了。现实是残酷的,现在光是想让wxLua中使用C++中创建的主窗口作为父窗口就搞不定! 最后是代码和逻辑的共享。这个问题不是很严重,如果是纯粹的计算逻辑最容易共享,一些常用的底层功能,两种语言都差不多拥有第三方库来解决。除了GUI,其他的代码(逻辑)要共享,通过luabind和SWIG可以比较方便地粘合起来。如果粘合起来还是犹豫不决,那就是架构合理性的问题了。 想不到这次决定构建一个基于C++的脚本扩展框架的应用程序,会引出这么多问题,大大出乎我的意料啊,我是一直以来对风险的估计不足啊!
今天完成了右键弹出菜单的插件扩展框架支持,基本上没有遇到什么障碍,跟原来想的一样简单。 除了这个,还把菜单、工具栏的插件扩展支持功能的代码重构了一遍,把这部分功能提取成一个独立的类,在类中完成插件扩展的相关功能,只有最终的事件消息响应函数仍然放在界面类中,这是因为才发现不是随便一个类的成员函数都可以绑定成事件处理器的。 顺便说个可能是wxWidgets的bug,动态创建的菜单,动态添加的菜单项,第一个图标总是显示不出来! 再一个是原本用SWIG生成的文件,我把它直接作为头文件,包含在另一个源文件中,而该源文件因为某些原因,经常会被重新编译,而恰恰这SWIG生成的文件体积巨大(超过25000行),所以编译要花不少时间。于是又仔细看了一下生成的这个文件,发现其实最终只是需要一个luaopen_libname的函数,这样SWIG生成的文件就可以作为源文件了,不用跟着其他文件编译了。
今天修改了插件扩展的描述方式,把菜单项、工具栏按钮的标题、路径和帮助文本,工具栏按钮的图片等信息,全都写到xml描述文件中,这样一弄,lua脚本确实精简了很多。到现在为止,已经可以正常地通过插件扩展实现主菜单和工具栏的点击响应了,如果要说更新界面状态,也不是很麻烦,也就是多添加一个消息连接而已。 再说右键弹出菜单,我粗略地想了想,应该不是很麻烦,也就是添加到各自的扩展点下即可。其实直到现在,我才想起来,我这种实现方式,其实应该跟Windows传统的GUI资源编程基本思路是一样的。主菜单用一个编号标识,然后是菜单项信息,需要足够多的信息可以标识出菜单项的位置(路径),然后是给菜单项添加消息响应。工具栏的实现也是类似,所以如果要支持右键弹出菜单,也沿用那套思路就行了。 昨天说到,如果在插件扩展中使用wxLua,那么wxLua不能使用宿主程序使用的wxWidgets二进制文件,于是我今天想用IUP来试试。我从CVS里取出IUP的代码,然后用MinGW编译出所有的dll文件,可是用的时候发现总是报IupClipboard符号在指定的dll中找不到,而我用depends看是有的,郁闷!但是用LuaForWindows里的dll是可以的,可是它是用VS2005编译的,要带一个VC2005的redist,不爽啊! 另外一个问题是,本来以为脚本扩展时用了wxLua,而宿主程序也用了wxWidgets,两个之间可以无阻碍地互相使用各种控件,今天才发现,当时太想当然了。我用SWIG封装了宿主程序中的一些代码,比如wxFrame,在wxLua中是不认识这种封装的,两种不是相同的类型。所以现在只能精心挑选一组必需的,常用的代码来用SWIG封装,现在让它生成的包括scintilla和scilexer以及wxcintilla的声明后,生成的文件有近30000行,编译要花不少时间。说起来,我应该再仔细研究一下SWIG的用法先。 这两天用wxWidgets,有时候感觉它比MFC、VCL要灵活,比WTL要易懂。这也许很偏面。不过我最不满的是它的资料太少,以及运行效率不高。
这两天又用wxWidgets,不得不感叹一下,资料实在太少了,只有一个现成的manual,其他时候就只有看看CodeLite、Code::Blocks的源代码了! 到今天为止,修改了脚本扩展的功能,可以在一个描述文件中定义多个扩展的信息。对于主菜单来说,倒是勉强够用了,不过当时因为想让描述文件中对扩展的描述尽量通用,将其他的信息都写到脚本里去了,现在看来如果要对工具栏也使用脚本扩展,那么这种方式实在太不方便了点,还是应该把这种静态配置信息的都放在xml格式的描述文件中,脚本中应该只有动态的逻辑。所以还需要修改。 今天又忘了,wxWidgets的程序如果使用Lua扩展,而扩展又装载wxLua的话,wxLua的二进制文件不能用和wxWidgets程序相同的wxWidgets二进制动态链接库,不然会出现各种奇怪的问题。这是让我目前比较头痛的问题。我现在是用MinGW来编译wxWidgets和相关工程,那么一来wxLua就只能用VC或其他编译器编译了,但我今天试了OpenWatcom和Borland C++ 5.5,连wxWidgets都编译不过,郁闷!
这两天在公司里,做那个插件架构,到昨天为止,大概实现了一半了,不过总觉得不对劲。这是一个没有经过实践检验的方案,看了那些已经完成的代码,再联想一下完全完成后的可能的模样,心里老是有点不爽,担心内存占用会不会太大了。 现在这个设计是在原来的基础上修改来的,主要的修改是在一个插件中可以定义多个扩展,插件只是扩展的容器,扩展才是真正实现可扩展性的设施。于是相比原来的设计,现在有了两种独立的对象,插件和扩展,而原来一个插件中只定义一个扩展,在代码实现时可以只定义一种对象。于是现在这种情况下,对现实世界的描述,大约会多出近一倍的信息量吧,这些信息如果全部保存到内存中,预计消耗会很大。本来这些信息是通过配置文件描述的,如果不全保存到内存中,就要能实时解析配置文件,这对运行速度也是一个考验,而且能否快速方便地检索到需要的配置文件目前也是个未知数。 崩溃!
因为要使得插件支持依赖,比如在插件描述中说明,某个插件A,依赖于插件B和插件C,而插件C又依赖于插件D,那么在装载插件A之前,需要先装载插件D,再装载插件B和插件C,最后才是插件A。 这个依赖关于跟C/C++程序代码中的头文件包含处理方式几乎一模一样,典型的做法就是把这所有的依赖关系最终用一张有向图表示,这样通过DFS可以查找到是否有循环依赖,如果有,可以彻底中断装载过程,或者只是简单地把最后一个回边打断而继续装载。 最终整理出来的插件装载顺序也是很容易的。首先查找没有依赖于任何其他插件的插件,无论是理论上还是实际上,肯定是有这种插件存在的。找到这些插件后,把对这些插件的依赖关系都删掉,这样肯定又多出一些插件是已经解决依赖关系的。再把这些多出来的插件作为被依赖的关系删掉,重复前面一步操作,最终可以将所有插件都顺利装载。
真的。 现在一个Lua解释器的封装类,一个插件注册表类,这样的结构是不够用的。至少需要有一个管理插件运行的模块,它可以屏蔽掉解释器的底层差异,使得使用这个模块的用户不用知道他们到底是在运行Lua脚本还是其他Ruby或是Python之类的东西。另外一点是这模块需要向不单是C++代码提供接口。也就是说,用脚本写成的插件需要使用这个接口。这个需求很合理,也很必要,不然的话,很明显的一大限制是不能再对插件进行扩展了。
因为怀疑,所以去确认了一把。自己也懒得编译了,直接从网上找了个人家编译好的wxLua,人家是用VC8编译的,我的工程是用MinGW编译的,结果真的可以加载了,我狂晕!不管了,大不了到时候提供个Lua for Windows的安装包链接。 再回来说插件的问题。昨天主菜单是能运行起来了,不过发现有个不爽的地方。因为插件是放在一个指定目录下的,搜索出来的顺序可不是人能控制的,于是添加到菜单上的顺序也是乱的,这就不好了。由此引出另一个需求,对于一个插件应该可以定义多个菜单项,这样至少可以让这一个插件中的菜单项保持可控的顺序。
想起插件的事,如果一个软件具备插件扩展能力,同时又希望其用户自行开发插件,那么这个软件一般说来需要提供一个良好的插件开发环境。纵观Eclipse,MSVS、MS Office等都是这样的,而且VS和Office中的扩展形式除了插件,还有宏,准确地说来,是开发宏的环境是随软件一起提供的,而插件的开发是要用其他工具的,比如VS。而我前面说的插件开发环境,其实对应的是宏开发环境。 这个开发环境简单的做法,应该是一个独立的程序,但与软件主程序之间有很深入的进程间通信,不然调试功能是不可能那么完善的。也有可能是还有一个中间的宏解释执行器,主程序和宏开发环境都是只与宏解释执行器进行通信,同时该解释执行器也有调试功能。这样做的一个明显的理由是,当调试宏时,主程序可能会被挂起,而这时调试界面则要求是活动的,所以放在主程序中是不容易处理的。 Eclipse可能不需要这么做,它也许可以在不同的实例中使用不同的配置,这样可以在一个实例中调试另一个实例。 还有一种比较极端或者不负责任的做法是,不提供开发环境,让插件开发者痛苦去吧。也许用比较高级的脚本语言来做为扩展架构的底层执行器,这个问题的影响会变小,因为脚本语言对调试的需求可能会小于像C++这种编译型语言。但我觉得无论怎么样,提供一点基本的用于调试的设施还是必要的,比如至少可以加入一种打印输出机制之类的。
首先,这个架构是一定程度上模仿Eclipse的,并做了大量简化,所以模仿得并不像,不过不得不说最原始的灵感和很多想法是从它那里来的。 支撑起整个可扩展架构是一个类,大概名叫pluginsRegistry的类。这个类一般可以使用singleton模式,它做一些与插件相关的最基础最底层的事。比如,在宿主程序(这里一般是一个C++程序)启动时,它负责扫描指定的一个目录(包括子目录)下所有文件,找出其中的plugin.xml文件,也就是插件描述文件。它并不一定要是xml来描述,也可以是用Lua来描述,毕竟Lua最早的用途就是作为配置文件的,而且这个文件并不会被程序动态修改,Lua也够用,但要注意的是名字空间污染的问题,一个办法是每个描述文件都使用完全相同的结构和变量命名,但每次都单独启动一个Lua解释器来解析。一般说来一个描述文件中声明一个插件,也就是一些基本的插件信息,包括插件id、插件扩展点和插件对应脚本文件路径这三项最主要的不可或缺的信息,以及一些诸如被扩展点,版本号,依赖关系,版权信息等等不那么重要的信息。扫描到一个插件后,这个类会把插件id,脚本文件路径对应着保存起来,并把该插件添加到指定的被扩展点上。所谓扩展点,其实准确一点说,应该是被扩展点代表一个插件会被激活(其中一部分)的时机。被扩展点一般也是由其他插件提供的,也就是说其他插件会在某个它认为合适的时刻,激活所有注册到被扩展点下的所有插件。所以插件描述文件中很重要的一点是,需要声明自己是扩展了哪个被扩展点,不然就永远不可能被激活。由此可以看出,另外一个需要注意的是,一个插件一般会依赖于另外一些插件,至少是依赖于提供它要扩展的被扩展点的插件。一个插件必须要指明它要扩展的被扩展点,这是别的插件提供的,另外它也可以提供自己的被扩展点,让另外的插件来扩展自己的功能,当然这不是必须的。为了说起来不那么拗口,在描述文件中,一般我称前者为扩展点,称后者为被扩展点,这是把同一类事物在一个所属中以其不同的功能或角色来区别而得来的。再回到这个类的功能上来,除了前面讲的这几点功能外,它还应该能向外界提供一个服务,通过该服务外界可以根据指定的被扩展点查询到所有注册在该被扩展点下的插件,理论是希望只是通过一个id就能唯一标识一个插件。这样每当时机合适时,提供被扩展点的插件就可以通过这个服务来做一些事情,最常见的是通知所有该被扩展点下的插件即可,那些插件自己应该清楚这时应该做些什么事情,还有种情况是,提供被扩展点的插件应该可以从中区分出一些插件,而不是全部,来通知。一个很常见的应用场景,主菜单,可以是一个菜单项对应一个插件,这时每当用户点击了菜单项,那么只要激活该菜单项对应的那个插件即可,而不是所有主菜单下所有的插件都要激活一遍。 通过前面的阐述,可以知道,这个类需要一个清晰简单的接口,这样才可以比较方便地既给C++代码提供服务,又给Lua脚本提供服务。尽管Lua从设计上就考虑了很多跟其他语言交互的情形,但这里我还是得小心一点,少使用一些只有某种语言特有的一些元素或特性。 最后,以一个实例来简单叙述一下这个架构是怎么真正让一些功能运作起来的。就还是以主菜单为例,主菜单也是一个插件,当然,它是用C++还是用Lua实现的我们不关心。重要的是主菜单插件首先有一个自己的id,并提供了一个被扩展点,假设叫view.ui.menu,这时假设那个类已经把所有扫描到的插件正确地分析过了,这个被扩展点下已经有一些插件了,比如file_open,file_save等等。主菜单插件在自己被初始化时,调用那个类来得到所有view.ui.menu下的插件,并依次激活这些插件的get_caption方法,根据这些个方法返回的内容,作为菜单项的标题,逐个添加菜单项,并把菜单项的id和它对应的插件(可能就是用插件id来表示)保存起来,当用户点击一个菜单项时,主菜单插件可以得知用户点击的菜单项的id,并从之前保存的信息中得到它对应的插件id,以此来再调用那个类来激活唯一对应的那个插件,那个插件知道用户是点击了菜单点,就执行一些操作,比如打开文件等等。 大致的流程就是这样。
重构auto completion和call tips模块,因为总体设计都被改得天翻地覆,而且决定开始使用TDD的方式进行,所以进度相对来说慢了些,更因为我自己一直静不下心来好好干活,真是令人烦恼啊! 话说其他一些相对可独立分类的小特性大部分已被我清理出来,但剩下还有一些杂七杂八的功能,我却不想再动了,因为从很早的时候就考虑好了这部分功能不应该由C++代码完成,而应该由host提供的扩展机制使用外部extension实现。但是现在的情况看来,这扩展机制短期内是不会加入的,因为老大似乎不支持这样的做法。另外一点是,组内大概除了我,也再没有其他人有足够深厚的兴趣和迫切的需求实现这么一个框架。 最早虽然想到了要用扩展,但并没有考虑很多,只是觉得只要能用内部嵌入的那个Ruby解释器执行一段脚本,而那个解释器同时也能访问到内部的一些数据结构和算法,应该就能处理目前的需求了。当时预见得到的需求也确实简单,比如点击一个菜单项,在当前光标位置插入一个字符串,该字符串可能是当前日期或时间等等。我当时想法相当单纯,甚至想的是菜单项还是依旧在资源管理器中画好,消息映射也还是添加好,最后实现的时候再调用Ruby解释器解释一个外部的脚本文件就可以了。即使这样简单,也比纯粹使用C++实现有一定的优势,至少如果需要修改实现逻辑,就只需要修改那个脚本文件,不再需要修改C++代码,不需要重新编译。 但是自从前几天快速翻看了一遍《Contributing to Eclipse》之后,我就想,要做就做得灵活点,也许不要求完全跟Eclipse一样那么强大有弹性,但也至少要满足以下几个要求:1、在主菜单、弹出式菜单、工具栏(、状态栏)上都可以扩展;2、在扩展之上还可以预留扩展点继续扩展;3、既然用脚本扩展,那么扩展加载应该也像Eclipse那样“懒加载”;4、需要有一种打包策略,足以支持起复杂的多文件的扩展。 暂时就只想到这些,嗯!重构完auto completion和call tips,就悄悄做这个。
下午去向人讨教了一下人家怎么设计实现Plugins机制的。据该人士讲述,当时他们的产品2.x版本面对各种千奇百怪的用户需求,以及进度压力(这与我们目前遭遇到的情况类似),经过研究COM相关技术和Eclipse(估计当时也是2.x版本)的Plugins机制,最后在3.0版本实现了目前(也是3.x吧)的Plugins机制。 首先,该软件产品一般的插件都是通过vbs脚本实现,他们内嵌了vbs脚本解释器,使用的当然是最流行最正规的IActiveScript之道。可以扩展的地方包括主菜单、工具栏、弹出式菜单、状态栏等。像Eclipse及其他很多软件一样,基本的界面元素是用XML描述的,以弹出式菜单为例,在XML中首先会定义视图之类的信息,而弹出式菜单是作为视图信息的子节点出现的,说明这个弹出式菜单是在视图上点击右键才会弹出。这里好像是XML里就直接指定了菜单项的ID,对应Windows程序里的命令ID,而ID范围是程序中已固化规定好的,不能超出这个范围。然后指定一个脚本文件,可能还会具体到其中某个函数,每当菜单项触发时,便调用这段脚本。可能还会有触发前、触发后的选项,可以继续使用自定义脚本扩展实现。另外,菜单项有一个状态,如disabled、checked等等,这是在另外一个属性中设置的,该属性同样是指定一个脚本文件或函数,刚好对应MFC中的ON_UPDATE_COMMAND_UI。还有一点是,菜单可能是针对某种具体的选中项才有项的,所以在XML中描述菜单时,可能会包含一个属性,用于指定对其有效的选中项类型,只有在该类型的界面元素被选中并在上面点击鼠标右键时,才会弹出这个菜单。再有就是菜单等界面元素不可避免的一个问题是国际化,他们是把各种语言对应的字符串信息分别写到不同的配置文件中,描述菜单信息的XML里通过指定个别名或ID来动态查找装入相应的字符串。如果激活扩展插件函数时,需要一些固有信息,而是通过规定的格式书写函数参数。 其次,除了支持脚本扩展,该软件还支持COM组件形式的Plugins,这种Plugins相比脚本Plugins肯定强大得多,也许就好比Firefox中的Plugins之于Extensions,不过在介绍时他们一带而过,似乎也不是很支持第三方的去使用这种机制。 最后说一点,为了实现能让vbs脚本访问host程序中的一些信息或方法,他们把所有的东西都用COM接口还实现。似乎这是目前而言,我们能找到的最简单的一种处理方式,所有的状态、中间数据信息都可以保存在host程序中,脚本应该只是描述逻辑,而不保存状态。但这也是我最不屑的,我还是比较欣赏Eclipse(3.0以后用OSGi的不知道有多少变化)的机制,希望我有机会能设计并把它实现!
这两天在想一些问题,怎样构建一个有足够扩展性和通用性的框架呢? 对Scintilla的使用有了一点经验后,就想好好利用它来做几个有点实用价值的东东,关键就在于想做的不止一个,但在文本编辑方面由于都是使用Scintilla,所以肯定会想到如果能让代码写得足够通用,所有工程都共享一个代码实现就好了,以后即便有了修改,只要修改一次,其他的最大程度上只要重新编译链接一下就可以了,不用再修改源代码。但这样的通用性要如何实现呢,组件化是一种常见的解决方案,这里Scintilla已经是一个现成成熟的组件,但它只是提供了最基本的能力,如果要把这些能力展现出来,还是自己写代码实现。 有鉴于Impeller项目越来越冗长庞杂的实现,我心里很是不舒服。它确实有那么多事要做,也许有些事不是它的责任,但那也只是极小一部分,但把所有事的实现都放在工程中用C++完成,我就觉得有待商榷了。比如有很经典的一段代码,用于在用户动作触发时,在当前光标所在位置插入日期和时间,这样微不足道的功能,花了好几十行C++代码。其实在大半年前,我还在维护编辑器模块时,我就想通过脚本来支持这些简单功能了,但后来因为这样那样的原因最终没有实现。这只是一个简单的例子,照我的想法,最理想的方案是程序从配置文件中读出相关扩展信息,根据配置在主菜单、工具栏、弹出菜单等用户最习惯的界面上添加可触发控制,当用户触发了这些控制时,程序从配置中读出需要执行的动作,可能是一段脚本,或一个脚本文件,或一个DLL导出函数,甚至是一个COM组件中的一个接口中的方法,总之在被触发前这些东西可是是实际不存在的,也即Eclipse提倡的懒加载规则。这里有几个实现上的难点,如何通过配置文件就动态地实现配置的用户界面;如何通过用户动作立即找到正确的执行动作;如何让主程序和扩展进行交互。一般说来主程序需要提供一些方法供扩展进行调用控制主程序的行为,于是有相应的问题是主程序通过什么方式暴露这些方法,又需要暴露哪些方法。如果这些问题都能解决了,还有另外一个问题,不同的扩展之间是否可以交互,它们的协议应该怎么设计。 总之在动手做那几个东东前,这扩展性和通用性的问题必须要有一个可靠可行的方案,不解以后自己得累死。
其实静下心来想想,这也是正常的,这样匆匆忙忙赶出来的东西,质量能好到哪里去,而且事实上不但稳定性差,易用性也是极差。照我自己的估计,再给两个月,才能基本到可用的程度,即稳定性和易用性都为大多数普通用户接受的程度。 心里好烦啊! 中午在菠菜里吃出一条虫子,我都怀疑我有没有吃下去更多条,晕!拿去换了10块钱和1盘西瓜,然后去买卡士喝了。疯丫头也吃出一个小蚊蚊,这是以前某人常用的叫法,然后也是换了10块钱和1盘西瓜。 唉,我终究是很普通一人,有时候确实太高估自己了。 asio用了这么些天,还是没掌握具体用法,用来用去还是问题一堆。 COM也是很烦人一东西,无奈的是有些时候不得不用COM啊,再加上组里最有话语权决策权的几人,都是COM的忠实粉丝拥趸,郁闷。也不知道是不是我自己太高傲了,总是要跟别人唱反调。但总是觉得人家确实也没多少让我佩服的地方,唉。 对于一牛x的编辑器,以UltraEdit为榜样来说,要直接支持脚本扩展,可以通过方便地激活一外部脚本,来操作编辑器,比如移动光标,输入字符,查找替换,复制粘贴,删除撤消等等,这是一类最基本最通用的扩展方式,可以有任意数量的脚本。另外一类方式是,可以配置宿主程序的界面,比如增加菜单项,增加工具栏按钮,而且这些菜单项和按钮的位置、文字、图标等内容是可以定制的,当然点击后,就会触发一个脚本的运行,这种脚本也可以有任意数量,任意配置。还有一类方式,是事件处理脚本,当宿主程序遇到某一事件时,就会执行相应的脚本,比如打开一个文件时,文件关闭时等等,理论这类脚本也可以有任意多个,但实际上不能太多,因为如果某事件触发时,结果要分别运行一堆脚本,这种性能问题应该会比较明显,并可能让用户受不了。暂时想到的是这3类脚本扩展支持,最近又因为对多种脚本语言的简单接触,又没有哪种让我觉得特别喜欢,所以我反而想要能同时支持多种脚本语言的扩展。这时,SWIG出场的机会来了,至少Python、Ruby、Lua、TCL都是被它支持的。 除了可以用脚本扩展外,是否还要提供2进制扩展接口,这点我还不太确定,2进制扩展可以有普通DLL和COM两种方式,差别不大,只是怀疑其必要性,它有多少价值,多少能力,有多少情况下需要它出场解决问题。 最后一点是,正则引擎需要能挂接,随时任意替换吗,UltraEdit是这样做的。
心血来潮,又去Songbird的网站看了一下,还把编译好的Preview的安装程序,以及SVN里的源代码都下下来了。只可惜看了半天的编译说明,还是没看懂,唉,这个说明也太烦琐了,条理都不清晰。这样看来,Mozilla的XUL解决方案怎么推广得了哦,想想Adobe、MS这些大厂商的解决方案,一整套完整的流程支持,各个环节都可能会有比较完善的工具支持,而且安装部署都会很容易,一张光盘,一个ISO镜像,一个setup.exe文件就搞定所有的事,一切都准备好给人使用,有多少比例的人愿意去花那么些时间搞那么麻烦的mozilla的东西。Mozilla社区确实应该好好想想,反思一下,为什么XUL技术出来这么多年,Mozilla里也用了那么久,却一直没有被大众接受,直到现在这些大厂商出来推,才火起来。也许从技术的角度讲,各个解决方案间没有特别大的区别或差距,但是易用性、友好性方面呢,可能差得太多了。其实这也是众多开源项目的通病啊,孤芳自赏的hacker想法是走不出hacker圈子的。 装上Songbird,听了几首MP3,就把它卸载了,现在的条件用XUL技术来实现这样的桌面应用时候还早了点,连一个窗口里点菜单,点右键,来回换输入焦点都会卡好几秒钟,有几个人受得了,换回foobar2000,看起来轻巧多了。所说Firefox3.0也是基于XulRunner来实现的了,就像Songbird一样,进程管理器里可能就看不到firefox.exe了,而是一个XulRunner.exe。这样就像Java之类的了,虚拟机实现的东西,除非是开发效率或其它有什么特别突出的优点,不然是不会被大众接受的。 Mozilla能有那样好的扩展能力,其实从某方面讲,跟Eclipse、Emacs等是一个原因,那就是脚本语言和本地代码的结合。它用XUL描述界面,用C/C++实现真正的逻辑,再用JavaScript把两者结合起来。这样看来,只要能把描述界面的部分规范下来,真正的核心逻辑用C/C++实现,再设计一个良好的两者互动通信机制,那么一个弹性极佳的系统也就设计出来了!LLYF Spy中,是应该好好设计一下了,2.0可以只做预研性的设计和实现,3.0可以考虑实现成一个程序员工具平台了,只要扩展机制实现得好,可以给它添加各种扩展功能,比如编辑器,比如听MP3,比如下载上传……
昨天偶然想到,IceSword使用的协件机制是一种处理主程序与其它相关性不大的功能之间关系的不错的方法。虽然想到了这点,但并没有马上去看它是怎么实现的,于是自己躺在床上一边嗑瓜子一边想,想了一会儿大概有了个轮廓。今天起来看了下IceSword,发现基本上我想的也差不多就这样了。它有一个C的头文件,提供接口声明,一个DLL提供进程间通信。而我当时想到的是需要一个LIB,可以静态链接进协件。如果有很多接口需要暴露的话,用DLL会好一点,这样相比LIB,能减小每个协件的文件大小。另外唯一剩下需要考虑的是,采用怎样一个良好的进程间通信机制,要快速稳定,同时又不能太消耗系统资源。 插件以前我只用过DLL形式的,其实似乎COM是很不错的一种选择,只不过我一直对COM没研究,看过一些文章,也还是没搞明白怎么用COM实现插件机制。了解过Eclipse和Emacs等弹性非常好的架构后,隐约觉得用脚本来实现插件也是一种极好的方法。重新修葺一遍代码,整理好功能接口,就可以为多种脚本提供支持了。不过还有一点需要注意的是,用脚本实现的插件,对界面的操作大概都需要主程序来支持了,比如显示一条消息,选择一个文件等。另外还有一点需要提到的是,如果主程序需要暴露很多接口给脚本插件,或者同时需要能支持多种脚本语言的话,使用SWIG是个不错的选择。
一直觉得Eclipse的插件架构很牛x,有时候自己写个小程序都想着怎么实现一个灵活的可扩展的架构,可是却不太容易,毕竟我软件工程方面的经验还是几乎为0。在网上闲逛看别人的blog时,偶然发现一个Dissect Eclipse Plugins Framework,对Eclipse的插件架构做了一定的描述,还自己用简单的实例来Dessect了一把,就像jjhou的Dissect MFC一样。对于自己要实现一个类似的,灵活的插件框架,无疑是很有帮助的,但是同样作者也是用Java来实现的,一定程度上讲,这种框架依赖了Java语言特有的语言特性,如果换成其它语言来实现,比如C/C++,或许还有其它的障碍,但总的说来,思想已经摆在那里了,Eclipse的那帮设计者真的天才!《Contribute To Eclipse》这书也写得挺好的,毕竟是两位实战和著作都颇有经验的大师合力的精心之作,中文版的翻译也挺不错的。 装了个Windows Live Writer,IE6也能标签(tab)浏览了,不过似乎有点问题,还是我自己没找到在哪里设置,每次新开窗口都是另外一个窗口,而不是一个标签,另外就是在标签间切换,有点闪。本来说起来像Maxthon这样的东西,我一直都只是因为它比IE多了个tab才用它,不过自从Firefox的易用性达到我的需求后,就再也不用了这些了,对于IE only的那些网页,还有IE Tab这样的插件呢!
Category lookfor
1月21日下午3点半就从公司走人了,到柯桥、绍兴路段堵了一会儿。
除夕,小丫头给我发短信说最近遭遇了很多很多不幸,跟做梦似的。她爸爸过世了,给人家干活时从屋顶摔下来。她自己流产了。我不知道自己可以做些什么。橙子在Facebook上说,还是放不下吗。我说,我想关心她,却没了以前的那种男女之情,倒有点像亲情。
春节的行程比较充实,初一中午在家接待干妈一家,晚上去干妈家。初二去大姨家。初三在家休整。初四接待大姨小姨,下午还去上坟。初五晚上去小姨家。初六,就是今天,到上海。
木有宽带的日子,真不习惯啦!
无意中偶尔看到的。你一定要幸福啊。居然只说“热死人了”,唔……
昨天晚上,近12点,锁好门,准备熄灯上床,却听到手机的短信铃声响起。当时我就猜,在这么个时间,说不定是那小丫头发的,不,应该是我很肯定,一定是那小丫头发的。拿起一看,果然是小丫头,那个我曾经叫她宝宝,后来一直称呼为小乖的女人。短信的内容倒比较意外,说自己头好痛,眼睛也好痛,要爆了,却又睡不着。于是我便拨回去。 两个人断断续续,说着从我毕业工作以来的两个人之间的几乎每一件事情。睡在同一个屋子里,一起逛街,一起去欢乐谷玩,给她买眼霜和书,帮她买数码相机和笔记本,她大队培训期间出去玩让我在家里着急,买了里芯已经烂了的苹果给她……她问我她要结婚了我祝不祝福她。我短暂地沉默后,回答当然祝福了。然后她就在电话那头哭起来,我问她为什么哭,是不是他对她不好。她说没什么,他对她很好很好。还说她最对不起的人就是我,我说我没有怪你,是我自己给你这个机会让你对不起我的。而且就算真的很喜欢很喜欢一个人,也不是一定要生活在一起的。以前听小思宇说起过,陈奕讯在一个访谈节目中说的,他都已经有小孩的人了,到现在心中还是一直放不下一个人,惦记着一个人。我也可以。 我给她说起我妈妈,那是一个眼光很挑剔的中年妇女,我把众多女同事,女同学的照片拿回家给她看,基本上都是挑缺点的。小丫头就说,是不是她的脸那么圆,我妈妈也是不喜欢的。我解释说,你那种圆脸,我妈妈是很喜欢的,还说了脸圆圆的,屁股也圆圆的,这样的女孩子才好。小丫头说,那她最终也没能成为我妈妈的儿媳妇。我说,那是我妈的儿子没本事,没福气。说到很少见小丫头哭,其中的一次,是那年雪灾,到了机场没车回家,给我发短信,在机场一个人哭,我正在家里吃饭,我妈问我在跟谁发短信,我说了后,我妈还叫我回短信让小丫头不要哭了,不然不漂亮了,而我却说小丫头脸圆圆的,哭起来的样子很可爱的。 还说到,我曾经在她的照片袋里看到她和一个男生的大头贴,我心好酸好痛,当时怎么那么老实,没有趁上街的机会拉她一起去拍大头贴。她说,那个男生是yaya以前的男朋友,居然让人误会了,哈哈,印象中好像也只有这么一个男生一起拍过大头贴。后来她又说到,当时我千方百计把她介绍进公司,本来是希望能离得近一点的,想不到一下就被派到成都去了,是不是当时后悔得要死。我说,后悔倒没有,就是很痛恨这个命运,想不到在命运的面前真的一点能力都没有。真的,我不但痛恨这个命运,还痛恨着这个公司,就是它把小丫头弄到离我那么远的地方去了,便宜了以后可能成为她老公的那个小子。我问小丫头,如果她还是一直呆在深圳的话,我应该还是有机会的吧。小丫头轻轻笑笑。 小丫头说,很怀念以前在深圳的日子。呃,她只在深圳呆了不到半年。我说我也是,我很怀念她在深圳的日子。 几乎把我觉得最幸福的事情都回忆了一遍,最后我说,以后不要哭了,你哭我也会难过的,你已经不和我一起生活了,那就要在其他方面有所补偿,你担负着让我们两个人都快乐的责任。
今天去关内给小丫头迁档案和户口,早上睡到8点多,很不情愿地起床,不过也比平时上班时晚了一个多小时了,昨晚睡得也不晚啊,怎么会那么困呢。洗漱完毕出门,已经过了8点半了,等328路,结果一直等到9点才勉强挤上一辆。 到了那公司,还不到10点,这出乎我原来的预料,心里顿时放松了一点。那么一个小公司,里面有个女人招呼我过去,我拿出迁户申请和商调函。被告知那些个人资料是要填好的,于是又打电话问小丫头那些东西怎么填。接着又被告知要交档案保管费,每月20元,从2007年2月交到2008年9月,还好不是很多,但我还是忘了拿钱上去,跑到楼下的招行ATM机上取了钱上去,结果那儿的财务部说他们不收现金的,但是大概看在我已经拿了几张红纸片的份上,乱糟糟地不知道从哪里找出一本开收据的本。最先招呼我的女人把档案都装入一个档案袋,贴上纸,盖了十几下章,然后找出小丫头的户口卡交给我,第一站的任务就基本完成了。 随后是要去高新派出所办迁入户口,因为不知道坐什么车,所以一下楼就打了个的。也不知道是不是绕路了,比我想像的要久。而且想不到那派出所在那么一个偏僻的地方,不过好在一进门就看到办理的地方,取号排队,开始还取错号了,大概一直排了半个小时的样子吧,才轮到我,那办理的大姐一看就说出我们公司的名字,看来我们公司在那儿的业务很多啊。没几分钟就办完了,时间都耗在坐车和排队上了。 出了派出所,看到路对面就是一个公交车始发站,看来只有转车了。这车也是绕路的,绕了好久,到了市民中心,本来想坐个391回公司的,结果等了10几分钟也没等到,失去了耐心,决定再次转车,先坐到梅林关,再爬上一个小巴,1点半差3分的时候终于赶回公司刷卡,这样就只需要报上午半天的假了。 坐下吃了块巧克力,因为早饭和中饭都没吃,饿啊!然后给小妞打电话,问她有没有吃的,她说有小面包。于是我先跑到人事服务中心,把户口卡和档案交回去,结果那管档案的mm说还缺转正定级表,我郁闷,这党员还真麻烦啊!指不准还得跑一趟关内,累啊,要是自己有车就好了!
早上接到小丫头托人带来的身份证,马上打开ppt看了看各个步骤,还是不明所以,直接就跑去人事服务中心找人。等车等了10几分钟,开过了五六辆,全是满员的。先问开具迁档案时要用的《商调函》什么的,结果问我档案现在什么地方,我一听就愣了,当时我问小丫头时,她自己都不知道在什么地方。然后去开迁户口的申请,结果那mm说要证明,这也是情理之中的事,不过小丫头给我的那个ppt里留的两个联系人明显不对嘛! 两边都办不成事,只好给小丫头打个电话先,让她马上发个邮件证明一下,又顺便扯皮了几句。开好迁户申请,打道回府,离回来快1个小时了,这办事效率也太低了点,瀑布汗~
要说起咖啡,我第一反应就会想到那特别喜欢咖啡的小妞,上半年时她以前的BF送了套煮咖啡的用具后,她遇到熟人就会叫去她的小屋里品尝一下她自己磨好煮好的咖啡,呵呵。 昨天跟小丫头打电话时,她说起要去开个咖啡店,还要自己会煮一种独特口味的咖啡,呵呵,挺小孩子气的语气说的。只是我确实也曾经多想去过这样宁静的生活的,以前还说要回乡下去养一群小鸡小鸭的,已经好久都没想过这个事了,渐渐地迷失在这个匆忙的生活节奏中了。 今天下午去中心书城逛了一圈,把几本稍微厚点的咖啡有关的书都买来了,也许这又只是一次心血来潮,呵呵。
今天去加班了,难得哦,突然一下子变得很忙,这星期连续三天晚上加班,对我来说几乎是难以想像的啊。加班回来就先给妈妈打电话,然后给阿姨发短信。 给小丫头打电话,没人接,于是放下,看网页。过了一会儿小丫头发短信来说,9点以后她就接听免费了。于是安安份份地等到9点,再给小丫头打。这次小丫头似乎心情不错呢,还好像比以前会搞笑了,真是有点意外,倒是换过来我唉声叹气了好几次。记得刚来公司的那一年,经常心情不好的时候就会给小丫头打电话,那时她还在学校里,而且几乎每次她都是很固定的活动,也是我们学校的人最平常的活动,上BBS、看碟、打游戏,以前我在学校的时候也是这么过的,所以总是给我一种很怀念的感觉。以前每次跟小丫头打电话都会把糟糕的心情变好,真的很奇怪,现在却好像不行了,可能是跟我的心态有关系吧,现在的心态跟以前不一样了。 所以,人千万不能随便动感情啊,不然像陷入了泥潭,难以自拔啊!
贫穷的人只能以贫穷的方式向自己在意的人祝福。 昨天忙乎了半个晚上,想今天给小丫头一个小小的惊喜,结果今天发现昨晚最后打包成安装程序的时候还是出了问题,枉费了我画了好一会儿的splash了。 不过大部分主要的功能还都是按照预期实现了,呵呵。 小丫头生日快乐哦!
就在出门前的半分钟,一条短信把行程改变了。 小丫头说,做女人好辛苦啊。我说,做女人长好看点,就有好多人追。小丫头说,没人追。我说,76GG啊,还有莫名其妙打电话来的啊。 做女人真的很辛苦啊,幸好我不是……
在上网的时候,小丫头突然打电话来,出乎意料地。然后两个人聊了大半个小时,照小丫头的说法,都从公司里聊到家里了。还是照原来一样,小丫头在那里抱怨了一通,呵呵。五一要不要去成都呢,犹豫ing…… 写程序总是遇到些奇怪的问题。这两天在研究直接用PSDK写一个能支持在2个TreeView中进行节点拖放的窗口,昨天还一直很奇怪的,只有一个 TreeView能作为拖放的宿,另一个则怎么也不行,但两个TreeView的代码明显是相同的,因为都是从同一个类中的方法啊!今天给窗口加了个拆分 条,可以让鼠标拖动TreeView之间的拆分条来调整两个TreeView的大小,结果稀里糊涂的居然发现两个TreeView都能作为拖放的宿了,真 是奇怪呀,明明我一点都没改动TreeView的代码啊! 从别人那里要来了一个通过COM接口跟GT3K交互的Demo,这个Demo是在Excel中用VBA写的,不知道如果在VC中用,还有多少困难,看来得学一下COM的知识了,比较麻烦呀! 另外一边的人打电话来说,要讨论一下单板软件的相关计划等,呵呵,要做嵌入式开发去了,这让我觉得有点兴奋,因为从来没有接触过这方面的东西,只是别人写的代码倒是看过不少,虽然也从来不看代码流程,只是为了PI值发现些很低级的语法错误。 SharePoint总算第一次被我调得可以显示一点东西出来了,不过还没有研究怎么使用,因为那台老爷机实在太慢了,我无法忍受在这样蜗牛的速度中 进行操作学习。SharePoint的资料是少了点,没办法的时候,只能跟别人交流交流了。而且,才发现目前只要装Windows SharePoint Service 3.0就够用了,不用装Server了,哈哈。 把输入法的界面改了一下,Comp窗口和Cand窗口合在一起了,就像现在流行的输入法一样,不再是传统界面啦,这有一个好处——可以方便地让它支持 Skin,或者不规格窗口。不过老问题还是存在:Firefox中还是出不来。而且一直想把设置窗口改成用PropertySheet样式,但总是要么不 出来,要么弄死机,郁闷,只好暂时就要原来的了。还有个问题,也是这两天才遇到的,在用UNICODE编译的时候,为什么stprintf总是得到乱码?
想起要写些关于Boost源代码的东西,要把代码贴到blog上来,不免想要弄稍微好看点,虽然有个Boost中自带的演示Boost::regex的cpp2html工具,不过觉得太单调了点。上Google搜索了一下,还是能搜索不少来,其中一个放在GNU上的source-highlight引起了我的注意,这是一个由Lorenzo Bettini编写的命令行程序,能支持好多种语言的源代码输入,同时又支持包括Html、XML、LaTeX、DocBook等格式的输出。看到最新版本已经是2.6了,不过作者已经不屑于发布Windows下的可执行文件了,只好去sf.net的GnuWin32工程里找了一个2.1.2版本用用。这个小程序做得挺灵活的,作为输入的源文件规则和作为输出的目标格式都是通过外部的配置文件来说明的,这样如果要添加支持新的语言,只要添加新的配置文件就可以了,不需要修改重新编译程序。这是个很棒的小程序! 小丫头现在都知道怎么骗我了哦,真让我感动得想哭,突然觉得这种感觉就像《Hunter X Hunter》里奇犽的哥哥说他妈妈哭了,因为奇犽现在都会砍她了,她好感动的。
有时候不禁要感叹,男人和女人对于同样的事情,平常的事情,怎么会产生那么大的意见分歧。下午的时候,小丫头给我发邮件,说ClearCase的命令不知道怎么用,我看了一下,觉得这些命令望文生意都能猜出大概的作用来,于是很直接地说,我觉得是因为你懒。没想到小丫头火冒三丈,说再也不理我了,还说为了这句话哭了。把我郁闷坏了,咋就为这么句话搞得这么严重呢。以前怎么说她,她都是不会生气的呀,都是懒洋洋或乐呵呵的样子,今天怎么就会哭了。心里必然不好受,坐在那里又觉得度日如年,于是只好出去逛一圈。回来还是郁闷,看看时间,还没过多久啊。于是试探性地又发了封邮件给她,语气自然是很诚恳的。还好看到她的邮件中说话已经略带娇嗔了,才舒了口气。呵呵,我竟然这样把小丫头弄哭了。 说实话,我当时还真的很怕她真的再也不理我了,我甚至把我能想到的最坏的结果的情景在脑海中都演了一遍,不过好在小丫头的本性是个温柔又随和的人。 晚上回到家,小丫头还在公司,于是打电话给她,一直打了一个半小时。从大年三十那天以来,我们一直没通过电话,因为在公司里可以用notes,同时在外面可以发短信。聊了很多,小丫头在那里不知道受了多少委屈,唉,可怜的孩子。 今天终于换了项目部了,不过似乎接下来的事我会做得比较郁闷哦!
我感到很难过。上班的时候我打电话过去,她说都是被我害的。虽然有点开玩笑的成分,但这个也是空穴来风啊!下班后还突然发个短信来说其实没这么严重,只是没事了发下牢骚。我其实已经从那天起,一直背负着愧疚和歉意,今天只不过又加重了一点而已。唉!
可以好好享受一家团聚的生活了!跟小思宇和我说的语气一样,小丫头说初十不想去上班了。呵呵,这家伙! 唉,我要好好想办法多赚钱,以后养个全职太太,呵呵!
下午我在干妈家,小丫头发短信来说,回不了家了,没车。当时小丫头的心情我是依稀有印象的,感觉像是很久以前也体会过。那种思家的情绪,对于每个才离家的人来讲,都是一样的。这样,小丫头在家的日子又少了一天,呼呼。
下午正在看碟,小丫头发短信来,说办公室里只有她一个人了,给家里打电话哭起来了。我辗转找到她办公室的座机号码打过去,小丫头略带哭腔地说,以前都没这样过。 我也不知道该说些什么,就跟她东拉西扯了半个多小时。可怜的小丫头,第一次离家在外一个人过除夕。真希望我能在她身边啊! 小丫头明天上午9点多的飞机,一路顺风哦!
下午离下班还有一个小时,就想逗一下教授和疯丫头。于是发了个群体邮件,把教授狠狠逗了一把。小丫头说,以前怎么没发现我这么有文采和幽默。我黯然,文采我是没有,没办法,可是幽默呢。我一直自以为还算会搞笑的,但小丫头却这样说。想起来,似乎afei也这样评价过我吧。以前小思宇她们不也说我自闭嘛,而且我就一直这样给自己下了定义了。其实仔细想想,对于小思宇她们来说,她们平常接触到的都是那些口若悬河滔滔不绝的做市场的人,这是普遍情况,我一个做研发的哪像那些人那么会吹呀!但对于小丫头来说,大概是因为平常和她在一起的时候,觉得是跟一个自己比较亲近比较亲密的人在一起了,就往往忘了表现一下自己开朗活泼的一面,而把深埋在心底的忧郁自闭的本性暴露出来了。我只愿意给她看到我的懦弱无助,而在其他人面前,我乐观嘻哈、放荡不羁、玩世不恭。可能这就是人的两面性吧! 明天就要回家了。想想当时跟小丫头两个人在那里扯皮,她要我陪她坐火车,我要她陪我坐飞机。可是现在,那个要我陪她一起坐火车的人不在了,我还是只能自己一个人走。唉,就让我叹口气吧,虽然我经常跟小丫头说不要叹气,叹气的时候幸福就会溜走,唉!
江南女子的特质。我这样形容小丫头,结果还被疯丫头笑了,这个蒙古女人,呵呵。
我站在你的门口,徘徊犹豫。我没有进去,我从你的门口走过。
我住在五楼,楼里没有电梯,每次都是走楼梯上下。我们对下的4楼一直特立独行,没有防盗门,我搬来半年多了,一直没有。那天星期五晚上,跟小丫头一起回来,小丫头爬楼梯可弱了,说累死了。到4楼的时候问我,到了没有。我说还有一层,就我们下面这个4楼的没有防盗门。 昨天晚上回来,一口气爬到5楼,心里闪过,怎么下面的好像有防盗门的?但也没有多想,就做其它事情去了。今天回来,看清楚了,确实装了一扇簇新的不锈钢防盗门!小丫头走了,它这儿也变了。 小丫头走了呢,去成都了呢!今天晚上小丫头就睡在成都的某个地方了呢!中午快12点半的时候,小丫头发短信说“上飞机了 再见了”,我故作镇静地说“呵呵,昨天就再见了”。下午快16点20的时候小丫头发短信来说“我已到成研”,我说“好好干,加油,多攒点钱,以后我去蹭你”。 看着手机,既希望有短信来,又怕有短信来。我忍不住,甚至有幻觉,好几次不经意间觉得闻到了小丫头头上那轻轻的香味。 突然觉得生活太没意思了,生命太没意义了。我讨厌这个世界,我讨厌这个人生。
这是小丫头留在深圳的最后几天。小丫头来深圳的情景,似乎就在不久以前。 星期四,下午,小丫头发短信来,说把她分到成都。我如同当头被打了一闷棍。当时,小丫头还没来报到之前,得知她会被分去北京或上海,我就已经痉挛了一阵子,好不容易慢慢习惯并接受了这个事实,并且下定决心,在网上把认识的在北京和上海的朋友、同学全都打了招呼,要过去那边。结果却是特别意外的另外一个说是打击都不为过分的消息——成都!我不知所措,刚刚还跟教授、疯丫头谈笑风声,紧接着的是一阵心绞般的疼痛,我疯了。晚上,QCC吃饭,我跟去,我笑不出来,却不能扫大家的兴,我勉强挤出点笑脸。我偷偷告诉雨烟。吃完饭,跟雨烟一起去百草园英华苑取了小丫头寄放在那里的行李箱。一边往研发东门走,一边雨烟不停地劝我开导我。走到东门,雨烟自己坐班车去了,我留下等小丫头出来。小丫头迷路了,在研发中心都迷路了。等到小丫头,一起坐班车,回住的地方。小丫头很疲倦的样子,我还好,只是心里像翻江倒海。小丫头玩起电脑,我坐在旁边看。很宁静,很安逸。告诉她明天要在8点10分前出门去坐车上班,然后就睡了。 星期五,一起出门,去上班。一起吃早饭。以前都是跟小妞一起吃的,自从搬了家后,一般都是一个人吃。这是和小丫头一起吃的唯一一顿早饭,以前就算在一起,在家里,都是睡过去了,一直等到中饭的。我告诉小丫头,我们一般在这个地方吃中饭,如果中午没人陪你吃饭的话,就来这里找我们。吃完饭,小丫头转头就要往外面走,被我叫住,应该往另外一个方向走。怎么mm都会有点路盲?小丫头在五楼,我在六楼。12点了,照平常一样出来,跟着雨烟和疯丫头。电梯上,雨烟回头问我,怎么跟着她们。然后两个人开始扯皮。雨烟问我不难过了,我说难过啊,难过也要吃饭啊,雨烟说怎么不去找大耳环mm一起吃饭,我说我一直跟你们一起吃的啊,雨烟说人家大耳环mm就要去成都了你也不找她一起吃饭,然后就转头跟疯丫头说昨天晚上我可郁闷了。然后教授他们插进来,开始一起扯皮。看到小丫头过来,疯丫头说欢迎插队。小丫头说,这样算不算插队哦,我说当然算啦。吃完饭,小丫头说手机没钱了,要给家里打个电话说一下情况。我把手机拿给她,她跟她妈说你要坚持住要有心理准备,我要去成都了。打完电话,我说手机下午你拿着吧,还要订机票的。下午快下班的时候,雨烟叫我过去帮她调自动化,其实是没有什么问题的,就是要等一会,她还没等一会就立马手动结束了。后来发现真的是只要等一会儿就行了,我就很大声地说,叫你等一会儿不等。然后扭头就走了,雨烟就在那里说,你居然这样跟我说话,不就是让你的大耳环mm多等了一会儿嘛。我头也不回,管自己走了。走到下面,刷了卡。没发现小丫头,于是想打电话。前台的还不能打外线,刚好逮到猫猫,就用她的手机打我的手机。小丫头说已经在排队刷卡了。后来她说,其实知道是我打过去的,因为一看是上面登了名字的打过来的。然后一起去食堂吃饭,再一起坐车回家。回到家,小丫头玩了一会儿电脑,说要出去跟大队培训的同学玩一下。小丫头出去了,我无所事事,翻起书来看。很无聊,很无聊,很无聊。10点过后,发了条短信,喊她回来。我骂自己,有病,又陷入这种怪圈了。过了20分钟,还不见回来,只好打电话,小丫头说马上就要回来了。我骂自己,有病,又陷入这种怪圈了。小丫头回来了,我静静地看着她。小丫头玩起电脑,我坐在旁边看。很宁静,很安逸。小丫头说,终于可以睡懒觉了,是的,大队培训期间睡不够是人所共知的。 星期六,早上9点,孙同学打电话来,我说在睡觉呢,她说两只猪。到了9点半,实在睡不着了。起床,到客厅看电视。很无聊,很无聊,很无聊。小丫头起床了。我在床边坐着,看小丫头收拾。小丫头说,要跟大队培训的同学去吃中饭。我说,算好时间,下午还要坐车去看你们的迎春晚会的。小丫头问我中饭怎么办,我说叫外卖呗,小丫头略带歉意地笑笑。看时间还早,小丫头玩起电脑,我坐在旁边看。很宁静,很安逸。小丫头说,怎么还不来啊。我说不用急,你们12点去吃,吃到1点半。后来果然,1点半的时候,小丫头就回来了。说要睡一会儿,然后我玩电脑,她在那边睡着。我去关门,回头看见她侧着身躺在那里,脸圆圆的,真可爱。孙同学又打电话来,说车子的事。我说睡着呢,她说怎么这么能睡。到2点过5分的时候,我把小丫头叫起来。然后出去等她,等她换完衣服。孙同学在小区门口的公车站等着,几个人吹了会儿牛。我等不及了,说先走了,跟孙同学说,你带着她,孙同学说放心吧,不会把你mm弄丢的。我到路对面的站坐391,到市民中心。我到的时候,已经开始2个小时了。看了一会儿,看了经典的《华为时代III》,然后就挡不住了,睡着了。等我醒来的时候,已经接近尾声了。抽大奖的机会没有了,因为我的奖券没扔到抽奖箱里去。结果还意外地弄到一个幸运奖,被人赶过来的位子,有个“福”字。会完了之后,就跟教授他们去找吃的地方,磨蹭了好久,之后是找不到哪里坐车,把雨烟弄郁闷了。最后坐公交车到梅林,吃小肥羊。吃了很多条泥鳅,疯丫头怕极了这个,哈哈。吃完,坐328回去,还怕回晚了,先给室友发短信,要是小丫头先回去了,帮忙开个门。结果等我9点半到了家,发现小丫头还没回来。孙同学说已经应该回来了。正如我估计的,小丫头找大队培训的同学去玩了。跟妈妈打了个电话,说话的兴致都没有。很无聊,很无聊,很无聊。把小丫头传给我的照片刻了张盘,然后就没事做了。11点过的时候给小丫头打电话,想喊她回来,结果没人接,只好发短信。回了个马上回来。11点半的时候,再打电话,小丫头说,就快到楼下了,不要慌。一种很奇怪的语气,以前从来没见过的语气。我在阳台上望着她回来。我在客厅里踱步等着她回来。小丫头见到我,轻轻地说了叫sorry,以前从来没听过。然后就进屋去,小丫头玩起电脑,我坐在旁边看。很宁静,很安逸。小丫头说,手机停机了,话费用完了,我说用我的吧。小丫头跟人语音聊天起来,不知道过了多久,我去睡了。我问她明天几点起来,她说9。 结果8点多,我就睡不着了。等着小丫头起床。然后一起收拾东西。她要回她以前住的地方,整理东西。在梅林倒车的时候,我问她想不想吃包子,她有点不好意思地说想。过去买了两个大灌汤包,结果她说不喜欢吃肉的,于是去换成菜包。到了沙嘴,小丫头有点感慨,离开了半个月的地方。她说,去吃饭,然后把我送走,然后她收拾东西。走到下面的一家湘菜馆,一人点了个木桶饭。两个人都没什么食欲,她是因为刚吃过2个包子,我是因为什么,我不知道。吃完说,去华强北看手机吧。于是坐到华强北,顺便把她买给她爸的衣服寄了。走来走去,说还是去看看以前的那些同事。于是打的到市民中心旁边的新少年宫。那些人看到小丫头,都特别热情。他们都很忙,于是我和小丫头走到观众席,看节目,一直看到6点,从4点开始,我就过半个钟头催一次。出来后,决定再回华强北,吃个晚饭,然后送她走。看到卖烤红薯的,小丫头就想吃,2块5买一小个,还真是贵。不过小丫头只能吃半个。下车刚好看到元绿回转寿司,就带小丫头进去吃,她说以前没吃过。小丫头吃不了多少,因为刚刚那个红薯就已经撑死她了。但是两个人还是吃了75块钱。小丫头说好奢侈啊,我说趁现在还能奢侈就奢侈吧,以后有老婆了,就要干吗干吗了。然后说起以后的事,我说2年后,如果有机会你愿意,我就把你弄到上海去。她说,那时候我就已经有老公嫁人了。我说,所以我留了后路的,说是你愿意的话,而且只说了2年,要是3年后,我已经估计你嫁人了。走到公车站,我说,我会去找你的。直到212路公交车来,那几句在心里构思默念了n遍的台词还是没说出口。等小丫头上了车,我把头扭到一边。直到车开动,我望着车里的那个小女孩,挥挥手。我掏出手机发短信给她,我一定会去找你的。我只觉得眼睛有点湿,有点忍不住,比当年我离开重庆时,在江北机场的时候感觉要舍不得得多,我不知道为什么,难到真的是因为心底里预见到这次的分别是这生的分别吗!小丫头发短信来说,其实我一直怕你放不下我。我说,放不下有什么用,该走的还是要走的,该分开的还是要分开的,我这几天觉得很幸福,让我有机会照顾你,尽管不周到。路边的店里适时地播起一个女声的“……寂寞沙洲我该思念谁……”
等你走后心憔悴白色油桐风中纷飞落花随人幽情这个季节河畔的风放肆拼命的吹不断拨弄女人的眼泪那样浓烈的爱再也无法给伤感一夜一夜当记忆的线穿杨过往支离破碎是黄昏占据了心扉有花儿伴着蝴碟孤燕可以双飞夜深人静独徘徊当幸福恋人寄来红色分享喜悦闭上双眼难过头也不敢回仍然渐渐恨之不肯安歇微带着后悔寂寞沙洲我该思念谁等你走后心憔悴白色油桐风中纷飞落花随人幽情这个季节河畔的风放肆拼命的吹不断拨弄女人的眼泪那样浓烈的爱再也无法给伤感一夜一夜当记忆的线穿杨过往支离破碎是黄昏占据了心扉有花儿伴着蝴蝶孤燕可以双飞夜深人静独徘徊当幸福恋人寄来红色分享喜悦闭上双眼难过头也不敢回仍然渐渐恨之不肯安歇微带着后悔寂寞沙洲我该思念谁当记忆的线穿杨过往支离破碎是黄昏占据了心扉有花儿扮着蝴蝶孤燕可以双飞夜深人静独徘徊当幸福恋人寄来红色分享喜悦闭上双眼难过头也不敢回仍然渐渐恨之不肯安歇微带着后悔寂寞沙洲我该思念谁仍然渐渐恨之不肯安歇微带着后悔寂寞沙洲我该思念谁
昨天晚上睡觉着,把电脑抱到床上,跟float聊了一会儿,她说要点名表扬我一下,因为我的blog上说了一些让她觉得要赞赏的话。好奇地熬到今天,去她的QQ空间看了一下,就抄了我三句话,不过也让我的虚荣心小小地满足了一把。 今天去买了机票了,11号的,去的时候6.5折,回来的7.5折,还是花了我2030个大洋啊,呜呜,越来越穷了。顺便去请了假,从12号开始请到17号,原来一直在等,等消息确定,自从知道小丫头被短信通知了后,我便可以心安理得、死心踏地地去请假去买机票了,今年,还是一个人走。所谓的人算不如天算啊!
今天下班后找小丫头一起去吃饭,等我走到百草园门口时给她打电话,说在等打针。我在门口等了一会,忍不住了就进去找她,原来是要打吊针。于是先出去吃饭,在百草园门口随便找了一家馆子,有粥喝就进去了。叫了个皮蛋瘦肉粥,一个黄金豆腐,还有个清炒生菜。除了生菜,另外两个的味道都不怎么样,黄金豆腐还都是用鲜蛋打的蛋花,晕! 小丫头不停地咳,还是带痰的。吃过饭就陪她去打吊针,吊了1个多小时。还说现在已经是有所好转了,前几天是还有发烧的,有一次去跑操,结果不行了,让一个男生背回去的,甚至连那男的是谁都不知道,长啥样都没看,可怜的小丫头。 小丫头说,她们部门已经给她发短信通知她不要急着找房子了,因为要被派到其它研究所去。呼~~~也许她在深圳,就只能再呆这最后一星期了。
小丫头下午发短信来,说在打点滴,病倒了。下班后给她打电话,本来想过去看看她的,顺便拉她去吃饭。这个家伙总是不想吃饭,还说医生说只要休息就行了。饭都不吃的人,休息有什么用。可惜她说要去上课了,于是只好作罢。
小丫头在大队培训,还当了个什么班干部,呵呵,这让我对人的性格决定命运这一论调更加深信不疑,像我这种人是绝对不会跑上去竞选的。她还说,当时因为在台上唱了几句,就选上了。我好奇地问,唱了什么。结果她唱起来,晕,小薇……还真有个性,呵呵。 昨天小丫头叫我上网找些配乐诗朗诵的东西,上网搜了一把,没多少,把能下的都下下来了,发现也才几十MB,刻个DVD也忒浪费了,于是把街舞教学的那些视频,加上K Mega Lite和千千静听一起刻了,刚好4GB。今天就给小丫头拿过去,本来说是到培训中心食堂找她的,结果她打电话来说,回百草园了。于是吃完饭,就走去百草园了,刚好身上也不带钱,就断了坐小巴的念头。刚走进百草园,小丫头就出来了。于是两个人一起往外走,去培训中心,小丫头还昏了头,走错路都不知道,呵呵。从她打电话的时间看,就知道她没吃中饭,这个家伙。还说带她去食堂买点吃的,结果走到教室门口的时候,好像里面有点事情,她就直接进去了。
在回百草园的335上,看着旁边闭着眼睛假寐的女孩,除了叹惜,实在想不出任何的神情和动作来表达我乱麻般的思绪了。 小丫头穿着浅绿色睡衣的样子真可爱。 唉! 前天,妈妈突然发短信来,说做了个很美的梦。梦见我带了女朋友回去了,我上班,婆媳俩在家带孩子。我晕倒,回说还早得很呢。估计我妈除了无奈,没有其它想法了。 套用某某人曾经很爱说的一句话:“大自然真奇妙!”
嘿嘿,小丫头说我只会记流水账,是啊,从初中开始,一直在写流水账,到高中的时候遇到一个比较宽容的语文老师,对于反应真实生活的文章,即使是没有文采的流水账,他也会赞赏,于是更加变本加厉,从此只会写流水账,哈哈!我这个没有文学素养的粗人,流水账也可以记录曾经发生过的美好和痛楚,平淡中见真知。哈哈,其实是借口啦,当然不像小丫头,一腔的忧愁、一肚的苦水、一堆的酸楚,化作让人心动的文字。男人不需要多愁善感,把所有的伤感和悲鸣藏在心底,带给对自己重要的人阳光和快乐。
昨天就发邮件打了个招呼,今天下班后,带着我的巨巨外置硬盘去了,想不到这位哥们的硬盘更大,是250GB的,比我的大了90GB,晕!电子书有20多个GB,看了看我的4个分区,本来是想放到专门放文档、资料的分区里的,一看居然只剩下8GB多的空间了,很奇怪,先不管了,放到另外一个空很多的分区里。后来才想起来,前段时间才用eMule下了17GB多的MAME ROM,还有很多其它的Emulator,当然占去了20多GB了。拷完东西,出来给小思宇打电话。把睡袋和垫子拿回来,小思宇说在收拾东西,因为明天就要回去了。真牛,她们领导也竟然真肯让她请假这么久,昏倒。 昨天晚上跟小丫头聊天,说了四五点原因,说得很沉重。其实我在想,如果在不远的以后的某一天,这几点原因中超过一半得到了改善,我可能还是会考虑、会继续。唉!
早上8点的时候,手机就响了,也不知道是谁,郁闷死了,一个打错的!然后想想就还是起来开始洗澡收拾,9点的时候出门,发了条短信。在梅林倒车,在金地花园下车。回忆一下当时走过的路,嘿嘿,还好还记得怎么走的。但哪个房间就忘了,只是依稀记得好像是10楼的,于是只好打电话问了,果然是在10楼的,呵呵。上去坐了一会儿,看了一会儿电视,都没几个台,因为没装数字电视,关外这点比较好,装了有线电视就可以收到好多个台。有个水电工在修下水管,下去买了个新的。过了11点半,说去吃饭吧,走到下面附近一个自助火锅,还真便宜,一人18元,锅底10元,哈哈,我拿了很多水果,吃了很多蟹肉。 吃完火锅,说去医院吧。于是坐到华强南,福田医院站,乱找了一通,总算找到了所谓的福田人民医院。走到体检科,玩了一下视力表,哈哈,我还有1.5呢。结果被告知下午不体检,只有每天上午8点到10点,郁郁地出来,既然都到了上海宾馆了,就逛一下街吧。去天虹、NICO、曼哈逛了,一直到5点多,累了,走进曼哈的麦当劳,买了可乐和鸡翅,亏了,没用优惠券,郁闷! 逛得腿酸! 突然想学一下make或bjam,或者两个都学一下。因为觉得用命令行只能每次全都编译连接一遍,有点浪费时间!写游戏还真是能学到不少东西,居然已经转换到这个上面来了,呵呵。
早上9点多时就被电话吵醒了,因为要来换抽水马桶。到了1点多的时候,很无聊,给小丫头发短信问她在干吗,然后决定去逛下街,就约好地点。比小丫头早到了大半个小时,说是堵死了,其实已经都到了,只是她不认识路。两个人逛了一会儿茂业,觉得买不起,于是走到曼哈,有些东西确实要便宜点。小丫头买了两件连衣裙,总共才花了315元,难得有这么便宜的女装哦!之后她也不想再花钱了,也差不多刚好到吃饭时间了。刚好找到这个机会有人一起去吃火锅,就跑去华神吃了一顿,浪费了一个白菜。2个人吃了142元。小丫头说,每次都是我请她吃,下次她请我,还说欠了我好多钱,哈哈。其实我就想找机会去吃顿重庆味的火锅,叫了雨烟好多次,均未果。 小丫头说我的blog写的都是方块,或者程序。我说偶尔也有写生活的呀,她说真的是偶尔才有哦。呵呵!
终于能连上来了,老泪纵横啊!这个时代,越来越依赖网络的时候,越来越不喜欢本土服务的时代…… 好不容易啊,终于可以在TImage上画线条了,晕死!剩下要处理的是,怎么把文件中的图片装成背景。还有就是,对于方块池和预览框,是大小固定的,不是用拉矩形框的,而是要跟踪鼠标的坐标直接画固定大小的矩形框。 下午,小丫头给我发短信说我们公司给她发录用通知了。说实话,就像我自己被录用那样高兴,昏。不过她肯定会犹豫,我当时不也犹豫了一会儿吗,后来还是乖乖老实地来了,因为我懒得再去花心思在找工作上了。不过小丫头现的情况跟我有点不一样,她是有正经工作的,要一个人下决心跳槽也许不是那么容易吧,不过要是换作现在的我的话,哪里给钱多,就去哪里呗,还追求理想么,干自己感兴趣的事?有点可笑的幼稚,理想是随时间和经历变化的,现在的理想就是想办法怎么赚更多的钱,赚更多的钱就是现在自己感兴趣的事!小丫头要是过来了,拿的钱会比我还多,晕!由此可见我混得多么失败啊,唉!
小丫头又跑到公司去上网了。我问她怎么就为了上网就跑过去了,她说想出来走走,顺便想写一下总结。然后两个人就东拉西扯了一会儿。其实我们聊的话题很少很少,每次我都是搜肠刮肚地想些事儿来说说,而且很多时候我发消息过去的时候,能预料到她会回复什么内容。我只是不想让它冷场,我不是不善言辞吗。小丫头脾气很大,出乎意料地对我破口大骂,我都开始怀疑是不是她的QQ被盗了。我还想我是哪里招惹到她了,会发这么大火,骂这么凶。不过马上,她说因为没人骂,就骂我了,我才舒了口气,原来我没招惹她。后来她快要下的时候,告诉我为什么她最近心情不好。其实我也是这样过来的,走出校门走向社会后,总会遇到一些以前没遇到过的事儿。然后谈起以前的事,心情超级沉重。小丫头是个固执而倔强的人,幸亏我们不谈恋爱,不然肯定会为一些其实不应该成为问题的事情经常吵架吧,呵呵。我也自认为有点霸道有点顽固有点小气,我想管得别人太多了,其实我完全可以不理会。 有点累。我用我的方式解决问题,但一定要得到有些人的认可才行。我不能忍受别人曾经对我的奚落、嘲笑和无视,我不会装作若无其事地坦然接受这一切,我在乎得很。我宁可重新另外找一个新的开始,也不愿再回头,乞求同情和怜悯。我对小丫头说,我的挑剔,来自于对自己的信心。还好,VC和GCC其实都不支持可变数目的模板参数的,那天是太紧张了,看到的其实是LuaTinker里另外一种奇怪的语法。hoho~~~
z3从下班回来,突然说公司要派他去北京长驻了。是,这变化还真快!本来他只是说要去北京出差2个月的,而且之前一段时间他也尝试在他们公司附近找房子,最后还是放弃了,说那边的房子贵,这边的便宜点。我当时还高兴了一下,因为我实在不是很喜欢一起住的人换来换去的。结果现在他居然要去长驻了,而他的房子也只能转租给别人了,还好那人也是以前的同学。 生活的变数真是大啊,我还不知道明年我会在哪里呢!我一直想的赚很多很多钱,然后回家养小鸡小鸭,但是这个大前提怎么满足呢。今天回到家,小丫头在QQ上,自从她搬了家后,就很少上网了,因为离公司比较远,而且住的地方附近比较乱。叫我帮忙给弄个word文档,大概就是一个普通大一计算机课的考试要求。要求还挺多的,为了找这样合适的文字还费了点精神。幸好这方面还勉强过得去,1个小时就弄完了。小丫头把那天一起去欢乐谷照的合影传给我,呵呵,我真的越长越丑了,小时候多可爱多乖的啊,郁闷,应该去剪头发了。 白天在公司,因为上周的一时热心,惹来一个麻烦的事儿。因为条件苛刻,真的很不方便。 把案例提交上去了。 接下来几天,希望能咬紧牙,先把我的方块搞定了。 我是个很浮躁的人!就这样生活吧。
排队排了n久,每次排好长的队,就为了那几秒钟的快感。我发现我的胆子越来越小了,还不如小女孩了,晕倒! 周一之前,要把TclSuck写完,那部分Functor实现了就可以了。
10月6日 虽然回来后没有马上爬到床上好好睡一觉舒服一下,还是整到2点多才睡,结果6点多就还是醒过来了,郁闷死了!然后起来打开电脑,照例听听歌,打打方块,看看论坛。后来想想还是把那些换下的衣服洗一下吧,就简单地搓了几天,清掉肥皂泡后,凉起来。估计9点多了,就出门去了。 上了328给小家伙发了个短信,小家伙还没起床呢!到了门口再打电话,说现在不准进来,晕,我就只好无聊地看看周围的环境,看看她们屋的电表转速,是那里10个屋里转得最快的一个。 好不容易等到小家伙出来,就一起去坐地铁到东门。这一天有点怪,地铁上一路几乎没人下的,都是上的,我郁闷,站了一中,到了东门都下空了!不知道从哪个出门出来,看到有个卖肠粉的店子,就进去权当作是中饭,同时补充早餐的欠缺,呵呵。我点了个虾肠粉,小家伙是香茹牛肉肠,又一人要了一份饮料。我倒是吃得还算爽的,虾是我喜欢吃的东西,冻奶茶也是很爽,就是那种从喉咙头一直凉到胃里的感觉。小家伙居然抢着把钱付了。 之后,就一起逛到太阳百货,逛了一下午,从底楼逛到顶楼,坐了一小会儿休息了一下后,又逛回底楼。从鞋类,看到少女装,再到化妆品,还有成熟淑女装。出来后,说去茂业看看吧,结果两个人都分不清方向。在一个天桥下,小家伙看到有卖水果的,说要吃,于是一人拿着一条哈蜜瓜咬着走,走到一个并非原本想去的茂业店里去了。又从底楼逛到顶楼再回下来,小家伙看到一件线衣,就在那里试试,最后要买了,顺便补了一句,买回去不好看就找你算账,说得我战战兢兢。 出来的时候,小家伙说累死了,我只好嘲笑说她不行,逛街都没有逛得厉害。又回到闹市区,我还是想找一下那个茂业,因为本来就跟同事们说好要在那门口集合的。小家伙又想去逛那些地下商场,草草地走了圈,在卖耳环的地方,小家伙就会停下来看,最后在一个铺位上我说一对挂的很多圈套在一起的好看,很适合,老板要价35,我随口说了句20吧,老板开始还说不行,小家伙就放回去了,老板就说好吧好吧,唉,这些生意人。出来后小家伙还埋怨我,本来想喊15的,我就很委屈地说,我以前没买过这些,又不知道它的行情,我只买过×10的那种价位的。 终于,在又走错几个路口后,找到了那家茂业!从-1楼开始逛,小家伙说要买靴子,看到一个3.8折的,小家伙还是比较心动的,但后来还是没下决心买。在茂业逛了很久,小家伙也试了几次衣服,但是都没买。我给妈妈打了个电话,其实是记错了,以为是周六了,但反正是中秋节,打个电话也是应该的。开始还想等xcc过来了再打,xcc刚从杭州旅游回来,还在回家的路上就给我打电话说要来找我一起玩,我就想,到时候妈妈问我在干吗,我就说在逛街,妈妈问跟谁在逛的时候,我就可以说在和xcc一起逛。小家伙说,你就说跟个女的在一起逛!我说我妈会很严肃认真地来搞“政审”的,会要跟那女的说话,打听那女的家庭背景,学历,收入水平等等等等。结果等不及xcc来了,我就打了,妈妈问我在干吗,我说在逛街,妈妈问跟谁在在逛,我说还在等几个同事过来,要一起去吃饭玩。6点半过的时候,同事们还没来,小家伙又去看那些小玩意的店。又过了一会儿,教授给我打电话,说在茂业门口了,我就过去,看到悍超他们都在。我过去对疯丫头说,你家属呢,怎么不牵他手啊,然后她就说,你怎么不牵你家属手啊,我说我要牵你们的手的啊,哈哈。 走到对面的小肥羊的隔壁的野山菌汤锅,开菜了一会儿,xcc才赶来。大牛的mm在坐我们对面,要我介绍一下。我看看小家伙,小家伙有点语塞,说你来介绍吧。我就说,某女人啊,从路上捡来的。大牛和他mm也不多说了,呵呵。十五六个人吃了,个人感觉口感还过得去。吃过后,一群人就去本色酒吧,有两张桌,都玩起摋子来。去蹦迪的地方看了看,太多人了,我变得很想回去学一下跳舞,至少不要像下面这些人一样,全都只会这样小幅度扭动一下腰。 12点的时候,小家伙说要回去了,因为第二天还要上班。于是xcc也跟我们一起走了,xcc打算去我那里睡了。一个新手司机在那深南路上转了好久,好远的路,才到了目的地,呵呵。结果问了一下,居然第二天不用上班!看到她们屋里多了个男生,听说还是和我一级的我们学校计科的,晕,没印象。一群从同一个学校出来的人在那里聊了一会儿天,我就叫小家伙一起去我那里,顺便把和她一个屋的我的一个师妹也叫上。 4个人先打的到梅林,吃了顿海鲜大排档,然后再打回我住的地方。玩了一会儿,都5点多了,于是我和xcc到隔壁房间睡了,这房间的兄弟只住了几天就出差去了快1个月了还没回来呢,呵呵。10月7日 早上大概才8点多吧,xcc就把我吵醒了,说要去买菜,我实现困得不行,死撑到9点多,起来看电视。我的所有的东西都在我的房间里,而她们两个还睡着呢。过了一会儿,实在忍不住了,就敲门把她们叫起来。我洗漱了一下,就和xcc去菜场买菜了。 买了些排骨,精肉,葱,小白菜,番茄,鸡蛋,剩下的,就都交给她们两个全权处理了。不过我还是做了些淘米之类的简单的活,呵呵。一直到下午2点左右才全部做完,可以吃了。味道真不错,呵呵。吃完后,小家伙还把厨房、客厅的桌子柜子使劲收拾了一遍,涣然一新!心里感慨万千……(此处省略N万字心理活动描写,N≥5)我挡不住了,就跟小家伙交待了一下,去睡午觉了。一直睡到5点半,起来,小家伙们也起来了,回去了。又过了一会儿,和xcc两个人烧了一点饭,热了一下汤,把晚饭也吃了。后记: 这样的生活我还是比较向往的,就是简单的居家,然后能和一些人一起去玩。可是,大部分的时间,我们还是在忙碌于工作,为了那点点生存需求而拼命。
Category CPPOOPGPXP
Clang for Windows早已经可堪实用,官方每隔一个月或几个月会发一个编译好的snapshot外,msys2项目也提供了不是特别新的版本(目前9.0.1)可以直接通过pacman安装使用。作为一个升级控,用上Nightly Build岂不是更爽!当然这不是官方的,而是需要自己下载源代码进行编译。
英文原文:https://www.modernescpp.com/index.php/thebigfour
C++20,近十年来最具影响力的C++版本,完成了!
原文:https://www.reddit.com/r/cpp/comments/f47x4o/202002_prague_iso_c_committee_trip_report_c20_is/
前段时间开了一个微信公众号《软件开发谈》,可以通过搜索ID“softwaredevtalk”找到,也可以通过扫描文末二维码找到,主要发些与我本职工作相关的Go、C++、软件工程方面的文章。到目前为止发了十几篇文章都是罗列了些modern C++的新特性:
之前已经在Windows上用clang编译Qt程序,但当时的Qt Creator并没有好好地支持,所以需要在控制台上直接使用命令行进行编译。今天偶然发现最新的Qt Creator已经支持clang-cl套件了,试了一下效果不错。
Go语言中有defer可以在退出当前作用域时执行一个函数调用,C++中以前常用的做法是创建一个类的对象,在该类的析构函数中写入需要执行的代码。而这个对象可以创建在栈中,也可以放在std::auto_prt<>或std::unique_prt<>之类的地方,只要退出作用域就会被销毁就可以。这在网上能找到不少的讨论,比如C++之父的这段,C++ Core Guidelines中的这段,以及Cpp Reference中的这篇。
几年前也曾经试图折腾过Clang on Windows,那时候的完成度还不高,只能配合MinGW使用,而且头文件搜索路径还是源代码中硬编码的。
C++11加入的lambda表达式是一大进步,大概这样用:
公司的项目至今仍在使用Boost 1.56.0版本,最近发现Boost.uuid在Windows上居然会一直尝试去访问/dev/urandom,进而转移到系统盘根目录urandom文件,然后客户认为这会有安全隐患,需要修正。我随手看了一下Boost.uuid在1.56.0和1.64.0上的源代码,貌似确实1.56.0版并没有分系统实现,在1.64.0上为Windows系统使用平台特有的实现。于是我就建议升级Boost,然后发现这个third party的owner居然是我们组,同事开玩笑地问我能不能去为几个平台编译一下Boost,我当场就拒绝了,但回到家我还是决定折腾一下。
之前提到过我用MinGW版本的Qt遇到几个问题,现在基本解决。
很早的时候,“道祖”Andrei Alexandrescu在“道经”《Modern C++ Design》中就有个简单的小结,列举了C++(当时还是C++98)中的可调用体:
项目组有定期的share,这个活动的负责人前些天跟我来说,让我讲讲C++11的东西,我说我也不懂啊,她说可以给我多点准备时间,书可以让公司买。
这两天在Windows下折腾clang。这东东前端是支持C/C++/Objective-C/Objective-C++,后端一般是用LLVM的。在Mac OS X上貌似用得很好,可以生成OSX和iOS的app,貌似在Linux或FreeBSD上也支持得不错的样子,不过在Windows上就纠结了。
首先,clang还是依赖gcc的crt和headers的。于是在Windows上基本上是用MinGW套件的。但是同样是MinGW,不同的人都能编译出不同的东西来,版本众多,质量也不同,貌似还是MinGW官方编译的版本最为稳定,MinGW-w64的x64版本貌似就压根编译不了clang。
众多32位版本的MinGW都可以编译clang,但是,编译出来的clang貌似就是能自举了,真是遗憾,也不知道是不是我哪里弄错了,4.4.0版本是报BFD模块中有个内部错误,4.6.3版本是在链接时报错,4.7.x版本则是编译第一个文件就报命令行参数错误。
我是在msys中编译的,值得提一下的是,它每次都要做rebuild all才行,incremental build貌似是不行的。还有就是perl中的pod2html.bat在msys中是用不了的,所以在make install时都会报错的。
最后要注意,编译clang前,需要修改下llvm\tools\clang\lib\Frontend\InitHeaderSearch.cpp中MinGW的头文件搜索路径。最简单的办法是硬编码增加搜索路径,但是这样你的MinGW和clang就只能存放在固定的位置了。我看了一下clang dev去年4月的maillist中一个thread,其他他们就是没找到一个高效低成本的方案来解决这个问题。于是我就自己用了一种quick & dirty的方案。先查找clang所在目录是否有gcc.exe,没有就找PATH环境变量中有没有,再没有就试试各个分区根目录下有没有mingw目录,如果能找到gcc.exe,就运行gcc.exe -v命令,得到target和version,这样就可能得到搜索路径了。自己写了大约200行代码,粘贴到这里了。
今天彻底打酱油了,我们shared dev team也只剩下我,老大和Jason三个人了。因为晚上2点才睡,才睡了不到6个小时,于是下午就坐在办公椅上睡了近1个半小时,最后是被他们讨论一个bug的声音吵醒的,啊哈哈,老大还说让我看一下,现在只有我在这方面有经验了,我囧,我完全没经验的说,后来还是Sherman厉害啊! 再后来,就跟老大讨论了一会儿C++ singleton的实现,以及跨DLL数据引用等等。问题是有个Watson的bug,我从一次crash的call stack中发现,程序在调用_exit后,该程序中的static object应该是已经瞬间被无声息地干掉了,所谓无声息的,就是说,连它的析构函数都没被调用的。但这时嵌入的CLR还需要做一部分扫尾的工作,而恰恰是这扫尾工作又反过来调用了那个貌似已经被干掉的static object,于是程序crash了。当然这只是我的猜测,我猜测嵌入的CLR就是要生存周期长一点,于是一直在代码中试图找一下它是怎么从C++端嵌入CLR的,然后怎么用CLR的。我发现的情况貌似是这样的,先用Managed C++写了一个dll,这个dll可以在DllMain,还可以导出函数,而据我前些天才知道的知识,.NET编写的普通的DLL形式的assembly跟原本的DLL不一样,没有DllMain的。而这个DLL通过导出函数返回一个对象的指针,这个exe程序通过GetProcAddress获取导出函数,再调用这导出函数获取对象指针。这个返回的对象呢,是个CLR Bridge,也就是说,通过这个对象,可以从C++端创建CLR中的对象,调用CLR对象中的方法等等。也就是说,从代码中,我没看到Jeffray Richter在《CLR via C#》中说的那种CLR host的方法。现在我仍然在怀疑,是不是我代码没看全,但我确实之前也在整个代码目录下搜索文本,没有那几个用于host CLR的API调用。似乎有点跑题了。然后我就跟老大说了一下我发现的这些情况,略微讨论了一会儿,老大表示自己也不知道,唔,其实我也不指望他知道,只是有这么一种想跟人分享自己的发现的欲望而已。基本上,我就觉得这很可能是此bug的root cause了,但老大说可能只是个cause,而不是root cause,好吧,其实就是缺少验证而已。一个比较有说服力的验证方法是自己用C++写个小程序,然后用相同的方法调用CLR中的代码,最后能制造出同样的crash,只是我最近木有动力去做这些事而已。另外就是,即使确定了这是个root cause,简单地说来,这个root cause应该就是对象销毁的顺序不对,这是可以肯定的,但之后也不好fix,因为这个程序实在太庞大了,有很多对象,然后引用关系也很复杂,以我目前对它的了解程度,根本没能力对理顺这个关系,于是也就fix不了了。而且还有个另外的问题是,那个static object是该程序中用于实现singleton的一种方式,我觉得比较奇怪,老大说,这是为了应付多线程的情况。还有种应用多线程的singleton实现方式是在create instance时加锁,唔。关于这个话题,在前段时间看到TopLanguage group中有个讨论,提到boost中某个库中的singleton实现,貌似很干净的实现,不用锁,也不是static object,能适应多线程,囧,具体的不记得了,貌似boost中有好几个子库中都有自己的singleton的实现,得再去看看代码才行,另外好像《Modern C++ Design》里也有对多线程singleton实现的讨论,春节放假看看去。 话说,今天还看到Mono,发现除了有Mono Touch外还有Mono for Android,不过免费试用版都只能在emulator上跑,最便宜的个人版license也要399刀。不禁大骂Qt的不给力,为毛只能为Symbian和MeeGo用,Android port至今还在alpha...
一直用GCC 4.4.0,之前也尝试过将sf.net上MinGW的各个包下载下来后解压覆盖到4.5.0,但最后编译我的工程时总是std::basic_string什么的一些libstdc++-6中的一些符号链接有问题,于是就搁置下来了。
今天偶然到了mamedev.org上看了看,发现它用的是4.4.3,于是想试试,后来干脆又去sf.net上找官方MinGW的文件来看,居然发现一个叫MinGW-Get的在线安装程序。MinGW很喜欢提供在线安装工具,而很少提供打包好的整体的解决方案,这是让我觉得很困惑的一件事,它的在线安装工具下载速度一直以来实在不能恭维。今天试了一下MinGW-Get,下载速度还能忍受,不过第一次仍然有好几个包下载失败,又装了第二次,才把所有选中的包都下载来了。然后把新下载的文件都覆盖到原来4.4.0的目录中,开始编译测试。
我的工程不大,才约5万行C++代码(不包括使用工程生成的代码),但依赖于一些第三方库,比如wxWidgets,Boost,以及几个wxCode中的子库。编译wxWidgets很顺利,发现在Windows下wxWidgets的表现确实很不错,有各种编译套件可用的工程文件和makefile,至少我用MSVC和GCC基本没遇到过问题。然后是编译Boost,前两天开发的时候发现用1.44.0的Boost,用MinGW编译Thread有问题,有个符号在链接时找不到,问题在这个ticket里有描述,于是仍然在用1.43.0的Boost,编译是可以正常通过了,不过最后使用的时候有点问题。拉下来是编译各个wxCode的组件,包括wxPropertyGrid、wxScintilla、wxFlatNotebook,另外还有Luabind,这些也都比较顺利,唯一有点麻烦的是,由于我是使用了Boost的bjam作为编译工具,而不是传统的make什么的,bjam有个很奇怪的行为是会把编译过程中生成的.o文件都存入到一个深深的目录中,目录路径中包括编译器名,版本号,链接类型,线程模型,debug/release模式以及项目名称,而wxScintilla中由于编译出来的.o文件比较多,最后链接的时候居然报命令行太长而命令不能执行,真是太囧了。
最后是编译我自己的工程,该工程是一个exe文件,需要链接前面提到的这些库,在链接阶段就会报出一堆关于std::basic_string等等的符号什么的警告,这些还不是很碍事,比较严重的是说Boost.Thread里有个叫_tls_used的符号与libmingw32.a里的重定义冲突了,问题在这个ticket中有描述。这个问题以前也遇到过,是MinGW使用的mingwrt 3.18中引入的,只要降级到3.17就行了,还有个办法是打开Boost.Thread中tss_pe.cpp,将那个名为_tls_used的函数屏蔽掉也可以。
编译后发现,生成的exe不依赖于原来的mingwm10.dll了,多了个对libstdc++-6.dll的依赖,其他的倒好像没什么大的变化,只是dll都变过了,需要跟着更新。
将MinGW中的GCC升级到4.5.0顺利完成!
今天搞到了C++Builder2010,里面的bcc是6.21版本,相比bcc5.5,也是经过4个版本升级了,隐约记得在某个版本中,把CRT中的内存管理部分改用FastMM了,所以它的表现应该有所不同。
经过与前一次基本相同的测试,得到结果。从该数据中可以看到,6.21版本提升了多线程情况下的小块内存操作的性能,在1024字节以下的malloc测试中,表现优于所有其他的编译器!但在1M字节以上的测试中,还不如bcc5.5版本。而且,它的new操作耗时比malloc操作耗时多很多,大约是半倍到一倍的样子。在单线程小块内存的操作中,表现可以用技惊四座来形容,直逼OpenWatcom,甚至偶尔略有超越。但是在大块内存操作中,反而都不如原来BCC5.5。
详细测试用可执行程序与测试结果可以点击这里下载。
前些天有人在群里说起测试malloc和HeapAlloc的效率,后来又在豆瓣上有人讨论起大块内存的策略问题,于是我决心再稍微仔细地测试一下各个编译器在这方面的表现。 首先,我选取了OpenWatcom 1.8、Digital Mars 8.51、Borland 5.5、MinGW GCC 4.4.0、MSVC 2008、Intel 11.0.061一共6种编译器,除了Intel C++,其他的编译器都可以在网上下载并免费使用。 然后写了一个非常简单的小程序,分别对1字节,1000字节,1024字节,1M字节,10M字节和50M字节进行重复的分配和释放,前三种大小重复15000000次,后三种大小重复150000次。为什么前三种的重复次数是后三种的100倍呢?因为测试过程中我发现,后三种的耗时在某些编译器中太长了,等不及了! 接着,使用所有这些编译器编译出4种不同CRT配置的可执行程序。分别是单线程静态链接,单线程动态链接,多线程静态链接和多线程动态链接。我都是使用bjam的默认参数编译的,其中Intel编译器不能生成单线程静态链接的可执行程序,但我想影响很小,也就不再追究。 最后就是运行每个程序,我的机器配置是Thinkpad T43,1.86GHz的P4m,1.5G内存,Windows XP SP3。每种跑10次,计平均时间,可以得到一些有趣的结果。从不同的维度观察这些数据,可以得到不同的结论。 先比较不同编译器间的差别。从实际上看,MinGW和Intel都是使用了msvcrt,只不过默认情况下MinGW使用的是6.0版本,Intel则使用当前安装的VC的最高版本的CRT库,我的机器上是9.0,所以总的说来这三者的差别应该不大。 在1字节的大小时,Digital Mars表现平稳而出色都在2s出头,而VC、MinGW和Intel都超过3s,OpenWatcom跟VC类似,但在单线程静态链接时就爆发了,只需要1s出头,而Borland在单线程中都只用1s多。 1000字节的测试基本与1字节的情况相同,但Digital Mars的耗时却飚升了近1倍! 而1024字节时,VC、MinGW和Intel的耗时又比1000字节时多了近1倍,看来这1000和1024之间有个阀值影响msvcrt使用不同的分配策略。 在1M、10M和50M字节的测试中,三个测试的数据差别不大,但与前三者的测试数据比较可以看出,OpenWatcom和DigitalMars的表现平稳,变化不大,但使用msvcrt的三者则耗时飚升,大约是前二者的400~500倍,是1024字节的200~250倍,这个差别比较大! 总的说来,Borland C++只有在单线程,小块内存分配时的表现还不错,这在DOS时代是好的,但进入了Windows时代,程序开发纷纷往多线程,大内存占用的方向发展时,它几乎没有进步。Open Watcom是受分配内存块大小影响最小的,几乎没有变化,而且总体上它在各个横向比较中性能是最好的。Digital Mars略次于Open Watcom,但它在单线程或多线程,静态或动态链接中几乎没有差别,估计最终使用的是同一个CRT库。VC、MinGW和Intel的表现基本相同,除了单线程静态链接小块内存分配外,其他情况都略好于Borland C++,所以可以看到Intel编译器的优化是集中在指令流的调整上,而对内存这块是忽略了。...
看了两天小说,呃,又堕落了。由于已经看完了,今天就比较认真地折腾起flex和bison。其实之前已经把lex和yacc脚本写完大部分了,至少可以从控制台打印结果出来了。今天就修改一下yacc脚本,把原来打印到控制台的内容保存在内存中,到时候转储成xml格式。因为只是要显示在界面的树视图中,我想了想,也就只有函数定义值得这么显示一下,所以也就只处理了这部分。 总的说来,感觉yacc有点土,它只能接受一种输入接口,而我用flex时发现可以生成C++代码,所以要给bison用的话,仍然需要把这个C++类的接口再适配成bison可用的C接口。 这种任务果然是实践性非常强的工作,本来看过一些资料,当然,能找到的资料也基本内容一样,翻来覆去那么几句话几个例子,等到自己要做时,不时地有些迷惑,只得慢慢尝试,倒也捣鼓出来了。 在yacc中可以为每个token或type指定一个union中的某个成员,其实这个成员的指定只在规则描述段中的action中有用,就我看来各种资料、教程中说的那一堆实在是扰乱视线。对于一个C/C++程序员来说,这种用法只是万千技巧中的一种,实在没必要说得那么严肃仔细,好像不那么用就不行了似的。 再说个我觉得yacc土的地方,由于这种格式上的限制,在action中只能访问一些全局的变量、对象等,至少在思维逻辑上很不连贯,其实lex也有这个问题。要我说,比较让现代化的做法是它应该生成一个类,每组action触发时,应该调用该类中的某个回调函数或虚函数,这里形式有好几种,都可以考虑,不知道boost.spirit是不是这种形式的,也许ANTLR等其他类似的工具就是这么做的。 最后抱怨一下,Lua Reference Manual中附录的complete syntax不能直接用的,至少不能直接用于yacc,有好些地方似乎没写全。
上午整了一两个小时,在wxWidgets程序中使用第三方库wxPropGrid,结果发现在VC2008中链接时有几个warning,虽然看起来刺眼,但似乎是可以正常运行的,也没有很在意。然后用MinGW编译链接,最后链接不通过,报未定义的符号,而这些符号是之前用VC2008时报warning的那几个,这就说明不是库编译得有问题,就是本身程序编译得有问题。 我先把焦点放在库上,wxPropGrid是编译成静态库的,这不但编译链接选项不同,连有个宏定义(静态库是WXMAKINGLIB_PROPGRID,动态库是WXMAKINGDLL_PROPGRID)都不同。我仔细观察了该宏定义对源代码的影响,并参考了wxScintilla的做法,发现区别很小,基本可以忽略。于是我琢磨着如果实在不行了,把wxPropGrid编译成动态库试试。正在这么打算的时候,突然想起来,这个宏定义在主程序中没定义啊!一定是这个原因!于是修改了主程序的配置,加上了这个宏定义,重新编译,发现果然有效,VC中也不报warning了,MinGW中也可以链接通过了! 其实这是个老问题了,只是平时很少遇到这种情形,一时没想起来。
最近一直在学习Martin Fowler的《重构》,并且对照我参与的一个已经投入至少15人年,历时3年,约20万行,目前仍然在继续开发维护的项目,让我觉得触目惊心,其中的代码,到处充斥着Martin Fowler所谓的坏味道,而又困惑重重,不知道别的项目代码质量是如何的。 下面就都只是随便举一下项目中的实际情况为例,项目是用MFC开发,使用了Codejock的Xtreme Toolkit Pro界面扩展库。 重复代码。有3处计算MD5的实现,分别由3个开发人员完成,大概实在是这种实现的代码在网上太容易找到了。另外有一个特性,可以与另一个服务进行文件的上传、下载、更新、同步,而文件因为类型不同,做这些操作时某些细节有细小的差别,但实现中却是为每一类文件具体而完整都实现了一遍这些操作。 过长的函数。有的开发人员就是习惯性地写出长函数。整个项目中,圈复杂度超过100的有4个函数,超过20的不知道是几十还是上百个。 过大的类。有一个类的cpp文件,是18000行,另外有一个类的cpp文件是10000行。还有CMainFrame类的cpp文件,用Source Insight打开后,在列出函数列表的窗口中显示“Too complex to parse”。 过长的函数列表。有一个cpp文件中共9个函数实现,每个函数的参数都超过7个,而且含义晦涩,自从原创人员两年前离职后,没人敢去动那块代码。 发散式变化。前面提到的一个18000行的cpp文件,是一个视图的实现。如果要给该视图的右键菜单中新增加一个菜单项,并进行响应,需要修改不知多少个函数,记得曾经有个开发人员,花了一周时间都在为了一个新增的菜单项。添加代码没花多少时间,时间花在添加后,因此引发的问题上。 霰弹式修改。有两个模块都需要一个高亮显示语法关键字的编辑功能。有一个基本的控件封装类,但要修改一些代码时,总是要很小心地去从头检查一遍另一模块的实现是否受影响。我的理解是,这个控件封装类的抽象不够通用,或者两个模块的相似度并不高。 基本型别偏执。这样的代码在项目中不好找,不过有类似的。项目中使用MSXML操作xml数据,在各个模块的实现中,都直接聚合了一堆MSXML的接口指针,操作xml的方法,和业务逻辑、界面响应完全混合在一起。 Switch结构。很多处又大又长的switch结构。 冗余累赘类。有两个(派生)类过于考虑以后的扩展性,而那种扩展性的需求至少在未来2、3年内是遇不上的。 夸夸其谈未来性。有一个快捷键处理模块,从项目刚开始就已经实现完成,但后来一直没被用过。项目没有开始实际编码前,超过5个人,花了2个月制订了各个模块需要暴露的COM接口,结果到现在3年了,真正实现的接口也才10个左右。 中间转手人。CMainFrame类已经成了各个模块用来转发消息的场所。一个重要的原因是界面与业务逻辑耦合,很多业务处理需要MainFrame转发到相应的界面实现类中进行处理。 狎昵关系。无论是各个Pane还是MDIClient,都与CMainFrame存在着这种双向依赖关系。 异曲同工的类。两个有交互的模块,居然各自定义了一组数据结构,用来描述现实世界中的同一种事物,中间又由CMainFrame来完成这两组数组结构之间的转换。 纯数据的类。很多时候,为了向线程函数传递一些数据(超过一个DWORD的量),就专门定义一个纯数据的类。 被拒绝的遗赠。两个平行的模块,一个类是从另一个类继承过来的,而明明有很多那被继承的类的功能,在派生类中是不需要的。呃,被继承的就是那个18000行的类。另外还有那两个需要编辑功能的模块,曾经居然也是一个类从另一个类直接继承,导致在派生类中变成不需要什么功能,就加些代码,把那部分功能屏蔽掉。 过多的注释,有一个开发人员,喜欢在自己编写的函数开头部分写上几十行注释,呃,全是算法描述和伪代码。 在公司4年,我参与过的略有规模的项目,除了这个外,另外有一个,基本是独自一人完成,代码量最高峰是7万行,后来路过不断的重构,在仍然有新特性增加的前提下,代码量缩减到4万多,现在回头看来,这个项目中代码的坏味道似乎少一些,但质量却也不行,崩溃经常发生,其他业务逻辑有问题的也不少。 所以,我就很是困惑啊,别人的项目是怎么样的情况?
几天没有正儿八经写代码了,今天又咬牙写了一会儿。在完成一个新功能后,开始重构原来的代码,把其中用于BOOST_FOREACH的地方都检查了一遍,看能不能重构掉。在刚有BOOST_FOREACH的时候,我还是觉得它很简单很方便很易用的,也许是当时觉得写for循环来迭代遍历容器步骤繁琐了一点儿。自从用上了boost::bind和boost::lambda以后,渐渐习惯了作用STL中的算法来操作容器,到现在,看BOOST_FOREACH都觉得很不舒服。 今天看到的几个BOOST_FOREACH,最后被我改得只剩下一处。其中有一处,需要用copy_if算法,而STL中明显是没有这个东东的,看《C++标准程序库》一书说的,如果要这样的功能,得用remove_copy_if,它是copy和remove_if的结合体。结果我开始用的时候没有仔细看它的使用说明,拿来便用,运行结果总是和我预期的刚好相反。我一开始总以为remove_copy_if,是先像remove_if那样,把满足op为true的元素都移动到容器的最后,然后把这些元素都copy到另一个容器中。实际上是我想差了,应该是它会把源区间内的所有元素都尝试copy到另一个容器中,在copy过程中会把满足op为true的元素剔除掉。我大汗,这个算法的设计实在不好,我就觉得很纳闷,当年那帮大佬们怎么硬是不提供copy_if呢? 回到家看了看boost sandbox中的algorithm库,里面已经实现了copy_if,以及其他几个很实用的算法,看注释似乎是作为TR2存在的,可能会加到C++0x中,但那实在是遥遥无期啊!
今天在Boost的开发maillist上看到有人在抱怨Boost Build系统的不好用,我难得耐下性子来看了看,其中提到好几个问题:Getting Start文档中没有明确的说明命令行;编译MPI库需要修改user-config.jam文件;与ICU一起编译Regex库会报静态链接和动态静态不兼容的错;解决了Regex编译时链接的问题后,用的ICU lib文件名却需要自己修改一下;编译Graph库时链接Expat时需要修改jamfile.v2文件来修改链接的lib文件名。除了MPI的问题外,其他的我也都遇到过,也都差不多自己解决了,我还真是个可以逆来顺受的人,虽然觉得很麻烦,但却想不起要求Boost来改进这些缺点。不过今天看到这个帖子后,感觉大快人心啊,哈哈! 顺便提一下,今天我找到可用通过cdb.exe来直接使用命令行对dump文件进行分析的的方法了,可以直接将分析结果在控制台上输出,这样就简单地利用管道将分析结果获取到了。这样基本解决自动分析dump文件的技术上的障碍,最多是要再自己写个小程序,可以分成两部分,分别是前端和后端。前端负责获取新的dump文件,可以是定时扫描某个文件夹,或者定时扫描email,或者通过其他的socket传输等,反正就是获取到一个新的dump,然后调用cdb.exe这个命令行,而后端则是将cdb.exe输出的结果重定向到其他地方去,可以是通过email发送出去,或者是写到数据库中,或是写到excel中,或是直接填充到WIKI上去。总之,现在怎么整都可以了。
前些天鬼使神差地换上了MinGW官方的4.4.0Release,当时也没怎么想什么后果,只是觉得这4.4.0无论是在语言上或者库上,都向C++0x靠近了不少,就应该拿来用用。昨天兴起,启动了CruiseControl,却发现其中一个用到了wxWidgets的工程构建不通过,依次修改,修改好几次,才终于搞定。 换编译器是件大事啊,boost要重新编译,wxWidgets要重要编译,这些都是比较正规的使用了C++的库,最近一次出错,是发现我的工程在链接时找不到一些符号,而其中一大批符号的名称中都有sjlj字样,想来是异常处理机制的问题了。上官网看了一下release notes,原来它把默认的异常处理机制从sjlj换成dwarf-2了,而我原来用的TDM-GCC是默认用sjlj的,所以只要全部重新编译工程就可以了。传说中,这个dwarf-2在没有异常时,是0开销的,不过TDM-GCC的网站上说,用dwarf-2前,要先仔细确认一下,该工程会链接到的那些DLL中如果要抛出异常,是用什么机制的,除非能保证它们也都用dwarf-2的方式或者干脆不抛异常,不然还是老实点用sjlj方式的好。不过我想,我在这方面的顾虑很小吧。
这两天在做一个特性,其中一段很经典的根据不同的类型id来创建不同的对象的代码,想到了《Modern C++ Design》中的那个实现,马上找来Loki用。 非常简洁的代码,定义一个基类,然后就可以根据类型id来创建对象了,如果创建对象的时候需要一些参数,也很容易,另外定义一个Loki::Seq就可以了。 每个派生类可以在源文件中用一个匿名的namespace保护起来进行注册,这样就彻底达到了只要加入该源文件,就有该类,不加入该源文件,就没有该类。不需要修改其它任何代码。 挺好用的!
本来我一直是觉得VS2008自带的Prefast在这方面的需求足够了,不过似乎老雷对于PCLint有着近乎宗教般的狂热信仰和崇拜,时不时地催促一下。 不过在公司里的项目中,折腾了不少时间,仍然没能正常使用,总是要么只输出一些头文件中的检测信息,要么就索性什么都没有输出。后来同事发现,这似乎是跟我们的代码包含的头文件关系太复杂有关,他从其他项目里随便找个cpp文件来,用PCLint就是很正常地检测了cpp中的问题。 昨天晚上回到家,从网上找到PCLint v8.00x,并从官方网站上找到最新的适用于v8.00的.lnt文件,然后开始PCLint的再次尝试。惊喜地发现,自己写的一个MFC小程序用PCLint确实可以正常输出些内容。但想想公司里的另外一个小项目,也是很简单的头文件包含关系啊,为什么就不能正常使用呢?最终还是没有找到确切的原因,太奇怪了,网上随便搜索了一下,关于PCLint的问题定位方面的资料几乎没有,全是些基本使用说明。 比较了一下,PCLint的速度真是慢得可以,似乎比Prefast慢很多很多。 在试用了PCLint和Prefast后,我发现它们对提高代码质量有客观上的能力和辅助作用,但我觉得人才是最主要的因素,我在短短的试用过程中,突然醒悟,很多时候是纯粹为了通过它们的检测而机械地修改代码,怎么能躲避它们的检查就怎么改,而完全丧失了作为一个有责任心有进取心的开发人员应该具有的致力于编写出优质无错的代码的积极心态,这实在是一件很恐怖的事情。再联想一下,对于衡量代码质量的其他静态指标,比如圈复杂度,重复代码行统计等,也有相同的问题。为了降低某个函数的圈复杂度,就无所不用其极地运用一些诡异手法,只是为了骗过工具的检查,反而降低了代码的可读性可维护性。 程序员啊,真是一个让人头疼的群体。
昨天开始,就有人发现最近的版本不正常,严重不正常,甚至都不能启动!这是个极端致命的问题啊,于是开始有同事着手定位。昨天没有进展,顺延到今天,今天上午也没有进展,下午的时候人都慌了,于是3个人投入进来定位问题。最初只是通过dump文件发现,在启动程序时,会自动加载文件,并通过正则表达式分析该文件,而这正则表达式使用的是boost::regex,可是在创建boost::regex对象时,它的构造函数就崩溃了,没有抛异常。那大量的时间就花在分析为什么构造函数会崩溃上。而且比较诡异的是,Debug版本是没有问题的,只有Release版本才不正常。于是全部人都切换成Release进行编译、定位。直到很后来,另一个同事发现,只要在该程序的任何处使用到boost的东西,就会崩溃!这没法活了!于是我们不约而同地想到,这应该是编译选项引起的问题。从回溯CruiseControl上的编译版本,发现最后一次表现正常的构建之后,有7次提交记录,才构建出下一个版本,范围可以缩小到这7次提交记录中。其中只有一次是我在工程设置中定义了一个预处理宏_SECURE_SCL=0,为了在VS2008的Release模式下编译过1.39.0版本boost::signals2的代码!把这个预处理宏去掉,并暂时注释掉因为没有这个宏而编译不过的boost::signals2应用代码,编译,发现一切又都恢复正常了! 该死的_SECURE_SCL,看来只能等1.40的boost了!
发现前段时间写的那些代码很不稳定,总是会崩溃!今天被人翻出来批判了一把,惭愧啊! 问题出在多线程上。一个编辑器对象创建后,会创建一个新的线程来分析编辑器中的内容,然后把分析后的结果保存在成员变量的。这时如果在保存结果之前,编辑器对象已经被销毁了,则访问成员变量也是不可行的,所以我在编辑器对象被销毁的时刻(析构函数中)强行打断线程的执行。 另一个问题,同样是编辑器对象创建后,要创建一个新的线程来分析编辑器的内容,然后根据分析后的结果,来对编辑器做些特定的操作。这里我使用了boost::signals2来进行通知,其实这不是必要的,用boost::function作为回调函数也是可以达到目的的,毕竟在我看来,使用boost::signals2的区别只在于它可以绑定多个接收槽。结果问题来了,boost::signals2的自动对象管理似乎只能依赖于boost::shared_ptr的对象生命期管理,而这boost::shared_ptr的使用在我这种情况下就比较棘手了,原来只是把该对象作为一个聚合对象实现,而似乎boost::shared_ptr的使用最好是从一开始就是在堆上new出一个来,并以boost::shared_ptr的形式保存起来,现在要改,也是有不小的工作量。说实话,在我看来,这样的接口,还不如boost::signals的trackable基类的实现好呢。而且另外还有个问题是,就算这信号-槽的机制真正正确起作用了,信号过来后,仍然是在一个工作线程中对编辑器对象进行一些操作,而这些操作进行到半途,如果编辑器对象突然被销毁了,那也是不行的,所在不得不在这个接收槽的处理过程中也加入线程中断的检测。 这样,貌似理论上两个问题都可以解决了。于是用boost::thread实现吧,它有比较方便的创建新线程的接口,可以方便地把一些参数传递给线程函数,这真是一个巨大的进步。其次,它有interrupt接口,可以在让线程被中断,有join/timed_join接口,可以绅士地等待线程结束。似乎一切都正是为我解决上面这两个问题问题准备的!但是,问题仍然困扰着我,居然,偶尔的interrupt并不能让boost::this_thread::interrupt_point抛出异常来,而这个“偶尔”实在在是太频繁了!还有,居然,似乎,偶尔join并没有真的等到线程结束就返回了!现有,这个join在等待的时候,会有死锁的现象! 我狂分特啊!到底是哪里出错了,而且这样的问题还都不是必然重现的,郁闷哇!
从网上找到一份Windows下的Intel C++ v11,装了来试了试,发现居然用bjam的话,不能正确为编译资源文件生成命令行,可是试了一下它集成在VC中的功能,似乎又是可以编译过去的,看来是bjam的问题了。在网上随便搜索了一下,也没找到什么有用的信息。打开Boost.Build.v2目录中的那些.jam文件,看不懂哇! 另外,boost也是需要单独使用icc编译了,才能为其所用,而且icc是和msvc一样可以支持auto link的,这点倒是不错。但是最不爽的是,wxWidgets似乎没有提供icc用的工程文件或者makefile啊,郁闷!
今天郁闷地发现,有一处代码,在CruiseControl上编译居然不过。很奇怪的是,在本地机器上编译是没问题的,而其中最大的区别就是本地以Debug模式编译,CruiseControl上则是Release模式。于是不甘心地在本地也以Release模式编译了一把试试,果然报错了。 那处代码很简单,就是调用boost::signals2的一个信号,明明白白Boost的文档和例程都是这么写的。于是拿出Boost的Example中的Hello World来编译,果然也不行。于是切换到VC2003去测试,居然过了! 同事通过Proxy上Google搜索了一遍,还真发现了有用的信息,居然是boost::signals2在1.39.0版本中的Bug,所说在SVN中已经修正了该问题,具体的信息可以从一个Google group的帖子上看到,另外一点有用的信息在CU的一个Blog上有提到,临时的解决方案也提到了,就是将_SECURE_SCL宏定义为0即可。因为暂时只有那个cpp文件中用到了这种用法,于是我在那cpp文件开头处添加了这个宏定义。但是这里又吃鳖了一次,在本地是能编译过了,在CruiseControl上还是编译不过,报的错也没变,说明那个宏定义没起作用。这时我就已经没有耐心再去仔细区别其中的差别了,差别大了去了,操作系统不同,编译器使用的SDK不同,鬼知道还有什么不同。最后抱着试试看的心理,把这个宏定义从源文件移到了工程设置中,终于编译过了! 估计那帮写Boost的人,主要还是用GCC来验证的吧!
如果胆子足够在,这两个网站上的都是值得试一下的,其中不乏一些好东西,比如日志库就有两个,一个叫Boost.Logging,一个叫Boost.Log。 https://svn.boost.org/trac/boost/wiki/LibrariesUnderConstruction http://www.boostpro.com/vault/ 对于进入boost的侯选库,有两个存放点,一个就是上面第2个地址vault,还有一个是boost svn中的sandbox目录。从Review Schedule中看来,似乎进入Review的库从vault中来得多一点,而sandbox又有点像boost正式库的一个draft。
这两天在抽空分析程序的崩溃记录,这些记录都按照版本号分别放在不同的文件夹中。早先exe文件的版本号并没有严格对应于svn revision号,周一时用一个修改PE资源的小程序搞定了这个事情,以后做这方面的事可要精确和省神多了。 今天分析到一个记录,印象中以前也有过类似的记录,一时没想起来,发现是一个线程函数数,对一个std::map调用find方法,结果在STL内部引起崩溃了。开始的时候,还以为是调用find方法时传入的参数有问题,引发了STL的某个未定义行为。于是另外写了个小程序简单验证了一下自己的猜想,结果不如自己所料。后来猜测要引用这个map的对象时,包含它的指针已经无效了。但为什么无效,我却也得不出什么结论。最后突然想到,从崩溃记录分析得到的最后堆栈信息中,看到是调用find方法后,find方法中取xtree的根节点引起的崩溃,那么是不是这个map对象本身就是有问题的了呢?灵光一闪,这个map对象是做为一个类的成员的,如果这个类的实例被销毁了,这个map对象自然也跟着被销毁,而这时如果再试图访问它,当然会有问题。 分析出来具体的原因,修改起来就比较容易了,在该类的实例被销毁时,应该通知那个线程马上结束,而且不要再试图去访问那些它的成员了。在修改这块代码的过程中,我应用了boost::thread,这大大简化和缩减了需要编写的代码。
什么Boost.DirectX啊,Boost.Debug啊,Boost.Cppgui啊,越来越疯狂了哦!
今天一个同事突然发邮件来说我的升级程序在生成文件列表时,给数字都以3个数字一段都加上了逗号,我狂晕!拿自己的debug代码试了试,发现果然如同事所言,看来是确定代码写得有问题了! 单步跟踪,最后发现我在把数字转换成字符串时,用了std::stringstream类的流输入方法,就变成那种样子了,稍微想了一下就明白过来了,以前一直都是没有逗号的,后来有过修改的地方也就是当时用ofstream写文件时,为了能支持中文的路径和文件名,在程序启动时调用了一句std::locale::global(std::locale(""));后来就有了这个问题。我狂分特啊,跟另外一个同事分享这个经验时,他还问我为什么不用boost::lexical_cast呢,其实据说boost::lexical_cast内部也是用的std::stringstream来转换的,哈哈!
说什么无法控制,说什么循环引用,说什么编译时间,都他妈的傻x。怎么不去关心一下CPU能不能控制,Windows能不能控制,还不是他妈的那儿老老实实用着。怎么不去用一下汇编,Fortran,狗日的哪来的循环引用。怎么不去用Debug自己输入二进制码,哪来的编译时间。 莫装B,装B被雷劈!
今天写代码,出了不少错,都是很低级的,状态不好啊。 先是连接一个MySQL数据库,从一个表中Select一些记录出来,死活没数据,还以为是SQL语句有问题,用其他客户端去运行,发现SQL语句是正常的。然后换了一条SQL语句,同样是Select的,发现又可以了,一步一步排查,发现是那个表中查不到数据,另外一个表中查得到数据,突然发现原来我连的MySQL地址不是我想要的那个! 接着是从XML格式的配置文件中读取配置信息,发现有的配置项好像怎么都读不出来,一直都是使用默认的值,后来才发现在判断值是否为空的时候,多写了个感叹号! 好不容易磕磕碰碰地调试通过了,编译了一个Release版本,用Inno Setup打了个包,放到目标机器上去运行,发现居然没反应,而且不巧的是我什么调试手段都没有,也没有什么日志。后来通过MessageBox发现,似乎配置信息读取又有问题了。然后发现如果是直接用Debug版本是正常的,于是想调试一下Release的,结果不知道应该设置什么选项,调试不了!只好通过OutputDebugString来打些信息出来。经过一番搏斗,发现原来我把装载配置文件的那条语句外面套了一个ASSERT,我狂晕! 以我现在的水平,状态好的时候,最多一个月也就能产1w行代码,而且代码质量还不能保证,唉,怎么才能让新写的代码跑得稳定呢!
今天在Boost的邮件列表里看到有人在项目中使用Logging v2,这是在去年3月时提交Boost后review拒绝的一个库,当时我也略微关心过,因为一直在找一个好用的C++日志库,最后看到被拒绝了,我也就有点死心了,用起log4cxx来,其实发现log4cxx也不是那么好用,而且最近公司里用的时候发现似乎会有内存泄漏的问题。 看到邮件列表里那人对Logging的评价很高,我就心动了,它有一个优点是header only,这是我很喜欢的一点。其他的灵活性之类的我也没用过,也不好评价。不过我决定了,先在自己写的这些程序中试用一下。
回到家,习惯性地更新了一下boost svn中的代码,从来都最多只看一下哪些文件更新了,至于具体更新了什么内容,却从来没有关心过,也不是我能关心的。 然后整了一下自己写的一些代码。 再之后是继续整前几天放假时写的一个小程序,结果突然发现编译不过了!开始还怀疑该不会是VC出问题了吧,重启了一下VC,没用!于是看了一眼出错信息,定位到出错代码行,是boost::signals2中的一个叫signal_template.hpp的文件中。众所周知boost的代码只有超人才能看得懂,而我很幸运地不是超人,所以就看不懂啦!折腾了一阵,也没有办法,后来猛然看到这代码中明显是语法错误嘛!我猛烈地faint啊,原来超人也会犯错儿呀!尝试了一下把这语法错误修正,结果编译时报的是其他地方的错了,这我就不晓得是什么原因了。无奈之下,为了能正常编译我的程序,只好回退到之前一次提交的内容去了! 目瞪口呆!
这两天看到TL里从MFC讨论到boost,无论是MFC还是boost,支持和反对的人都有,大打口水仗,我也是个不小的愤青,也去凑合了几下。 因为在公司里的项目用的基本上就是MFC,其中也穿插用了不少boost的东西。说心里话,至少目前我对它们没什么不好的印象,对于boost更是有种赞赏的感情,它在C++语言的基础上创建了那么一个通用的可移植的庞然大物,确实为我节省了不少工作量,这是最让我高兴的原因。 TL上的口水仗最后也沦为抓住一丁点儿瑕疵穷追猛打,实在无聊得紧。在我看来,这么一个东西,它确实对我有帮助,也许节省了10%~20%的时间,这就足够让我继续坚持用下去了。
今天跟一个同事讨论起在项目中使用boost::signals,发现有些情况下很适合,比如我们的程序有时候会做些耗时的操作,而且这些操作过程中可能会去访问子窗口,而子窗口却不一定继续有效,于是可能就会有问题了。原来的办法是保存好这些子窗口的句柄,然后给它发消息。但有了signals就可以稍微做得更好一点,把子窗口的类从boost::signals::trackable继承过来,这样子窗口对象销毁时,会自动把它从信号槽中移除,不再需要自己费心管理它是否有效。另外一点的好处,也是boost的各种类惯用的手段,做为回调,只要签名相同,即有唯一确定的返回值和参数列表,而不用在乎它最终是什么形式,全局函数也好,仿函数也好,成员函数也好,都可以作为回调。 从1.39.0开始,boost中有了signals2,相比signals,它有不少改进,但在我看来最主要的是线程安全和header only。其他的用法倒还是和signals一样。不过无论是boost::signals还是boost::signals2,似乎都没有办法解决一个问题,就是Windows GUI的多线程操作。还是得另外想办法啊! 烦躁!
偶然发现WTL已经出到8.1版本了,可是好像CVS里却没有更新,原来是已经切换到SVN里去了,还枉我时不时地update一下呢! 这次更新号称是兼容VC2008,结果我升级了一下,发现原来的一个使用WTL写的程序工作不正常了,居然接口行为都改变了,晕死!原来的8.0版本在VC2008下使用也没什么问题啊! 郁闷!
TDD中说的是要先写测试用例,再写功能代码,可是无论如何,我都做不到这一点,我无论如何都要先写好功能代码,再回头来写测试用例。 不过虽然这么做了,但我觉得还是不影响我做单元测试的,哈哈。今天是我将CppUnit换成googlettest以来第一次正儿八经地写单元测试用例,感觉还是比较爽的,有种写代码就是一种享受的感觉。用googletest可以比用CppUnit少敲不少字,而且我猛然发现,不用GUI的TestRunner,也没有什么不好的感觉。 通过单元测试来保证类或函数的功能,最适用的场合是算法性的代码,真是太安逸了。
早上起来看了一眼邮件列表,发现boost 1.39.0居然发布,这次好像测试都没有多少消息,怪不得前两天就有人在邮件列表上开始说要1.40.0的release building了,真是快啊。这个节奏还真让人有点手足无措的。 在公司里,用的都是正规release出来的版本,那样每次build出来的lib和dll一般都是没有问题的。而在家里,我都是直接从svn里check out来的,里面有的代码还存在些bug,有些则可能连编译都成问题。本来因为懒得编译的原因,我一直都是只用header only的库的,可最近因为公司里那个项目的影响,用了boost::regex、boost::program_options、boost::system、boost::file_system等的库,渐渐对这些需要编译的库也有点依赖心理了,防范心理也弱了不少,可是svn里的代码几乎天天有所更新,编译的话,就太头痛了。
今天在公司里看到google test和google mock,又好奇心起,看了看,觉得比起CppUnit来真的简洁不少,而且CppUnit没有一个好用的用于插桩的框架,那Mockpp和Mockcpp都有很明显的很影响使用的这样那样的限制和缺点,而google提供的这两个框架则比较好地解决了这些问题。 回到家又上网下载gtest试试,它有msvc的解决方案文件,也有GNU make的makefile。不过msvc倒是能直接编译通过,而MinGW则是不行的,要改些地方。首先要将MINGW的识别宏添加到GTEST_OS_WINDOWS宏定义中,然后在几处使用了SEH的地方,__try/__except都是VC才用的东西的,只要再在编译开关处把MINGW去掉。这样gtest库是可以编译通过了,不过有一个自测试文件gtest_unitest.cc却还是有问题,要加个文件头包含limits.h,这样就可以全部编译通过了。 又顺带看了一下googlemock,它依赖于tr1。在公司里,我什么都没修改,直接用VS2008编译过了,在家里却不行,总是报VC的xtr1common文件中的什么tr1没开启。上网找了下解决方法,加入boost就行了,不过我试了发现从trunk中取到的boost不知为什么不行,最后还是从googlemock的官方网站上下载到一个他们从boost 1.36.0中提取出来的tr1中tuple部分,这样在编译包含路径中添加boost和tr1的路径,就可以编译过了。但它在源代码中明确限制了只能使用VS2005或更高版本来编译,看来要用在MinGW中是有点困难了。
其实只是封装了其中很小很小的一部分,DOM的那部分,DOM中DOMElement相关的那部分。接口是模仿那个同事的MSXML封装类来的,应该说,只有最初的灵感是来源于那个MSXML封装类的,后面真正用得最多的部分,实际上已经是被我修改过的。其中最有用的部分是,对属性和文本内容的设置和获取,针对不同的数据类型作了特化,以及对NodeList部分增加了iterator来适配STL算法。 对于这个封装的意义,或者说价值到底有多少,自我感觉,至少在现在手头这个项目中,在boost::bind、boost::lambda配合STL算法的联动操作下,让代码少了好些,不过也许带来的问题是,可读性变差,以及不再去思考是否有其他更好的方案的惰性增加。
再次尝试,终于可以在WIND中使用boost::program_options了,其中付出的代价是,不能使用STLPort了,因为最直接的原因,不知道为什么,在release模式下,编译就会出错! 这之前提到过,用vc9编译boost时,会只生成几个静态链接库,而且这几个静态链接库实际上并不能正常使用,现在发现原来只要在编译前,在命令行环境中设置好vc9的路径,也就是先运行一下那个vsvars32.bat,就再进行编译就可以了。 这次编译我在命令行中添加了--buid-type=complete,耗时巨大,至少1个多小时还是因为磁盘空间不够而结束了。不过确实生成好各种类型的链接库,以目前program_options来看,共有7个库,其中2个是动态链接,分别有debug和release两个模式下的,从文件名中可以区别开来,debug下的文件名中有gd字样,而release下的是没有的。静态链接的库文件共有5个,都是libboostxxx.lib的形式,可以看到其中s表示编译器的runtime是静态链接进来了,gd则还是表示debug的意思,mt则是多线程的意思。所以照这个原则推测,其中有一个是单线程静态runtime链接版本,不过这对我来说,也没什么用了,一般说来,我写的程序肯定是使用多线程版本的runtime的。 终于搞定了,除了不能用STLPort有点遗憾!
今天去把那几个函数重构了,第一印象中用template method pattern是可以解决的,于是翻了下GoF,里面对template method的描述基本没出我的意料之外,还是可以理解的,不过可能是受限于当年的C++技术水平,也可能是其他未道明的原因,GoF中说是在派生类中用覆盖方法实现的。 我却认定了要用callback,因为我想用boost.function和boost.bind,于是三两下就搞好了,果然很简单,而且仔细想想,似乎相比用继承的方法实现,我现在的方案有一个优点是,可以把可变逻辑控制在更小的粒度上。比如本来我是一个算法的几个步骤,其中一个步骤是调用STL中的算法,而该算法需要一个谓词,这个谓词是可变的量,该谓词要被提取出来,这可以通过boost.function和boost.bind实现得像一个closure一样,在template method的领域内不需要知道谓词的具体实现形式,它只知道它接受一个boost.function,该function接受一个参数,之后返回一个值,至于到底是用functor实现,还是C global function实现,或是C++ class static function实现等等,它不需要关注,因为boost.function会打理好一切。而如果是用继承的方法实现,可能我就需要把那整个调用STL算法的步骤提取出来了,这样粒度就大了,就削弱了原本使用template method的意图和优势了。另外还有一种方案,还是用继承,只把谓词逻辑提取出来,STL算法调用时,用boost.bind来封装,但我想这是行不通的,因为编译期并不知道要调用哪个派生类的方法。 用boost.function和boost.bind实现template method果然安逸,design pattern果然只是一种思想,而不受限于实现,哈哈!
这个标题很恶心,不过暂时想不出更能容易我现在心情的话来了,就先这么着吧。我就是想表示一下对boost的崇敬和感激之情! 昨天发现用boost.graph可以解决我的问题。今天还是继续昨天的遗留问题,boost.graph确实跟STL那样,提供了抽象的,类型无关(真的无关么?我不确定,但我猜应该是)的算法,但是为了能用它,也着实费了我好些功夫。 我只是为了用它的DFS算法,找出一个有向图中的环。为了配合它的使用,我把之前的代码都丢掉了,重新写了一遍,不过逻辑似乎更清晰了。为了取得里面的back edge,要提供一个回调函数,而这个回调函数的参数类型都是模板参数,而这个参数却是包含了我需要的back edge信息。这就困扰了我大半天。翻了很久的帮助文档,也胡乱看了不少它的examples,最后终于发现有一个source函数和target函数,可以取出edge中的前后两个vectex。 解决了,就像一个同事说的,舒了一口气! 昨天还顺便统计了一下我在工程中主动用到的boost库,一共有9个,分别是utility、foreach、bind、function、lambda、graph、conversion、format、tribool,如果没有boost,我的日子应该会难过得多吧,呵呵。
偶然发现需要一个遍历有向图的算法,而且遍历不是主要目的,而是为了找出所有环。翻了一下《算法导论》和《算法概论》,对遍历算法有了个大概的印象,用DFS或BFS就可以,不过要找出环,就晕了。 同事说只要记住游走的路径,如果在一条路径遇到已经访问过的节点,就是环了。虽然说起来简单,但我想用代码实现起来我还是觉得吃力的。 另一个同事说,用boost.graph好了,我早想到了,但出于天生的那点畏惧感,总觉得没那么简单。抱着试试看的心理,看起boost.graph的文档来,惊讶地发现,原来这些常用的图算法都已经封装好了,只要以规定的格式准备好图的数据信息,然后调用一两个函数,就能实现遍历或找出环,实在是太牛了!
话说昨天被XML摆了一道,发现一种不同模块间交互的方式,就是使用回调。在早期的C语言实现中,回调函数的使用极其简单,Windows的API中就有很多使用这种方式的,可以是一个普通的全局函数,也可以是一个类的静态函数。在C++时,可调用体多了一种类成员函数,这种调用体在被调用时依赖于一个实例指针,因为编译器会自动在该函数的第一个参数前再插入一个函数,即实例指针,作为回调,就稍微麻烦一点。关于可调用体的封装和泛化,可以参考《Modern C++ Design》,中文版《C++设计新思维》。 昨天最后的结果是用boost.function,不过并没有发挥出它应有的作用,还是傻乎乎地把实例指针也传过去了,这跟直接使用原始的成员函数指针没有什么区别。后来想起来,有boost.bind的配合,可以把一个可调用体再作封装,以boost.function的形式而行为上类似于那些脚本语言的closure。在这个案例中,就是把实例指针绑定上去,这样另一个模块就根本不需要知道回调函数的原始类型了,无论是C风格的全局函数,还是类成员函数,在boost.function和boost.bind的联手作用下,都是一样的外表。这带来一个极大的好处,两个模块从此彻底解耦了。
前几天偶然lint了一把我在做的项目的源代码,结果发现近千个error。这让我比较困惑,大致看了一下,有不少是我并不期望它进行检查的,但又不能简单地把这类检查项屏蔽掉,所有就不知道怎么办了,lint应该是有意义的,但具体要怎么做,做到什么程度,我就完全没有头绪了,如果仅仅是为了减少错误项的输出而屏蔽检查项,那就失去lint的意义了。 我还是比较努力地希望自己能尽量写出一些优雅少错的代码的,也尝试在实际工作中使用一些方法和理念。今天在公司定位崩溃报告模块的问题,最后发现读取PE文件版本信息就有问题,但本来出于该模块的特殊性,很难直接在IDE里调试该模块,经过一些时间的折腾后,给取PE文件版本信息的类写了个单元测试,用CppUnit来跑,就算被测代码逻辑有问题,调试起来也方便多了!于是我又想到,这单元测试还真是个好东西,为什么我(们)就是不愿意做呢?我想主要原因还是在于,对TDD对项目进度的影响仍然没有足够的信心。另外再扯远点,我有点不想用CppUnit了,总感觉有点麻烦,现在这类框架倒也不少,google、Boost都有单元测试框架,其他还有什么UnitTest++、CppUnitLite等等,可选择的范围倒是不小,但我有一个顾虑是,这些框架输出的报告能不能像CppUnit那样跟CruiseControl日志合并呢! 另外再说说重构。我现在倒也确实有这样的倾向了,不断地在重构和实现功能这两个角色之间来回切换,也很习惯这种工作方式。看这个项目的代码,虽然没有翻天覆地的变化,但确实也有不少的改变,而且代码量也比最高峰时期少了20000行左右,这个比例不小啊,1/4多。不过我还是很明显感觉自己在重构这方面有待提高,首先是缺少理论方面的学习,然后再来考虑怎么应用到实际的编码中去。真的要抽时间好好读一读书架上那几本书了!
经过小小的思想斗争,最后我终于决定引入ACE,这个颇具盛名的跨平台网络库。犹豫是因为2个原因,一是我本来没有使用ACE的经验,如果在使用过程中遇到问题也没有求助途径,另一是以前在网上看到过有人说ACE跟MFC配合使用时会有内存泄漏的问题。 但是想了想,如果直接使用socket来写的话,开发效率更低,需要编写的代码更多,更容易出错。之前也是用了boost::asio,大概是因为没用好,反正不但代码写得难看,也没有能照预料中的那样正常工作。 同事在一个小程序中使用了ACE,虽然他用的是WTL,却仍然无形中给了我一种鼓舞,最终我还是决定用吧,泄漏就泄漏吧,反正只是个小程序,不会像服务器那样长时间运行的。稍微熟悉了一下reactor的使用方法,还算容易理解。它通过类继承,虚函数覆盖的方式来响应特定的事件。相比boost::asio使用functor回调的机制,更OO一点,而对于我来说,boost::asio可能多了需要对各种对象进行管理的工作。 争取在剩下的两天里,完成点对点文件传输的功能!
还是没干什么事,看了一阵书,话说昨天把《设计模式解析》第二版还掉了,其实旁边的同事又马上借回来了,于是乎我就拿来看看,看得囫囵吞枣的,不过也比直接看GoF的要省力得多。其实一直以来我都很少会认真仔细地从头到尾看完一本技术类书籍,很多书甚至是只看了前言、序,或者目录就直接丢到一边了。虽是这样,就算没完整看完一本书,像那种武侠小说中描述的那样,像我这样的小虾,向大师学习时,能领悟到个一招半式也是受用无穷的了。 到今天为止,大致了解了Adapter、Facade、Bridge、Strategy、Abstract Factory这几种模式。简单地说来,Adapter是为了转换接口,Facade则是为了封装并简化接口,Bridge说是把抽象和实现解耦,在我看来,实际是把几种不同类的概念分类,避免组合爆炸,Strategy是为了封装算法,Abstract Factory则是封装一系列相关的类的实例化过程。在阅读《设计模式解析》的过程中,我还发现一个比较明显的现象,有些模式,或者说有些解决问题的方案,其实都是通过将问题细化,将较细粒度的变化进行封装来实现的。比如书中讲述Strategy模式时,一开始例举的是直接继承,在论述了该例的缺点后,才抛出新的方法,其实就是把更小更精确粒度的变化提取出来并进行封装。在讲述Bridge模式时,也有类似的倾向和做法。再回想《重构》一书中,作者Martin Fowler则是更激进的做法,如果要给一段代码添加注释,则把这段代码提取出来,用有意义的函数名来阐述代码的作用。这从另一角度促使了小粒度代码段的生成。 《设计模式解析》一书的写作风格也是让人比较舒服的。作者会花一些章节进行理论或实际例子的讲述,再用一些章节描述模式,再讲述一些通用的理论,如此穿插的作法,反正我书看得少,正是第一次看到,感觉比较容易让人接受并领悟。
虽说好久好久以前就认识到设计模式的重要性,也好几次都决心要认真系统地学习一下,但是每次都没能坚持下来,每次看到GoF的书,立马一个头变成两个大,实在是枯燥乏味啊。倒是总能看到那么多人,学这么枯燥的东西津津有味的样子,然后头头是道是品头论足,心中不免有一丝的羡慕,什么时候自己也能那么熟悉并熟练地应用这些设计模式该有多好啊! 当兴趣渐渐从纯粹的编程语言技巧转移到架构设计、软件工程方面上来时,就有意无意地拿起《重构》、《敏捷软件开发》、《重构与模式》等书看。这些书有一个比较有趣的特点,就是互相引用,于是,我发现不懂设计模式已成为我前进道路上最大的障碍。我要进步,就必须要清除所有的阻碍,所以我要再次开始学习设计模式。 仔细考虑一下,为什么之前我每次都会放弃,是因为GoF那书太枯燥抽象了。所以要去找几本通俗易懂的书来先补充一下这方面的不足。《设计模式解析》第二版似乎还算入门级的,从公司图书馆中借到一本,抽空要快速看一遍。看网上的评论,《Head First Design Pattern》更加适合初学和进阶,所以要看看。另外,看到这些书中都提到了Christopher Alexander写的书, 有中文版《建筑的永恒之道》和《建筑模式语言》,这是关于建筑学的书,但是软件架构设计就跟建筑学有类似的地方,而且设计模式的起源据说就是从Alexander的研究中开始的,就当开阔眼界也好,也买来看看。 我并不是想做一个软件架构师,我只是想能轻松地写出结构优美,弹性十足,易于维护的程序来。
虽然几年前就知道SWIG了,但一直以来都没真正用过,又是一次叶公好龙。 今天在公司里跟同事偶然谈起项目里嵌入的Ruby解释器的问题,于是回来兴致高涨,决定研究继续研究一下CryptTool遗留下来的问题。 首先介绍一下CryptTool。这是一个可以使用多种算法计算文本或文件内容的hash值的小工具,最早的原型是几年前还在大学时写的一个计算文件md5的小程序,去年做一体化平台时,有一项内容是要用一个单向散列值来近似唯一地标识一个文件,所以顺便找了一个几种常用的hash算法源代码,包括md2/4/5、SHA1/224/256/384/512、haval3/4/5、CRC、GHash、Gost3/5、RMD128/160/256/320、Adler32、FCS等。回家用MFC写了一个,完成了多种算法计算的功能,当时突然兴起,觉得可以嵌入脚本解释器,实现外部插件扩展。结果只是实现了搜索指定目录下的脚本文件,并添加相应的项到主菜单中,通过菜单项激活脚本执行。连脚本执行都没实现,因为当时贪心,又觉得好玩,打算把Python、Ruby、Lua都嵌入进来,确实都链接进来了,却没有实际的功能。 再简单介绍一下SWIG。早先,我只知道它是用于嵌入和扩展脚本解释器的,但具体详细的作用却并不清楚。现在,我有了新的认识,SWIG主要作的是扩展脚本解释器时,将C++代码做一层封装,实现自动向脚本解释器注册相关的信息(如函数、变量、模块等等)。说起脚本解释器的扩展,大多数的资料,甚至连SWIG的帮助文档里,都是说的将C++代码编译生成动态链接库,然后官方的脚本解释器会载入该动态链接库,并在解释执行脚本时使用动态链接库中的内容。而我现在的需求,前面已经略有提及,是把我自己的exe程序里嵌入的脚本解释器扩展了,并且我要的是实现该扩展功能的代码是exe的一部分,而不是独立的动态链接库。两年前,用C++ Builder写过一个用于数据处理的小程序,其中就花了不少精力实现了嵌入Python、TCL、Lua,并扩展了几个函数,当时全部都是通过手工编写代码,按照标准的官方推荐通用作法实现,以至于连续近2个月几乎每天都是后半夜2点才睡,到后来精疲力竭,连上WC掀马桶盖都觉得异常吃力。 现在用VC实现嵌入和扩展理论上应该也不会有多少差别,只不过扩展部分是用SWIG完成的。先写一个后缀为.i的文件,定义扩展的模块名和扩展的函数原型,如果有变量也写上。然后在命令行中运行SWIG,用法行简单,命令行参数也很简单,因为是放在MFC工程中,所以理所当然地把输出限定为C++类型的代码。这里值得提一下的是,指定输出的文件名,用.h文件比较合适,它里面是一堆函数的实现,但并没有单独的原型声明,所以在实际工程中,只要直接include该文件就行,而不是当成源代码.cpp添加到工程,不然编译会比较麻烦。另外还有一点是,写在.i文件中的变量类型,不要用宏定义,而是用实际的标识法,开始我用LPCSTR和LPSTR分别表示const char *和char *,结果在脚本调用时,就会报类型不匹配,直接写成const char*和char *就没有问题了。再有一点,SWIG生成的代码中,会有一个初始化的函数,该函数完成各个扩展的登记注册功能,在EXE内嵌入脚本解释器后,需要自己调用这个函数。而且从该函数可以看出,Lua的就需要一个lua_State指针,说明Lua是能支持进程内嵌入多个解释器的,而Ruby和Python都是没有参数的,说明一般说来只提倡一个进程内嵌入一个解释器。 曾经看到有人(似乎是SWIG的作者吧)说,SWIG生成的代码可读性很差,今天我看了看,觉得还可以,需要关心的部分还是能大概猜出一点意思的,而其他的都是辅助性的代码,也就是完成实际的接口转换工作的。除了这个问题,还看到网上有人说过,SWIG实现的粘合层,在效率上会不如直接手工写的那种,今天我看这些生成的代码,觉得此种言论是立不住脚的,因为完成实际接口转换工作的代码都是固定的,应该也是SWIG的开发人员先手工写好的,在效率问题上并不是值得纠缠的。 用SWIG扩展exe内嵌入的脚本解释器,可以大大减少工作量,降低出错的机率,实在是一种值得推广的工具。比如最近在考虑的,在C++程序中实现一套仿Eclipse的插件机制,使用外部脚本实现程序的业务逻辑,这时用SWIG就可以直接将大量内部核心接口转换成内嵌的脚本解释器可接受的形式,极大地提高工作效率,对于使用COM接口的方案,真的是不太感冒!
TDD,即所谓的测试驱动开发,哈哈,我也开始用了。项目负责人花了两天时间总算建起一个可以正常跑起来的CppUnit工程,经过另外一个同事的验证,确实也能加入测试用例来跑。于是我兴高采烈地加入几个正儿八经的测试用例,结果发现用例是跑起来了没错,可是当从VC中想直接check in源代码到VSS中去时,VC就不干了,说两个工程不在同一个起始目录下。因为正式的功能代码是直接从原来的工程那里引用过来的,而偏偏测试工程是放在平行的目录下,因此有了这样的问题。万般无奈之下,只好亲自动手,把测试工程也移入正式工程的目录下,修改一下路径包含,一切OK,check in也没问题了。 几乎所有看得到的讲到TDD的书、资料上都说,在写功能代码前,要先写好测试用例。但是我发现直接这样做还是比较困难的,我现在的做法基本上是先想好,会有哪些功能类,然后就写好对应的测试类,再写好功能类中的成员函数声明,并用Visual Assist X生成一个空的函数实现,再跑到测试类中添加对应的测试函数,这样测试工程应该还是能跑起来。接着,我基本没按书上说的那样按部就班先写好测试函数内容再写功能函数内容,而是两边来回切换,一边写一点切换到另外一边再写一点,来回倒几次后,也基本都完成了。我不知道我这样做有没有什么不好的地方,反正用CppUnit这样做,进行单元测试确实方便,对于一些算法性的函数实现,直接在功能实现工程中往往不好测试,而放在CppUnit的测试工程里,则是再合适不过了。比如今天从别处抠来一段用WinINet进行Http下载的代码,略作修改,放在测试工程里测试,太方便了。 另外还有点体会是,设计模式是一定要学的,但总觉得GoF的《设计模式》看得太乏味,太枯燥,太艰苦了。Bob大叔的《敏捷软件开发》,Martin Fowler的《重构》都是要认真看的,还有《重构与模式》、《修改代码的艺术》、《反模式》都要好好看一下。提升个人能力,这些是必经之路。
今天又没动手,人越来越懒了啊!总是在想,既然功能基本正常,就不要去动它了。就像Martin Fowler在书中说的一样。感觉有心无力,唉,心中有那么一点畏惧和抵制。 不过后来花了点时间,在纸上乱画,针对自动联想功能,清理了一下设计思路。现在的实现真的是很C风格化,所有的代码都是揉合在一个类中,所以相关的功能都在这个类里实现。重构时,希望尽量向OO的方向靠拢,那些设计准则,也要尽量地遵守。 从现存的代码看,自动联想从表现上看,可以分为3类,分别是Auto Completion、Call Tips、Code Snippet。其中Auto Completion是通过已输入的几个字符,根据上下文环境,给出候选的可能匹配的完整token,Call Tips则是在当输入函数调用的实参时,以tooltip的形式给出函数原型以提示,而Code Snippet则是在用户触发了事先绑定的事件时,根据已输入的字符,或者也可称为命令符,自动以代码片段替换该代表命令的字符串。总之这3种特性都是为了减轻编码者记忆负担,减少键盘敲击次数,降低出错概率。 当前的实现是当打开一个文件时,或者截获到换行操作时,进行扫描,记录当前文件及其相关包含的变量和常量的定义,除了名称,还需要类型。这样在输入变量时,可以根据名称进行提示,输入方法时,根据类型可以从数据库是查询到相关方法。所以扫描是为了Auto Completion和Call Tips作准备,Code Snippet不需要这些。 当初实现这些特性时,只考虑到了Ruby语言,所以紧紧围绕着Ruby这个主题开展,代码几乎没留下任何一丝空间以供后续扩展。不过既然这次要重构,无论从设计角度,对象职责上看,或是以后要添加扩展新语言支持,都需要把这块代码剥离出来。一个重要的原则是,剥离出来部分不能再跟界面有耦合了,不然单元测试几乎不能做了。 界面部分还是全都放在控件类中,控件类调用Auto Completion、Call Tips实现类获取待显示的内容,实现类应该从统一从一个抽象类继承,每个实现类可以对应一种(或一类)语法。这里需要引入一个工厂类。原来的助手类应该拆分成两部分,即代码扫描分析部分和信息存储查询部分。其中代码扫描部分也有一个抽象基类,从它派生出对应各种语法的具体实现类,把扫描分析的结果存储到信息存储部分,同时,信息查询部分从信息存储部分获取内容,信息存储部分的数据一部分来自于扫描分析部分,另一部分来自于固有持久化层,可能是一个数据库,可能是一个文件文件,可能是一种外部输入数据结构。这样,任何一部分的变化,都会尽可能少地影响其他部分的实现,而且这些实现除了界面相关部分,其他的应该都比较容易做单元测试,自我感觉设计得不错,只是可能工作量大了不少,很容易让人产生放弃的念头,呵呵!
因为主工程是用VC9的,所以想用CppUnit的话,一般说来也是用VC9的。不过很郁闷的是,无论怎么弄,总是不正常,不是编译不过,就是运行就崩溃的,真是奇怪呀! 如果实在不行,就换用VC7.1来用CppUnit算了,毕竟照在公司里使用CppUnit的经验,在VC7.1下是好好的,可以有经典的红条,绿条,也可以直接输出测试报告到文件中,嗯,今天就先到这里,又费了一晚的时间!
自从知道CruiseControl之后,一直很喜欢这个东东。这回项目组里开始兴起XP、Agile、Refactoring这些东东,于是我就想着希望能尽可能地向书上、网上写的那样,把CI搞起来,现在这个CruiseControl只用来编译一个发布版本的,照他们的说法,不是持续集成,而是持续编译,而且这里连持续编译都算不上,因为不是自动定时轮循的,而是手工去点一下那个force build按钮。鉴于我一个人在做一个项目,中间也没人过问,极大的自由度,照负责人的说法,试验田。呵呵,这次我就把CppUnit和Code Metric集成了进来。 我首先弄的是Code Metric。工程是用VC++开发的,于是用了一个在公司内被推广的工具Source Monitor,开始时没有仔细看它的帮助文档,还冒冒然给作者发了封邮件,问他能不能提供一个命令行版本。作者还好,回了封邮件说,Source Monitor本来就是支持命令行的,可以通过写一个XML格式的命令文件,通过命令行进行相关的代码度量工作,简单试了试,果然可以,基本能满足要求。然后又看到Contrib目录下有几个XML文件,通过ANT来转换Source Monitor生成的XML文件,太好了,又学到一招简单易用的,通过几个xsl文件,把Source monitor生成的度量数据用html格式呈现出来,在CruiseControl中没找到合适的地方显示,就只好把这些svg、html文件都拷贝到artifacts目录下。 然后弄CppUnit。CppUnit其实是个好东西,好处不用多说,但坏处在于它是JUINT的Cpp port,所以某些第三方的支持就不如JUINT的好。比如ANT是直接支持JUINT的,CPPUNIT就不行。另外,CPPUNIT原生支持的XML导出测试报告并不兼容CruiseControl的输入。走了一小点弯路,在网上搜了一下,发现CPPUNIT有个Contrib下的xsl文件,可以把它的原生XML输出转换成JUINT的XML格式输出,于是乎,就可以被CruiseControl接受了,哈哈。便宜说一下,似乎正式发布的源代码包里是没有这个xsl的,但从1.11.0开始就已经有这个了,需要自己从CVS里找。
简单看了看log4cxx的例子,上网找一下相差的资料,它自带的例子实在是太简单了,虽然知道它源自于log4j的移植,但到底它移植度有多少就不得而知了。从网上找到的资料看来,log4cxx对log4j的配置文件支持就很完备,直接在外面写一个配置文件,程序中只要添加一行装入配置文件的代码,然后所有的修改只要针对配置文件进行就可以了,不需要修改程序源代码,真是方便至极呀。 尝试了一下给WallpaperHelper加入日志功能,对于这样一个完全不需要追求运行性能的桌面应用程序来讲,加入日志功能似乎只有好处没有坏处,至少可以在程序出现问题的时候根据日志记录定位问题发现的现场状况。 偶然上apache的网站看了看,自从我从svn里check out出源代码来编译了一把log4cxx以后,某一天居然正式发布了0.10版本,气愤,于是只好再update一把,重新把各个VC版本的都编译一把,这个确实让我觉得有点烦,这类工作最好完全自动化,自动从svn里更新代码,自动调用ANT来编译,而且要能自动应用多种版本的VC来编译,然后分类打包好,唉!CruiseControl本来是做这种事情的好东西,不过我却没有完成利用起来! 在boost的news group上看到,1.36版本居然不打算正式支持VC7.1了,晕倒,看来迁移到VC2008还是正确的哈!
偶然发现Boost已经发布1.35.0了,还是因为看到cppblog上有人写到怎么编译1.35.0才意识到的。最近已经不像以前那样对Boost狂热了,只是觉得它是个好用的类库,而且一直以来都是直接从SVN里取得最新的源代码,根本不关心它的官方release版本是到多少了。对于大多数的Boost库来说,不需要编译,所以任何时候从SVN里取下来的代码一般都是可以直接使用的,更加让我对正式发布版本的忽视。 先到news group上看了看,果然有发布公告,然后到官方网站看,只是提到一些新添加的库,其实这些库我好早就已经从SVN里取下来,压根就不晓得原来还没有发布,呵呵。
突发奇想,想编译log4cxx来试试。在官方网站上只看得到0.9.7的源代码包,这个源代码包是有VC工程文件的,可以直接用VC.NET2003打开升级工程文件进行编译,最后生成.lib和.dll文件来用。不过这不是我的目标,我想编译的是直接从SVN里取出来的代码,其实是偶然间看到硬盘上好久以前写的一个从SVN里CO出log4cxx源代码的批处理文件,里面只有一行内容:svn co http://svn.apache.org/repos/asf/logging/log4cxx/trunk loggin-log4cxx,随手点了一下就把文件都取下来了。看了它的INSTALL说明,就很想把它编译出来。 编译需要用ANT,要是在不久之前,我肯定直接放弃,不过前些日子搞CruiseControl时,也看了几行ANT脚本,至少知道ANT是用来做像make那样的事的。刚好CruiseControl中带了一个1.7.0版本的ANT,满足它1.6.1的要求。还需要cpptasks.jar和ant-contrib.jar,可以到http://sourceforge.net/project/showfiles.php?group_id=36177下载,解压到ANT的lib目录下即可。接下来需要apr和apr-util,不知道这是干什么的,但反正编译时会去找它们,把它们的源代码和编译好的二进制文件都下载来,因为我尝试用VC2003直接编译它们的源代码并不能正常通过,所以也懒得弄了,把源代码分别解压出来,命名为apr和apr-util,再到它们的include文件夹中,把几个后缀为.hw的文件复制一份后缀改为.h。 需要准备的东西差不多齐全了,在运行ANT进行编译前,先修改一下build.xml文件,里面有几处名为comment和dependency的节点,注释掉,不知道干什么的,反正我编译的时候这里会报错,注释掉后就能通过了,而且好像对生成的文件没什么影响。再看看该文件中为VC6编译写的一小段配置项说明:-Ddebug=[true|false]-Doptimize=[speed|size|none]-Dversion=n.n.n-Denable-shared=[yes|no] (default yes)-Denable-static=[yes|no] (default yes)-Denable-char=[0, 1] (expose char* API, default 1)-Denable-wchar_t=[0, 1] (expose wchar_t* API, default 1)-Denable-unichar=[0, 1] (expose UniChar API, default 0)-Denable-cfstring[0, 1] (expose CFString API,...
昨天晚上回来看news group上的消息,前不久提交review的Logging库被认定为unacceptable,所以暂时还是没有日志库用了。今天看到Logging的作者说,打算再根据这些review意见写一个新的,估计在七月中下旬提交review。 一直需要一个好用的日志库,但看来看去都没有觉得满意的。ACE太庞大了,日志功能只是一个辅助,log4cpp和log4cxx不知道哪里惹到我了,就是有很大的抵触情绪,不想用。于是一直在等待Boost::Logging的问世,谁知还得等待。 希望不会让我等太久。
继续捣鼓CruiseControl,从头到尾看了一遍Config Reference————的目录,发现有几项东东还是挺有趣的,主要集中在所谓的“持续反馈”部分。CC能支持Email通知是早就知道了,在公司里都偷偷用公司的SMTP给notes发过,只是后来想想公司那么刻板的信息安全问题,立马取消了。今天看到有一项是htmlemail,说是可以支持发送htmlemail,以前虽然在书上或网上也看到过截图,它能把Buildresult以在Web浏览器中看到的形式发送邮箱中。但我却发现自己的都只能发送一条链接信息过来,很奇怪。 本来都快放弃了,隐约都开始怀疑别人说的真实性了,后来偶然发现控制台里的输出信息,说是找不到那些个XML格式的日志文件。再后来突然想起来,它怎么跑到CC所在目录下的logs目录中找那些日志呢,我明明把路径都设置到其它地方去了啊。不过这样也好,至少知道可能是因为这个问题引起的不能发送htmlemail了。于是马上把日志目录再次改回CC所在目录下的logs目录,再试一把,果然OK啦! 再看,CC还能支持把build result发送到blog上去呢,不过我试了一下这个在blogger.com上的blog,没成功,我估计是因为CC要求的XML RPC地址没写对,我找不到哪里有这个地址,先不管了,呵呵!
在家无聊,看到CruiseControl里的东西就想整一下,一直以来只是抄袭了同事的脚本在这里跑,只能手动地去点击一下按钮才能激发,想着就不舒服。从网上搜了点资料看看,实在是找不到有用的,于是再回来看自带的帮助和自带的例子,偶然发现,虽然命令行中老是输出一堆一堆的内容,其实对于出错的情况还是解释得比较清楚的,尽管不详细。仔细调试配置脚本,终于可以定时轮循VSS中的文件并做出相应的响应了。其实非常简单,只是以前一直没有静下心来搞而已:
<listeners> <currentbuildstatuslistener file="${ccworkspace}/logs/${project.name}/status.txt"/></listeners><bootstrappers> <vssbootstrapper vsspath="${vsspath}" ssdir="${ssdir}" login="${username},${password}" serverpath="${serverpath}" localdirectory="${ccworkspace}/projects/${project.name}"/></bootstrappers><modificationset quietperiod="30"> <vss ssdir="${ssdir}" login="${username},${password}" vsspath="${vsspath}" serverpath="${serverpath}" dateformat="yy-MM-dd" timeformat="HH:mm"/></modificationset><schedule interval="600"> <ant antscript="${antpath}" antworkingdir="${ccworkspace}" buildfile="build.xml" target="wallpaperhelper_All"/></schedule>各节属性的作用都可以查看CC帮助了解,只要把该填的都填好,就基本上没什么问题了。用VSS跟用SVN或CVS还是有一点区别的,网上很难找到用VSS的例子,好在也确实不复杂,呵呵。 解决了这个问题后,我就开始得寸进尺期望CC能在后台运行。CC自带的解决方案是用一个叫Jetty的应用程序服务器,然后通过JAVA来运行。从这里可以看出,应该是能用Tomcat之类的其它的应用程序服务器来运行CC的,而Tomcat又能跟Apache配接在一起用,所以我觉得大概这是最好的方案,不过就是对于几人几十人的小项目来说,似乎有点杀鸡用牛刀了。其实再看一下那个启动CC用的bat文件就能发现,只要预先设置好几个环境变量,然后就能在后台用JAVAW.EXE来启动CC了。这里还有一个问题是,CC启动时,会在当前目录下寻找config.xml文件,所以一定要把config.xml文件放在它找得到的地方,我的办法是给这个命令行建立一个快捷方式,然后把开始位置设到config.xml所在的目录下,把这个快捷方式放到开始菜单的启动文件夹中,就可以让CC随着系统而在后台一起启动了。但是,后台运行也有一个不好的地方,不能随时看到CC最新的运行状态,通过浏览器的信息总感觉有些许延迟。
网上随便一搜就能找到一堆一堆的文章,讲述如何使用xUnit进行单元测试,虽然我这个标题也的是用CppUnit进行单元测试,但我不会重复一遍n多先辈们说过的话,因为即使说了,也肯定不如那些话来得精准、全面和专业。 今天花时间看到一下CppUnit自带的例子,结合以前在书上看到的,我意识到,测试用例确实不能跟项目代码混在同一个工程里。于是我把其中一个例子的代码全都抠出来,把我那些测试用例放到里面,然后生成一个TestRunner,嗯,基本完美解决了,呵呵。原来也就这么回事呀,嘻嘻!
今天偶然发现,用boost::bind传递了一个std::vector的引用过去,想在那个绑定的函数里修改这个std::vector的内容,结果居然在函数里的好像是另外一个容器,对外面的那个std::vector压根没有影响。幸亏发现得早,但也已经写了好几处这样的代码了,不过总算都改过来了。 也不知道是我哪里用错了,还是boost::bind本来就不能支持,晕!
经过几个小时的努力敲打键盘,终于让自己的数据结构支持std::for_each了。昨天我是过高地估计了其实现难度,其实看看for_each的实现代码,非常简单的算法,只要能让iterator支持前置++和提领(这是jjhou的叫法,就是对指针取值)操作符即可。这些内容昨天就知道了,但是自己没有动手做完前,总是心虚的。 实现过程基本上还算顺利,虽然老是编译不过,但VC的提示信息很详细,准确性也很好。在这个任务中,我觉得最好iterator不知道指向的类型,STL就是这样做的,也不是为了什么软件工程或者代码美感方面考虑,而是这样做对于实现者来说似乎更容易理解。 我在中间也犯了个比较严重的错误。因为NodeList已经被封装成一个类了,而我的设计里,iterator需要保存对NodeList的引用,所以我就很习惯成自然地用这个封装类了,另一方面,因为需要,NodeList封装类中也需要这个iterator类型,于是就成交叉引用了,编译都过不了。后来才想到,在iterator中使用封装类并没有得到多少好处,反而似乎增加了实现复杂度,直接用MSXML中的原始类型就行了。 嗯,略有收获,呵呵!
今天看到代码中有很多处遍历XML DOM的NodeList中所有元素的操作,同事用MFC的CString在MSXML上面又加了一层封装,使得MSXML用起来更加方便,但在这个NodeList的封装上,遍历操作只有通过next方法,或者以索引号遍历,我开始用他这个封装时抄的他的代码,都用while循环next方法来遍历,现在看多了,就觉得不爽了。刚好这个项目中因为用了Boost中的bind和lambda库,所以大量用了std::for_each算法,于是就想这里的遍历操作是否可以转换成用std::for_each来实现呢? 以前没做过类似的扩展STL的事,所以没有经验,不知从何开始。看了一下几本经典的STL相关的书,大概了解到要自己写个iterator类,这个类需要能支持++、--等操作符,然后NodeList的封装类也要加一些STL风格的方法,比如begin、end、size、empty等。虽然已经有所了解,但动手的时候还是没什么思路,搞了一个下午,也只弄了一点点,还没涉及到核心部分。 我对STL、GP的了解还是太少了,真应该好好学习一下,毕竟仔细想想我还没能非常熟练地掌握并使用一种语言及它主要的程序库,现在看来我只有对C/C++稍微有点基础了,但对标准库的了解却很肤浅,虽然之前也一直要用C/C++写代码,但是没怎么使用标准库,现在在重构等思想的熏陶下,不自觉地希望写出优雅清晰的代码来,好好使用标准库正是其中一种方法。
昨天在小卖部买了本持续构建的书,后来又看了一天敏捷方法的资料。今天突发奇想,想要在我的工程里加入单元测试的代码,工程是用MFC的,所以很自然的想到用CppUnit,Boost压根就没被我想起来。 之前有过好几次想学一下CppUnit的使用,可是最后都放弃了,每次放弃的原因都一样,静不下心来,觉得太麻烦了,不知道从哪里开始。今天就先问了一下旁边的一个同事,他告诉我只要从某个类继承,就可以写测试代码了。然后看了看Impeller中的代码,尝试着给我的工程里加入使用CppUnit的测试代码,一切顺利,太好了。这样也算是又学会了一项技能吧,哈哈!
其实我根本不懂什么叫持续集成,为什么要每日构建,但是我还是很喜欢用CruiseControl,我喜欢让它能为我写的每一个程序都构建一个项目。其实我也根本没怎么利用CruiseControl的多少功能,我只是让它在我点击按钮时从VSS中下载源代码编译最后打包而已。 今天下午花了大概2、3个小时的时间,把我在做的那个项目放到组内服务器上的CruiseControl上去了,因为是我在自己本地建了一个VSS库,所以先要把VSS库的目录共享给服务器,然后慢慢配置ANT脚本,而且相比我自己的机器,服务器上少了很多东西,比如没有Xtreme Toolkit Pro,没有Boost,没有Inno Setup,没有doxygen,没有upx。一一复制过去,经过10来次的试验,总算大致可以了,但还是少了用doxygen生成文档的步骤,后来想想暂时也不需要让人家看到这个源代码的文档,所以也先搁下了。 回到家,也暂时不想写代码了,就整一下自己机器上的那份CruiseControl,上次系统还原后,移动硬盘再接上去后,盘符全都变了,我也不想再冒险去改。改过脚本里的一些东西,但原来的那个编辑器的项目还是没能全部一次pass。今天仔细改了改,不光可能是CruiseControl脚本有问题,连VC的环境配置也有问题,当时没把一些必要的路径设好,比如Scintilla的头文件路径,Xtreme Toolkit Pro的路径等等。顺便把SocketHelper也加上去了,心里那个舒服呀!其实我对ANT脚本没了解,里面很多写死的路径,每次如果有变动,要改很多地方,这是很让人郁闷的。
Boost中的Regex需要编译后才能使用,这让人觉得有点难过,而且相比Greta,Boost::Regex居然默认是不能直接支持宽字符的,而且有个同事在那里抱着快是10年前的性能比较结果,说Greta比Boost::Regex好,真是让我觉得很不爽啊。 不过不爽归不爽,有些固有的缺陷我们还是要面对的,就说对宽字符的支持吧。看Boost::Regex的文档,只要有ICU的支持,它也是可以的。今天我就下定决心,要用VC7.1编译一个出来。 首先从ICU的主页下载,有源代码包和几个主流平台的2进制文件包,目前最新的稳定版是3.8,不过3.8版的VC解决方案文件是for VC8的,而且连可以下载的2进制文件都是用VC8的,真郁闷,IBM那帮家伙真是不会做UCD啊!退而求其次,用3.6版的好了,它的解决方案文件就是for VC7.1的,其实我猜直接拿它的编译好的也可以用,不过自己编译的心里舒服。编译ICU很简单,什么错误都不会有,直接通过生成一堆的DLL、EXE和LIB文件分别放在bin和lib目录下。然后可以开始编译Boost::Regex。 一般说来,编译Boost用Bjam,如果没有Bjam可以直接上网下一个,或者自己拿它的源代码编译一个。然后在命令行下,转到有Jamfile.v2文件的目录下,输入bjam回车就可以了,如果要编译所有的Boost库,则可以出去逛一圈,或者睡个午觉。我这里只编译Regex,不过很遗憾的是,用Bjam直接编译我并没有居功。偶然发现相同目录下还有个vc71.mak文件,打开看看,里面有个ICU_PATH预定义选项,后面写上icu所在的路径即可,它会自动找到下面的bin、lib、include目录,不用担心。然后先运行一下vcvars32.bat,再输入nmake -f vc71.mak回车,它就会生成一堆的dll和lib文件,而且最后还会自作主张地复制到VC的bin和lib目录下去。 搞定!
今天突然想起来,要一个同事教我怎么冒烟。项目组里用的是CruiseControl这个持续集成框架,通过编写xml格式的脚本,可以让它自动从版本控制系统里获取最新的代码,自动编译,自动打包,最后进行发布。同事大致给我讲了一个需要进行修改的三个xml配置文件的用途及里面一些元素的使用方法,然后我就开始在自己的电脑上进行实验,开始遇到一点困难,怎么都弄不好。先是要用它来启一个Web服务器,好像自带的是apache,因为要用JSP,还要用ANT,所以还得装JDK,装好JDK却不知道还得在环境变量里添加一个JAVA_HOME设到JDK的目录去,所以总是连网页都显示不出来,后来在同事的指点下,设好环境变量,页面终于出来了。不过取代码、编译、发布的过程总是失败,最后发现,好像是首先,指定的路径不能再空格,即使是使用8.3格式也不行,然后,得小心地设置各个源代码、工程等的存放路径,这样才能继续,保证编译时能取到正确的工程文件。其实到后来才了解到本质,就是一堆命令行的集合,只不过有些常用的功能它提供更方便的命令来执行,比如文件操作、版本控制管理系统操作等等。 现在,我给自己也建了个本地的CruiseControl,可以每天冒烟了,哈哈,这有一个好处,每天可以自己设定一个时间,然后让它自己运行,编译完后执行安装程序的脚本,制作好安装包,再压缩打包,最后就是一个完整的程序包。 仔细想想,转项目部后的近半年,还是学了一些有用的东西。比如除了这个外,还有MFC编程,至少现在能用MFC+Codejock的库写些简单的程序了,使得我现在几乎完全放弃使用C++Builder/Delphi了。对COM编程也有了很肤浅的了解,对Scintilla的使用方法的了解……等等等等,说不定对我以后都有帮助。 现在要做的一体化平台已经决定用Boost了,老大应该也不会太反对了,因为我的方案已经基本确定,Demo都给他看过了,现在可以好好使劲用一把Boost中的一堆堆让人眼花缭乱的模板了,哈哈哈哈,真是开心!
在maillist上看到review result,估计没什么意外的话,UUID库应该是要被接受到Boost里去了。这样的库有时候还是挺有用的,像我这次做的东西,为了测试方便,专门写了个函数可以调用Windows下的CoCreateGuid来生成一个高度离散的值,转成字符串来用,呵呵。不知道Boost接受一个库是依照什么标准,这次看到这个库在被review到后期,有人提到几点,首先是license问题,其次useful,再次performance,还有security,好像还跟作者的积极程度有关,有人发现了bug或提出了建议,作者能及时积极地修正和回复。Boost真是个好玩的东东啊,不过我现在的感觉是,Boost不适合企业等正规场合使用,而是适合个体户或爱好者用用,因为它变化得太频繁! 昨晚11点就关了电脑,然后花了一个小时飞快地翻了一遍《应用密码学》,了解了一点最最基本的概念,打算有空了整个Crypto库来玩玩。 公司里的事弄得头昏脑胀了,从VSS2005的ssui.dll里找了几个对话框资源出来加到自己的项目中,工作比想像的大多了!每个对话框都有10来个控件,要写各种事件处理的代码,唉!实际的功能却还是没进展。另外那个SharePoint的事老大又来催了,还要我下周三就拿出个样子来给他看看,他是心急了啊,还以为多好玩的东西呢!跟室友简单地交流了一下,他说我是没有做设计,所以很乱,而且还说如果没写设计文档,应该一天的代码量要一二百行,我说我一个月是写了约3000行啊。 熬过这个六月,应该就都会好了吧!
在经过Beta、RC后终于在5月12日在主页上宣布1.34.0发布了!相比之前的1.33.1改动是比较多哈,当然,加入的新库都是些小规模的,好在不用编译,哈哈! 昨晚堂哥告诉我二伯被人砍了,今天打电话去问候了一下,背上、头上、臂上各中一刀,所幸都没中要害,力道也不致命,那种凶手真是猪啊,老大的年纪了脾气还这么坏,这样的大人都教育出什么样的小孩来呢! 参加一个正式的项目对人的锻炼还真是有点用的哈,至少我现在知道有序列图,UML图这些东西了,哈哈,而且逼得我用MFC写程序,确实不知道为什么,用VC写代码风格总比在BCB下写的好看,呼呼! 用StarUML来建模,呵呵,只要开源软件足够好用,还是很能吸引人的。 从微软的网站上下了个XML Notepad 2007来写简单的XML文件,也挺好用的,至少比直接用UltraEdit来写方便多了,哈哈,这也是免费的。 关键是这些工具比起那些商业付费的同类来说,很小巧啊,而且功能上已经能够满足我目前的需求了。但是有些软件是不得不用D版啊,比如Office、VS、BDS……
这算不上最新消息,因为从Boost Develop的maillist上看都已经是前天发出来的消息了。上周C++标准委员会在英国Oxford召开了一次会议,主要是为了能在今年秋季时在Kona召开的会议中完成标准的草稿。完成草稿后,就会发布给ISO的成员国以及公众,以便收集各方的意见,这将持续1年时间用于处理各种意见。然后就可以发布正式的标准了,而ISO还会再经过1年时间对这个标准进行批评认可。 在csdn的blog上还看到过有人兴奋地谈到,这个C++0x说不定是C++07,这样看来,如果以ISO发布的时间点看,应该是C++09了,呵呵。 之后,照安排,C++标准委员会还会有几次会议: - July, 2007, Toronto, Canada. - October, 2007, Kona, Hawaii, US. - March, 2008, Redmond, Washington, US. - June/July, 2008, Sophia Antipolis (Nice area), France - October/November, 2008,...
在看《Conversations》的时候,看到有一章,专门讲到了Boost::any,不禁又勾起我对Boost的敬佩之情。 打开any.hpp,看到any类的实现非常简单,2个构造函数,1个拷贝构造函数,2个赋值运算符重载,1 个指针类型的成员变量,以及几个辅助函数。可正是这样一个简单的类,实现了极为巧妙极其方便的功能。看看C++对COM中的Variant的封装,把各种 想得到的数据类型都嵌入到union中,同时需要一个附加字段来指定当前实际的数据类型,代码看起来不但臃肿冗余,而且也不好用。 来看看any的实现代码,首先它是被放在boost名字空间的,其次,any当然不是一个模板类,不然在对不同的数据类型实例化后,不能方便地以统一的类型表示了: class any { public: // structors any() : content(0) { } templatetypename ValueType> any(const ValueType & value) : content(new holderValueType>(value)) { } any(const any & other) :...
今天在各处blog闲逛,发现有谈到asio的,这个在很早前就听说过,Boost想要合入一个网络应用开发库,于是提到了asio。以前这方面只听说过ACE,但想想也知道不可能把ACE合入Boost,一是,ACE太大了,源代码压缩的体积超过现在所有Boost库的合集,再则ACE的实现方式跟Boost的风格截然不同。 看到asio已经到了可以实用的阶段,我也索性再多看几眼。asio和其它的Boost库一样,只有头文件,而且唯一的依赖就是C++标准库和现有的Boost库。看了看从CVS取出的最新Boost代码,里面已经有asio了,但文档只有用BoostBook格式的,从它的官方网站上看到还是有html格式的,还是比较完整的,像是用doxygen生成的,照我说来,Boost里的众多库帮助文档的风格太不一致了,连表现方式都不一致,有的是html的,有的是BoostBook的,有的是man的,不过虽说不一致,它们的内容还算是详细的,但像asio做的,好像没有其它的了。 以后要是Boost有个日志库了,那就可以彻底不用ACE了,呵呵。不过还不知道asio什么会被合入进来呢,最近在maillist上也好像没有特别提到这个库啊。
今天跟同事谈起我看过的C++方面的书,说到《C++设计新思维》,我说只看过前面7章,后面的几章因为涉及到设计模式了,我又不懂设计模式,就看不下去了。同事说,设计模式一定要懂啊,对写程序很有用,设计好了,再怎么绕也不会出错。想想也算是有点道理吧,回到家,看到沉睡多时的GoF《设计模式》一书,不禁有点感慨,想当年在学校,确实也是精力旺盛,还特地从图书馆借出来复印了整本书,不过当时大概也是水平不够,大部分内容基本上看不懂,根本不能理解作者的意图。后来进了公司,从另一位同事那买了本二手的,书保养得很好,大概他也没怎么看过吧,毕竟要能从头到尾把23种设计模式都玩熟了,对人本身的基础要求就比较高,一般要么是程序设计狂热爱好者,要么是肩负架构设计重任的架构师,其他角色的人,实在提不起多少信心吧,呵呵。 这次下决心了,在6月底之前,至少要把书完整看完一遍,对23种模式有个大概的了解。 白天在公司实在无所事事啊,又发呆了一天,虚度光阴啊!把Boost的帮助文档打包成了一个CHM文件,也挺无聊的。我现在对技术方面,只对C++还残留着些许的兴趣,而且主要是泛型编程方面。两大宝藏STL和Boost是必须要研究的东西,所谓不光是技术的宝藏,更是思想的宝藏,呵呵。回家看了看Boost的maillist,有人决心要做一个日志库,这让我觉得有点高兴。我就很需要一个好用的日志库,以前看过ACE里的,觉得很好,不过一来ACE这个库太大了,二来不知道为什么我在和VCL混用的时候,编译就会出错,后来就再也没碰过了。曾经也冒出过“自己写一个”的想法,不过实在不是很实际啊,看了maillist上他们的讨论,要做好一个日志库真的有很多超出预计的困难,就等他们了,嘿嘿。 另外还有件事,今天才发现,newsgroup上很多人都在学习C++下一个标准中的特性了,现在大概只有gcc 4.x的某些alpha版本能支持一些特性,但人家确实也写出了那样的代码了,tr1的内容赫然列在maillist上。于是又想当一回追星族,翻了几大C++网站,包括Bjarne的网站和C++标准委员会的网站,搜罗了一堆建议、草稿,准备好好研究一下。这样想想,我们国内的技术水平大概永远也赶不上国外吧,那样的大师怎么也不会出在中国大陆吧,唉。
可以编译出很小的可执行文件来,跟SDK写的有得一拼,而开发效率比SDK当然要高出一大截,估计和MFC差不多吧。是个值得一学的东西,只是最近很懒,呵呵。
昨天说到,用Borland最新的C++编译器在编译模板的时候,对于成员函数模板的情况,如果只是函数返回值是模板参数时,是不会自动选择对应的特化版本的,而一直使用泛化版本,而VC至少8.0版是能自动选择的,记得当时用7.1写TclSuck时也用到了这样的特性,所以应该也是直接支持的。 不过,现在发现了让Borland编译器也能自动选择的作法,其实很简单,只要在成员模板声明和定义的地方加些东西就可以了,仔细看下面的代码,比较和昨天的代码的不同点,呵呵: class kk{public: template<typename T> static T test() { T t; cout << "general edition" <<endl; } template<> static int test<int>() { int i; cout << "int edition" <<endl; }...
现在的新问题是,编译器不能编译显式特化泛化类的成员函数模板!从BDS的联机帮助上看到,这是编译器显式禁止的。郁闷!也就是说,LuaTinker中的代码,是不能直接用上来的!唉,真想不用BDS了,用VC不就行了。可是用VC的话,我只会用SDK,画界面真的太费时间了!其实还有个办法,就是好好学一下C++的模板元编程(template meta programming),再自己写一个好用的C++ Wrapper for Lua,呵呵。看几本书:《Modern C++ Design》、《C++ Templates》、《C++ Template metaprogramming》;研究几个源代码:Boost、Lua、LuaTinker、LuaBind。 有点多哟!
用的是BDS2006,看版本号是5.82版的编译器了,相比以前即BCB6里带的编译器,虽然没有评估过有多少改进,明显的只是编译速度较之以前大大提高了。今天为了LuaSuck,一边改LuaTinker一边编译,发现它居然对成员函数模板的特化视而不见! 用的BDS2006里的编译器,这样试一下: class kk{public: template<typename T> static T test() { T t; cout << "general edition" <<endl; } template<> static int test() { int i; cout << "int edition" <<endl; }...
Lua5.0和5.1的区别还是有一点的,用LuaTinker的时候,它是为5.0版本设计的,改成用5.1的编译链接后,连例子程序都有点问题,不过大部分的功能还是都实现了的。但是,可恶的是,不知道为什么,在用Borland的C++Builder进行编译时,总是出现Internal Compiler Error F1004,连一点可参考的信息都没有,郁闷啊!不知道是哪里出问题了! 不过对于怎么使用Lua与C++进行交互,在阅读LuaTinker源代码的过程中,又有了一点新的认识,呵呵!而LuaBind似乎就太过复杂了,还用了Boost里的不少东西,包括MPL、TypeTrait等等。先就只研究一下LuaTinker吧,呵呵。
在看LuaTinker代码的过程中,惊奇地发现,它居然用了可变数量的模板参数!!这个这个这个,对我来说,不啻于晴天霹雳,《Modern C++ Design》上可是写着“Variable template parameters simply don't exist.” 我打开VC2005又试了一下,明明白白,VC7.1到VC8,都是可以这样用的。到底是哪里出问题了,谁错了…… LuaTinker在处理C++ free function的时候,是把pointer to function当作light userdata压入了virtual stack,网上到处都流传着一份不知道从哪里散发出来的用proxy手法解决的方案,感觉不如LuaTinker的爽。
基本上没怎么费事儿,比原先想象的工作量要少好多,甚至处理分发函数和map都是用的同一个。就是保存函数指针的实现跟原来的不一样,从R (*f)(...)这样的形式变为R (C::*f)(...)这样了,多了一个C,其它就是一路走下来,没什么难点。 而且,顺便把tcl_state::close()改了一下,刚好可以用来释放map里保存的那些东西。 不过,还是没想好,怎么实现functor的调用,如果实现了这个,就可算是一个完整的C++ wrapper了,呵呵。
虽然在公司加了2个小时班,回到家比平常晚了2个小时,但这次比较奇怪的是,我居然没有堕落,把QQ关了,也不开网页,而是专心地写代码。太好了,TclSuck已经初具雏形了,可以方便地定义普通的函数扩展了。这样下来,至少可以当作写技术报告的素材了,哈哈哈哈,就这样哄骗过去吧。其实要好的话,最好加上对类成员函数的支持,还有函数对象。这个慢慢来,呵呵。 I's有2集已经down完成了,随便打开第1集看了几眼,熟悉的情节,大一时候在宿舍里看过漫画。原来I's是男女主角的名字缩写,因为当时没看最开始的几本,所以错过了!这是一部很感人的漫画,男女主角互相暗恋着对方,却不敢向对方吐露心声,一直坎坷的感情经历,最后终于在一起了。所以,爱了,就要勇敢地表白自己的心情,要让对方知道自己爱着ta,即使被拒绝,也至少不会在多年后为了年轻时的胆怯而后悔不已。
在实际写代码的时候,才突然发现解决不了的问题,原本还以为只要花几分钟或者十几分钟就能搞定的事,郁闷!只好放下,又看了一下C++/TCL的代码,仔细地想,为什么它就可以这样大摇大摆地做那些事情。真是实践出真知啊! 收到按键精灵的作者转来的300块钱了。好happy,简直像捡来一样,只是down了个国外的杀毒软件,扫了一下说有Adware,哈哈。有外快的感觉真好,真想再其它地方想想办法挣外快,谁叫工资这么低呢! 做完了TclSuck,要不先把LLYF Spy移植成一个按键精灵的DLL插件,看能不能赚点钱来。
Category Lua,Script
今天开始整理代码,突然又觉得现在嵌入Lua的方法实在太丑陋了。
为了连接C++和Lua,我用了Luabind、SWIG和wxLua。而主要问题在于这三者在映射C++的自定义类型时对同一个C++类型做出了不同的映射,所以不能互相兼容使用。
最早决定是引入wxLua的,因为一开始是确定用wxWidgets框架,并嵌入Lua做扩展,于是必然的Lua会要操作wxWidgets的类型,同时Lua扩展也会需要有一些界面需要画。但实际上,当时没搞清楚使用wxLua到底能不能满足这些需要。而经过真正使用后,才知道wxLua中的类型并不能直接用于让嵌入的Lua解释器来映射到宿主程序中的wxWidgets的类型。于是现在的状况是,wxLua和宿主程序的wxWidgets是互不相干地使用着。wxLua仍然用于画些对话框,做些文件IO之类的操作。宿主程序的wxWidgets组件却是由Luabind和SWIG来实现粘合的。
使用SWIG,是由于要在Lua中操作wxScintilla类型,而Scintilla有几千个常量,然后自己又定义了一堆方法,于是用SWIG感觉是顺理成章的。
而使用Luabind,只是觉得它的call方法很方便,基本可以做到无视函数参数个数和参数类型从C++调用Lua函数。只是马上发现,通过Luabind来调用Lua函数时,把C++对象传递过去时,即使时实际上的同一个C++对象,在Lua中表示的类型却是Luabind中的一份,跟SWIG中注册的类型全无关系,跟wxLua中的也全无关系,比如说一个wxString,三个工具/库,有三种表达方式,互不兼容。
于是我就觉得很丑陋了。突然就有种冲动,自己实现那么一套东西,应该是集合了SWIG和Luabind、wxLua的特点,却又能互相通用。也就是说,有工具可以自动扫描C++声明,生成胶水代码,又有库,可以自由绑定C++类型,同时又提供对wxWidgets,甚至Qt和Gtk+的绑定。其实说起来这并不是非常困难的事,只要修改一下SWIG生成代码的方式,以Luabind的方式生成胶水代码就可以,而wxLua则也以Luabind进行绑定,这样应该就是我想要的那套东西了吧。
Lua跟众多其他开源的脚本语言一样,都没有一个官方的或绝对统治地位的IDE。而与诸如Python和Ruby这些大红大紫的脚本语言相比,Lua算不上一个流行的语言,也就是当年WoW的推出,带动了Lua的发展,相应的,Lua的开发工具也就显得更加落后,不但缺少一个比较正统或权威的库集合,还缺少好用的编辑器。之前我已经介绍过LuaPack,一个与Lua For Windows定位类似的开源项目,提供了几十个常用功能的第三方库打包。这回就介绍一个目前看来最好用的Lua IDE,叫DForD LuaCoding,它在LuaPack中也集成了,但它是个共享软件,在LuaPack中集成的那个版本只有在每次启动时弹出个要求输入注册码的对话框,只要点击“试用”按钮就可以继续使用了,除此之外没有任何其他的时间或功能上的限制。但是在DForD LuaCoding的官方网站上下载的版本,除了弹nag窗口,还有试用30天的时间限制,之后就只能花99美元购买了,当然网上也有0day。 DForD LuaCoding采用解决方案、工程组织方式来管理文件,任一时刻最多可以打开一个解决方案,而每个解决方案中可以有任意多个工程,这种组织方式与Visual Studio类似。另外,DForD LuaCoding还有通过文件名快速定位并打开文件的功能,这在Visual Studio没有直接的支持,需要装像Visual Assist X之类的第三方插件才行。这个功能对于一个解决方案中包含了大量文件的情况下特别有用。 DForD LuaCoding使用Tab浏览多个打开的文档,得益于Scintilla控件,语法着色,代码折叠等现代代码编辑器常有的功能几乎都有。不过由于DForD LuaCoding的定位是一个专业的IDE,而不是一个通用的代码编辑器,所以跟SciTE、Notepad++这种编辑器相比,就少了一些平常不太用的功能,比如复制行,交换行等等。不过总的说来,作为一个IDE内嵌的编辑器,当前已有的功能足以满足99%的编辑需求。 DForD LuaCoding提供了一个有点模仿TextMate的Code Snippet功能,不过TextMate中叫Tab triggers,该功能全部通过Tab键完成,而DForD LuaCoding中使用了三个不同的快捷键分别用于缩写展开和编辑热点前后跳转。这两种方式可以说各有优缺点吧,总的说来,我个人不太喜欢TextMate中一个Tab具有不同含义的作法,而且DForD LuaCoding中的三个快捷键分布得还算方便。 DForD LuaCoding提供了一定程序的Auto Completion,即自动完成。对Lua标准库的支持比较完善,不过也是因为Lua标准库很小很简单吧,呵呵,还支持几个其他的第三方库。但要说的是,该Auto Completion功能的准确性不高,有时把当前文档中的单词都列出来了,有时把所有库的表名列出来了,有时把所有函数名列出来了。不过实话说,有了这个Auto Completion,只要记住前几个字母,后面可能的候选字都列出来了,仍然可以减轻记忆负担,减少击键次数和拼写错误。另外,DForD LuaCoding对标准库中的函数,还提供了简单的call tips说明,只要鼠标光标停留在函数名上几秒钟,就会弹出一个tooltip,显示出该函数的简单说明,了胜于无吧。 最后值得一说的是DForD...
在Lua神作《PIL》中操作XML的示例是用expat库的,众所周知expat是用类似SAX的接口的,这里介绍一下使用其他的库来实现DOM接口操作XML。 可以使用的库有几个选择,包括ltxml,xerces,rapidxml等等。ltxml使用TinyXML和TinyXPath提供的服务,xerces使用Xerces-C++提供的服务,而rapidxml则是使用RapidXML。这三个库我都有过一段时间的使用,不过都没怎么深入过。总的说来三个库各有特色,呃,其实是它们依赖的C/C++库的特点,ltxml我不是很喜欢,当初用的时候发现不知道为什么,同样一段代码执行多次后,打开并读取XML文档就会出错。于是后来转用xerces,它倒是基本让人满意,不过得附带一个Xerces-C++的DLL,感觉有点不爽,而且Xerces-C++应该说是比较完整的实现了XML的几个接口标准,但xerces只是封装了其中DOM读写的很小一部分接口。而rapidxml胜在运行速度飞快,从RapidXML的项目主页上可以看到一个简单的横向评测结果。xerces和rapidxml的Lua接口非常相似,除了几个节点类型常量的名称和载入的表的名称不同外,其他的读写接口名称和签名几乎一模一样,它们的源代码可以在它们的项目主页上通过svn下载得到,但需要用户自己编译,当然也可以下载安装LuaPack,LuaPack提供已经编译好的xerces和rapidxml文件,但要注意的是由于使用VC2010进行编译,只能在Windows XP SP3或更高版本的Windows系统上运行。 下面以rapidxml为例,简单演示一下如何操作XML文档。 新建一个XML文档,并保存: require "rapidxml" local doc = rapidxml.parse( "" ) -- assign root node xml text local root = doc:root() for i = 1, 10 do...
Lua官方只提供了一个解释器和一个编译器,不像Python、Ruby那样有一个大而全的标准库。但是Lua仍然有众多的第三方库,像Luaforge上就托管了一大批Lua相关的项目。
为了方便用户使用,也有第三方贡献者将一些常用的第三方库编译并打包在一起提供,比较著名的是Lua For Windows(简称LfW),而这里要介绍的是另一个刚开始没多久的项目,叫LuaPack。LuaPack受LfW的启发而创建,而且比LfW走得更远。LuaPack不但已经完成了对Windows系统的良好支持,从其SVN仓库中可以看出,现在正着手努力使其支持(Ubuntu) Linux和MacOSX,这是LuaPack与LfW最大的区别,而LfW从项目名称上就可以知道是只支持Windows系统的。另外,LuaPack打包了一个专业的Lua IDE,叫DForD LuaCoding,这是一个由DForD Software提供的针对Lua语言开发的IDE环境,勿庸质疑DForD LuaCoding的功能比LfW中附带的基于SciTE的编辑器要强大得多,但DForD LuaCoding是个共享软件,未注册版将会在每次启动时弹出一个要求输入注册码的对话框,除此之外没有任何功能或使用时间上的限制。最后一点小区别是,可能是基于创建者自身的价值理念,LuaPack和LfW打包的第三方库有些许不同,有的库只在LuaPack中存在,而另一些库只在LfW中存在,而且LfW是使用VC2005编译,所以可以在Windows 2000及更高版本中运行,而LuaPack使用VC2010编译那些Lua扩展库,所以只能在Windows XP SP3或更高版本中运行。
就我个人而言,LuaPack更值得推荐使用。
俗话说,磨刀不误砍柴功。对于这句话,我一直都自认为是辩证地看待的,在某些工作前,先做些准备工作可以极大地提高之后的效率,好比Kunth老爹的TeX。不过很多时候,磨刀也是件很费时费力的事情,好比Kunth老爹的TeX。
这几天一直在考虑实现ZenHTML,这是一种极大提高hard coding效率的code snippet方法。其中有一种可以认为是一种“小语言”,呃,这是《UNIX程序设计艺术》中的说法,用GoF的《设计模式》中的说法应该算是interpreter模式。不管怎么说,反正就是有一项任务是要解释字符串,根据字符串的不同表达式来作出不同的响应。
刚开始的时候我是觉得这个解析工作似乎非常简单,没有必要把它提高到“语言”这种层面对待,只要识别出两三个操作符就可以了。不过后来马上发现,实现起来并不轻松。我意识到,用Lua实现的话,用LPeg将是最合适的解决方案。今天又翻出LPeg的manual来看,还是看得有点糊里糊涂。明天继续。
所以说,磨刀也费时啊!
其实这个问题老早就有了,当时还在Lua的maillist上提过,不过当时我只是发现LuaJIT2在执行Lua脚本时,如果Lua脚本调用了不存在的C函数时会使宿主崩溃,Mike Pall同学(LuaJIT的作者)倒是很爽快地解决了这个问题。后来发现,Mike Pall解决的只是一部分,我这里因为用到了Luabind,通过Luabind来调用执行Lua函数,如果Lua脚本又调用到不存在的C++函数,进程就会无声无息地退出,而如果是官方Lua的话,则是会老老实实地打印那些出错信息出来。
昨天忍无可忍了,就又向Lua maillist发了封邮件,今天发现Mike Pall和Daniel Wallin(Luabind的作者)争起来了,呵呵。Mike Pall说问题在Linux上和Windows/x64上都没能重现,不知道Windows/x86出了什么问题,可能是Luabind重复抛出异常了,Daniel Wallin则说Luabind只是简单地调用了lua_error,他倒是能在虚拟机的Windows环境下重现问题,最后他又给出了一段简化后的代码,只要lua_error调用后面有C++对象的析构,LuaJIT就会出问题。
我倒是偶然看到今年1月份的Lua maillist上的邮件,Mike Pall曾经说过Windows/x86上MSVC实现try/catch是用SEH实现的,这个LuaJIT处理可能有点问题。但他后来的邮件中好像又说在新代码中已经解决这个问题了。我于是用MinGW试了试,GCC 4.4.0编译出来的,确实是没问题的呢!
不过最后,又看到Mike Pall好大一篇解释,最终结论是建议所有用户都升级使用x64,囧!
今天主要搞定了源代码断点,之前遇到的如果有断点,debuggee启动就会崩溃的问题,其实是通过socket发送命令过去后,debuggee在接收时会把不完整的信息压入到队列中,跟昨天遇到的回应消息不完整是一个道理。
最后我仍然是采用了完全使用debug库的功能实现的方式,这种方式的缺点是调试执行的效率很低,因为每次debug库回调时,都要判断一下是否在当前行有断点。至于之前我想过的那种快速断点的方案,就留到以后版本中实现吧!
这两天整调试器,经过不怎样的努力,到现在为止,功能上基本算是具备了,不过就是剩下些bug,主要有:
从debuggee发送过来的信息有时候经过XML解析会出错。
从debuggee发送过来的信息,有时候没有调用栈信息。
断点工作不正常。
有时候刚启动debuggee,debuggee就崩溃。
明后天就集中精力修改这些问题了,哈哈!
在Lua的maillist上已经放出了5.2的第一个work version,引起一帮人热情高涨。
不过那帮人说话也真不客气。Mike Pall发难说,不要引入bit库,看不起Lua开发组的同学啊。Alexander Gladysh同学则是先后几次纷纷列出众多已实现却没有在文档中提及的变更。
初步看了一下changelist,看得我有点儿心惊肉跳,相比5.1还是有不少改变的,至少已有的代码有些是要废掉了,比如没有LUA_GLOBALSINDEX了,光这一点就让不少C扩展库和绑定库罢工。
虽说现在只是一个work verison,以后的实现会有所修改,但我对于能提供向5.1的兼容比较悲观。不过想想现在还有不少人用着5.0的,心里稍微平衡了一点儿,等我用到的那些第三方库都能提供5.2兼容后,再考虑升级吧,先继续用5.1!嗯,升级机会得利用好!
话说我已经怀疑起engine和controller都反应慢是由于延时轮循引起的,于是下定决心要改成通知的方式。翻了一篇Jeffrey大牛的《Windows核心编程》,发现只要用Event机制就可以实现了。不过如果直接用API来操作Event,我就有点儿不爽了,现在这个项目我比较希望它能在源代码层次尽可能地平台无关。于是又在Boost文档是找了一遍,发现thread库中似乎有对应的设施,其实这是可以理解的,本来就是线程间通信,同步的机制嘛,thread库虽说比较轻量级,但有这么个功能也是理所当然的。修改完代码,测试了一下,果然无论engine还是controller都是立马响应了,安逸呀!
昨天又去了一趟4S店,没想到买个车上个牌有这么麻烦,还要等于1月15日才能在这边上,于是只好再去领了张临时牌照,可以拖到15日了。回来后就没什么心思继续写代码了,唉,我的意志力真是薄弱地几乎没有!
昨天晚上躺在床上,突然想起来,原先定的调试器三步走,后面二三两步的顺序应该反过来。因为engine端的启动(注入)方式修改后,必然对controller端要进行一定的同步修改,为了减少这部分同步修改的工作量,就不应该先把controller端合入到宿主程序中去,目前使用控制台方式的controller修改起来应该工作量要少得多。接着又担心起controller合入到宿主程序中的方式,因为可以预见到的是界面到时候会根据网络通信线程中接收到的信息做出不同的响应,照以前的经常,如果用的是MFC之类的方案,可能就是SendMessage给界面线程就可以了,可现在用wxWidgets,不知道应该怎么处理,看来又得好好看看Code::Blocks和CodeLite的代码了。
今天终于把基于socket的远程调试架构搭建起来了! 昨天定位到controller给engine发送命令后,engine并没有收到,于是今天首先是开起两台机器,这样就可以用Wireshark抓包了。经过抓包发现,controller确实已经把命令发送过来了,只是engine没有正确接收。一番折腾后,参考了一下lldebug的代码,把engine端的代码从io_service.run()改成多次io_service.poll_one(),居然正常运行了。这怪我没有认真理解asio的用法,io_service居然有4个用于处理事件的方法,除前面那两个外,还有run_one()和poll(),从文档中我实在分不清到底它们有什么区别,以及分别适用于哪些使用场景。不过既然现在可以正常运行了,那我暂时也不去管它了。 socket的问题解决后,我就埋头于定位,修正controller与engine的交互过程。在我看来,这应该是状态机,controller端一个,engine端一个。不如我没有仔细考虑,只是因为现在的问题很简单,步骤不多,随便跑个例子试一下,有问题就解决,到现在基本上也是ok了。 编码过程中,发现boost::shared_ptr是个不错的东西,尤其适合于asio。比如要发送一段数据,把这段数据放在一个boost::shared_ptr中,无论它怎么传递,不用管它的生命周期。 自从远程调试架构完成以来,我就发现一个问题,从controller下发一个命令,engine要过一会儿才会作出响应,而engine反馈了信息回来,controller也要过一会儿才会显示出来。开始的时候我以为是网络传输延时的问题,后来把双机调试改成在同一台机器上调试,loopback应该够快了吧,结果仍然没什么变化。最后我想到,估计是我其中加入的延时操作引起的,如果在写之前发现队列为空,那么就一直等待,每隔1秒钟看一下队列中是否有可写的内容。所以要把这个设计改一下,不能用定时轮循,而要用事件通知,又得好好复习一遍《Windows核心编程》了。 接下来,就是实现各个调试命令了!
估计这个Lua调试器是最近几个月来遇到的最具有技术挑战性的特性了,大概要分三步走。 首先,确定使用远程调试架构。用C++实现与用户交互的操作程序和与Lua解释器交互的执行部分。现在仍然在这个阶段。昨天差不多把socket通信的部分搭起来了,这也花了我不少精力,是用boost.asio做的,实然觉得自己对boost.asio的了解增进了很多,也突然觉得其实boost.asio似乎挺好用的。但是仍然有点小问题,比如我本来希望执行部分作为C/S结构中的客户端,它能在连接上服务端后立马写点数据给服务端,可是似乎总是没写出去,要先收到些东西再写才会成功。不过现在暂时不管这个问题,今天在写与Lua解释器交互的部分,发现代码真的是越来越多喽,一个又一个新的类被创建出来,真是面向对象惹的祸呀!没写完,中间脑袋稀里糊涂的,明天继续。 接着,把与用户交互的操作程序改写成Lua,并与宿主程序集成,可以在IDE的编辑器上就让用户进行操作和反映调试器执行结果。这里要注意的是,到底到时候要放多少代码是在宿主程序中实现的,多少代码又是让Lua脚本实现的,又有多少代码是用C++写成作为Lua的扩展库的,几部分又是如何交互的。 最后,把调试执行部分改成dll,以便注入到被调试进程中去,这样就可以调试任何嵌入了Lua解释器的程序了,只要Lua解释器是个dll即可。注入后,要hook掉几个Lua的C API,包括获取lua_State,装入文件。这里应该要注意的是,使用Lua解释器的C API不能直接调用和链接了,要动态获取API地址了,这样才能使用注入进程的那个Lua解释器的dll了,不过其实可能不需要这么复杂,只要额外说明如果要用本软件调试的话,要求用我指定的Lua解释器的dll和lib即可。我觉得这点是可以做到并且在某些情况下必须做到的,因为曾经还听人说过,很多内嵌Lua的游戏,都是静态链接Lua的,所以既使我能注入,也hook不到那些C API的。
今天在群里有个人问,他初始化Lua解释器后,用C代码执行一下lua_replace然后崩溃了,报没有环境。我觉得比较奇怪,看代码我觉得应该没有问题,但人家确确实实崩溃了。后来他解决了这个问题后,在群里公布解决方法。他看到一个老外的帖子,然后照他们说的,把调用lua_replace的那个C函数放到Lua中进行调用,一切都OK了!我仍然没明白其中的所以然,后来另一个人贴了个网址,是他自己写的一篇blog,其中解释了为什么在调用lua_replace时会崩溃。经过他的解释,是因为Lua的调用栈要求不为空,否则lua_replace就会崩溃,至于为什么要这样他也不明白。实际代码的解决办法就是在lua_replace前call一下Lua函数,比如前面说的,放在Lua中调用,那么理所当然调用栈中至少有本函数嘛。 我又看了几遍那篇blog,其中说到要嵌入的Lua解释器中要初始化标准库时,要用luaL_openlibs,如果用luaopen_base之类的直接调用就不行。这时我才渐渐地有点头绪。当年在嵌入Lua时,最早的时候用luaopen_base之类的是没问题的,后来确实不行了,在lua的maillist上有人告诉我要用luaL_openlibs,我还说应该不是这个原因,但他们说这是5.1.x之后才这么做的。现在回想起来,大概就是因为5.1.x修改了这部分的实现,而且看了一下luaL_openlibs的代码,确实就是把luaopen_base这些函数让给Lua来调用了,其它的没有区别了。 通过这件事,让我又一次深刻地认识到阅读分析Lua源代码的重要性,Lua本身的资料仍然太少,从源代码中可以得到很多undocumented的知识!
本来以为自己对如何实现一个Lua调试器已经有了足够的知识储备,于是今天就提枪上马,结果无奈地发现,说是一回事,自己做是另一回事。我最终的目标是要达到Decoda那样的效果,但一开始只能慢慢一步一步来,先实现类似lldebug的debuggee部分。但是就算是这样小步开始,也仍然困难重重,很多问题其实我都没有吃透。 首先是发现在sethook时,只有按line回调是正常的,而call和return都没有回调,这让我感到很迷惑,无论是用C代码的hook还是Lua代码的hook,都是存在这个问题,而且用lldebug是正常的。所以我最早怀疑跟Lua代码有关的猜测也不成立了,只好试图从lldebug的源代码中寻找答案,当然寻找到的lldebug源代码跟我的代码没有本质的区别。最后过了很久才隐约记起来,我用的是LuaJIT,好像它对debug库的支持是有些跟官方Lua不同的地方。于是立马换回官方Lua,发现果然无论是C代码还是Lua代码都照预期的执行了。 之后是发现,hook的回调是能正常执行了,但程序还是自顾自地跑下去了,那怎么处理单步和断点呢。然后是回头看lldebug代码,发现是在hook回调函数中,处理完对应的事件后,应该要等待命令。一开始我还想不通,要怎么等待命令啊,后来突然明白过来了,比如我这个是控制台操作的,那么在这里接收一个控制台的输入就行了,不就变成运行一下,停一下了嘛! 我写了两个测试脚本,用于观察Lua的debug库三种hook回调的行为。发现Lua在执行一个脚本文件时,首先是将整个脚本文件看作一个整体,用Lua的话说,应该是一个chunk,而它执行这个chunk是个call操作,所以执行一个脚本文件会先有一个call回调,在整个文件执行完后,会有一个return回调。如果一个脚本文件中又执行了另一个脚本文件,那么就可以到嵌入call/return回调。当执行的代码是一个函数的定义时,会先在函数的end行有一个line回调,然后在函数的function行有一个line回调。当执行的代码是一次函数调用,那么会先在函数体(参数列表后面)的第一行有一次call回调,然后再在该行有一次line回调,在结束函数时,先在函数end行有一次line回调,再在该行有一次return回调。 再之后是开始考虑要支持哪些调试命令,以及怎么实现。简单地看了一下别的调试器的实现,我就暂定要支持step into,step over,run to cursor,breakpointp这几个操作了,step into大概是最容易实现的,就是debug库中按line回调即可。step over可能稍微麻烦一点,应该先假设是按line回调来处理,如果从该操作开始第一次回调的是call,那么应该记录下call的次数,并计数return回调的次数,直到return回调的次数跟call回调次数相同,再下一次line回调就达到step over的效果了。run to cursor也比较简单,按line回调直到当前光标所在行即可。breakpoint跟run to cursor的处理方法一样。 除此之外要注意的是coroutine的创建,会返回一个lua_State,所以需要拦截这个创建函数,对这个新创建出来的lua_State也sethook。因此在调试器中还得为不同的lua_State保存各自的调试上下文。 以上都是不考虑执行效率的做法,在云风的blog上有一篇文章,讲到他设计的一个提高调试器执行脚本效率的方案,似乎是勉强能提高一点性能,但要求用户修改Lua脚本来定期轮循调试器是否有新命令下发。其实在这个基础上,我们可以更进一步,修改Lua脚本的工作由调试器完成,对用户透明。而且定期轮循可以修改成只要下了断点的行的最前面自动插入一个调试器定义的函数调用,也就是将执行控制权再次转移到调试器中。这就比较像C/C++调试器中插入int3的做法了,如果断点是固定的话,那么调试器执行脚本的效率将几乎是无损耗的。除了效率上的提升外,各个调试命令的实现也将变得更加容易。但这个方案有一个问题是,这插入断点指令的操作必然是在脚本文件在被执行前完成的,如果在调试运行过程中有新增断点,那么仍然得退出原来的那种靠debug库line回调的方式了,除非重新启动调试。
准备自己实现一个Lua的调试器,以前没做过这方面的工作,所以只好拿现成的开源代码来研究了。 比较容易找到的调试器代码有好几个,比如lldebug,RemDebug以及wxLua中的那个调试器,各自的实现方式有所不同,但万变不离其宗的是都使用了Lua自己的debug库sethook功能。还有个共同点就是远程调试的架构,而且都是用socket实现的。 RemDebug完全用Lua写成,一个只有两个文件,加在一起代码才500多行。其中一个文件中实现的是调试引擎,负现各种调试功能的实现,另一个文件是用于实现人机交互的接口。 lldebug是个日本人写的,简单看了一下,也是跟RemDebug类似分成两部分实现。它的人机交互部分就比较高级,用wxWidgets实现了一个GUI,可以直接在上面打断点,单步,查看回调栈,查看变量等等,可算是debugger部分,另外实现一个单独的程序用于执行Lua脚本,这里可称为debuggee,其实也就是在执行Lua脚本前设置一下调试选项,以及拦截一些Lua的C API。 wxLua带了一个调试功能,它跟lldebug比较像的一点,有一个独立的程序执行Lua脚本作为debuggee。另一部分则是用C/C++实现的Lua接口,可以由用户自己用Lua脚本来实现debugger,这是它相较于前两者比较独特的一点。 通过sethook实现的调试器,要特别关注coroutine的处理。 我一直比较羡慕的是Decoda的那种功能,简单说来就是它可以直接调试其他嵌入了Lua解释器的应用程序执行的Lua脚本。当时我一直想不清楚这是怎么实现的,只是看到它向被调试的应用程序进程注入了一个dll,于是猜测它拦截了应用程序对Lua的C API的调用,而拦截了C API后要做些什么我就不知道了。现在想起来,似乎也就是只要在应用程序执行Lua脚本前,对lua_State设置hook,于是就跟前面提到的那些传统调试器一样了。但另外要注意的问题是,抢在什么时候将这个dll注入,应该拦截哪些C API。如果能在应用程序创建Lua解释器前注入,那么拦截lua_open就可以了,通过修改PE文件的导入表,基本可以达到这个目的。如果不能保证注入的时机,那么比较合适的被拦截C API应该是lua_load,但要注意的是拦截后设置hook时应该注意一个lua_State只要设置一次hook就行了。
看了两天小说,呃,又堕落了。由于已经看完了,今天就比较认真地折腾起flex和bison。其实之前已经把lex和yacc脚本写完大部分了,至少可以从控制台打印结果出来了。今天就修改一下yacc脚本,把原来打印到控制台的内容保存在内存中,到时候转储成xml格式。因为只是要显示在界面的树视图中,我想了想,也就只有函数定义值得这么显示一下,所以也就只处理了这部分。 总的说来,感觉yacc有点土,它只能接受一种输入接口,而我用flex时发现可以生成C++代码,所以要给bison用的话,仍然需要把这个C++类的接口再适配成bison可用的C接口。 这种任务果然是实践性非常强的工作,本来看过一些资料,当然,能找到的资料也基本内容一样,翻来覆去那么几句话几个例子,等到自己要做时,不时地有些迷惑,只得慢慢尝试,倒也捣鼓出来了。 在yacc中可以为每个token或type指定一个union中的某个成员,其实这个成员的指定只在规则描述段中的action中有用,就我看来各种资料、教程中说的那一堆实在是扰乱视线。对于一个C/C++程序员来说,这种用法只是万千技巧中的一种,实在没必要说得那么严肃仔细,好像不那么用就不行了似的。 再说个我觉得yacc土的地方,由于这种格式上的限制,在action中只能访问一些全局的变量、对象等,至少在思维逻辑上很不连贯,其实lex也有这个问题。要我说,比较让现代化的做法是它应该生成一个类,每组action触发时,应该调用该类中的某个回调函数或虚函数,这里形式有好几种,都可以考虑,不知道boost.spirit是不是这种形式的,也许ANTLR等其他类似的工具就是这么做的。 最后抱怨一下,Lua Reference Manual中附录的complete syntax不能直接用的,至少不能直接用于yacc,有好些地方似乎没写全。
本来是有ltxml这个库的,这个库使用TinyXML和TinyXPath,本来用着,也勉强,可以读取xml文件,但也不时地出点小问题,不过都让我规避掉了。这回是想写xml文件了,结果发现ltxml的接口我很不习惯,嗯,不喜欢,于是想自己重新写一个新的绑定。 我首先看了一下libxml2,发现它的文档和例子都不是很清晰,不想继续投入精力去研究了。剩下两个选择,MSXML和Xerces C++。这两个库我都用C++的类做了一层简单的封装,可以适配应用STL中的算法。后来想想,MSXML的那个封装因为当初只考虑配合MFC/WTL使用,所有的字符串都用CString了,而且另外一点是MSXML是只在Windows上可用,Xerces C++是跨平台的,特别是可以用gcc编译,于是最后就选择了Xerces C++。 本来我的那个封装是只针对DOM接口的,同时有4个类,分别对应DOM文档、DOM节点、DOM节点列表,以及DOM节点列表的迭代器。绑定的过程参考了ltxml的实现,但只给DOM文档和DOM节点定义了userdata,因为Lua有table,所以可以用来表示DOM节点列表。 绑定完成后,简单试用了一下,读取,写入都基本满足当前的需求,除了不知道怎么让它写入的时候进行format pretty print,老是多加个换行符,中间有空行可一点都不pretty。
宿主程序提供了界面国际化,那么插件不能提供国际化就说不过去了,至少得有这样的机制以供支撑该种需求嘛。 得益于wxWidgets对国际化的良好支持,要让嵌入的Lua解释执行的Lua脚本也能根据宿主程序的本地化信息进行正确的处理非常简单。wxWidgets中对要进行国际化的字符串用_()进行包裹,其实这是一个宏,用于调用真正的翻译功能,比如wxGetTranslation。所以在嵌入的Lua中将wxGetTranslation函数注册到Lua中即可,然后在Lua脚本的最开始处将该函数换个更简单的名字,比如_,这是最好的名字了,哈哈。这样就可以在Lua脚本中对需要进行国际化的字符串也用_()进行包裹,它会调用wxGetTranslation函数。 GNU的国际化方案套餐中,提供一个叫xgettext的工具,可以从众多编程语言的源代码文件中提取出字符串,生成po文件以供翻译生成mo文件。比较不幸的是,xgettext不能支持Lua语言,同时由于我这个项目中使用的插件描述信息中有一部分界面信息是在xml文件中的,这也是一种自定义的格式,所在很不幸地xgettext更是不能处理啊!所以我在想,我是否要先写个可以支持Lua和我这种xml格式的类似xgettext的工具呢?Poedit太扯蛋了,居然只能认它自己生成的那种po格式的文件,稍微改一点就报错了!
上午花了几个小时修改了Auto Completion功能后,用起来的感觉已经超过LuaForWindows中带的SciTE了。于是又开始寻找起可以分析Lua代码并生成AST的东西,google了大半天,发现了几个Lua项目,一个ANTLR的文本,最后都可耻地放弃了!因为那些Lua项目全都由于这样那样原因而不可用,而ANTLR,呃,我试了下,它是用LL分析的,语法元素的分析顺序不能直接为我所用,而且我在之前一点都不了解ANTLR这个东西,我甚至翻遍网络,找不到怎么让它在需要的时候记录下行号!后来又翻了一下Lua的源代码,呃,说实话真没习惯它几乎每次函数调用都有一个回调函数的用法,嗯,我真的只会一点C++了,放弃! 真是个头痛的问题啊!我觉得我还是退回去,老老实实地再温习一下编译原理,用flex和bison自己写一个分析模块吧,毕竟Lua的语言核心真的很小很小!
到昨天为止,基本完成Code Snippet的框架,剩下的都是些体力活。该特性要求在点击菜单项时,根据当前光标所在位置的字符串,替换成对应的代码片段。由于菜单项是通过插件添加实现的,而且Code Snippet又根据当前编辑的源代码对应的编程语言不同,也会有不同的处理,所以也是通过不同的插件实现的,这就要求插件可以再次调用插件。好在当初设计插件扩展框架时,已经考虑到这一点,所以虽然有实现过程中有需要慢慢调试的地方,但没有特别大的障碍。 完成Code Snippet后,应该开始Auto Completion特性的开发。该特性是本项目中可算是难度最高的特性之一,同时又有比较高的准确性和运行效率等要求。还有点比较头痛的是,针对不同的编程语言,可复用的东西不多。 此外,还有个功能应该尽早加入,就是处理文件的不同编码。比如通常,尤其是早期的代码,都是直接使用ANSI编码保存。而现在已经比较常用的是保存成UTF-8等编码方式,特别是像LaTeX的一些处理器直接要求输入文件是UTF-8编码。所以应该能在文件的装入和保存时,可以自动处理文件的编码问题,这可以通过iconv或ICU实现,不过问题就在于有了选择,才是苦恼啊!目前我倾向于使用iconv,因为相比之下更轻量,而且够用。 这些天发现,Lua的字符串连接符..效率还真低,怪不得Lua要提供*all和table.concat等设施。 本来Lua中操作XML有几种不同的选择,这跟在C++中情况差不多,我选择的是比较轻量的ltxml。而昨天在Code Snippet特性的开发过程中发现,我把所有的信息都保存在xml中,而每次完成snippet时都从xml中读取,开始几次还是正常的,但只要过一会儿,在调用xml.open时就会报什么试图index一个function值中一个number值,还真是诡异,但调试发现这时无论xml.open还是传入的参数都是正确的,很是纳闷啊。于是只好规避一下,只在开始时读一次,全部都装入到内存中,以后就直接读内存了。 一直以来,都是通过print来进行Lua脚本调试,真是应了那句“一夜回到解放前”。前两天才在界面上加了一个专门的输出窗口用于从Lua脚本打印字符串过来。好比是当年写Windows GUI程序时,用MessageBox调试进化到用OutputDebugStrng进行调试。昨天记起来有LuaLogging这么个第三方库,于是仔细看了看,很简单的功能,只有几个lua文件,可以记录日志到文件、控制台、socket、email或数据库中。于是我参照这些appender的实现,加了一个新的appender,用于将日志打印到宿主的插件输出窗口中,感觉不错。 接着是使用luabind的问题。在网上看到有人说luabind的各个版本都存在指针的double deleting问题,这让我有点惶恐。好在今天看邮件列表时,看到luabind的作者说,这种问题只出现在使用智能指针或类继承时切片的情况,而且要求是Lua的state先于这些对象被销毁,现在没有好的办法来修正这个问题。我想了想,这几种情况我现在都不会遇到,我只有最最简单的嵌入和扩展交互。之后,又发现有人在邮件列表中写了一个luabind和SWIG的性能比较,SWIG的封装比luabind的快一倍。看到这个结果,我觉得是意料之中,SWIG的封装方式比较底层,调用快也是正常的。不过luabind的作者说,他写了些benchmark的测试,在未发布的luabind 0.9中已经有不小的改进,虽然仍然不比SWIG快,但相比0.8.1版本,差距缩小了约一半,期待0.9的发布。 昨天无意中看到云风blog上一篇老文章提到有Lua Ring这么个库,可以在Lua代码中再创建个新的Lua state,让某些代码在这个新的state中运行,从而保护比较重要的核心state。我潜意识中认为,像我现在这个项目使用嵌入Lua来作为插件扩展的运行环境,确实要用一个比较安全的环境,即所谓的沙盒,但这个Lua Ring怎么应用上去,以及能有多少效果,仍然有待考察。 前些天,从SVN上更新的了wxPropertyGrid的代码后,发现用GCC编译不过了,直到昨天仍然不行,实在忍无可忍,真要骂娘了。上它的sf项目见面看了一下,自11月25日更新代码后,估计作者就压根没发现这个问题,于是在上面提了个单。今天发现作者已经回复那个单,并在svn trunk中已经修正了该问题,总算松了口气。 今天仔细学了一下如何让wxWidgets支持国际化,发现非常简单。只要在程序初始化时,自己创建一个wxLocale对象,把mo文件的搜索路径加进去,设置好当前要使用的语言。其他想要被翻译的字符串用_()宏替换wxT()和_T(),如果是个wxString对象,就用wxGetTranslation(),这样在这些字符串会自动从mo文件中读出相应的翻译后的文本,感觉比ini等配置文件,或是国际化资源dll的方案方便很多。不过为了让插件支持国际化,也可以使用类似的方案,但是我有poEdit时发现它只能从源代码中提取出需要翻译的字符串,不能全新的创建一个,这太土了,以后一定要自己写个好用的。 最后的一个问题是,现在的插件扩展机制,容易出现重复代码,比如相同的功能会在菜单中写一遍,在工具栏中也写一遍,这该怎么修改一下呢,呃,得仔细考虑考虑
今天本来打算把那几个菜单项的功能完成的,不过后来又转去做其他事情了,计划执行力不强啊,唉! 要在Lua中操作xml,在现在的软件开发中,这是个很常见的需求,xml已经变得无处不在了。在神作PIL中提到的是用expat库,呃,我只会用DOM,所以只好找其他的库了。前些天在luaforge上看到一个叫ltxml的,才0.2版本之后就没更新过了,用的是TinyXPath和TinyXML,我决定好好考察一下。 它没有文档,只有一个readme后面四五行C代码示例,不过这足够了,看一下那个cpp文件中注册的方法,基本可以猜出用法。总的说来,先require,再用xml.open方法打开xml文件,然后就可以用TiXMLDocument的select等方法得到TiXMLNode,就跟我熟悉的用C++操作DOM的做法一样了。 说起来TinyXML的表现不差,基本能满足我当前的需要,我有点儿后悔当年花了那么大力气将Xerces C用VC2008编译了一遍,又绞尽脑汁用MinGW编译了一遍,还自己封装了一把,以适应STL中的算法。对于我来说,它太庞大了,让我畏惧,那么大一个却仍然要让Xalan来处理XSLT和XPath。同样,libxml和libxslt给我的印象也差不多,它们甚至没能让我顺利编译! 昨天说到的,现在程序崩溃总是无声无息地自动退出了。今天想了想,其实之前好像也想到过,会不会是因为LuaJIT的缘故,于是换了官方的Lua的dll来用,果然在原本会引起退出的地方,Lua只是而压了条错误信息到栈中,LuaJIT的行为没跟Lua一致啊!在Lua list上发了个邮件问问,结果一个老表说他没能重现,问我有没有证据,我汗,用Wink录了个8MB的操作录像,然后发现这maillist限制最大附件是40KB,严重超标,还要等人审查。总结一下崩溃的条件,在Lua代码中调用第三方C/C++代码注册的类和方法,如果方法、成员不存在,就会退出。而Lua是能处理成将其识别为一个nil,然后报不能在nil上进行函数调用之类的话。 总之,一切在向好的方向发展,甚至自己已经能渐渐地习惯于写Lua代码了,不像之前那样非C/C++不爽!
昨天偶然发现一个超级严重的问题,程序运行一小会儿就会自动退出,什么提示都没有。至于没提示,这已经有一段时间了,照理说,内部状态、逻辑不正常么,可以给个Windows的崩溃报告嘛,可是它偏偏没有,弄得我要跟着崩溃了。 后来在代码中加入一些跟踪语句,发现出错的原因跟我的猜测一致,内嵌的Lua解释器栈溢出了。这是个很头痛的问题,以前听人说过,如果没有sandbox,插件运行环境是不可靠的,呃,最出名的是chrome的架构,经典的sandbox。但是我这个程序跟它的情况有点不同,在主窗口和子窗口上都有大量的用户交互操作,以及主窗口和子窗口之间大量的交互,子进程间的通信会很复杂。而且现在引起崩溃的,都是主窗口中的逻辑,所以还是会导致整个程序的不可用。 昨天晚上调试了好久,发现只要更新工具栏按钮或主菜单项的界面状态的响应函数打开后,过一会儿就会退出。所以最后可以把范围缩小在C++调用Lua函数的那一块代码上。我不怀疑Lua的代码有问题,凭我现在对Lua的了解,即使真有问题,估计我也是束手无策的。既然是栈溢出,而且时间不长就可以重现。我仔细地看了那块代码,又看了Lua manual和PIL,以及Luabind Documentation,发现我一直忽略的一个问题,在调用Lua的C API出错后,Lua经常会把出错信息压入栈中,而Luabind可能会直接将其封装为luabind::error类型的异常抛出,然后我就只是看一下那个字符串内容,却没其他处理了。这是一处错误,应该在提取字符串后,将其弹出。另一处错误是,我这里调用Lua中的函数,都是存放在一个表中的,所以中间无论哪个步骤出错,都应该把先前压入栈中的东西弹出。还有一处错误是,最后我从Lua栈中获取到函数后,用luabind::object封装了一把,然后luabind::call_function来调用,这时我又直接返回了,却没把这个放在栈中的函数弹出。 昨晚解决了这三个问题后,还以为所有问题都已经修正了。今天又测试了一遍,发现过了约半个小时后,程序还是自动退出了,而且连那exe文件都没了!我要疯了! 唉,这什么都是从零开始的,风险实在太大了。使用wxWidgets是第一次,复杂的内嵌Lua扩展框架是第一次,使用Luabind是第一次,使用wxLua是第一次,把所有东西混在一起用更是第一次!而且很不爽的是,已经用惯了MS的解决方案的我,没有像MSDN这样的大而全的文档极不适应,那些说使用开源的东西成本低的人,不知是真的短视,还是别有用心呢。
经过定位,方法很简单,在有怀疑的地方加入跟踪语句,打印栈大小,发现确实还是在那几个地方,栈中项的数量稳步增加,这才想到,会不会是从表中获取某个元素后,那个表还在栈中呢?看了下文档,也没有相关的说明,只好先作这个假设。在调用表中的函数后,应该弹出两个值,这样修改后,果然过了一个多小时也没退出,而且看栈中的项也确实没泄漏的。 昨天修正了对TeX代码高亮的问题。原本发现有TEX和LATEX两种lexer,如果直接设置好lexer的话,LATEX只能着色,没有代码折叠,而TEX有代码折叠,不能着色。看了代码似乎也都不用设置什么关键字字符串的,没办法只好到scintilla的maillist上问一下,Neil回复说SciTE中用的是TEX。于是我又看了一下TEX的properties文件,发现还有4个专用的property要设置,加上后果然好了。开源就是开源,只有通用的scintilla接口文档,却没有针对每个lexer的文档,唉! 昨天还写了个小程序,用于将原本给另外一个程序用的Scintilla的所有lexer的语言配置文件从xml格式转换成现在正在进行的这个程序可用的 lua脚本。这是个很省事的活,不过这小程序也是花了不少时间修改,因为要生成的lua脚本也在不停地修改。从这看出,xml真是一种存储数据的好格式 啊,可以方便地转换为其他格式。要是SciTE的配置文件也是xml的就好咯,想当初为了把众多lexer的配置从properties格式转换成 xml,可是花了我好几个晚上的业余时间的。 接下来应该要实现其他一些基本的功能,以及好好考虑下如何实现针对不同lexer的各种功能。
这几天似乎渐渐进入了正轨,发现并解决了一堆的问题。 从github上下载的0.9版Luabind可能不稳定,毕竟是没有正式发布,之前没有经过仔细的试用,后来实际用的时候总是这也不行那也不行,万般无奈之下退回到正式发布的0.8.1版。两个版本确实有不少区别,至少源文件个数都不一样。在实际使用的过程中发现,0.8.1中如果注册一个类时,无论有没有注册它的构造函数和析构函数,都要求它们是public可见的,而0.9似乎没这个限制。 比较郁闷的是,没找到一个可靠的办法,把一个类中的STL的容器类型的成员变量传给Lua。Luabind中有个return_stl_iterator策略,似乎是可以把它传给Lua,也能在Lua进行迭代,但是在应用程序退出时,就会报未处理异常。我想以后如果真的一定有传容器的需求,可以试一下SWIG。 在Lua和C++之间传递字符串是个很头痛的问题。C++中的字符串类型太多了,几乎每种框架或大规模类库,都会有至少一种自己的字符串实现类。在wxWidgets中用的是wxString,但跟Lua交互的最好就是C的字符数组。如果是只读的访问,那还是比较容易处理的,Luabind默认处理了std::string类型的转换,SWIG中只要包含了std_string.i,也是差不多透明地处理了。但是如果要把字符串作为输出参数,那就头痛了,Luabind中是有out_value策略和pure_out_value策略,但实际上我发现在Lua中用的时候程序就崩溃了。暂时也不想再深究这个问题了,顶多在必要的时候考虑修改一下接口了。 又是才发现,SWIG和Luabind中注册的类型是不能互相混用的。比如SWIG中注册的某个函数,返回一个类的实例,而Luabind中又注册了这个类的话,是不能作为那个返回值的类型的。所以有时候可能需要在两边都注册一遍某个类型。比较安慰的是,基本数据类型还是能混用的,呵呵。 对于有缺省值参数的函数,SWIG会自动封装成多个函数,每个函数使用相同的名字,只是参数列表不同。而Luabind一次只能注册一个函数,那个完整参数列表的函数,如果想要达到SWIG那样的效果,大概只能自己老老实实一个一个注册上。 再有是Luabind中,不能随便注册char*类型参数的函数,要注册得指定out_value策略,不过说到这里我就有点疑惑,Luabind好像不支持多个策略的啊,如果有多个参数要指定策略怎么办?而且虽然我没经过测试,但我想除了char *外,其他的自定义类型作为参数的,都有这个问题吧!
花了两三天时间,总算是从头到尾看了一遍Luabind的使用手册,呃,为了确保没有漏过的内容,甚至还把整个文档都翻译了一遍。在看文档的过程中,还是比较感叹该库做得功能强大的,不过在实际用的时候就比较郁闷了。 我用Luabind绑定了一些类和函数等内容到一个模块中,用了SWIG把几个头文件处理了一遍的,把所有内容都放到同一个模块中。一开始发现在Luabind中绑定的类在Lua中死活不能用,调用成员函数时,总是说那个类是个nil,不能被index。 后来尝试了下,把Luabind中绑定的内容放在全局域中,发现居然可以了!虽然这样似乎可以工作,但我想让所有由内部C++代码提供的服务放在同一个模块中。后来想了想,把SWIG和Luabind的注册顺序换一下,改成先注册SWIG的内容,再注册Luabind的内容,嘿嘿,真的也可以了!我猜想可能Luabind的注册内容是采用追加的方式,而SWIG却是覆盖方式。这个猜想没有经过证实,只是如果真是因为这个原因的话,也是可以理解的。
描述一下问题,程序主框架是用C++实现的,GUI框架用的wxWidgets,有一部分功能通过嵌入Lua解释器调用Lua脚本完成,如果要在Lua脚本中用wxLua实现个对话框的这种情况下,需要一个父窗口,而最好的父窗口是由C++实现的,现在就需要能把C++中实现的窗口传递给Lua,并让wxLua作为父窗口使用。 问题根源是出于偷懒的考虑,我把C++中需要能被Lua调用的类、方法等用SWIG嚼了一遍,生成了脱水代码。这样用SWIG返回的wxWindow*跟wxLua中的wx.wxWindow就不是一种东西。 解决方案比较quick and dirty,过程略有点曲折。昨天偶然在wxWiki上看到一段文字,描述了如何将MFC的窗口关联到wxWidgets中,我就想如果wxLua是严格移植了wxWidgets的话,应该也很容易实现的。不过很沮丧的是SetHWND、AdoptAttributesFromHWND、Reparent这三个方法wxLua一个都没有实现!于是又去wxWidgets的Google group上找了找,发现一个叫AssociateHandle的方法,可以关联一个原始的Windows窗口句柄。到了这一步,我已经没有其他出路,只好修改wxLua的源代码,在wxLua\modules\wxbind\src\wxcore_windows.cpp这个文件中给wx.wxWindow添加一个新的方法void SetWindowHandle(long hwnd),代码实现可以抄SetWindowStyle的,函数签名相同,里面的步骤也类似。最后要在wxWindow_methods的初始化列表中添加这个新增的方法,就可以重新编译wxLua了。 有了这个修改过的wxLua,再在自己的应用程序中暴露一个方法以便Lua获取主窗口的句柄,接口就可以在Lua中这样使用了: local win = wx.wxWindow() local hwnd = frame:GetMainFrameHandle() win:SetWindowHandle(hwnd) 这个win就可以作为wxLua中创建的子窗口、对话框的父窗口了!
昨天发现LuaJIT2.0跟某些第三方Lua库不正常使用,于是在Lua的maillist上发了个邮件问问,结果今天看到Mike Pall的回复说是IUP、IM它们的代码里插入了硬编码的已经被编译成字节码的Lua脚本,而这些脚本在IUP中处理时,没有正确处理出错的情况,于是说这个不是LuaJIT的问题,应该向IUP提交这个Bug。 这让我比较纳闷,因为我不知道到底问题出在哪里,即使要向IUP提交bug,只说一句Mike Pall说的你们的代码有问题,LuaJIT2.0里不能require,而明明官方Lua和LuaJIT1.0是可以正常使用的,人家会睬我吗? 今天我又发现,在require另外一个叫iupluaim的库时,LuaJIT 2.0会崩溃!于是我想我先看看是LuaJIT中的哪行代码引起的崩溃,用VC2008创建了个解决方案,添加了代码进去,编译出Debug版本的LuaJIT,重现问题,最后发现居然是lj_vm.obj里崩溃的,而这个lj_vm.obj文件是通过一个叫buildvm.exe的程序生成的,所以VC的调试器跟踪不到它的代码里面去,唉,只好放弃了,反正也不能说一定是LuaJIT的问题,或一定是IUP的问题,只有Mike Pall才知道。 最后,我把直到昨天下午编译出来的众多第三方Lua库都用LuaJIT来require,发现2.0版本中一共有9个dll不能require,而1.0版本只有一个会崩溃。现在想想,这些2.0版本中不能require的dll都是IUP、IM和CD中的,这些库其实我暂时也用不上,IUP可以用wxLua代码,而IM和CD是跟业务基本无关的,就直接用LuaJIT 2.0就行了!
偶然看到云风blog上讲到LuaJIT2.0 Beta发布了,于是很好奇地到它的官方网站上看了看。以前也是听说过有这个东西的,不过以前根本不用Lua这东西,看过也就忘了。 这个东东据说是从API到ABI都是兼容官方Lua的最新版本的,所以一般说来,用官方Lua做的事情,用LuaJIT也可以做。但是它的强项在于,它执行Lua脚本比官方Lua要快,最慢的是快一点点,大概一点几倍,好的情况下能达到几十倍。 这次说的2.0 Beta版本据说是VM部分跟1.x版本来说完全重写了,效率又是提升了n倍。这个效率有提升,其他代价也几乎没有,这等好事不能错过,于是下载了它的源代码来体验一把。 它的编译方法跟官方Lua的很像,反正很容易。在Windows平台最后会生成一个dll文件一个exe文件,这点跟官方Lua也是很类似。只要在编译的时候保证dll的文件名,这样就可以把这个dll拿到其他嵌入Lua的项目中去用了,那些项目的源代码是不用修改的,因为API兼容嘛,而且好像也不需要重新编译,因为ABI兼容嘛。 经过短暂的体验后,发现Beta果然是Beta啊,直接require那iuplua只报什么call nil value,另外就是我自己的那个嵌入Lua的程序会崩溃,具体就没有定位了。而这些问题在1.1.5版的LuaJIT中是不存在的,所以2.0要能正式Release应该还需要一段时间。
之前说过,wxWidgets程序是用MinGW编译的,所以用到的wxLua就只好用其他编译器了,试了BCC 5.5和OpenWatcom 1.8,都因为不能顺利编译wxWidgets而放弃了,只好再掉头用回VC 2008。 既然用了VC编译wxLua,而前些天用MinGW编译的IUP等用起来又有问题,于是就索性让VC把IUP、IM、CD等其他的库也都编译了好了。因为只有最最核心的功能是用C++写的,其他的功能能用Lua的都用Lua写,所以就需要有比较完善的常用功能的库。除了wxLua、IUP这等GUI库外,剩下还需要数据库访问的,至少是能访问sqlite3的,网络通信的,XML操作的,正则表达式,MD5等散列值计算的这几方面的库。现在暂时还没编译,等到时候真正需要的时候再搞吧。 在编译和使用wxLua和IUP的过程中,遇到不少问题。 Lua脚本在require一个模块时,会去几个固定的路径下搜索名字匹配的文件,于是我照LuaForWindows的做法,把dll都放在exe程序所在目录的clibs子目录中。发现一个一直以来的错误的认识,以为一个dll在载入另一个dll时,会像exe一样首先搜索自己所在目录。错了,一般情况下是不会搜索dll所在目录的,而是搜索载入该dll的exe文件所在的目录。所以一开始总是不能正确地让wx.dll载入wxWidgets的dll,后来将wxWidgets的dll放在exe所在目录后,又报不能载入msvcp90.dll,这是VC的重发布文件,本来exe是通过manifest文件来指定这个文件的搜索路径的。所以经过试验,发现wx.dll和wxWidgets的dll是没有包含manifest资源的,只好用命令行mt.exe -manifest xxx.dll.manifest -outputresource:xxx.dll;2这样把manifest再注入进dll。命令行参数都容易理解,最后个2,我猜测是注入后的资源编号,manifest类型资源在exe中是1,在dll中是2。经过这样处理的dll,都能正确载入msvcp90.dll等重发布文件。 接着再解决dll存在位置的问题。本来这些dll只是为clibs下的dll依赖的,我当然不乐意让它们放在clibs外面,所以在网上找了一下,发现确实可以为单独的exe文件设置dll搜索路径。只要在注册表中 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths 下添加一个新的键,项的名字就是exe文件的名字,比如CodingStudio.exe,然后在这个新键中写入字段,默认字段的值为exe文件的完整路径,再添加个新的字符串,名称为“path”,值为dll所在的目录完整路径。这样不但可以在“开始”-“运行”对话框中直接输入exe文件名来启动该程序,还可以让该exe在载入dll时搜索那些目录。 编译IM时,有个im_capture库,在Windows下是依赖于DirectX的,需要先安装DXSDK,现在MS网站上只能找到2008年发布的,版本至少是9.0以后的了,这里有个问题是,im_capture用到了qedit.h文件,该文件中又包含了dxtrans.h文件,而这个文件是没有的。在网上找的方案基本上有两种,一种是在其他地方找个dxtrans.h文件,然后就行了,不过我没找到,另一个方案是修改qedit.h文件,不要包含这个文件,然后在它的开头定义4个宏:__IDxtCompositor_INTERFACE_DEFINED__、__IDxtAlphaSetter_INTERFACE_DEFINED__、__IDxtJpeg_INTERFACE_DEFINED__、__IDxtKey_INTERFACE_DEFINED__。这样就可以了,im_capture只需要DXSDK的头文件,不需要DX的什么库文件。 还有个im_wmv库,依赖于MS的Media Format SDK,可以在MS的网站上找到。其实只是需要它里面的一个叫wmvcore.lib文件,其他的头文件是不需要的,如果把头文件路径添加到搜索路径,反而编译会出错。 最后是发现,在方能iupimglib时,VC的编译器就占满CPU然后就挂死了,郁闷!只好继续用前些用MinGW编译出来的iupimglib.dll和iupluaimglib51.dll了。
知道IUP应该是去年的事,有个叫LuaForWindows的集合,里面就带了一个,上网了解了一下,知道还有一起的IM和CD。LuaForWindows已经提供了使用MSVC2005编译好的二进制文件,不过我不喜欢。我打算用MinGW编译一把。 开始的时候我以为可以直接用自带的makefile编译。结果是我花了半天时间,在msys里编译,还试图根据编译时报的出错信息,来修改makefile。在msys编译失败后,我尝试看那个自带的makefile,以为用TecMake可以编译通过,事实又是让我那么的失望! 最后,经过我对makefile的简单解读和分析,我决定自己写下个bjam的编译脚本。总的说来,我深信bjam是很适合用来编译库的,毕竟boost就是一堆的库。经过近一天的努力,除了那些需要依赖OpenGL、Windows Media SDK、DirectX等额外库支持的库,其他的基本都被我编译出来了。 本来bjam是可以支持一次编译多个工程(库),或只编译一个工程(库)的,不过那种bjam脚本我还不会写,我只能分别为IUP、CD和IM各写了一个bjam编译脚本。看来还是得再深入学习一下啊!
做IDE,很重要的特性是对代码进行分析,并根据分析后的结果做些其他的事情。 出于好奇,在google上搜索一下python、ruby、lua的相关资料,只要以AST为关键字进行搜索,就能找到一些信息。其中,Lua有好几个第三方的项目,专门或顺带实现了AST操作的功能。Ruby的也是第三方的项目实现的,Impeller就是修改了某个第三方实现。Python则比较强悍了,由官方标准库中提供该功能。 虽然这些脚本语言的核心解释器都是用C实现的,不过这些AST功能的实现一般却是直接用脚本完成了,这也是可以理解的,或多或少地可以利用核心解释器中的一点功能嘛!
之前因为使用wxLua,发现如果宿主exe使用的wxWidgets动态链接库如果和wxLua使用的一样,则不能在Lua中正常加载wxLua。虽然可以通过使用不同的wxWidgets动态链接库文件来规避这个问题,但实在是很丑陋的一件事情。 今天想起来,能不能把wxLua内嵌到宿主exe中呢,这样就都使用同一份wxWidgets了。于是看了一下wxLua的代码,代码文件组织是很清晰的,很快就明白了各个文件夹下的文件是什么作用的。使用wxLua的一种方案是,它最后需要编译生成一个叫wx.dll的文件,Lua中可以直接require这个wx模块来使用。打开它的VC工程来看,也就是那么几个文件编译出来的,直接照它的样子把这些需要的文件添加我的工程中,然后编译,看情况需要修改的有几处:因为我的工程用了WXUSINGDLL宏,但这个宏会让wxLua中的一些类变成dll linkage的,所以要把这几处编译开关修改一下;有一个for wxLua的wxApp派生类,删掉;还有一处最主要的,luaopen_wx函数,有一个wxLuaState的对象,要改成直接在创建对象时把lua_State指针传过去,其他有些分析命令行参数之类的代码也是多余的可以删掉。另外还有个问题,在VC9里cell控件的代码中有一个GetRef方法,链接时报错,很诡异,搞不明白,暂时屏蔽掉那行代码。 经过这么一番折腾,终于可以直接在exe中用内嵌的Lua解释器使用wxLua了!
因为怀疑,所以去确认了一把。自己也懒得编译了,直接从网上找了个人家编译好的wxLua,人家是用VC8编译的,我的工程是用MinGW编译的,结果真的可以加载了,我狂晕!不管了,大不了到时候提供个Lua for Windows的安装包链接。 再回来说插件的问题。昨天主菜单是能运行起来了,不过发现有个不爽的地方。因为插件是放在一个指定目录下的,搜索出来的顺序可不是人能控制的,于是添加到菜单上的顺序也是乱的,这就不好了。由此引出另一个需求,对于一个插件应该可以定义多个菜单项,这样至少可以让这一个插件中的菜单项保持可控的顺序。
弄了一整天,插件框架基本上运行起来了,至少主菜单部分能出来了,证明这套机制是没什么大问题了,剩下的没解决的都属性主菜单的问题,而不是插件框架的。 不过之后郁闷地发现,用MinGW编译的使用了wxWidgets的工程,不能使用wxLua,无论是通过C API加载,还是通过Lua代码加载,都不成功。用VC编译的工程就不存在这个问题,如果是普通的工程,没用wxWidgets的工程,也是可以加载的。于是我猜测是不是因为加载相同的wxWidgets而冲突了啊!因为wxLua是用MinGW编译的,还没试过用VC编译来wxLua来试试。开始还怀疑是不是因为路径的问题,或者是用了Luabind的问题,或者是用了SWIG的问题,后来实验发现好像都不是。 用VC编译了wxLua来试试吧,如果还是不行,就没办法了,只好不在扩展脚本中使用wxLua了,唉!本来还以为用wxWidgets的工程用wxLua是绝妙的搭配呢,大不了再试试IUP之类的呗。
写着写着,发现Luabind不是先前想的那样有了SWIG就可以抛弃了的,还是有用武之地的。 主要体现在两个地方。 一、从C++调用Lua函数。Luabind提供了两个方法,在Boost的协助下极其出色地分别实现了调用全局函数和其他可被作为函数调用的对象的调用。这两个方法都以C++模板实现了可变参数类型和可变参数个数的调用,而不是C库中printf使用的那种方法。这得益于强大的Booster::mpl。 二、提供C++中自定义类型的高度灵活的部分封装。用SWIG通过分析C++声明一股脑儿全都封装了,当然可以通过预定义宏SWIG可标识不想被封装的部分,但这需要修改C++源代码,以致于破坏C++源代码的整体风格,而且灵活性明显不行。用Luabind可以随心所欲地把任意一个类的其中几个方法封装了,这个优点是我在看了Luabind中自带的几个example才想到的,比如它演示封装了boost::regex,boost::filesystem,如果想用SWIG,几乎不可能达到目的。
首先,这个架构是一定程度上模仿Eclipse的,并做了大量简化,所以模仿得并不像,不过不得不说最原始的灵感和很多想法是从它那里来的。 支撑起整个可扩展架构是一个类,大概名叫pluginsRegistry的类。这个类一般可以使用singleton模式,它做一些与插件相关的最基础最底层的事。比如,在宿主程序(这里一般是一个C++程序)启动时,它负责扫描指定的一个目录(包括子目录)下所有文件,找出其中的plugin.xml文件,也就是插件描述文件。它并不一定要是xml来描述,也可以是用Lua来描述,毕竟Lua最早的用途就是作为配置文件的,而且这个文件并不会被程序动态修改,Lua也够用,但要注意的是名字空间污染的问题,一个办法是每个描述文件都使用完全相同的结构和变量命名,但每次都单独启动一个Lua解释器来解析。一般说来一个描述文件中声明一个插件,也就是一些基本的插件信息,包括插件id、插件扩展点和插件对应脚本文件路径这三项最主要的不可或缺的信息,以及一些诸如被扩展点,版本号,依赖关系,版权信息等等不那么重要的信息。扫描到一个插件后,这个类会把插件id,脚本文件路径对应着保存起来,并把该插件添加到指定的被扩展点上。所谓扩展点,其实准确一点说,应该是被扩展点代表一个插件会被激活(其中一部分)的时机。被扩展点一般也是由其他插件提供的,也就是说其他插件会在某个它认为合适的时刻,激活所有注册到被扩展点下的所有插件。所以插件描述文件中很重要的一点是,需要声明自己是扩展了哪个被扩展点,不然就永远不可能被激活。由此可以看出,另外一个需要注意的是,一个插件一般会依赖于另外一些插件,至少是依赖于提供它要扩展的被扩展点的插件。一个插件必须要指明它要扩展的被扩展点,这是别的插件提供的,另外它也可以提供自己的被扩展点,让另外的插件来扩展自己的功能,当然这不是必须的。为了说起来不那么拗口,在描述文件中,一般我称前者为扩展点,称后者为被扩展点,这是把同一类事物在一个所属中以其不同的功能或角色来区别而得来的。再回到这个类的功能上来,除了前面讲的这几点功能外,它还应该能向外界提供一个服务,通过该服务外界可以根据指定的被扩展点查询到所有注册在该被扩展点下的插件,理论是希望只是通过一个id就能唯一标识一个插件。这样每当时机合适时,提供被扩展点的插件就可以通过这个服务来做一些事情,最常见的是通知所有该被扩展点下的插件即可,那些插件自己应该清楚这时应该做些什么事情,还有种情况是,提供被扩展点的插件应该可以从中区分出一些插件,而不是全部,来通知。一个很常见的应用场景,主菜单,可以是一个菜单项对应一个插件,这时每当用户点击了菜单项,那么只要激活该菜单项对应的那个插件即可,而不是所有主菜单下所有的插件都要激活一遍。 通过前面的阐述,可以知道,这个类需要一个清晰简单的接口,这样才可以比较方便地既给C++代码提供服务,又给Lua脚本提供服务。尽管Lua从设计上就考虑了很多跟其他语言交互的情形,但这里我还是得小心一点,少使用一些只有某种语言特有的一些元素或特性。 最后,以一个实例来简单叙述一下这个架构是怎么真正让一些功能运作起来的。就还是以主菜单为例,主菜单也是一个插件,当然,它是用C++还是用Lua实现的我们不关心。重要的是主菜单插件首先有一个自己的id,并提供了一个被扩展点,假设叫view.ui.menu,这时假设那个类已经把所有扫描到的插件正确地分析过了,这个被扩展点下已经有一些插件了,比如file_open,file_save等等。主菜单插件在自己被初始化时,调用那个类来得到所有view.ui.menu下的插件,并依次激活这些插件的get_caption方法,根据这些个方法返回的内容,作为菜单项的标题,逐个添加菜单项,并把菜单项的id和它对应的插件(可能就是用插件id来表示)保存起来,当用户点击一个菜单项时,主菜单插件可以得知用户点击的菜单项的id,并从之前保存的信息中得到它对应的插件id,以此来再调用那个类来激活唯一对应的那个插件,那个插件知道用户是点击了菜单点,就执行一些操作,比如打开文件等等。 大致的流程就是这样。
仰天长啸三声,哈哈哈!一直没想出或找到什么办法可以比较方便地解决这个问题。我的需求是,在C++中随时可能生成一些对象,而这些对象随时可能需要被Lua获取并进行一些操作。 在网上转了很久,看过LuaBind,还有一些文章。只有LuaTinker有一个可以把C++对象映射到Lua全局变量的方法,似乎有点接近了。但实际上离我的需求还是有点距离,比如它需要由C++代码知道这是给Lua用的,并主动把对象映射过去,而且是映射到Lua的全局变量中,通用性不够。我希望C++代码可以不跟Lua交互,其次,应该由Lua主动去获取它需要的C++对象,这样Lua可以自己决定把这个对象保存到什么地方。 今天又看了一下SWIG的文档,发现SWIG对Lua的封装做得实在太好了,它可以封装出自定义类型的指针,例子代码中以FILE *作了示范,想了想,我在C++中写个函数,返回相应的对象指针不就行了!试了试,果然可以,这下终于搞定了,可以继续写编辑器了。昨天还在想,有一部分Scintilla的初始化工作,代码好长,虽然初始化内容是保存在配置文件中的,但是配置项多,而且互相之间比较独立,C++代码仍然需要一个配置基一个配置项地写,我就觉得这部分应该交给Lua去做。这里Lua的功能除了原有的保存配置的功能外,还兼任了使配置生效的责任,而且仍然保留了原来配置文件的不需要重新编译主程序就能修改行为的优点。这个思路是对的,但技术难点就是Lua如何操作那个编辑器,这下好了,没问题啦,SWIG真是个好东西,还要Luabind之类的C++ Wrapper干什么!
昨天又看了一下《Contributing To Eclipse》,思路有点清晰了,应该有一个任何地方都能访问到的地方,Eclipse中叫插件注册表,存放着所有插件的描述信息,这样无论是核心还是插件,都可以随时读取到与自己相关的插件的所有必要信息,实现相应的功能。 之前还疑惑,与界面相关的插件处理流程会自相矛盾,现在看来应该能解决了。首先需要确认一点,暴露被扩展点的,无论是核心还是插件,都可以从插件注册表中读取扩展的信息,比如菜单项名称,这样就可以添加一个新的菜单项,以及维护一个处理关系,Eclipse中有个某某proxy的机制,这形式不重要,关键是暴露被扩展点的那个部分应该在添加了新的菜单项后,能在菜单项被点击时,准确地知道哪个菜单项被点击了,并依赖插件注册表找到对应的处理流程,以我目前的情况而言,即对应的Lua脚本文件,Lua脚本模块名称,以及处理函数名称,然后将这些信息提交给插件运行模块来运行,插件运行模块则又要与插件装载模块合作,如果运行时发现没有对应的模块或函数,则要先装载对应的脚本文件到解释器中。
又看了一会儿PIL,以及云风blog上的一些文字,以及Lua Manual等等,终于有点眉目了。 完全可以下放权力给Lua,让它来创建wxScintilla对象,然后通过某些方法,把这个对象返回给C++,在C++看来,就是一个lua_touserdata吧。 至于如何保存和索引这个userdata,从PIL中看到,可以保存到registry中,也可以在registry中再多加一层索引,放个weak table。而索引方式,可以用一个C++指针,在Lua看来是lightuserdata,作为索引的最好方式之一,不过我还没想明白,到底怎么转化为实际生产力。倒是看清楚了些registry的操作方式,就是一个表,只不过该表在Lua栈中的索引是固定的值。还看清楚了些weak table的工作方式,weak table,也许叫weak hash或weak map更能让习惯用C++的人明白些,里面的每一条记录,都是一对key和value,而这个weak table可以将它的key,或者value,或者两个都是设置成weak的。weak的意思是说,假设我这个值(key,或value,到底是哪个,要看这table的属性,把metatable中的__mode域设成\"k\"或\"v\")已经没人用了,就把这条记录在垃圾回收时都删掉。原来就是这么一回事,PIL中说,应用lightuserdata时,要结合weak table来用才好,并一笔带过举了个窗口消息处理的例子,我没看明白,晕!其实,我想我是知道作者的意图,我在Lua中创建了userdata,一方面要能方便地供C++和Lua两边都能使用,另一方面,要防止Lua自作主张地把userdata回收掉。用weak table大概就是为了能让程序员来控制userdata销毁的时机吧。
今天没干什么事,看PIL去了,结果一脸茫然。昨天兴奋地以为用luabind就能把那些问题都解决了,实际上高兴得早了点,而且我也想偷懒到极致,用SWIG生成胶水代码后,再在C++和Lua中进行无差别地使用对象。我现在的应用场景是,在C++中创建了对象,如何在需要的时候,调用Lua脚本的某个函数时,在那函数中能方便地访问到那个对象进行操作。看LuaTinker是可以把C++对象直接映射到Lua脚本的某个全局变量中去,不过我感觉使用全局变量不太好,而且是C++在主动做事。我希望的是这样一种形式,C++在调用Lua函数时,把该对象的指针作为参数传递过去,Lua函数能根据这个参数取得实际的对象,进行操作。在网上又看了些文章,感觉这应该是一种很常用的用法才对,也不知道别人是怎么用的。 初步的想法是C++创建对象时,用lua的newuserdata来分配空间,在这空间内进行创建。然后有了个地址,即指针,把这对指针和数据保存起来,可能用得到设施有registry和weak table,还有lightuserdata这种东西,但具体怎么用,还没搞明白。看PIL云里雾里,还是得写些代码实验一下。
今天偶然看了一下luabind的官方网站,发现1月4日时有0.8版出来了,让我有点惊喜,想想上个版本0.7,是2006年1月时放出的,沉寂了20个月,2008年10月才有0.7.1。中间这漫长的近两年时间,让我都以为这个项目太监了呢。 兴匆匆地把代码下载下来。印象中,网上有人说过luabind不需要事先编译,直接把源代码加入到工程中一起编译就能用。不过我这次还是想试试把它编译成单独一个库。看到0.8只有一个Jamroot,设置好LUA_PATH和BOOST_ROOT,把bjam.exe复制过来试了几次,说找不到什么文件或者目标,晕,对bjam可是一点都不了解,也不知道从何下手。从网上看到有人说luabind只能用VC7编译,我诧异了,还是想试试MinGW的编译。直接自己输命令行g++来编译,只要设置好lua和boost的包含路径,是可以编译的,每一个.cpp文件都能编译通过。最后从0.7里提取出makefile来,这个makefile也有点问题,编译命令行参数要改一下,主要是包含路径,然后就可以用MinGW编译生成一个libluabind.a了。 这下好了,苦恼了很久的怎么让Lua脚本使用C++对象的问题应该很容易解决了。至于MDI中多个视图的问题,简单点,就每次都把当前激活窗口的视图指针传给脚本,稍微麻烦一点的,用C++写个方法来获取想要的视图指针,返回给脚本使用。昨天研究了wxScintilla.h文件,直接用SWIG就可以生成一堆胶水代码,不过还没有试过能不能正常使用,想来应该没什么问题,对SWIG的好感不是一天两天了,哈哈。
因为考虑到要跨平台,所以不能用MSXML了,而且对于MinGW能不能直接使用MSXML我都不抱希望,于是在几个开源的可跨平台的XML解析器中进行选择,并且只能是用于C/C++的。候选项包括expat、TinyXML、libxml/libxml++、Xerces-C++。我不喜欢expat的实现方式,也不习惯TinyXML的只有DOM的解析方式,而libxml/libxml++则是因为捣腾了一阵子还是没能用MinGW正确编译,最后的选择只剩下Xerces-C++。而实际上编译Xerces-C++也花了我一些时间。网站上最新的是3.0.0,倒是有VC7、VC8、VC9的编译好的包,不过我要MinGW的,所以下载下来源代码,看了一下网站上的说明,先装好msys,选好参数运行./configrue,就会生成makefile。而这生成的makefile似乎并不能直接用MinGW的make过,需要稍微修改下,也就是把其中所有的什么dirstamp目录的创建和依赖都删掉,方能编译。 编译wxLua稍微好过一点,不过一开始绕了点远路。从CVS下下来的源代码,到build/msw下找makefile.gcc文件,这个文件少了写了两个编译选项,以致于在生成库时在链接时总是去找WinMain,开始不明所以,硬是把LDFLAGS设为-shared,在编译库时是没问题了,但编译出来的.exe文件就不行了。后来发现只要添加LINK_DLL_FLAGS := -shared和LINK_MODULE_FLAGS := -shared就可以一切正常了。当然wxLua依赖于wxWidgets,所以事先要设置好WXWIN和WXCFG环境变量,而且最后面不能有反斜杠。只要设好了这两个环境变量,用VC9倒是可以很顺利地编译过。 有些时候不免要抱怨一下,开源的东西,易用性可能确实差了点。
今天又看了一下wxLua,其实很简单一回事只要把用CVS下载来的wxLua源代码编译一下,生成一个wx.dll文件(当然是在Windows平台下的),该文件依赖于wxMSW的两个dll,分别是wxmsw28u.dll和wxmsw28u_stc.dll,如果用不同的编译器,或者编译选项,可能会有不同的文件名后缀(注,不是扩展名)。我是用MinGW最新扩展4.3.2 TDM-2来编译的,把编译出来的dll放到搜索路径下,用lua.exe就可以直接运行wxLua自带的几个例子程序了,比如auidemo.wx.lua。 开始时,还在想到底是嵌入一个纯粹的Lua解释器,还是嵌入wxLua。其中的区别就是嵌入wxLua可能会需要多点C/C++代码加到工程中,作为胶水代码连接lua代码和wxWidgets。现在发现,其实不用管这么多了,只要嵌入一个纯粹的Lua解释器就够了,再设定好搜索路径,即package.cpath,就可以自由地装载wxLua了,其他的第三方库也可以用了,比如LuaXML、LuaZip等等。 我仰天长笑,接下来的问题是,如何让外部的Lua脚本识别出各个scintilla控件。MDI界面必定会有多个Scintilla视图,怎么能让脚本方便自主地获取到自己需要操作的那个视图呢?
两年前,就嵌入过python,那时宿主程序是用C++Builder开发的,python还是2.4,没用第三方库,完全用python C API直接操作,而且当时要暴露的接口不多,才4个C函数,当然还是费了不少力气。嵌入python的目的是为了主程序可以实现外部脚本扩展,只有一个很简单的应用场景,点击一个菜单项,就执行一个py文件。首先是要让它能执行起来,python文档有很多C API,例程却极少,记得当时连接1个半月每天至少到后半夜2点才睡,最后累得上wc连掀马桶盖的力气都快没有了。而且很大的问题是,在家里自己的电脑上终于可以跑起来了,拿到公司的电脑上却不行,每天只能晚上回家调,白天再到公司测试,很郁闷,我已经忘了最后是怎么搞的,反正是最后发现在公司的电脑上缺少一个site.py文件,直到这一刻才发现,这是python官方发布包中的一个文件,当时是自己放了一个0字节的文件在那里搞定的。那次这么多精力的投入真是不值,做出东西来本来想得个满分的,结果只打了个C,而且当时指定了4名专家评审,结果只有2个专家发表了评论,另2个还没评论就走到下一环节,直接C了,唉! 今天又看到很久之前写的计算hash值用的小程序CryptTool,核心功能早已完成,就是计算字符串,或文件的hash值,包括多种算法,比如MD2、MD4、MD5、SHA1、SHA256等等等等。后来出于尝试的心理,想给程序加上外部脚本扩展的功能,准备支持Lua、Python、Ruby三种脚本,而且不自己写粘合代码了,而是采用SWIG自动生成。Lua和Ruby的支持很快就完成了,可是Python的却一直有问题,网上翻了不少代码,以前C++Builder中的那个代码也翻出来,都是有问题,那时就搁下来,今天又心血来潮地想弄一下。 最主要的困难还在于对Python缺少了解,但这并不能成为借口,Lua和Ruby不就好好地嘛!这里我用的方法是把外部脚本文件作为module,import进来,但是一直返回一个空指针。实在没办法,PyErr_Print打印的内容又是输出到控制台的,而我的是个标准的MFC写的GUI程序,所以只好另外建了个控制台的测试工程,幸好模块独立性较好,几个文件拷过去略作修改就可以了。通过控制台输出的出错信息才知道,原来是import时,还会连带着import一些python自己的库,于是把python的lib目录添加到sys.path里。另外,如果说import这外部脚本文件时,报找不到该名字的module,就把脚本文件所在的路径也添加到sys.path里。终于可以在import时,执行一遍该脚本了!不过还有另外一个问题解决不了,就是调用Py_Finalize崩溃!在网上找了一圈,也有一些老外遇到这个问题,不过要么就是没有下文,要么就是给出的解决方案不适合我这种情况。因为我是import来执行脚本的,当没有Py_Finalize,而同一进程内再import时,就不会再执行了,作为外部扩展,有一个办法是定义一个基本规范,脚本中一定要实现一个指定名字的方法,再由宿主程序来调用这个方法,但这太不友好了。其实如果能用PyRun_File之类的API来强制运行一个文件的话,也是可以达到目的的,但还是绕回原来的路上去了,我这里PyRun_File这类API死活不能正常执行一个脚本文件,天呐! 于是还剩下一个遗留问题,怎么能解决脚本每次都能执行的问题呢?嵌入Python真辛苦啊!
今天又培训了一把ruby,再次让我感受了一遍ruby的强大,真是一个无所不包的魔幻型语言啊! 开始,老大先演示了一个分布式ruby包的应用,几行代码,就能实现一个服务器端组件,再几行代码,又实现了一个客户端,调用了服务器端的对象,其简便程度太让人吃惊了。这种应用很能吸引人,特别是可以做一些加密功能。但我想我还是不放心就这么去用它的,我很担心它的性能。反正WEBrick开的Gem server有内存泄漏问题,就一直让我对ruby做实际应用持有怀疑心理。在我看来,也许脚本语言的真的主要战场在字符串处理上,写个小程序也许可以应付,开发成本比起C++来确实低得多,但做稍微有点规模的应用,就还是让C++来吧。 而Lua这种,在我看来真的还是用来做为C++应用的扩展机制,描述一下插件逻辑,我想不出还有哪里能更适合它的,和还有哪个脚本语言比它更适合来做这个的了。 Ruby让我最不爽的是,对嵌入支持不好,《Programming Ruby》一书就提到,ruby不是设计成用来嵌入的。不过我在想,以我目前的需求,即使要嵌入,一个进程用一个解释器应该能满足需要了。看公司那个项目里,为了让嵌入的ruby解释器多做点事,就创建了一个又一个新的工程来嵌入,也是一种解决办法啊,哈哈。
虽然几年前就知道SWIG了,但一直以来都没真正用过,又是一次叶公好龙。 今天在公司里跟同事偶然谈起项目里嵌入的Ruby解释器的问题,于是回来兴致高涨,决定研究继续研究一下CryptTool遗留下来的问题。 首先介绍一下CryptTool。这是一个可以使用多种算法计算文本或文件内容的hash值的小工具,最早的原型是几年前还在大学时写的一个计算文件md5的小程序,去年做一体化平台时,有一项内容是要用一个单向散列值来近似唯一地标识一个文件,所以顺便找了一个几种常用的hash算法源代码,包括md2/4/5、SHA1/224/256/384/512、haval3/4/5、CRC、GHash、Gost3/5、RMD128/160/256/320、Adler32、FCS等。回家用MFC写了一个,完成了多种算法计算的功能,当时突然兴起,觉得可以嵌入脚本解释器,实现外部插件扩展。结果只是实现了搜索指定目录下的脚本文件,并添加相应的项到主菜单中,通过菜单项激活脚本执行。连脚本执行都没实现,因为当时贪心,又觉得好玩,打算把Python、Ruby、Lua都嵌入进来,确实都链接进来了,却没有实际的功能。 再简单介绍一下SWIG。早先,我只知道它是用于嵌入和扩展脚本解释器的,但具体详细的作用却并不清楚。现在,我有了新的认识,SWIG主要作的是扩展脚本解释器时,将C++代码做一层封装,实现自动向脚本解释器注册相关的信息(如函数、变量、模块等等)。说起脚本解释器的扩展,大多数的资料,甚至连SWIG的帮助文档里,都是说的将C++代码编译生成动态链接库,然后官方的脚本解释器会载入该动态链接库,并在解释执行脚本时使用动态链接库中的内容。而我现在的需求,前面已经略有提及,是把我自己的exe程序里嵌入的脚本解释器扩展了,并且我要的是实现该扩展功能的代码是exe的一部分,而不是独立的动态链接库。两年前,用C++ Builder写过一个用于数据处理的小程序,其中就花了不少精力实现了嵌入Python、TCL、Lua,并扩展了几个函数,当时全部都是通过手工编写代码,按照标准的官方推荐通用作法实现,以至于连续近2个月几乎每天都是后半夜2点才睡,到后来精疲力竭,连上WC掀马桶盖都觉得异常吃力。 现在用VC实现嵌入和扩展理论上应该也不会有多少差别,只不过扩展部分是用SWIG完成的。先写一个后缀为.i的文件,定义扩展的模块名和扩展的函数原型,如果有变量也写上。然后在命令行中运行SWIG,用法行简单,命令行参数也很简单,因为是放在MFC工程中,所以理所当然地把输出限定为C++类型的代码。这里值得提一下的是,指定输出的文件名,用.h文件比较合适,它里面是一堆函数的实现,但并没有单独的原型声明,所以在实际工程中,只要直接include该文件就行,而不是当成源代码.cpp添加到工程,不然编译会比较麻烦。另外还有一点是,写在.i文件中的变量类型,不要用宏定义,而是用实际的标识法,开始我用LPCSTR和LPSTR分别表示const char *和char *,结果在脚本调用时,就会报类型不匹配,直接写成const char*和char *就没有问题了。再有一点,SWIG生成的代码中,会有一个初始化的函数,该函数完成各个扩展的登记注册功能,在EXE内嵌入脚本解释器后,需要自己调用这个函数。而且从该函数可以看出,Lua的就需要一个lua_State指针,说明Lua是能支持进程内嵌入多个解释器的,而Ruby和Python都是没有参数的,说明一般说来只提倡一个进程内嵌入一个解释器。 曾经看到有人(似乎是SWIG的作者吧)说,SWIG生成的代码可读性很差,今天我看了看,觉得还可以,需要关心的部分还是能大概猜出一点意思的,而其他的都是辅助性的代码,也就是完成实际的接口转换工作的。除了这个问题,还看到网上有人说过,SWIG实现的粘合层,在效率上会不如直接手工写的那种,今天我看这些生成的代码,觉得此种言论是立不住脚的,因为完成实际接口转换工作的代码都是固定的,应该也是SWIG的开发人员先手工写好的,在效率问题上并不是值得纠缠的。 用SWIG扩展exe内嵌入的脚本解释器,可以大大减少工作量,降低出错的机率,实在是一种值得推广的工具。比如最近在考虑的,在C++程序中实现一套仿Eclipse的插件机制,使用外部脚本实现程序的业务逻辑,这时用SWIG就可以直接将大量内部核心接口转换成内嵌的脚本解释器可接受的形式,极大地提高工作效率,对于使用COM接口的方案,真的是不太感冒!
今天突然灵光乍现,觉得这个输入法里可以嵌入Lua解释器,用来作些额外处理。当前想到的可以让Lua处理的事务主要是有些零碎的任务,比如将特定的组合字串翻译成另外的候选字串,比如在可以在词库中添加一条记录wygd,对应的五笔应该是“今天”,但在用户词库里多加一条记录对应是%%today,然后在匹配的时候发现%%,就取出后面的today,然后调用名为today的Lua函数,并把组合字串和当前的输入法模式作为参数传递给该函数,函数应该根据实际情况,返回诸如“2007年6月18日”之类的字符串,这样就可以扩展输入法的词库了,而这个词库里的内容是可以根据实际情况自动变化的,并且不需要修改输入法的源代码。不错不错,这是很好的一个使用Lua的场合啊。加入解释器后,Debug模式下ime文件是1MB左右,Release模式下是400KB,也不是很大,用UPX最高级压缩一下,可以减小到200KB左右,呵呵。
Lua5.0和5.1的区别还是有一点的,用LuaTinker的时候,它是为5.0版本设计的,改成用5.1的编译链接后,连例子程序都有点问题,不过大部分的功能还是都实现了的。但是,可恶的是,不知道为什么,在用Borland的C++Builder进行编译时,总是出现Internal Compiler Error F1004,连一点可参考的信息都没有,郁闷啊!不知道是哪里出问题了! 不过对于怎么使用Lua与C++进行交互,在阅读LuaTinker源代码的过程中,又有了一点新的认识,呵呵!而LuaBind似乎就太过复杂了,还用了Boost里的不少东西,包括MPL、TypeTrait等等。先就只研究一下LuaTinker吧,呵呵。
在看LuaTinker代码的过程中,惊奇地发现,它居然用了可变数量的模板参数!!这个这个这个,对我来说,不啻于晴天霹雳,《Modern C++ Design》上可是写着“Variable template parameters simply don't exist.” 我打开VC2005又试了一下,明明白白,VC7.1到VC8,都是可以这样用的。到底是哪里出问题了,谁错了…… LuaTinker在处理C++ free function的时候,是把pointer to function当作light userdata压入了virtual stack,网上到处都流传着一份不知道从哪里散发出来的用proxy手法解决的方案,感觉不如LuaTinker的爽。
基本上没怎么费事儿,比原先想象的工作量要少好多,甚至处理分发函数和map都是用的同一个。就是保存函数指针的实现跟原来的不一样,从R (*f)(...)这样的形式变为R (C::*f)(...)这样了,多了一个C,其它就是一路走下来,没什么难点。 而且,顺便把tcl_state::close()改了一下,刚好可以用来释放map里保存的那些东西。 不过,还是没想好,怎么实现functor的调用,如果实现了这个,就可算是一个完整的C++ wrapper了,呵呵。
虽然在公司加了2个小时班,回到家比平常晚了2个小时,但这次比较奇怪的是,我居然没有堕落,把QQ关了,也不开网页,而是专心地写代码。太好了,TclSuck已经初具雏形了,可以方便地定义普通的函数扩展了。这样下来,至少可以当作写技术报告的素材了,哈哈哈哈,就这样哄骗过去吧。其实要好的话,最好加上对类成员函数的支持,还有函数对象。这个慢慢来,呵呵。 I's有2集已经down完成了,随便打开第1集看了几眼,熟悉的情节,大一时候在宿舍里看过漫画。原来I's是男女主角的名字缩写,因为当时没看最开始的几本,所以错过了!这是一部很感人的漫画,男女主角互相暗恋着对方,却不敢向对方吐露心声,一直坎坷的感情经历,最后终于在一起了。所以,爱了,就要勇敢地表白自己的心情,要让对方知道自己爱着ta,即使被拒绝,也至少不会在多年后为了年轻时的胆怯而后悔不已。
Category Be Old
1月21日下午3点半就从公司走人了,到柯桥、绍兴路段堵了一会儿。
除夕,小丫头给我发短信说最近遭遇了很多很多不幸,跟做梦似的。她爸爸过世了,给人家干活时从屋顶摔下来。她自己流产了。我不知道自己可以做些什么。橙子在Facebook上说,还是放不下吗。我说,我想关心她,却没了以前的那种男女之情,倒有点像亲情。
春节的行程比较充实,初一中午在家接待干妈一家,晚上去干妈家。初二去大姨家。初三在家休整。初四接待大姨小姨,下午还去上坟。初五晚上去小姨家。初六,就是今天,到上海。
木有宽带的日子,真不习惯啦!
好久没来更新了,本来照往年的习惯,跨年时总会写点过去一年的回顾和对新一年的展望的,不过这次12月31日晚上就回浙江去了,然后没有宽带,于是也就没写。后来每天都有每天要做的事,于是一直拖到现在。
2011年是很折腾的一年,7月底又跑到上海来了,然后生活上,发生了一些很狗血的事件。本来到上海,主要是为追寻爱情而来的,可是仍然没有收获。至于事业,也是毫无进展。意外的收入是靠着Ninayan这个小程序,上半年Nokia送了一个C7,下半年CSDN主办的Qt应用开发大赛匆匆提交后,得了个二等奖,奖品是N8。从4月份开始找工作以来,就没怎么写过代码了,看到之前自己写的那些代码竟感到特别陌生。
2012年,可能会是有很多事发生的一年。想去旅行,说了好多年的北京,以及突然这两个月突然冒出来的新加坡。要努力写程序,赚钱。现在计划中有三个项目。一个是烂摊子,要改。另两个还没开始。
然后,可能是消失。
唔,又老一岁了。以前说这话的时候,有点装逼的感觉,现在说这话,则是有点心有戚戚了。
其实昨天晚上到后来我自己都已经差不多忘了,11点多时就打算去睡觉了,不过后来玩着玩着就到11点50几分了,然后看到木耳说“换个电池 关键时刻不能没电 8mins”,我还没反应过来,后来不知道是被什么事提醒了一下,才意识到木耳应该是在等00:00这个时刻了,于是心中便不免有点期待,也有点紧张。
果然到00:00后木耳发了祝福推出来,很激动,更是感动。刚回复完木耳,便收到晓晓的短信,后来知道晓晓也是特意没睡等着给我发短信的。然后我的mention timeline瞬间被祝福推刷满了。没多久莎莎也发短信来,说来晚了,嘿嘿。很有趣的是墨墨,1点的时候,我都刚刚迷迷糊糊快睡着的时候,居然发短信来了!
谢谢木耳谢谢晓晓谢谢墨墨谢谢莎莎,还有所有祝我生日快乐的推友们。
好吧,突然发现twitter上很多人说要写年终总结神马的。
总的说来,又是一事无成的一年,做SW已经一年多了,收入只够支付空间和域名的费用,这个太凄凉了,有点奇怪。想想可能是方向有点偏门,然后品质又达不到目标用户的挑剔的要求。所以最近一两个月已经在作些调整了。一方面,原有的IDE产品线,要继续推出其它编程语言的支持,以及支持TextMate的Bundles机制,还有实现几种最流行的SCM工具的集成。这三条是做为杀手锏的。另一方面,开辟新的产品线,已经有一个SNS/RSS客户端目前正在开发,完整的计划是PIM产品线,包括GTD、PKM、理财、日记、Email以及SNS/RSS的完美整合的客户端,而且是要覆盖Windows/Mac/Linux/Symbian/MeeGo这些平台,甚至Android与iOS可能也会有支持,这是后话。
再说到上半年,还以为能脱光的,结果可耻地失败鸟,倒是有点怨气的,花费了不少时间和金钱,不过也只能以发现得早代价小来安慰自己了,尽管这个代价已经超出我的底线很多。突然很想念小妞,思思她们,以及跟她们一起生活的时光。
至于对明年的期望,呃,还是老样子啊,希望SW事业能尽快走上正规,甚至飞速发展。然后有点底气后,希望能顺利脱团吧。啊,我只是想脱团,还没想结婚,我说过没有买得起上海或杭州主城区180平房子的能力前,暂不考虑啊。
其实我一直不是很确认小妞生日是哪天,只模糊的知道是5月底的某一天。本来翻出以前那个已经掉了6个键的Nokia N73,看到屏幕上赫然列出“小妞生日”字样,但我仍是不确认。前些天还试图打电话问小思宇的,不过她居然不接我电话,不知道是确实没接到,还是因为看到陌生号码故意不接。直到刚才,我跑到QQ空间上去看了一下,发现今天确实是小妞的生日。
于是给小妞打电话问候了一下,她正跟俊英在百草园吃蛋糕。上次打电话,是两周前了吧,我很失落,很无助,想寻安慰,然后小妞耐心地开解了我很久,听到她在电话那头打哈欠。
小妞生日快乐!
2009过得很快,真的好快,感觉没做什么事,却又真的发生了些什么事。 不过我的记忆只到2009年的春节。在春节前,我仍然做着那看不到尽头的一体化平台项目,哦,后来有个正式的名字叫流程集成管理平台。春节后,经过各方的努力,我被调回自己项目组内做Ruby IDE,本以为这回是自己感兴趣又熟悉而富有想法的事了,可以大展拳脚了,可是现实老是跟理想偏差很远。一切都显得那样自以为是的混乱而不求上进。这样的状况一直持续到9月底辞职。 是的,辞职,我终于辞职了。记得清明放假回老家的时候,遇到一个看相的女人,说我今年工作会变动,当然她说的语气要难听一点,说是我工作丢掉了。当时我还是有点嗤之以鼻的,我是个比较向往真有神之类的存在的,但同时我却又是个比较坚定的无神论者,所以我觉得这种神棍的话,好听的可以听听当作鼓励,难听的就要过滤掉了。现在回想起来,我也不清楚到底当时是怎么下定决心辞职的,其实我很是怀念在深圳在华为的生活的。正是因为对在华为的生活方式的不舍,去年腾迅给我的offer我都拒绝了,当然还有其他各方面的原因。又想想,如果去年真的去了腾迅,我是不是会一直在那里干下去了呢。 辞职的时候,需要跟四级部门主管开始往下的各级领导沟通。所以能遇得到的最高级别的领导就是四级部门主管了,当然我果真见识到高级别的人眼光和视野确实是更锐利和明亮一些。给我印象比较深刻的是他当时问我“难道你就真的对自己以后在华为的发展这么没有信心么”,一句话说中了我辞职的最大的原因。是的,没信心,一点都没有,所以我只能离开,寻找自己的理想,追求自己的野望! 说实话,我一直没有很明确的思路,自己以后要怎么做的思路,我只有一个大致的目标和方向,甚至于这个目标和方向都时不时地产生模糊的变化。不过辞职后,我有了大把的自由支配的时间,我越来越觉得如果不辞职,根本不可能支撑起我想做这些事的欲望。但是,尽管每天的时间全都给了我自己,时间仍然是不充足的,我仍然要花大量的时间去堕落和颓废。辞职前,我曾经想着好好看一些书,好好学一些东西,结果到现在仍然没有进展。 2009已经过去,充满机会的2010已经开始。曾经数次列入新年规划的计划,每年都没有得到有效的执行,所以仍然要列入2010规划之中。我希望,2010是我事业上能够明显看到成功的一年,我需要组建一个小公司,招收一些人马来实现我的理想!
不知不觉,2008已经过去,又是一事无成的一年,凄凉到我有点不堪回首。 12月31日是江江的生日,江江居然邀请我到她家去吃火锅,这让我有点受宠若惊。记得30日时她发邮件,我还没反应过来,一直到31日上午才明白,于是思量着送点什么小玩意儿意思一下。一直到下午快下班的时候才跑到孙同学那里去,抢了她放在机箱上的娃娃。说受宠若惊,不是夸张,而是有原因的。一是我自以为跟江江并不那么熟络,二是我知道江江有BF但她却一直吞吞吐吐,这么邀我去,不就让我什么都知道了吗。不过太多的猜测,或者说心里搞得太明白,反而会让生活变得累人,所以还是不管那么多了。到了江江家,是一套七八十平的两室两厅,有点温馨的感觉。江江的BF似乎有点眼熟,可能是以前哪里见过,但我一点都记不起来,但是他说见过我,汗!火锅味道不错,还有很多肉和丸子,是我很喜欢吃的东西。吃过火锅又打麻将,一直到午夜12点,真是心旷神怡啊!没想到这次新年钟声响起时,我是在打麻将,哈哈。以前的各次印象已经差不多全没了,只记得有一年,大三吧,居然是在自习,欢呼声传出时,我刚刚走出二教大门。 1号,也就是昨天,在家宅了一天,连饭也没正常吃。先是捣鼓了一阵wxLua,它的出现让我犹豫,我是只嵌入Lua,还是嵌入wxLua呢。用嵌入wxLua的好处是,除了用脚本来表达业务逻辑外,界面的一部分也可以方便地用脚本来做了。但从网上看到的一些文章看来,wxLua的评价并不高,而且最大的问题可能是绝大部分开源软件都有的问题,技术支持太少,出了问题不知从何下手寻找解决方案。从CVS下载下来最新代码,直接用MinGW编译还不过,要改下makefile才行,而用vc9编译,则完全不知道如何下手修正了。然后出去吃了个KFC,修剪了一下头发,就看小说去了,看到后半夜! 2号了,好些天前就跟猫猫约好去看电影,起床玩了一会儿电脑,掐着时间出去坐335,到中信广场。来深圳这么久,看电影只去过1次CocoPark的百老江,去过3次东海太平洋。这次不知猫猫从哪里弄来的电影票,刚好去看看新南国的环境怎么样。先去吃了顿泰国菜,然后晃悠上去。片子还是不错的,冯小刚作品,葛优,舒淇主演《非诚勿扰》,有点搞笑,中间有点悲伤和无奈。看完电影,去购书中心晃了一个多小时,跑去喝鸭血汤作为晚饭,然后打道回府! ……
自从离开了老家,就开始以公历计算自己的生日。又是一年生日到,早上小思宇发邮件给我,让我小小地感动了一把,真还有人记得哦,于是开始商量晚上去哪儿吃饭。下午的时候小妞也发邮件过来,不过上周五的时候小妞就说今天没空,于是就没喊她一起。然后叫上两个cm0同学一起去湘江老厨吃了一顿。下班时,老大说晚上的新员工预答辩人人都要参加,我马上说要请假,理由是晚上约了人吃饭,老大说了句哦,特殊情况,就放我走了,哈哈。也没吃多少,最后埋单时我都没看是多少钱。吃完饭,小思宇把小妞叫出来,一起到百草园游泳池边吃蛋糕,蛋糕其实大家都吃得很少,小妞是在减肥,真是计算着卡路里来吃东西的,而剩下我们几个是因为刚刚吃完饭,肚子还是比较撑的。 总之,祝自己生日快乐,在3个mm用她们的手护着那支小蜡烛不被风吹灭时,我飞快地许了3个愿望,我说我要多赚钱,多讨老婆,哈哈,还有一个我没说出来,希望大家都平平安安。
贫穷的人只能以贫穷的方式向自己在意的人祝福。 昨天忙乎了半个晚上,想今天给小丫头一个小小的惊喜,结果今天发现昨晚最后打包成安装程序的时候还是出了问题,枉费了我画了好一会儿的splash了。 不过大部分主要的功能还都是按照预期实现了,呵呵。 小丫头生日快乐哦!
遥祝小思宇生日快乐,一年复一年,一年何其少。最近昏得连日期都忘了,昨天下午下班后回家,突然想起来,慌忙拿出日历看了看是几号,还好没过,今天早上起床便发了个短信意思一下,嘿嘿。 界面基本上搞得差不多了,争取在放假前剩下的四天内,把与GT3K交互的部分完成,至少接口都要实现好,估计那些跟用例交互的部分是不会有这么快出来的。今天得到一个VC写的Demo,估计也只是时间问题了,哈哈,小小地开心一下。四天内如果时间有空闲,可以再完善一下那个一体化平台的设计需求,还要研究一下那个单板软件的需求。都是要新学的,也好,平常自己都不忍心逼自己,趁这次机会刚好对嵌入式开发和COM都有新的认识。
真又大了一岁了,中午去梅林小肥羊吃了一顿,包厢里是有300块的最低消费,大概是因为不喝酒的缘故吧,吃了250的时候,我们就差不多有点饱了,最后50块的是又随便点了点东西。从小肥羊出来,就不知道去干什么了,8个人意见不统一,其实我心里是比较倾向于去天籁村K歌的,因为便宜而且能消磨掉一下午时间,不过居然连猫猫都不想去,真让人觉得奇怪。几个人走来走去,在梅华路上来回了几趟,还说去打乒乓球,不过想打的人好像不多。最后还是决定去打牌,就是梅兴苑后面的一个茶艺馆,以前xcc跟我说过,在里面打过一个通宵的牌。这次我们也包了个中包,18点以前20块每小时,18点以后就25了,lyy回家去了,剩下几个人就打麻将去了,而我跟疯丫头则在那里看了一会儿《我猜》,然后开始下棋。开始疯丫头说要下围棋,把我吓到了,心想这回要丢人了,因为以为她这样主动说的应该有点厉害吧。结果这个家伙让我活了一小块她原本以为能吃死我的棋后,就说要重下,嘿嘿。然后开始下五子棋,她说她以前都没下过,所以我就很随意地跟她下了,慢慢地发现好像她变厉害了,呵呵。教授和悍超两个人来看我们下,看了一会儿都看不下去了,说我在那里放水,结果让疯丫头感觉是被人泼了冷水,呵呵。一直弄到7点半才出来,天下雨了,就近找了个东北饺子馆吃,吃了60块钱,其实我挺饱的。 小丫头还发短信来,说了好一通话,呼呼。又长了一岁了,祝自己生日快乐的同时,希望能在之后的半年内有好的发展吧!
今天是教授的27大寿,其实好多天前,好像还是大牛生日前后的时候,我就已经想到今天了,还跟疯丫头说了,还去逗教授玩,说给教授去弄个礼物来。遗憾的是,疯丫头是一直没出席过最近几次同事们的生日宴,从猫猫到大牛,再到今天的教授。 今天白天是评议了一天,上午2个小时,下午接近3个小时,几乎没有时间干点其它的事情,实在是讨论得全身难受,而教授则像是被人先整了,不知道谁用他的notes发了个邮件,疯丫头还说是我弄的,结果只骗了她一个人。哈哈,看那邮件的内容似乎是一本正经的样子,也难怪疯丫头这么信教授了,呼呼。 下班后,一群人奔向湘江老厨,雨烟还想鼓动猫猫也送教授花,结果如我所料,猫猫是肯定不会送的,最后就挑了个小森林,哈哈。 我发现我有时候的脾气还真是挺大的,结账的时候,他们多算了一个人,我就很大脾气地冲过去叫他们数数凳子,而且好像很凶的样子说,难道我们13个人坐12个凳子。小思宇曾经还说过很怕我生气的样子,有时候打的,我在前面跟司机犟的时候,她们在后面吓得直发抖,呵呵。我还怕小思宇呢,倒吸一口凉气也是最经典的一幕呀! 不扯别的了,教授又大了一岁了,怎么还不着急找女人呀,呼呼,我都急呢。总之,教授生日快乐,在新长的一岁里,找个好女人!
大牛两天前开始就发邮件问,周五晚上有空一起吃饭。我当然无论如何是有空的啦,哈哈,再怎么说有得吃饭,优先级是最高的。 今天下了班,跟猫猫、晓妮、悍超和教授一起,到湘江老厨,好happy,蛋糕好好吃呀! 大牛生日快乐!
猫猫的生日挑得太是时候了,居然是和圣诞同一天。 一整天都掂记着去吃晚饭,好不容易熬到下班啊!直奔肥牛府,雨烟这个家伙竟然还想不去,被我好说歹说拉去了。猫猫真是太单纯了,太容易哄了,hoho~~~我叫教授去买花,教授买了3朵粉红玫瑰,把猫猫逗得全脸通红。后来吃蛋糕,所有人都是抢着吃,没人分,也没人砸,吃得好爽哦。 想起去年平安夜,和学校的一帮人一起在肥牛府吃的,那次我喝得有点多。一直以“冷血”自居的小丫头以前经常说,没有谁离开了哪个人会活不下去。是的,没错。
lyy前一天就跟我说,周五晚上一起去吃饭吧,请我。我觉得很奇怪,怎么无缘无故要请吃饭呢,后来才告诉我,是生日喽。 下班了,就跟疯丫头一起,当然还有lyy,去坐班车,又蹭了一张车票,嘿嘿。其实我有车票的,一直没机会用出去(借口!借口!!),呵呵。 到了梅林,找到小于儿,疯丫头突然提议去吃韩国料理。韩国料理以前吃过,有烤肉的那种,那时跟小妞,小玉玉,小思宇她们一起,还有彭彭啊以及其他一些人,到坂田路口那家(我都记不起名字来了),那时大家都是抢生菜叶,抢烤五花肉,现在回想起来还有点心有余悸(“而力不足”——小玉玉语)。回到正题,梅林也有一家,环境还可以,但不像坂田那家,包厢里还是日式的。点了五花肉、秋刀鱼、牛舌、猪排等等,吃好饱,其实是喝得有点胀,疯丫头的那瓶啤酒都只喝了一杯多,剩下的都是我干掉的,晕。 酒足饭饱,就走到lyy和小于儿的温馨小窝,真够小的小窝哦。开始点蜡烛,喝生日歌。疯丫头说我走调好厉害,真的吗,我都不觉得耶,郁闷!拍了各种表情姿势的照片,lyy许愿,开始吃蛋糕。结果吃了一半多一点的时候,几个家伙就耐不住了,开始互相在别人脸上抹蛋糕了。小于儿从大战伊始就宣称中立,在那边拍照录像。她们两个则开始围攻我,几轮攻击下来,三个人都伤亡惨重。更倒霉的是屋子,墙上、门上、地上全是蛋糕,有得小于儿收拾了。想起那次小玉玉生日时她被抹满脸的奶油,以后估计再也不会有这样的机会了。当时我跟小玉玉说:“如果明年我还能帮你庆祝生日……”果然,不能了。好像在哪里看到过文章说,事情的发展,似乎人类对更糟糕结果的预测总是很准,比如装了三明治的盘子从桌子上掉下来的时候,总是装了三明治的那面先着地,为什么! 大战终于结束,洗了一下脸和手,便回来了。lyy和小于儿送疯丫头回去,我则一个人去坐公交车。 跟小思宇说,现在跟同事玩得多happpy的,有时候我自己都觉得奇怪,要是换成以前的我,估计是不会这样的吧。 总之,雨烟生日快乐!
Category Job
事先大概没人(普通民众、老百姓)会预料到武汉肺炎的疫情会严峻到这种程度。
自从知道rapidxml以来,我就一直尽量在需要XML parser的地方用rapidxml,我能说出好几个理由为什么用rapidxml而不是其他的诸如tinyxml,msxml,xerces-c++,expat等等,比如:
公司项目里使用SQLCipher用于本地加密存储数据,之前发现在iOS上打开数据库后执行第一条CRUD特别慢,经过几番优化尝试,发现只要在编译选项指定使用Apple Common Crypto,就能比使用OpenSSL提升100倍性能。但是Android平台上也只能使用OpenSSL,性能问题两年多来一直没解决。
我们维护的项目代码量不大,冗余度倒是不低,光是XML parser就有expat,tinyxml,libxml以及一个自己(其实好像是另一个第三方库自带的)手写的parser。我观察了一下,觉得可以把expat和tinyxml都替换为libxml,这段时间就在做这项工作。
进这公司两周多了,分给我5个crash bug让我看。第一个因为没有symbol文件了,所以没继续看。第二个在Mac上,幸亏可以100%方便地重现,然后找到一点线索,转给其他team去了。后面三个都是只有dump文件让我看,一个是只能看到项目代码里从容器里取出一个野指针,一个是只能看到项目代码里似乎一切正常但进了CRT后一个字符串拷贝操作崩溃了,最后一个是在基类里有一个方法会调用一句
周二来报道的,那天直接主管去开会了,于是我在办公区门口等了一个多小时,还是联系了东家的人,再让别的组的人把我领进去的。
今天简单地测试了一下Amazon EC2连接Amazon S3和ElastiCache的传输性能,记下以作备忘。EC2、S3、ElastiCache都选的是Tokyo机房的。其中S3是通过这个库做的,ElastiCache其实就是memcache,是用这个库做的。
之前提到的Thumbnail Service是用准备用Amazon S3来存储的,因为图省事,网管找了个s3fs把S3 bucket直接mount到本地,于是就当成本地目录一样读写。今天网管突然提到S3连接并发和性能的问题,找了篇文章看了看,大概意思是并发过多或过少性能都不好(废话)!
今天终于把Thumbnail Service的性能问题解决了。
昨天提了离职了。至于原因,我说是冲着钱去的。其实我之前就想过了,即使不加钱,我也不想继续在这干下去了。
这个项目很早前就听说要做了,一直拖拖拖,我实在很想做这个东西,周一就跟TL说,然后就简单谈了一下,确定了架构和分工,于是就开始了。
很长一段时间来,一直偶尔有发现进程在收到SIGTERM或SIGKILL后,仍然不能完全退出。之前总以为是sighandler写得有问题,还怀疑过是SIGTERM不够强力,需要用SIGKILL,事实证明其实都没关系。
以前吧,虽然经常被骂,还被气得肝疼,但那都是人际方面的问题,还可以安慰自己至少做的事情还是比较有兴趣的。现在嘛,被骂得少了很多,倒是做的事情越来越没意思了。
最近一直在用shell脚本自动在跑一个简单的测试,就是不停地停止和重新启动一个relay进程,如此反复轮循,这样每过一段时间,比如两三天,或者更短或者更长,就会遇到一个问题:再也停不了任何一个relay进程,也不会重新启动进程。
之前一段时间一直遇到一个问题,假设有L和R两个程序,L负责启动R,杀掉R,或者在R异常退出时自动重启R,众所周知在Linux上一个程序要运行另一个程序,是先fork,然后exec执行另一个程序代码。于是问题来了,大绝大多数情况下L和R都如预期地运行,但有时候会出现R没被运行起来,用ps看是两个L在跑,也就是说fork了之后没执行到exec那儿!
之前提到过在公司的一个项目里用了websocket,client侧用C++开发,选了libwebsockets,使用的过程中遇到一些问题,这一个星期都是在不停地解决各个问题,好在现在终于基本上都搞定了,现在记录下来。
Relay在线上时不时报些bug,不但客户和公司的人怨言颇多,我也苦不堪言。每次出现问题的时候,美国的PM都会在邮件里说Relay是个very important的东西,万万不能出问题,可是我怎么没看出公司对Relay有very important的重视和投入呢!整个项目除了web前端页面,其他的几乎是我一个人在开发和维护,而且我全职投入也就不到一年时间,后面就重心放在其他项目了,特性仍然在加,bug仍然要改,投入时间却是越来越少,直到现在每个月都不能保证有一二十个人时在上面。前些天一个QA说Relay的bug最多了,这时另一个开发帮忙说是因为投入时间太少。虽然说的是实话,但仍让我感到很惊讶,总算还有人知道实情。可是那些PM,Director之类的却不知是真不了解情况还是故意视而不见。
前些天Google突然宣布中国开发者可以向100多个国家地区发布付费用户,中国开发者注册账号以及收款啥的也都有了极大改进,我本来就一直有想法要在适当的时候注册一个开发者账号的,于是立马冲动地去花了25刀,还把istkani传了上去,不过后来发现一些问题。当初为了买Nexus 5,把这个账号地址设成一个美国地址了,貌似现在这个开发者账号也成了美国的开发者。听说没有办法改成中国的,除非新注册一个账号,囧。发布的app改不了价格,在后台改价格是成功的,但前台看到的价格仍然是老的。不过有一个比Apple App Store方便的地方是,Google Play似乎几乎没审核,发布上传新App的操作也简单得多,之后等几个小时就直接在Google Play里能搜到了。
之前遇到一个bug,一直想不通为什么会出现。具体现象是程序一直尝试去连接一个没打开的端口,过一段时间,可能是几分钟,也可能是几天,那个端口突然被程序自己打开并连上了,然后读到了一些计划外的东西接着断言失败了。我仔细检查过整个程序的代码,有哪些可能会打开一个新的端口,结果没有发现。后来用gdb挂上跑,在listen,bind之类的函数打断点,也没见hit,但bug仍然出现了。
之前说过,我把一个项目中的程序线程数都尽量减少了,差不多就是一个程序用一个线程来跑一个event loop来服务所有socket,结果这几天发现似乎性能有点跟不上了。
到今天为止,IPC协议的重构也进行了一部分,效果不错。原本每秒一次的查询是否有新命令,现在使用阻塞式的查询,有新命令会立即到达,可以立即执行,原本一条新增instance的命令要大概3秒才能得到回应执行完毕,现在基本上下发命令就立即能得到回应了。同时删除instance命令也由原来的平均0.5秒耗时变成立即完成。
之前说过,Relay项目要重构,第一件事就是要把每个程序的线程数减少,甚至改成单线程的。最近这一周全都在做这件,略有成果。
这周一直在按计划重构Relay,今天就做到改用netlink监控进程退出事件。发现如果是普通用户的话在bind socket时就会返回权限不够的错误码,尝试用sudo来运行就可以正常bind了,这让我不由郁闷了好一阵子,因为我一直想的是Relay可以用普通用户就可以正常运行的。后来再想想,把Relay当成像nginx之类的服务来设计的话,要求用户以root权限来启动似乎也不是太过分哈。照计划中,估计也只有Linux上用netlink是要用root吧,Windows和BSD系的方法我猜是不需要特别的权限吧。
前面提到过,因为了读了一点《Linux多线程服务端编程》,觉得自己对网络编程有了更多的了解,可以对公司里负责开发维护的那个小项目动手重构了。这个小项目从功能上简单说来,就是个流量转发器,也可说成是个中断器,所以项目名称就叫Relay了。几乎每个刚听到这句话的人,都会第一时间发出疑问:这种功能网上开源代码或现成工具应该有很多,比如nginx就有类似的功能,为什么要自己做一个?答案可以从两个方面来回复,一种霸道无理点的说法是,这是公司策略,这个理由足以堵住所有质疑者的嘴巴。另一种理性点的说法是,自己做可控性好,可扩展性也好,比如我们要有实时的流量统计,我们要自定义高效的传输协议,像nginx的http传输性能不能完全满足我们的需求等等。
公司里一个小项目的方案,原本就强烈建议小正太把业务逻辑提出来,单独写个server,不要把应用层代码写到nginx push stream module里去,让人家module只做单纯的协议层数据转发。小正太一直以性能消耗要多一次请求为由想把业务逻辑合到nginx的module里去,我真是无语透了,这是多丑多dirty的设计和实现啊!好在昨天又讨论这个方案时,另一个同事基本上同意我的说法,然后两个人把小正太说得哑口无言。现在公司里的人,上到boss、CTO、Director,下到team leader、PM、普通developer,几乎都对软件工程、架构设计毫无概念,脑子里眼里只有source code。很久以前我就在想,如果有人说公司能做出现在这种产品真不容易,我肯定竭力赞同,在条件这么恶劣的情况下一群水平这么次的员工还是能开发出来每年卖上千万刀的产品,确实很不容易啊!
前几日在重构一个小模块。这个模块的架构本来就很畸形,因为它被要求在不同的设备不同的平台不同的endpoint上运行不同的逻辑,却要做在一个模块里,能给用户一个.a或.lib就可以使用。于是第一版的实现中就有一个变量来区分当前endpoint是哪个,开始还好,后来越来越多的if条件判断endpoint来运行不同的逻辑,代码就丑到令我觉得恶心。于是我就蠢蠢欲动了好久,最后看重构的工作量也不是很大,就跟design这块的小leader打了个招呼开始重构了。
花了几天时间,把原本基于XML的IPC重要部分都改成用Protobuf了,之前以为会大幅度提高运行效率,结果发现原本用RapidXML库生成消息,比填充Protobuf结构慢不了多少。不过可以肯定的是,消息长度缩短为差不多是原来的1/4了,原本16KB左右,之后4KB多点。
在新公司上班一周了,过上了坐地铁上下班的日子。以前每天自己开车上下班时,还有点向往那种坐公交地铁上下班的人,觉得可以在路上看到各种各样的人,还可以拿个手机或平板在路上看书。现在这样过了没几天就厌烦了,地铁太挤了,每天上下班一路会挤得浑身大汗,根本没心情看什么书,除了网络小说。
第一周干不了什么活,连产品的源代码都还没看到,说要我先写个小程序,写完了才给我看,原因是之前有个人去干了两天就跑了,他们担心源代码泄露。好吧,这次要在Linux下用socket写个C/S的小程序,但我今天突然发现他们现在的想法是不是有点问题,还是我没有彻底理解他们的需求。好吧,小公司确实是小公司的样子,感觉做事就是没条理,有点乱糟糟的,也许是以前呆的公司不是跟IBM学了IPD流程,就是跟着Microsoft的Workflow走,淡定点。
要在自己机器上至少装个Linux发行版,好好学习下Linux下的socket程序编写。是不是该去买个VPS,然后可以反向连接到公司里的Linux虚拟机上去。囧,这么大强度做Linux上的开发,居然还是只用虚拟机。
今天是在Wicresoft上班的最后一天,中午请share team的所有人去食堂吃了一顿饭,其实食堂也不便宜,原本我打算在华师大的秋实阁请的,但是暑假了华师大食堂都关门了。于是在紫竹一食堂吃了,16个人542块钱。
这次跳槽是出于两个原因,一是经济方面的考虑,对于目前的我来说,跳槽是涨工资最快的方式,另一方面是工作内容,在Wicresoft做Dynamics AX的SE工作,我的生产力极其低下,查了一下过去一年的成绩,我的产出大概连Michelle的一半都不到,这让我很忧伤,这样的状况让我连向领导提出加薪的勇气都没有。新的工作我的要求是要多做些编码,SE工作可能一个月都写不到一行代码,我觉得我写代码的能力这样下去会退化干净的。而且我一直以前都只能说会C++,熟悉Windows平台桌面应用开发,却没有一个真正熟悉、精通的领域,这次新的工作会涉及到多媒体视频、网络传输方面的内容,这样我也就有机会拥有一两个领域的专业技能和知识了。
办离职手续其实总共花了不到2个小时时间,但跑来跑去还是挺累人的。
上周基本解决了一个dump文件分析的问题。
一开始,问题没有弄复杂,只是从最后异常看到call stack,大体得出某个类的指针为NULL,却被继续使用,然后fix的话只要在被使用前判断一下是否不为NULL就行了。
不过这个fix有一点没有考虑到,是该方法一开始就有一个分支对该指针进行了判断。所以如果该分支确实成立的话,我的fix就说明有问题了。于是新的问题就成了验证该分支的条件是否成立。
分支的条件是判断另一个对象的每个成员是否为空。本来,这个对象一开始是new出来的,指针是某个方法的局部变量,一般说来是放在栈上的。不过通过call stack切换到那个方法的context后,发现查看局部变量并没有那个指针。通过查看反汇编的代码,才发现原来该指针被优化了,并不存储在栈上,而是存储在寄存器r13上了。于是我就开始想着如何可以查看某一级call stack时的寄存器,一开始我以为每次call指令时,会自动把所有寄存器的值都压栈的,后来发现不是,还特地去找了Intel的指令手册看了一下说明,反正没说有压栈寄存器,大概是我记错了。问了一下那个老外同事,他说没什么办法,只有想办法从栈里找。
这样没头绪了几天,后来灵光一闪,偶尔发现在call stack中使用r13存储指针的方法的下一级被调用方法的反汇编代码中,把r13压栈了!于是只要在栈中就肯定能找到那个指针的值了。至于怎么找那个栈中的位置,从函数的返回地址找!从最后的esp值开始大地址(栈的生长方向是往小地址方向生长)开始搜索那一个方法的返回地址,找到后再往小地址找压入的栈的寄存器值,果然找到一个值,可以通过dt来查看,还可以通过dds该地址的vf-table来查看它的虚表包含的虚函数名称,这样就可以验证是否是要找的那个对象。果然没错!
前面的blog中,网友sali98提到可以用#pragma init_seg(compiler)等来安排全局对象的构造和析构顺序。这倒是我以前没有想到的,不过经过实际测试后,发现这个方案并不能解决我的问题。
在原来的定位结果中,以为单纯是嵌入的CLR对象晚于C++对象的销毁引起的问题,实际上问题要稍微复杂一点。首先,上次提到的使用_exit引起的对象无声息的消失,不是主要问题。这里调用_exit是在之前有个人把exit换掉的结果,他以为_exit不会调用对象的析构函数,于是不会引起析构时资源销毁时机不正确的问题。事实上这个fix是不起作用的,因为从call stack来看,_exit对嵌入的CLR似乎不起那个作用,而且无论是exit还是_exit都会在对象正常或不正常销毁后仍然有消息循环存在,消息循环中某些处理代码仍然会继续运行,而那些代码也是有可能会引用已消失的singleton的。
最早我想的解决方案是基于这样的想法,既然是C++的singleton在被销毁后没经检验就来使用,那么就把singleton改好一点就行了,我想过《Modern C++ Design》中提到的Phoenix Singleton,也看过一些boost中的Singleton的实现。不过后来都感觉太麻烦,没必要。于是今天试了一个很简单的方法,增加一个static bool变量,标记当前singleton是否有效,然后在每个非static的method开头都先判断一下。简单测试一下,倒是能勉强工作了,不过发现另外一个问题,这样的singleton不止一个!而且另一个不好的地方是,每个非static的method都要修改一下,不必要的改动太多。
今天又看了一下crash的call stack,我就觉得单纯修改singleton的实现似乎不是很高效。于是我就想,是不是有办法在调用exit或_exit前就自己写代码把CLR卸载掉,把消息循环停掉?以我对.NET的粗浅的了解,我觉得嵌入的CLR是应该可以主动卸载掉的,只不过也许某些正在使用的资源会成为阻碍,这个要仔细调研一下。而停掉消息循环这个,感觉也是可以的,增加个标记,在消息循环里判断一下,可以自己主动跳出循环。
今天彻底打酱油了,我们shared dev team也只剩下我,老大和Jason三个人了。因为晚上2点才睡,才睡了不到6个小时,于是下午就坐在办公椅上睡了近1个半小时,最后是被他们讨论一个bug的声音吵醒的,啊哈哈,老大还说让我看一下,现在只有我在这方面有经验了,我囧,我完全没经验的说,后来还是Sherman厉害啊! 再后来,就跟老大讨论了一会儿C++ singleton的实现,以及跨DLL数据引用等等。问题是有个Watson的bug,我从一次crash的call stack中发现,程序在调用_exit后,该程序中的static object应该是已经瞬间被无声息地干掉了,所谓无声息的,就是说,连它的析构函数都没被调用的。但这时嵌入的CLR还需要做一部分扫尾的工作,而恰恰是这扫尾工作又反过来调用了那个貌似已经被干掉的static object,于是程序crash了。当然这只是我的猜测,我猜测嵌入的CLR就是要生存周期长一点,于是一直在代码中试图找一下它是怎么从C++端嵌入CLR的,然后怎么用CLR的。我发现的情况貌似是这样的,先用Managed C++写了一个dll,这个dll可以在DllMain,还可以导出函数,而据我前些天才知道的知识,.NET编写的普通的DLL形式的assembly跟原本的DLL不一样,没有DllMain的。而这个DLL通过导出函数返回一个对象的指针,这个exe程序通过GetProcAddress获取导出函数,再调用这导出函数获取对象指针。这个返回的对象呢,是个CLR Bridge,也就是说,通过这个对象,可以从C++端创建CLR中的对象,调用CLR对象中的方法等等。也就是说,从代码中,我没看到Jeffray Richter在《CLR via C#》中说的那种CLR host的方法。现在我仍然在怀疑,是不是我代码没看全,但我确实之前也在整个代码目录下搜索文本,没有那几个用于host CLR的API调用。似乎有点跑题了。然后我就跟老大说了一下我发现的这些情况,略微讨论了一会儿,老大表示自己也不知道,唔,其实我也不指望他知道,只是有这么一种想跟人分享自己的发现的欲望而已。基本上,我就觉得这很可能是此bug的root cause了,但老大说可能只是个cause,而不是root cause,好吧,其实就是缺少验证而已。一个比较有说服力的验证方法是自己用C++写个小程序,然后用相同的方法调用CLR中的代码,最后能制造出同样的crash,只是我最近木有动力去做这些事而已。另外就是,即使确定了这是个root cause,简单地说来,这个root cause应该就是对象销毁的顺序不对,这是可以肯定的,但之后也不好fix,因为这个程序实在太庞大了,有很多对象,然后引用关系也很复杂,以我目前对它的了解程度,根本没能力对理顺这个关系,于是也就fix不了了。而且还有个另外的问题是,那个static object是该程序中用于实现singleton的一种方式,我觉得比较奇怪,老大说,这是为了应付多线程的情况。还有种应用多线程的singleton实现方式是在create instance时加锁,唔。关于这个话题,在前段时间看到TopLanguage group中有个讨论,提到boost中某个库中的singleton实现,貌似很干净的实现,不用锁,也不是static object,能适应多线程,囧,具体的不记得了,貌似boost中有好几个子库中都有自己的singleton的实现,得再去看看代码才行,另外好像《Modern C++ Design》里也有对多线程singleton实现的讨论,春节放假看看去。 话说,今天还看到Mono,发现除了有Mono Touch外还有Mono for Android,不过免费试用版都只能在emulator上跑,最便宜的个人版license也要399刀。不禁大骂Qt的不给力,为毛只能为Symbian和MeeGo用,Android port至今还在alpha...
把Charles Petzold的关于打印的那章代码拿来都试了一遍,发现PopPad工程里的过程就是我想要看的。对比了一下代码,沮丧地发现貌似两者只有获取到DC的方法不同,PopPad里是PrintDlg返回的,而bug里的代码是通过CreateDC创建的。但之后也发现了,这个代码很奇怪啊,不但有CreateDC,还有CreateIC,经过调试发现,大部分时候都是在调用CreateIC的,这让我纠结了好一会儿,想不明白为什么要调用CreateIC,MSDN上明明说的CreateIC返回的DC是不能用来画东西上去的,只能用来查询信息的。又经过几次调试,发现CreateDC是在打印前在调用了n次CreateIC后最终会被调用一次的,这时候才发现,传给CreateDC的DEVMODE*居然里面的dmCopies值一直是1,而我明明需要的是2啊!于是我就猜,是不是application层把明明是2个copies合并成1个了,然后相当于只打印1个copy,于是打印机的设置只对第1份copy起作用。因为这个猜想,又小小地郁闷了一把,该不会要去调试application层的X++代码吧。不过马上,在kernel层的call stack乱翻,翻到其中一个地方,硬是把所有dmCopies值都改成1了!把这行代码注释掉试了下,果然如愿可以把设置应用到第2份copy上了。我猜,当时这代码的作者大概是考虑到不是所有的打印机都支持multi copies的,所以干脆把这个字段都改成1了。然后就是写邮件啦啦啦啦啦!
这事一了,人突然就松懈下来了。
又回到以前那种每次写blog都是写工作内容的流水帐的状态了么,这是不是意味着离我辞职又不远了。
好吧,上午还是在继续折腾SQL Server版本兼容性的bug。主要的代码昨天就修改完了,今天要提交code review,就再仔细检查了一遍,然后发现,因为多加了一个.cs文件,于是在enlistment的根目录下build所有工程的时候,某一个工程会出错。之前加了这文件,是直接在某个目录的sources文件,嗯,类似于makefile的一种文件里,添加了新增加的那个.cs文件路径就好了。于是在整个enlistment里搜遍了所有sources文件里的内容,愣是没在其他sources文件里找到有引用这些文件的。后来看了一下error log,发现它是在进入某个目录build时报的错,到该目录下又不死心地看了下sources文件,没找到要添加文件路径的地方。后来看到一个.csproj文件,打开看了一下,死马当活马医,把新文件路径加进去再build,居然通过了。艹,这个build system太贱了吧,不同的工程用不同的描述方式。
下午继续折腾打印设置不生效的问题。好吧,一点头绪都没有,一点进展都没有,跟几个同事讨论了下,几乎也没有有价值的提示。现在还剩下两件事可以做,一是试试其他report的打印有没有这个问题,这可以基本上确定root cause是在application层还是kernel层,大体上我现在是比较倾向于认为是kernel层的问题,大概就是打印API使用的问题。二是自己写个打印demo,仔细观察一下打印API的工作方式,也就是通过这个demo来模拟bug的运行流程。
好吧,我又无聊了,又写工作上的事了。
今天可是过得很纠结,两个bug开始全都一愁莫展。一个是打印设置的bug,搜索了一下以前的相关bug,看现象跟我现在的这个很类似,结果人家只是改了一下DOCINFO中的datatype字段的取值就搞定了,到我这里就不知道该怎么进行下去了。下午就在折腾另一个bug,安装程序在安装extension时只检测了SQL Server 2005和SQL Server 2008,于是在只有SQL Server 2012的机器上进行不下去了。需要修改的代码还是有好几处地方,照样画葫芦地改了一下,结果拿给人家测试时因为强命名的问题折腾了近一个下午。这里顺带提一下,如果把assembly拿到64位的Windows上去测试,用sn添加验证入口时不光要用32位的sn添加一遍,还要用64位的sn添加一遍。而且要注意的是,这个sn运行是在测试机器上运行的,不是开发机上。后来才知道,原来tester们有一个job跑一下,一台测试机就可以彻底屏蔽掉强命名的验证的,叹气。不过还好后来在在下班前终于编译了个private build让tester去测试一下,晚上回住处后看了一下公司的邮件,tester说在32位和64位机器上都测试通过了,稍稍心安了一点。
晚上team building,在蜀香村吃饭,算是农历年年前的散伙饭。Fiona也来了,她在元旦前辞职后就没见过了,估计这次也是最后一次见她了吧。她比我稍微晚一些日子进的team,实际上她是build team的,接触并不多,只有过两三次因为build上的问题打过点交道,但感觉是个很nice的人。很瘦,说话轻声轻气的。
从昨天下午开始check in,到今天下班仍然没有完成,太囧了,什么乱七八糟的东西,叫了组里最有经验的同事,还有build team里的妹汁来定位,仍然没有搞定,昏特了。
倒是另一个分给我的bug,貌似快要被我搞定了。这次这个bug问题出在C++写的内核里,用Visual Studio 2008调试经验死掉,于是刚好用WinDBG来调,除了有点不习惯,其实WinDBG好像稳定多了,也快多了。其实一般在Visual Studio里调试,也就用到断点,单步,查看变量这三板斧,即使一点没有WinDBG的基础,也可以很快transfer过去。然后用Source Insight看代码写代码,好happy!只是如果仅仅用WinDBG做这些事,有点暴殄天物了。可是我不会其他高级用法,唔…
话说上周五的时候让我给team里的人做WinDBG的training,然后我就随便写了几页ppt,忽悠了50分钟,只提到了怎么用WinDBG实现VS中的那些常见的调试任务,至于WinDBG最擅长的memory corruption,resource leak和postmortem debugging全都没提到,然后老大很不满意,唔,其实我这是故意这么安排的,虽然我自己确实对后面三个topics也没有研究,但要循序渐进嘛!
长假后第一天上班,恶补了下.NET Data Access、ADO.NET的基础知识,叫我这样一点都不懂的人给人去培训,汗。今天看《C#高级编程》看了40页,明天继续看XML相关的内容,也是40页。
然后是安排在下下周五给自己team来个WinDBG的培训,这也是赶鸭子上架,其实我现在的水平,只是比他们多看了一两本书而已,实际能力跟他们差不多,只不过是让我负责这一块而已。我估计着这块的内容可以讲两到三次,每次两个小时,大体上可以分为基础知识,事后调试以及结合本项目调试。
今天快下班的时候,老大才告诉我,昨天让我看的那个bug之后随时都会assign给我处理,我囧,我一直以为老大是看我闲着没事干才让我看着玩的,叹气,形势认识不清!
然后么手头一直有一个watson的bug,虽然这类bug是没有时间限制的,但确实没有头绪,如果一直没有fix,总感觉不太好。
昨天么老大还说跟我聊聊,然后说可能马上会让我抽出一部分时间去做培训讲师,囧。一个现实的问题是,公司确实招不到顶尖的优秀毕业生的,所以只好自己派人去,给那些有意向的学生做相关的技术及soft skill的培训,并筛选出符合要求的人来。原来公司是在花桥有个培训基地的,不过现在听老大的意思,不太赞同那个跑去那边培训的方式,好像就只在公司这边搞一下。
今天旁边的同事接到一个bug,跟TTT(Time Travel Tracing)相关,老大就跟我说这是你的一亩三分地啊,我表示听说过这玩意,老大觉得很诧异,这是MS内部的工具啊,我说我一两年前在某个google group上看到有人讨论过,说gdb也有类似的技术。其实啊,我现在倒真想好好学习使用WinDBG,甚至不用VS的JIT debugger,据说高手们,呃,大概只是MS内部的那些变态们,是不用VS JIT debugger的,比如现在我们对口的FTE那个印度佬,据说以前是IE开发组的,声称调试只用WinDBG。叹气。
goagent貌似只是浏览网页表现好啊,我把gtalk的代理设置成goagent就经常连不上。Ninayan也用不了goagent。
好吧,才发现文章少了一篇还是两篇,估计是换服务器时没留意,数据没同步过来。
今天跟老大谈了下,老大说希望我以后主要研究下Dr.Watson这玩意,另外再加一两个features吧。哈哈,我正好对WinDBG比较有兴趣,我想如果能用WinDBG达到像用VS里的JIT-debugger的熟练程度,那用GDB应该也能比较快上手了吧。
不过这里说用Dr.Watson主要是进行postmortem debugging,也就是说对core dump文件进行分析,可是今天发现,这些core dump文件都是mini dump的,没有包含足够的内存数据,比如heap上的东西就查看不了,这比较纠结,而AWD这书基本上讲是的用WinDBG进行live debugging,叹气!
算了,先不管那么多,肯定随着经验的增加,postmortem debugging的水平也会提高的。星期天上卓越把几本关于.NET、C#以及调试和逆向工程的书买来。
这几天一直在搞LaTeX中的一套符号工具栏按钮,符号一共有500多个,全都放在工具栏上,就需要500多个图片作为按钮图标,这实在是一项繁琐的工作。
图标是从另一个软件中通过截图抠出来的,每个图标截出来后,要用图标处理工具把周围其他的颜色都去掉,然后可以添加到我的程序中,而我的程序又分两部分,一部分是xml描述,另一部分是功能代码,这样的操作需要重复500多次。
这样已经有6天了,而完成的只有100多个图标吧。当然这5天里还包括了其他的一些事情,比如这个工具栏以前是没有的,放在了另外的位置,于是主框架上C++代码也加了一些,这些编码时间应该是接近2天了。还有就是之前在抠图标时方法不是很高效,花了一些时间,后来找到一个比较省事的办法,人也轻松多了。
总的说了,每天要完成固定的工作量,这样日积月累下来,总有完成的一天,而不会到时候进行回顾,发现自己不知道做什么去了。也许每一天看起来做的事情并不多,但贵在坚持。
今天花了点时间在修改升级程序。这个程序完成后,一直没有进行过有效的测试,而是直接给别人用了,呃,这里的别人指的是部门内的其他有项目升级需求的同事。实际上,至少有3个其他项目中使用了这个升级程序,但我自己却没有真实地体验过。总的说来,这个程序在功能上,基本能满足当前的绝大部分需求,从当初的质量部的地个项目中独立出来后,一次大规模重构,代码结构作了不小的调整,当然这调整的原因是原来的架构已经不能适应后面增加新特性的需求了。 曾经倒也是规划过一个比较长远的版本计划,呃,也许不能称之为版本计划,称为需求实现计划更合适一些。不过后来还是剩下几条没有实在,因为没有工作量分配过来了。今天的投入则是现在发现,在某些情况下,它会崩溃,这是最不能容忍的致使问题。不过很无奈的是,原来没有使用google breakpad来生成dump文件,现在加入了这功能后,暂时也没能把它弄崩溃,于是也压根不知道问题出在哪里。只能听天由命了!
也算是体验了一把面试官的感觉,好好玩哦,看着有些人紧张的样子,想想当年自己在学校时那紧张的情形,只能感叹时间的匆匆流逝!
又要开始做环境设计编辑器了,几乎是全部重新做过。这次的计划是自己画,可是现在的我却兴致缺缺,想当年,嗯,也就是一两年前吧,我是多么的希望可以自己动手专心地实现一个这种图形编辑器啊。 我现在的想做的是把自动分析崩溃报告的事情做好。不过这种事情收益有一些,不过却不是主要业务,因为对用户来说,没有多少良好的体验可以从中体现出来。唯一的好处是,开发人员可以减少工作量,嗯,这点上我倒是真有点典型的程序员风格——懒惰!
今天下决心修改一个崩溃的问题,只要快速打开多个文件,再通过菜单“关闭所有”窗口时,就会崩溃,通过一次又一次的崩溃实验,分析每一次的dump记录,居然意外地发现每次崩溃最后的堆栈信息都不一样,总共有三处代码。 把这三处代码仔细推敲之后,发现确实有可能引起崩溃的原因,而这样的代码如果让我仅仅是通过正常的审视,是绝对看不出什么问题来的。修改完这三处代码,再实现,又暴露出另外一个崩溃的问题,也是那些代码附近,真是汗颜啊!
给升级程序加了多线程http下载后让同事试用,结果今天他打来电话报怨下载速度太慢了,甚至比以前单线程的时候还慢。用netmeeting看了一下,发现本来预计有5个线程同时下载的,现在居然是5个线程一个接一个地进行下载,这样明天会比单线程的要慢了,因为多了几次等待网络连接的时间,而且事实上自从改用多线程后才明显感觉到有时候一个网络连接的等待是好久,可能是十几秒。我在虚拟机里又试用了一下,还是5个线程并行的,那就郁闷了! 后来又想到一些可以改进的地方,但没动手,只是记到todo list里了。 唉,钱好少!
今天终于把升级程序的http下载部分改成多线程下载了,用的WinINet用5个线程同时下载,发现总是会有1到2个线程会阻塞在连接操作上,这是花费时间最多的地方!暂没想到好的办法,先这样了,对于大文件来说,确实能提升不少下载性能。
发现在有很多事可以做,发现自己一件都不想做,哈哈! 今天老大跟我说,是不是忘了件事,那个gem升级也得做进升级程序中去。我说那不是说另外还要用wxRuby做个程序的嘛。老大说,这种建功立业的好机会,怎么可以让。我狂晕! 找原来开发这个功能的同事咨询了一下基本原理,发现简单得令人发指,当然这种实现方案在我看来也是丑陋得一塌糊涂。看了一下他的代码,发现原来真的是那么一回事,基本的代码结构和思路都是很清晰的,除了有一些废旧的注释和代码。 我开始头痛界面的问题。原来的实现使用了XTP的ReportControl,我想这么一个原本应该尽量精简轻巧的升级程序现在已经被我弄得渐渐肥大起来了,再加个XTP就太恶心啦!而且另外一个问题也已经浮现,越来越多的命令行参数,已经让眼下那种依次比较字符串的方式不再继续适用,引入boost::program_options也势在必行,天哪!
今天发现一个很囧的问题,在保存文件的时候出现堆破坏。跟踪了一下,看到的代码才让人一阵恶寒。先到文档类中的保存代码,该函数会在之后向主窗口Post一个消息,主要是把保存的文件路径发送过去,这个文件路径保存的空间是在堆里动态分配的,到了主窗口中处理该消息的代码直接把该消息Send到另一个视图,而这个视图中处理该消息的函数会取出这个路径,最后销毁这块内存。问题就出在这块内存上,原先发送方把这字符串以ANSI形式表示,后来整个工程从ANSI转换到UNICODE后,只修改了处理消息的那边,而没有跟着修改发送消息的这边,于是两边认为的内存块大小就不一样了,于是就堆破坏了。而让我恶寒的是另外一个原因,为什么要向主窗口Post个消息,再由主窗口转发一遍。一方面运行效率低下,另一方面就是接口变动后不容易找到受影响方,这次就是活生生的例子。我想,用个observer就可以缓解这些问题吧!
花了近半天时间,把about对话框弄完了,不过有点小问题,不能设置tab页的title。整天琐事很多,最近把崩溃问题解决方案稍微整理了一下,说实在的,我心里是没底的,这个任务对我来说似乎要求高了些。我也希望程序能7×24小时地运行不中断,可是无论怎么弄,稍有点复杂的功能肯定就埋藏了大量的bug。
今天发现原来我的机器上一直跑得好好的程序,到其他机器上就不行了。于是另外找了个装了Win2003和MS Office2003的机器上调试,发现首先我用了一个Excel2003中不存在的接口,Excel2007中是有的。于是绕了个圈子也勉强达到原来的目的了。 接着发现把图表copy到系统剪切板中再取出来存成图片的文件不行了,根本枚举不到GIF类型的剪切数据。在网上找了个剪切板观察工具,发现确实没有那个数据,不是程序的问题,原来Excel2003的接口功能就是要比Excel2007弱。于是绕了好远的路,换个接口,把图表当成图片copy到剪切板中,发现剪切板中有Meta file picture类型的数据,再用Win32 API把这数据保存成文件。很扯的是这文件不知道是不是需要什么句柄释放操作,反正直接是不能修改或删除的,不过还好能复制。接着用GDI+把这个wmf文件转换成jpg或gif。结果郁闷地发现,转换后的图表背景变成全黑的了,想了好多办法,转来转去都是黑的,只有wmf和png看起来是白的。其实大概是透明的,整了好久都没办法,下班的时候跟老雷说起这个事情,老雷说先设置一下背景色。我真想拍一下自己的脑袋,怎么就没想到这点呢! 明天再去弄了。
星期天去参加1783的石头河溯溪,结果被小路晃点了。溯溪回来跑去南山找阿布拿手机,然后去他家吃晚饭,见到了他老婆,真没想到啊,他儿子居然2岁多了,真以为是90后的呢!吃完饭,坐了一会儿,一群人决定去唱K,结果不知道喝了多少酒,反正第二天是谁把我送到的士上的我也不记得,迷迷糊糊回到家,倒头就睡,于是,一天没上班! 今天去上班,不知怎么的,情绪很低落。整了个版本给人测试,发现根本没法用,几个严重问题,崩溃、崩溃、还是崩溃!以前的设计有问题,或者说压根没考虑到后来会需求会变化那么大,这实在是可以原谅的。这次还有一个重大的变化是,模板文件中加入了宏,于是用COM操作后再关闭会问你要不要保存修改,尝试了半天,发现只要先关闭workbook,再关闭workbooks,再退出就可以了。因为关闭workbook时有个参数可以指定是否要保存修改,而且关闭workbooks时则没有,会自行弹出个消息框来确认。
今天旁边的同事突然问我有没有空一起去吃饭,本来还以为算是几个同事的年终聚餐,结果到了餐桌上才知道,原来他马上要离职了,就在这三四天里会办完手续。 这样自发地跟项目组里的同事出来吃饭,我还是第一次。我真是个很奇怪的人,当年在测试组时,第一年,也是不跟测试组的人一起活动,直到后来搬了家,才开始慢慢和他们一起玩。发现自己其实很势利啊。 今天喝了一点啤酒,话也多起来了。平常跟同事说的话也不多,而且脾气也挺坏的。说了很多公司的事,有点惆怅,也许跟我这几天心情本就不好有关吧。 人来人往,没有终点。
昨天偶然发现,我的程序根本检测不到Excel文档的修改,太让人郁闷,之前完全没料到这个结果啊!后来回想一下也想通了,Excel文档那么复杂的一种文件格式,不使用像txt之类的修改方式,完全是可以理解的。不过理解归理解,问题变得棘手了,怎么才能实现那个需求呢! 今天没写代码,倒是在自己建的wiki上写了几篇文档,有关于设计方案的,也有关于使用说明的。我要开始准备撤退了,出于道义上的,或者说职业道德上的考虑,也是为了让自己以后少被人骚扰,我要输出尽量能解释清楚我目前所做的一切的文档。 写文档也是个很累人的体力活啊,也许是因为几乎从来不写文档,让我觉得很多事情都不知道从何说起。心中很清楚明白其中的每个细节,却不能用文字表达出来,或者说即使能零碎地写些文字出来,却不能有效地串连起来,形成完善的文档。 今天质量部的老大把我叫去,谈了一下之后的计划,我刚好趁此机会明白地告诉他,我对之后的维护性质的工作实在没多少兴趣的,而他居然出乎我意料地说,如果是这样的情况,可以换个人,而且还肯定了我之前所做的,这让我心里比较高兴,哈哈,仰天长笑!
被另外一个同事说了两次了,说我最近越来越酷了。今天我就问哪里酷了,他说竟然敢当面顶撞王总了。我心中冷笑,多从来不认为公司里这种领导对下属可以指手划脚,颐指气使,我从来只觉得领导也不过是个打工的,只不过与其他下属的工作内容不一样,他的职责不是领导人,而是协调各种资源,包括人力。 不过最近脾气比较坏倒是真的,我完全是被搞烦了,我也顾不上那么多了,气不过我就要反驳。今天早上的站立式会议时,我还对老大出言不逊了,我就直言他们对COM的过度热衷和盲目崇拜。 后来老大找我沟通,说我是不是对现在的项目很有情绪,我说是不爽,而且感觉付出和回报不成比例,付出得太多,回报得太少。 下午在回顾今天发的版本发现的问题后,质量部的人又在那里摆了很久龙门阵,知道我们想要撤出,便在那里说了一通项目的前景,个人的前景,画了好大好大一个饼,呵!
今天终于搞明白为什么昨天构建我的项目要2个小时了,原来是内存耗完了! 本来一直没这种问题的,也就昨天突然发现,我的项目集成构建一次,最多的时候要206分钟,瀑布汗!当时还以为是中间的哪个环节出问题了被阻塞在那里了,看了下进程状态都是好的,主要的时间都花在doxygen生成文档上了。但看看doxygen也是正常的,有条不紊地dot。 其实昨天就已经搞好了,因为当时发现本来2GB的物理内存,又设了2GB的虚拟内存,可是看看整个系统的内存使用量居然也是3GB多。关了一票的没用的进程,包括普通应用程序和系统服务,发现又变快了。 今天重启了系统,同样关掉那些没用的服务和应用程序,再看CruiseControl,终于恢复正常了,15分钟就能完整地执行完一次构建! 唉,服务器资源还是有限啊!
前天,公司请MS的人来做交流,我也去听了一下,虽然只听懂了20%~30%,还有有翻译,尽管翻译的水平不咋的,连蒙带猜的大致上也能搞明白他在讲什么。其中让我印象最深感触最深的一个实践,是用wiki记录开发文档,其他人也可以修改文档,有新人加入时,就可以通过wiki进行学习,我深以为然。 昨天,老大提出,我们项目组也要组建公共知识库,也包括开发文档。有个同事提出,他倾向于使用Word文档来进行记录这些内容。这不禁让我开始思考,用wiki和用Word来记录开发文档,各有什么优缺点。 大体说来,我是倾向于用wiki的,因为我觉得wiki的形式更能鼓励人们不断跟着代码变化而自发地更新文档,并且wiki一般自带版本管理功能,使用更方便,另外一方面,开发文档并不需要多丰富多样的格式,有简单的文本和插图一般够用了,而Word文档拥有的其他功能,可算是累赘了,比如要比较两个版本的差异,就相对要麻烦一点点。 说到底,我其实最看重的是wiki形式的约束下,人们会更多地完善文档,我们项目组目前的一大问题是,并没有多少文档,代码中偶尔有几行注释就算是全部的文档了。假如我们也像产品开发人员那样有非常详细的从SRS到HLD,再到LLD,那用wiki和用Word文档,或者其他什么记录形式,根本没有区别。
今天整了一天,把原来的一个列表,整成了5个tab页分成的5个列表,每个列表显示不同的内容。 这次是深切体会到当初设计的草率,把许多应该放在文档类中的数据成员和方法都放到视图类去了,结果现在本来还是同一份数据,要给多个视图共享使用时,就需要大量的修改。 不过这样的修改从长远看来,说不定是塞翁失马。不光结构上有调整,在某些接口实现上,也有修改。总的说来,比又前更合理,更简单。 当然一天下来,功能匆匆忙忙实现了,代码实现细节上却没有多加考虑,还是需要后续重构的。比如有一份代码,在4个视图类里各写了一遍,应该是用模板方法可以重构掉的,还有份代码,在2个视图类里各写了一遍。以前遇到这种情况可能会头痛一下,现在有了之前的使用boost.funciton和boost.bind的经验,应该很自然地能解决了。 本来这个需求并不是最紧急的,但是一方面我自己比较想做,另一方面,它涉及到的面比较广,早弄好,其他部分也方便点。
今天去整编辑器了,加上了函数定义的跳转功能,总共大概花了4个小时左右吧,因为没有功能良好的语法解析器支持,所以基本没什么技术含量可言了,就是判断一下当前光标所在位置的单词,假设该单词是一个类的方法名,去数据库中查询一下该方法所在的文件路径和行号,如果有多条记录,则弹出个对话框,列出所有的位置,让用户自己选一个。 下午的时候跟老大说,老大竟然说我做那么快,看来以后得多分点任务。我郁闷!不过做这部分的时候,倒确实有点轻车熟路的感觉。添加对话框,给对话框添加必要的控件,给控制添加必要的消息响应,等等。以及添加新的类,在类中实现该它实现的功能。 不过又想到语法解析器,没有它,做什么都是残废的,唉,什么时候一定要抽时间实现一个。
程序终于改得主要的核心功能比较稳定了,这是最让我觉得安心的事了。这个项目无疑是到我投入时间和精力最多的项目了,中间过程也是竭尽全力、绞尽脑汁、使出全身解数,充分发扬拿来主义,使用了好几个第三方的开源代码,大概列数一下就有ACE、Boost、iconv、zlib等。眼下流行的工程方法,开发方法也被我有选择地用了一些,感觉自己的水平确实也有了一定的提高。 但是我还是对项目、对我自己并不满意,随便列举一下。 对系统的总体架构不满意,目前只有客户端,我的想法是至少要是C/S结构的,但是这样无疑会大大增加工作量,这也是眼下的无奈之举。 对系统的性能和稳定性不满意,这是代码规模稍微大了点就出现的问题,而且一直也是无能为力的,这方面要有所改进,可能会涉及到整体架构的变更。 对开发模式不满意,纯粹的乱搞方式,没有完善的流程和规范,敏捷很好,却没有实行起来。 对程序结构和编码能力不满意,有不少看起来很丑陋的设计,有不少看起来很丑陋的代码,这点基本上可以通过开发人员的主观努力慢慢提高的。 对自动化程度不满意,现在可以在每次build时自动修改资源中的版本号,每次commit后又可以通过CruiseControl自动集成最后生成安装文件,但测试却只有少量单元测试,还有崩溃报告每次只是通过邮件发送到邮箱中,照我的理解状况是有一个后台服务可以自动收集这些崩溃报告,然后自动进行分析,把尽量详细明显的分析报告提取出来,而且对于已知问题可以直接提示用户。 对持续集成程度不满意,中间的各种测试、度量功能没有好好地利用起来。比如圈复杂度度量、源代码行数度量、重复代码行度量、PCLint、单元测试等等,有的没做,有的做了却没关注。 对与客户之间的关系非常不满意,开发人员太弱势,对于需求基本上没有拒绝的权力,在我看来做了一些可有可无的功能,还做了一些愚蠢错误的设计,对于版本规划等主动权也不够。 这些是大的几点,有的是可以通过自己努力得以改进的,而有的则会涉及到其他方面的人,则只能听天由命了,呵呵。
今天上午去听了软件工程大会的几个议题,发现挺没意思的,没有多少收获。大部分都是炒冷饭,没有激情,没有让人耳目一新的感觉。全是敏捷来敏捷去,持续集成来持续集成去,TDD来TDD去的。 于是下午就没去了,写了几行代码,把log4cxx加到工程中了,用xml格式的配置文件,看起来比较统一,所有的配置文件都是用xml的,哈哈,不过我的配置文件也太多了点。发现还是不能直接在代码中用unicode,编译时没问题,但是链接不通过,不知道什么原因,难道是哪里设置的问题。不过中文倒是可以了,在家里编译的不行,输出全是乱码,而且同事也一直说是乱码,不知道是编译的时候用的操作系统影响的,还是编译器影响的。
今天终于发版本发出去了,但是,用别人的话说,几乎不可用。 这个版本确实进行了大幅修改,不但增加了新功能,还进行了重构,对原来使用的那一套机制50%被翻修过了。 那些出现的问题,都落在没有经过单元测试的模块,但是那些模块都是我不知道如何进行方便有效的单元测试的。 其中主要的还在于两个模块,一个是界面交互,确实不好测,另一个是数据库操作。当时的接口设计可能过于复杂了,导致后来想做单元测试时,很是畏惧。实际上,数据库操作部分,也是可以进行单元测试的,而且我想着要把本地数据库从Access换成SQLite,更是应该趁这个机会补充单元测试用例了。
今天写代码可用马不停蹄来形容,一天下来,不停地敲键盘,不停地commit,不停地收到CruiseControl的构建报告。一直到下班,回顾一下,觉得好像也没做很多事情,可能是太零碎了,写日志的时候,看了看SVN里的commit记录,确实可以写好多条。 明天就要发版本了,不知道有哪些地方落下没考虑到的! 倒是在用hhc.exe编译doxygen生成的文档时,老是崩溃,搞得我有点郁闷。本来嘛,一个工程有一个chm文档就够了,现在好了,只能用zip把众多html文件打包,要看的时候还得解压,而且解压速度不快!
昨天就发现了,程序结束时,会退不出,看样子是死循环。今天单步跟了一下,发现特别恶搞的原因,在一个while后直接一个分号,单步时还没看清楚,只是奇怪怎么一直在这一行跳,还以为VC调试器出问题了呢,汗! 中午时,突然想起来,这几天一直被之前的思路占据着,还是沿用老的那一套,结果搞得我午觉都没睡安逸,心里惦记着一件事情,真不爽啊,差点还以为之前写的都要推倒重来,下午调了调,发现还是可以保留一部分代码的。CppUnit用得还是安逸的,昨天从网上找来了CppUnitLite、CppUnitLite2、GoogleTest、UnitTest++几个测试框架,打算稍微看一下,最后选择其中一种来用。先看了CppUnitLite,没有文档,有一个简单的demo,对我来说,上手太不容易了。我估摸着,最终还是会继续使用CppUnit的。 又有人提到加强编辑器的联想功能了!VAX确实可算是所有代码编辑器自动提示功能的典范,我们一直在说,我们做不到像VAX这种程度,是因为Ruby动态语言的特征,不能通过静态分析得到某个对象的类型。我有时在想,假如我们用的是C++,我们能做到像VAX那种程度吗?针对这个问题,我回了一封邮件给老大,分析了VAX的自动提示功能分成三部分来做,我们有什么对应的策略。这三部分分别是,分析源代码,得到各种变量、对象的类型进行提示;编辑代码片段,设置快捷键进行提示;加入拼写检查,可在一定程度拼写错误的情况下,进行提示。第一点,需要一个完善的语法分析器,目前我们没有;第二点,技术要求不高,原来我也想过要做,结果被其他事缠着,就搁浅了;第三点,从来没有研究过,没有技术积累,根本不知从何下手。邮件发出去,估计老大也是眼睁睁地看着没有办法,所以什么回应都没有。
今天上午下决心问了一下同事,又用proxy登出外网,搜了几下,终于搞定通过弹出Windows域账户对话框来输入新的用户名。代码在codeproject上有完整的,效果很好。弄得我心情很愉快,自我感觉良好,极大的改善了易用性啊! 完成了这个后,却没有做多少其他事情。其实我也没有多少懈怠,只是偶尔停下来休息一下,但进展确实很缓慢。我现在丝毫不怀疑单元测试的作用和必要性,尽管它似乎花我了不少时间,但我总觉得是值得的,无论是对我心情的调节,还是对代码质量的保障,都有很大作用。 后来主要集中精力在做组织结构管理模块。该模块将数据保存在远程数据库中和本地配置文件中,而两个地方保存的数据的格式差别比较大,读出来的还需要再互相转换一下。这不但需要多写不少代码,而且可以预见到的是,也会占用不少执行时间。我都开始怀疑当时把两边的格式差异弄得这么大,是否很不明智。结果到下班,还是没有完全搞定格式转换部分,只好明天继续了。另外想起来,应该提供一种途径,可以执行一些特权操作,比如明确从某配置文件加载数据,明确将数据写入数据库等等。总的说来,机制部分基本做得差不多了,后面实现用户交互部分应该没有多少工作量了吧!
再一次出乎自己的预料,太慢了! 不过通过单元测试,来保障代码的正确性,实在是一个非常不错的办法。我用的是CppUnit,写测试用例还是比较麻烦的,要在.h和.cpp两头写,每次都是复制其他的代码结构,据说CppUnitLite等等新生代的单元测试框架用起来要省事一些,不过我没用过,并且我现在很看重CppUnit能使用MFC的界面,也能输出XML格式的报告,而且还提供一个xslt文件,可以把报告格式转换成和JUnit类似的格式,这样CruiseControl就能直接合并到它的日志里。就是这些原因,使得我迟迟不愿意再花时间和精力去了解其他的框架,继续忍着那些小麻烦。 现在用起boost.bind和boost.lambda来,比以前熟练了不少,但还是只用到一点它的皮毛。前几天看到一篇blog,讲boost.function和boost.bind结合使用的威力,让我大吃一惊,原来boost可以这样用!就这么投入中去了,再好好学习巩固一下STL,学习一下算法,学习一下boost的应用。
估计真的是体力透支了,影响到正常的工作了,提不起精神。 说起工作,一个小小的需求实现,也原来要涉及到这么多模块,真是郁闷,我的架构设计能力还是不行啊,继续努力学习啊!明天开始着手另外一个大需求的实现吧,三天,能做成什么样子呢?我早已没有之前估计工作量时的那么乐观了,过高地估计自己的能力,过低地估计了实现难度,唉!
当时看到phpBB后台有选项可以选择认证方式,有三种,分别是DB、Apache和LDAP,我就觉得要糟,老大知道后肯定会要求用NT域账号方式认证登录。 果然昨天下班后,老大就发了邮件,说最晚下周要搞定这个问题。我郁闷啊,其实我早就开始想办法去寻找解决办法了,当时直接切换到LDAP认证时,提示说LDAP扩展没有安装,而用Apache认证方式时,说什么账号名要一致云云。 到网上找了很久,也没有发现有价值的内容,倒是sf.net上有个for phpBB 2.x版本的mod,可以使得支持LDAP认证,不过我装的是3.0.2,而且下载下来那个mod,我都根本不知道即使我装的是2.x版本的,怎么应用上去,所以此路不通。 不过看到Apache认证方式,再结合项目组用VisualSVN Server搭建的SVN服务器,给我一点思路。我是可以通过Apache来实现NT域账号认证的,再让phpBB来使用Apache的认证结果。虽然思路是有了,但实际上,我根本不懂Apache的配置文件要怎么写,看了半天它的手册,也不知所云,只知道它是有mod可以支持ldap认证的。最后实在没办法,抱着试试看的心情在公司网上发了个帖子询问,终于有个人回复了,问他要了点例子参考,果然OK了! 基本搞定phpBB的NT域账号认证登录问题!
今天开会的时候,不知怎么的,提到源代码管理的问题,直接就扯到要把源代码从VSS迁移到SVN。这是我之前几次考虑过的事情,不过当时的想法是,既然是迁移,就要把所有历史记录都迁移过去,费了好大的劲,最终还是没成功。当时的问题是,vss2svn并没有转换成功,后来想想继续用VSS也并没有多大影响,于是还是继续用。今天老大就说,历史记录丢了就丢了吧,反正VSS还在,到时候实在有必要的时候,还是可以看的。这样一想,也就霍然开朗了。会后立马动手,从VSS上Get latest整个目录,然后import到SVN上,基本没费什么力气。而且趁此机会,把方案、设计文档、帮助手册、会议纪要也都传了上去。然后绑定redmine上的版本库记录,不过有点问题,据同事说,不但需要svn的客户端程序,还需要重启系统,光是重启redmine服务是不行的,我大汗!
今天继续昨天的工作,要能给流程也添加关联的文档和子流程,当时评审需求的时候,我还以为没多少工作量的,这两天做起来才发现,大大地错了,要做的事还是很多的,不过幸好当时也是怀着一点小心思,多报了点。 首先,数据库处理模块需要增加相应的接口,因此COM组件也同样需要加一下封装。然后,核心业务处理模块需要封装数据库处理模块的接口。最后是界面响应增加入口,而且界面响应有三处需要增加入口的。 有了添加关联,同时也就需要查询和删除功能,都需要做不少事情。而之前的代码写得也略微复杂了点,现在增加代码时,发现有不少需要重构的。自从读了《重构》后,把这种活动看作理所当然的,不知假如我没读过该书,仍然遇到这样的事情,会怎么处理呢? 后来偶然看了一下版本计划,发现这些需求竟然不是要求最近这个版本实现,而是再下一个版本,这下我就怵了,宝贵的时间就这么消耗掉了。于是马上掉头做另一个需求,要能实现关联超链接。这时,又发现一个UCD的问题,关联时,弹出太多对话框了,版本历史上最多的时候有3个对话框需要用户进行交互,现在已经减少为2个,但还是不爽,应该在1个对话框里把所有这些都搞定,于是再次重构! 没完!
本以为今天闲一点了,可以干点其他事了,于是琢磨着把工程从VS2003升级到VS2005。升级的事,之前一直有想,但一直由于这样那样的原因而放弃了。这次又动了这样的想法,一方面是因为VS2005上才有Refactor!,另一方面是换了高版本的dot后,dot本身就带有8.0版本的crt dll,所以想着如果把7.1版本的crt dll换掉,感觉会舒服一点。 先看了看最基本的ACE和XTP有VS2005编译出来的lib和dll,然后开始升级工程。这次学聪明了点,不停靠VS2005自己的升级功能,而是直接自己编辑.sln和.vcproj文件。基本上只要把版本号改了,就可以了。为了回退方便,我先复制了各个.sln和.vcproj文件,并改名,然后才改版本号。再用VS2005打开,编译链接。这个过程倒没出多少问题,2005和2003最大的几点区别是,2005中对字符串操作的函数作了扩展,其次是manifest的引入。这都没有引起多少麻烦的事,只略作修改就可以了。 最后却因为另外一个没想到过的问题而促使我放弃了升级:编译太慢!真是没想到啊,也不知道是本来VS2005的编译器就比较慢,还是说这个编译器在遇到某些情况就会性能降低,比如使用了大量模板等等。反正最后我忍无可忍了,rebuild一次,就要好久好久,2003下明显要快得多,没多少犹豫,决定还是继续使用VS2003吧,顺便庆幸了一下,Impeller幸亏不是用VS2005编译的,不然会多花多时间啊!
今天偶然发现有一个图,dot会崩溃,换到2.20.x版本后,就没问题了,看来在适当的时候,升级是很有必要的。但是同时又引出一个新问题,高版本dot生成的svg格式,里面使用的坐标系比以前的复杂了,居然出现了科学计数法和负数,这让原来勉强能工作的格式化后活动框的定位又不行了。经过一番研究,发现在svg的开头有一个transform属性,该属性的值分成三部分,其中一部分是translate,经过试验发现,该translate的值加到下面的坐标系中的值,刚好能对应上以前使用的那种方式的坐标系统表示的值。于是乎,也就是说,又要多一步操作了。 升级到高版本的dot,同时也带来一个新问题,就是如果发布这个dot套装。反正我是不想在我的安装程序里面再执行一遍Graphviz的安装程序了,像Wireshark一样,感觉不是很舒服。之前的低版本(好像是2.05.x还是2.15.x)dot,很简单,一个exe文件,五六个dll就搞定了。而新版本的dot而远远不是,经过在一台没装过Graphviz的机器上实验发现,比较省事的一个办法是,复制dot.exe和所有同目录下的dll,一个config文件,一个msvcr80.dll和对应的manifest文件,以及Graphviz安装目录下的lib和etc目录下所有内容,大了不少啊! 今天又想了想,要是有个服务器端的话,有些事情可以容易得多。比如今天突然给了我一堆域账号,我要一个一个在MS SQL Server里先添加账号,再把账号添加到数据库中,很是麻烦,如果有了服务器端,就不需要这步了,最多自己维护一个自定义的很简单的列表;有了服务器端,可以通过服务器端对所有客户端进行广播,而现在的架构如果来做广播,似乎有些不伦不类;如果有了服务器端,就可以优化网络连接和数据传输,从而对系统响应的速度有所提升。不过很大的一个坎,如果有了服务器端,开发、调试的难度将大大增加,维护工作量也随之增加。
今天突然想到,之前遇到的两个操作Excel的问题,该不会是在2007里对2003版本的修正吧! 最早使用COM操作Excel2003出现的问题是,在我的电脑上,打不开Excel文件,硬是说没有正确的序列号,我分特,公司花了那么大一笔钱买了license的!想了一些办法,仍然没有解决,为了不影响进度,忍痛在512MB内存的机器上装了个2007版的Office,但是奇怪的是,如果直接运行Excel 2003 SP2,编译文件什么的,都是好好的。 第二个问题是,突然一夜之间,所有的使用Excel 2003的机器上,都不能对图形全选操作了,用鼠标是可以选择的,但如果通过代码来SelectAll则必定异常,无论是在VBA中,还是通过COM接口操作,屡试不爽!很无语的是,当时定位了好久,也因为只有我自己的开发机上是用的Excel 2007,根本暴不出这个问题,最后找到出错处后,仍然束手无策,一狠心,再也不copy图片了,而是提取出各个图形节点的位置信息,自己用GDI一个一个画出来,同时带来很严重的失真现象。自己画的线条没有抗锯齿,没能好好计划节点内的文字大小和位置,没能按照连接线的原始图样进行绘制,不过总算也勉强能蒙混过关。 第三个问题是,发现解析所有图形节点时,发现多了一两条不可见的line,但是同样一个文件拿到我的机器上,通过Excel 2007的接口解析,却没有这两条line,瀑布汗!所以图形在我的机器上显示的好好的,到了别人的机器上就多出一个虚线矩形框和一个实线矩形框,只好额外写几句来特殊处理一下! 我猜,第二个问题和第三个问题,会不会是由同一个原因引起的,会不会是由于2003和2007版本之间的一点不兼容性引起的,2003创建的文件被2007编辑过后,再拿到2003上去就会有点表现不正常?还是说本来就是2003就有问题了,只不过2007上有了改进?
从没用过C++的异常,都是看到别的代码抛出异常来,我自己的代码里try...catch(...),甚至从来不知道catch里到底是要什么类型的。 这次有这样一个需求,在一个比较深的调用层次的地方,不但要返回成功过失败,如果失败了,还希望能得到原因。其实这个需求之前就有了,但当时没有放在心上,觉得不做也不要紧,而且当时的想法是像Windows API那个,设置一个全局的值,即Error Code,任何操作之后都设置一下这个值,其他地方就可以直接获取到失败原因。当时想到这个方案时,心中也有点不舒服,这也是导致一直拖着不实现的一个原因。 昨天做过功能的,直接就想到用C++异常来实现。今天先看了一眼msdn,然后就决定,这么简单的需求,就不需要自己写个异常类了,直接抛个字符串出来算了。字符串内容是从资源里取的,所以最后就直接throw一个CString出来了。效果还是不错的,不过有一点是需要特别注意的是,本来都已经通过返回值知道操作不成功,就可以跳出这个流程了,但有了异常,就需要在任何可能调用到这个路径的某处上层,进行try和catch,不然程序就直接down掉了!
叫老大过去真是有效啊,哈哈,虽然加了一些额外的需求,却把另外一些需求的实现期限往后推了,这让我心里觉得无比舒坦,这才是正常的工作方式啊,哪有总是有突发的需求加进来冲击原本已经排得满满的进度。 今天解决了两三个问题,花了几个小时总算实现把一个活动根据多个角色拆分成多个活动。结果下午4点的时候又被叫去讨论问题,这让我很头痛,那么多的讨论,纯粹是浪费时间,花在写代码上的时间就被不断缩减。而且一讨论就没完没了地纠缠一些毫无意义的问题和细节,自以为是地出些馊主意,还不能拒绝。
一个月前申购的1GB内存条今天终于领到了,还顶着大太阳跑到K4地库去领来的,又等了快2个小时才让人装好,顺便还去领了根音频延长线来,不过已经最近没有机会用自己的电脑,所谓“兵马未动,粮草先行”啊,哈哈!现在应该跑VS要顺畅一些了吧,跟家里一样,把虚拟内存也去掉了。 今天没干什么事,上午不知道怎么就混过去了,下午就是去领了下内存条、等人安装,接着又开了2个小时会,于是一天也就过去了,现在我真的很讨厌开会。不过现在也明白一个道理,以后开会一定要拉着老大一起去,他说话的份量确实比我足多了,我就在想要是还是我一个人的话,今天肯定还是会有不少情况下要跟人起争执的,而老大去了,很多时候他出面说话,别人都不怎么争吵,我那个汗啊!
今天去加班了,其实很不想去的,但是弱者是没有决定权的,连同自身的自由! 终于搞定也几个催得最紧的问题,问题还在于逻辑跟界面绑定了,不能用CppUnit做单元测试,所以在这种纯逻辑的情况下进度慢了很多,因为测试验证相对比较麻烦。 本来还想把开发环境从VS2003换成VS2005的,在冒烟服务器上也装好了VS2005,但最后还是没有继续下去,因为升级环境要做的事情还真是不少。首先,那些第三方库需要用VS2005重新编译,比如XTP、ACE、CppUnit;其次,VS2005之后引入的Side By Side,让我有点惧怕,谁知道会不会有什么不正常的;再次,担心有的第三方库在VS2005下直接使用会有问题,比如iconv,我是直接把iconv.lib拿来用了的;最后,我的机器上装的VS2005运行得好像有点点不正常,设置了编辑器字体背景颜色有时不能立即生效,如果设置了是浅绿色,则只有空白处才是浅绿色,有文字的地方还是白色的,而且连语法着色都没有了,前景全变黑色了!另外还有一点是,毕竟还是疲于奔命在项目的功能实现上,实在没有多余的心情去做那样的事啊!倒主要也是为了使用一下那个重构工具,唉。不过看来公司内也许像我这样边编码边重构的人还是不多的吧,至少我周围那几个人是不这样的。 其实我也只会用那么两三种重构手法,最常用的便是提取方法,重命名方法名或变量名,将方法其实从.h文件移到.cpp文件。偶尔可能也会用用提取类等等手法,但这样的机会很少。所以还需要继续学习和实践啊。
又去受了一回气,要把google桌面搜索,google地图的功能都做进来了,真是痴人说梦话,还总是说没工作量,神经病! 今天把格式化显示时乱码的问题解决了。其实不是MS SQL Server那里引起的,而是从Excel读取数据后转换成XML中间格式就出错了。如果是原始的干净数据,是没有问题的,只有当原来已经有同名的流程已经存在时,跟新的流程数据进行合并时,才会不正常,主要是没把连接线中记录的两端的图形节点uuid值改换回旧的,于是跟图形节点中的uuid值对应不上了,生成的dot文件中又是以uuid来作为节点标识的,当然出错了。 另外又发现一个判断上下级关系的方法写得有问题,光是看代码就看出来了,果然他们实际试用的时候也是不正常的。但实际上这部分代码我都是纯粹凭想像写出来了,根本没经过什么测试。主要原因还在于这部分代码跟界面绑在一起了,都不好用CppUnit进行单元测试,所以逻辑正确性都不能保证了,看来抽时间还是得把这部分重构一遍,不要跟界面绑定了! 今天又偶然看到一个可以Visual Studio 2005和2008下使用的重构Refactor!™ Pro for Visual Studio,在公司里找到一个似乎是免费版的,装了后在VS2005上看了看效果,从界面上看很酷啊,哈哈,不过公司里只用VS2003,真是遗憾啊,只能继续用VAX里带的那点重构功能了,尽管大部分情况下也勉强够用了!
今天狠了狠心,直接又加了一张表,把原来用XML表示的组织结构信息存储到数据库中去了,原先过高地估计了难度,其实是心里有抵制情绪,心理暗示这用二维的关系数据表来表示树型结构很不方便。其实不然,只要每一条记录里保存一个指向父节点的引用就可以了。 于是最后的攻坚战接近尾声了。权限相关的问题基本上从编码角度讲,差不多完工了,就剩下及时刷新客户端的组织结构显示了。而另一个主要问题,格式化显示流程图的问题,就我现在的猜想,问题还是出在MS SQL Server的使用上,自我感觉其他各部分的实现还是经得起推敲的。 自打从CodeProject上又重新找了一个自动更新版本号的插件后,工程的版本号终于又能跟着每次编译而自动增长了,到今天为止,都已经到1000多了,这样好过以前要手动修改资源,但似乎有点不太专业。就我理想中的应该是,每次CruiseControl进行自动构建时,帮忙自动增长版本号,而不是我一个本地构建时进行增长。现在只有我一个人修改代码还好说,如果多人协作,目前这种做法明显行不通。
觉得自己很可怜,唉,状态很差,生活、工作都很糟糕。今天去汇报工作进度,被领导认为这两周来没做什么事,郁闷!遇到个变态的领导,让人如此无语,用小妞的话来说,有过这样的经历后,以后觉得什么人都是挺好的了。 今天又因为忘了std::map的自动排序功能,而花了不少时间去修正那些bug。我把句柄作为key,该句柄上的标题文字作为value,本来想这样的结构用std::map挺好的,结果整了好久才发现插入容器时的顺序跟容器内的节点顺序不一样,才猛然想起来,这个std::map会自动根据key的值排序一把,而我恰恰不需要这个特性,于是想起去年,做编辑模块的语法提示功能时的情景,用了std::vector<std::pair<HANDLE,CString> >的结构,有一点std::map的样子,但又保留进入容器的顺序。 代码真的越写越乱了,现在连接口都是混乱的了。相似的方法名,容易产生歧义的参数列表,以及更多耦合的类划分。为了完成功能,我只好不管这些了。还有,我似乎也有点完美主义,上周讨论下来的结果,那个方案,我总觉得太土太不专业,总想用另外一种我自以为要好得多的方法来实现,但是脑海里另一个声音却是“先完成功能,不要管实现得好不好看”! 在公司论坛里看到一个monaco字体,等宽的,发贴的人说是最好的编程字体。开始我还不以为然,看到另一个人解释说什么叫好的编程字体,一要等宽,二要容易辨别o和0,1和l,剩下的则是见仁见智,觉得挺有道理的,虽然贴图上的样子看起来并不好看,我还是下载下来试用一把,把VC2003里用了一年的FixedSys换掉了,感觉还是挺爽的,看来大概是用了太久了,审美疲劳了。
经过最近几天的努力,终于基本实现了通过dot的帮助,格式化显示流程图的功能。还记得当天晚上因为发现dot的功能,兴奋地睡不着觉。前天完成了把XML格式的数据转换成dot文件,再用dot生成PNG和SVG功能,昨天又换回GDI+,把PNG图片显示出来,今天则是把SVG自行解析了一把。dot生成的SVG文件确实是用UTF-8保存的,但是一开始发现用MSXML死活加载不上,后来慢慢定位发现是最开头位置有一句DOCTYPE,把这句删了就能好好地加载了。我估计是我没用好MSXML,不然也太扯了吧。不过这里我也懒得去追究了,直接处理了一把文本,把那句删掉了。然后装入,果然所有需要的信息都解析出来了。中途还遇到个小麻烦,发现识别鼠标位置总是有时行有时不行,还单步跟踪了好久,后来一狠心先把所有节点的坐标打印出来,再对应点击的坐标来看,到底是实现逻辑还是哪里有问题。发现原来就是一个单位转换的错误,一时疏忽了,SVG里都是用磅表示的,而这里我要的是像素,乘上这个比值就可以了。 离最后期限发布还剩下的一个大问题是权限。权限系统当时考虑地太过简单了,不过也归结于当时的需求或者设计都没有想到现在会变得这么复杂。当时确实只想到了某个组织下属某些组织或个人,而根本没考虑某个人会需要作些特别的操作。现在的一大问题是,某个人可能同时分属于几个不同的组织,另一大问题是某个人需要有一种角色,管理员角色,这样可以拥有一些特殊操作的能力,还有一大问题是,在客户端对组织结构及角色进行修改后,该修改要让所有客户端知道。现在的做法很明显很难适应这些需求了,因为我把组织结构保存在一个配置文件中,而该配置文件是放在各个客户端中的,所以修改只在本地进行,不影响其他客户端。没头绪啊! 下午的时候,算是阶段成果汇报,中途我溜了出来透透气。老大说我做这个程序,很有些想法。让我不禁有点得意,同时也特别悲哀,原来我这么容易满足,只是别人这么一句普普通通都算不上夸奖的话,就让我觉得高兴了。
昨天从网上查到,要让dot支持中文,必须得把dot文件保存成UTF-8编码,可是我用C Runtime、MFC CFile、C++ iostream都只会保存成ASCII的,于是不可避免地要再多一道工序把字符编码转换一下。 从一开始我就想到了iconv。先拿来它的可执行文件,在控制台上尝试了几次,原来是要把中文的设置为gbk才行,如果是ascii或者gb_2312-80都是不行的。知道iconv确实是可以将编码转换后,就放心大胆地在程序中使用iconv库了。从公司归档库中找得到的只有1.9版的,但好在.h文件和.lib文件都有,看了一下头文件中的声明,猜猜也就是先iconv_open,然后iconv、最后iconv_close共三步操作而已。于是先把文件都读出来,然后iconv。可是死活不能把转换后的内容存放到目的缓冲区中,而源缓冲区,以及返回值,还是源数据长度和目的数据长度却都是对的,实在不得要领。这样郁闷了好久,还是不得其法,于是准备直接用iconv.exe来转换算了。 iconv.exe转换时会把转换后的结果直接在控制台输出,可以通过管道重定向到文件中,可是在程序中要得到这个结果就遇到了些挫折。首先想到的当然是CreateProcess,然后通过管道捕获输出,可是发现这新生成的进程一直不结束,我估计是哪个参数没设对,这个API的参数也太多了点,昏厥!放弃,试了试C runtime函数system,倒是可以直接像在控制台上写一个有重定向的命令行,可是在执行时,会出来两个黑的控制台窗口,这用户体验也太差了!再放弃,看了看ShellExecute这个API,但好像不能重定向。 还是转回来用iconv库吧!最后还是从网上找了一段代码,先要iconv传入几个空指针的调用,再一行一行地从源文件中读出内容,再一行一行地调用iconv,最后一行一行地写入目的文件,这样居然就行了,大汗淋漓!
此乃人生之大不幸,竟然让我遇到了。什么事情到了他嘴上都是很简单的,任何问题他都可以说得睁着眼睛理直气壮地说没有难度,还会装着问你一下有没有困难,如果你说有困难,他就会很不屑地说,这有什么难的,不是很简单吗!有着这样唯心主义的领导,事情做好了,是理所当然的,事情做不好,简直是罪大恶极。 也许这就是所谓的驭人之术,可以被手下看不惯,甚至觉得愤怒,想法可以荒唐不切实际,但最终在一定程度上某些方面确实有所输出。 工作以来,从来没有这么气愤过,最多是有过深深的失望和无奈,但这次真的是愤慨。 我已经没有心情再跟他争辩了,反正无论怎么争辩都是做无用功。有句很流行的话,把生活比作被强奸,我想这句话套用在工作上也是恰如其分的。无论做什么,我同样是拿着这点微薄的工资,没了我,地球依然会转。 最近倒是隐隐有种感觉,似乎自己写的代码,结构组织方面比以前要做得好一些了。但在那种大框架,或小技巧方面,还是没有长进。一方面,半路出家,没有经过系统的学习培训;另一方面,缺少大型软件架构设计的经验;还有,编写代码行数确实还不多。 在技术方面的追求,未来的三到五年还是不能放下的,毕竟我年纪也并不大。只是除此之外,也要多关注学习一下其他诸如管理、营销之类的知识,这些方面跟技术才能相辅相成吧。
无限佩服cracker们,25日发布的Tiburon,今天偶然发现网上已经有对应的xx出来了,对于这种叫好不叫座的产品,实在是致命的打击。 今天又被叫去汇报,气死我了,我的脾气现在也实在不是很好,可是又不能把人家怎么着。啥也不懂,却要装做啥都懂,偏偏又能以权压人。这样的社会真是太可恨了,这样的世界实在太没趣了。于是下午几乎就没什么心情干活了,随便整了一下,反正代码check in后CruiseControl会自动编译打包的,所以就出去闲逛,跟人聊天吹牛。一直到快下班的时候,才发了个邮件说可以下载最新的安装包了。 倒是看到同事在用一个叫EA的东西,全称是Enterprise Architect,简单说来是个像Rational Rose一样的东东,用于画画类图、序列图,然后可以通过简单的配置直接生成代码框架。我问了下同事,跟Rose比,有什么区别,同事说EA功能多,支持全流程,而且体积小,才几十MB。然后我就顺便跟他扯起来,说我们也可以做个这样的东西,他就说这是需要一个公司来做的。于是我就举出StarUML的例子来说明,三五个人也是可能做出来这种东东的。 想起来,做为一个开发工具供应商,比如原来的Borland,除了提供IDE,即开发阶段的支持,另外对设计阶段的支持也是很重要的,特别是现在各种软件工程方法论的越来越盛行,所有开发者,对建模的重视程度也是越来越高,现在好用的,功能强劲的,确实基本都是价格昂贵的企业开发,像StarUML这样的已经是免费软件中最好的一类了,其他廉价或免费的质量能达到这种程度的,确实也很难找到了。这类软件的利润应该很高,但估计对售后培训等的需求也比较高。
开了一天workshop,上下午各3.5个小时,谈及了部门目前存在的问题,以后的发展方向,规划等等在我看来似乎离得不近的东西。不过通过今天一天的workshop,总算让我的心态又调整了一点,本来是很不爽现在做的事的,结果我又被说服了,我觉得现在做的事还是比较有趣的,有价值的,至少可以让自己的技术得到提升。话说昨天小妞的老公还叫我不要太沉迷技术,可是我发现我其他的什么谋生能力都没有,实在是不得已而为之啊! 昨天晚上居然兴奋得睡不着,试用过dot的能力后,越来越觉得格式化显示流程图的功能可以用dot来做,可以让它导出成png(或jpeg或gif)之类常见的图片格式,再导出成svg这种文本格式,通过解析svg来获取到各个图形节点的坐标位置,通过png来进行实际的显示。只不过昨晚简单看了看dot生成的svg,里面用的尺度单位又是那该死的“磅(即pt)”,大概我们目前最常用的分辨率下是1磅≈0.75像素,这样就又多了一次浮点乘法运算。还是得去图书馆找一本讲svg格式的书来看看,主要了解一下它怎么描述坐标系统。 自从基本用ACE搞定了文件传输功能后,我又开始在心里有点蠢蠢欲动了,在这个工具里面加入Kademlia会怎么样呢,当然现在这个工具的用户还太少太少,看Kademlia的那些参数定义和设置应该是依赖于一定量的用户数的基础上吧,可能是几十万,也可能是几百万,那样才能发挥出分布式hash的效用。看我做的这个工具,只有几个人用,最多也就是几十个人吧,也许通过一些政治手段,可能达到几百人,但还是太少了,根本不能体现这Kad的作用,不过我就是想把这工具做为一个试验田,既然干得不开心,就努力为自己争取些其他方面的收获嘛。
今天终于把文件传输部分改得几乎能正常传输完整个文件了,试了2KB、84KB、2MB三个文件,都没问题,其中2MB的是个Rar文件,能正常解压缩,说明应该是没有一个字节是错的了,而且速度在局域网内也基本在一个可接受的范围内。 昨天传文件的时候,还一直会丢失些数据,反正发送端是应该没什么错的,老老实实把整个文件的内容都读出来,然后一次1KB左右发出来,可是接收端总是收到不在期望内的数据,或者就是收到几个数据包后,就再收不到什么数据了。当时我还怀疑是不是因为发送得太快,但又觉得加个延时进去明显不太合理;又怀疑是不是收到数据包的顺序可能跟发送的顺序不一致,所以还试了试给数据包加入序号,但这个举措明显解决不了前面提到的两个问题。昨天可谓是毫无头绪,连猜带蒙地整了一天,结果就是证明了那些想法都是不可行的。 今天也算是灵机一动,想到了曾经看到过http下载文件,多线程下载时,就是可以指定下载文件的偏移量,于是我想,我也这样做,而且每次只发送一小点,接收端收到后再请求下载另外一部分,这样就直到把整个文件下载完,于是,果然可以完整地传输完整个文件了,虽然代码写得很dirty。现在想起来,在这样的策略下,要让这个操作支持断点续传和多线程下载也不是很麻烦的事了。 搞定了文件传输问题后,感觉心情一下舒畅了很多,换了另外一个工具的维护工作,要增加一个新功能,当时我估摸着可能要花些时间,于是跟那同事说要2天工作量。也不知道是不是心情好的缘故,不到3个小时就几乎搞定了,同样代码写得很dirty,而且这个工具最初代码是另外一个已经离职的人写的,他的代码风格跟我的路数不一样,我在这样的基础上进行维护,代码看着要多别扭就有多别扭。不过这只是个小工具,功能很弱很少,所以这些都不用太关注,要求实现的功能做了就行了。 之后又看了一会儿dot的user guide,开始还以为用它来画流程图很符合格式化后流程图的显示的形式,只要用一组比较清晰简洁的语法,直接可以生成一张图片,但是后来发现我这工具中对流程图的可控性要求比较高,不但要求显示,而且要求一定程度的编辑的能力,即需要能随时方便地知道某个坐标下是哪个节点,或者某个指定的节点在哪个位置,但是今天看了dot的只是直接输出成某种图片的格式,可能比较复杂。现在想想还是有可能知道是,比如SVG、PS之类的格式dot也是直接支持输出的,这类格式的文件其实是文本内容,应该保存有这类节点标识和位置信息的映射关系的,只不过再要解析它们,复杂性如何就不得而知了。
上周没调完,今天接着调,调了一天,勉强可以实现点对点文件传输了,但还剩下不少问题,比如我会在服务器端先读入整个文件,如果该文件很大很大,岂不是很占内存,如果超过了物理内存的容量,要动用虚拟内存,岂不是效率又会降低不少!这只是众多问题中的一个,还有其他各种问题,只能走一步算一步了,关键是先把容错性做好,不要动不动就崩溃。 现在的情况是一个程序里,又当服务器端,又当客户端,两边我都是用reactor实现的,其实我对其中的工作原理一窍不通,只不过抓来几个例子,照着书上写的拼凑起来,好在调试工具还算好用,加上一点点的抽丝剥茧,总算理出点头绪,也得到些经验教训。 首先,不要为了图省事而使用那个全局单件reactor对象,我开始的时候服务器和客户端共用这个对象,后来觉得不妥,把客户端的改成一个客户端连接临时生成一个reactor,使用调试工具发现勉强可以用了,服务器端却不会自动调用handle_output,后来把服务器端的那个reactor也换成自己生成的,竟然也可以了,也许是我没用对,但反正现在它几乎能运行起来了。 其次,无论reactor是用在服务器端还是客户端,都要run_reactor_event_loop一把,这个调用一直不返回,大概直到end_event_loop之后才返回吧,所以要另开一个线程来调用,除非是不想干其他事情了。这样,还可以看到一点,就是在适当的时机,要调用这个结束的方法。这和boost.asio的做法很相像。 再次,发现ACE_Message_Queue里居然只能存入16个最初压入的记录,后面再压入的全都被丢掉了,也不知道是不是有方法可以扩充到更多个数的,或者我觉得STL里的deque也不错,可以在头尾任意一端进行存取,不过ACE_Message_Queue似乎可以通过模板参数指定线程同步等选项,deque大概就完全要靠程序员自己把握了。 最后,要调socket程序,拥有和掌握好用的调试工具实在很重要,Wireshark这个开源的东东实在不错,只不过公司里居然装WinPCap是受限的,不过那个检查工具是防君子不防小人,好在可以通过改注册表中的卸载项来骗过它。另外从公司网上找到几个可以模拟TCP/UDP的Server/Client的小程序,很容易用,有这样的工具,就可以先调试其中的服务器端或客户端,等这样单独的调得差不多了,就可以进行联调。不然同时联调的话,出了错还不知道到底是哪边的问题。
今天倒没怎么投入到那个劳什子一体化平台中去,上午先是整了一下故障注入工具的PC端,只是加了个生成函数时的选项,最早是只能支持GNU编译器的,后来发现需要能支持Diab编译,只是在对话框上加了两个单选按钮,很简单,另外一个新需求更简单,只是改了下字符串。但也花了些时间,而且因为VSS不能访问了,于是索性把源代码都导入到SVN上去了,重新做了个安装包。 下午先去了趟图书馆,还了两本即将到期的图书,随便逛了一圈,没发现什么想借的书,空手而回。然后还是看了一眼一体化平台中那个权限问题,一直我都对外强调这个权限问题很棘手,工作量很大,然而其实在前不久我已经完成了绝大部分的代码,虽然发现有工作不正常,但也正好应了我原本一直宣称的没做好的事实,今天看了看,好像只是因为从数据库中取记录时没有把文档密级字段封装好返回而已。接着又看了一下编辑器中自动格式化的一个问题,这自动格式化已经成了一个顽疾了,而且不时地爆出全文格式化和换行缩进行为不一致的问题,这让我感觉头痛不已。总觉得现在那套代码写得太混乱,根本没有清晰的思路,但是我现在却实在不想费心去搞那东西了,唉! 今天是最近这段时间来感觉比较轻松的一天了,不是说工作量大小,而是说精神上的压力小了不少。
今天发现很多崩溃问题,主要是因为前段时间确实作了大幅度的修改,连数据库表结构都做了改动,幸亏也是今天让人试用了一把,发现得早。但同时也似乎引入了一些很难找到原因或者即使找到原因也不容易找到好的解决方案的问题,这才是让人郁闷的。 本来还想找来了个人一起做,结果是个新员工,还对C/C++、MFC并不熟,并不能立马就投入,反而要腾出时间来跟他解释原来的那些遗留代码是怎么回事,真是偷鸡不成啊! 另外还有个挂在我名下进行维护的工具,今天又收到几条新的需求,结果发现前些天那个VSS服务器不能访问,现在那个工具的所有源代码和文档都在那个服务器上,都取不出来,暴汗!
今天抓紧时间把那个格式化显示流程图的部分搞了一下,但是效果是很差的,这方面我一直都很弱,没有系统地学习过算法,更没有专业的图形算法知识。以前看过StarUML,可以格式化排版类图,现在要的就是像这样的效果,可我以为,这虽然可能可以做到,却是吃力不讨好的事。现在做的事情越来越偏离正轨,提出的新的需求总是搞混人和机器的能力,别人是扬长避短,而到了这里却总是安排些本不擅长的事情来做。 总之很郁闷啊!
话说周五下了班,直接爬上335奔向莲花二村,根据同事给的地图,坐391到关山月美术馆似乎更近点儿,不过等不到391了。也不知道这段时间是怎么了,坐公交车入关,好像总是在查,堵得很厉害。好不容易晃悠到了莲花二村,看了一下公交车站上的地图,发现好像并不是很远,走路也赶得过去吧。结果走错方向了,绕了一点路,等我赶到那咖啡厅的时候,已经比约定的时间晚了15分钟了。 两个人一边吃饭一边谈话,开始的时候还扯得比较远,后来渐渐地他把话题拉到TX公司上来,公司的过去、现在、将来,他负责的部门的情况等等,期间也穿插一些技术方面的话题,还好总的说来,他提到的一些关于技术上的事,我基本上都有所了解,也不至于太丢脸,那时我都自己佩服我自己了,居然知道那么多东西,哈哈。 去之前,我还在想,如果对方再加点钱的话,我是否还会坚持得住。结果是我想得太天真了,钱是不会再加了,只不过真像小妞说的那样,给我画一个很大的饼,说是过不了多久,可以让我负责一个研究方向,带一些人,隐隐一种leader的架势,但实际上这只是一种事实上的leader,并不一定会被公司承认的。除了这些,他还提到他现在手下的那些人,去年进去的,今年准备给配点期权了,大概意思是说万一我现在过去,也许过个一年也就会有这些东西了。 可能是看到我还是一点都不心动的样子,他似乎有点无奈或是无趣,问我究竟想要什么。我其实自己也不清楚想要什么,从薪水上讲,那个价也基本不算亏待我了,毕竟我这样的资历,没什么特长的人,是不会有特别的待遇的。其他的呢,我真不知道,那样负责一个方向,带些人,真的是我想要的吗?我发现我真的比想像中的更不爱钱,说起来这样的待遇,比起现在这边,几乎是长了30%左右吧,可是我却发自内心的一点都不在乎。 我把我最近想做的事情说给他听,他说原来你就是想做一个完整的product,我说也不一定要product,他说那就是framwork之类的,我说对的,就这种东西。他也马上提出现在他手下就有这样类似的东西在做,但是我却依旧不是非常感兴趣。也许我真的只能自己出来干了,这大半年来,一直堕落地看着小说,一部接着一部,被这事一搞,反而弄得我有点紧迫感了。
本来周二电话里已经把人家拒了的,今天又接到电话,说要谈谈,让我有点觉得不好意思,看出来人家似乎还是挺有诚意的。不过小妞说,到时会给我画很大一个饼,让我觉得在那里会多有前途。小妞还说,反正是两边互相忽悠,没关系的。 我都想不好了,到底应该怎么选择呢!因为电话里说不清楚,于是约了明天晚上下班后去关内的一家咖啡厅里聊聊,唉,心好乱!
睡得少,白天果然很吃力,这是已经亲身验证过无数遍了。 本来想着是上午给个新的编译版本让他们测试一下,结果发现,一个最最最基本的功能都不能用,直接弹出消息框。其实是COM接口抛了个异常,虽然我没有用try...catch来处理,但最后还是被我挂接的未处理异常过滤函数捕获到了,弹出个没有内容的消息框。 于是下午调了近2个小时来定位哪里出的错,因为我自己的电脑上无论怎么样都是正常的,而别人的电脑上无论怎么样都是不正常的。猜了几次,最后想到一个地方,Excel中的CShapes::SelectAll方法,不知道哪里吃错药了,只要一调用该方法,它就抛个异常出来,倒是可以用try...catch捕获到,但却没有什么实际意义,因为我不知道这为什么错了,我以为这就是最正确的用法。 冥思苦想了1个小时,毫无进展,于是上楼去找老大诉苦,我当然不会指望老大知道怎么解决这个问题,而只是想让老大知道我很郁闷很痛苦。 再回到座位上,照老大说的,把自己的进展,遇到的困难写邮件抄送给所有相关人,这样至少让他们自己我还是在干活的。一直到下班的时间,质量部负责这事的人跑来跟我说,这二三四季度的绩效考评放到质量部来做了,我彻底郁闷了,成质量部的人了!不要逼我啊!
照着红宝书上讲的,用ACE写了TCP的服务器端和客户端进行文件传输,代码量真的很少,而且可读性也很好,虽然没经过测试,但我自以为应该不会有多少问题了。 ACE还算好用,呵呵。既然这样,以后就考虑一直用ACE来做这方面的应用了,又能满足我跨平台的需求。 另外,我还是想建一个图形库,像visio/rose那样的功能,也许功能没有那么强大,但是效果就是朝那个方向发展。
看了他们整理了有十几条新的需求,另外bug也确实不少,跑去请示了一下老大的意见,是要认真到这个东西做下去喽。既然这样,就暂时放下编辑器和扩展框架的事了,计划一下如何把这个东东做好点。原来的有些设计是不合理的,在时间充裕的条件下,是肯定有更好的解决方案可以替代的。 如果真要专心做这个东西,有两点是可以很大优化的。一个是图形库,整出一个像edraw样效果出来,让该死的Excel见鬼去吧。另一个是分布式文件共享,看了Kademlia的一些介绍,不禁有点蠢蠢欲动,如果自己能实现一个通用性好的,后续的价值太大了。 这两块是相对较大的改动,其中还会涉及到数据库的设计等小细节,想起来居然隐隐有点儿兴奋。
又看到José León新发的blog,再结合吃晚饭时,同事的抱怨,不禁羞愧难当,伟大的Borland,伟大的Delphi,哪怕是几经更名,哪怕是几经易主,曾经的IDE霸主,编辑器就是应该这样的做的。 今天花了点时间重构编辑器的auto completion、call tips模块,框架早已完成,剩下的是只让整个流程运作起来。中途发现几处笔误和遗漏,都不是大问题。清理了原来的代码,从原来的几百行的规模,拆分成现在几十个文件和类,本意是让设计更容易理解和维护,也尽量往容易进行单元测试的方向靠拢。不过等都完成后,回想起来,这样的设计仍然觉得不是很爽。类与类之前的关系略显得混乱,有些依赖关系感觉不是很符合OO的那些基本原则,但具体怎么做能更好,我却没什么头绪,大概也是因为理论理论和实践经验的两重不足引起的吧,只能靠不断修炼,逐步提升自己的exp了。 同事抱怨说自动提示功能很少能正常工作,我觉得很惭愧,当时刚做出个样子来时,心里还是比较自豪和骄傲的,不过现在事实摆在眼前,离真正可用,好用还差得很远。幸好现在已经有了思路,用lex和yacc来做,再好好设计一下,争取让这功能真正好用起来,计划花一周的时间完成。再花两天,把编辑器View的基类提取出来,以后所有需要代码编辑功能的View,只要从这个类继承,就可以得到功能基本完善的编辑特性集合。最后,花两周时间,把外部脚本扩展的框架实现。
今天有个项目部的主管来找我,问我那流程平台工程做得怎么样了,他们部门目前新员工多,觉得这个工具或许可以解决当前的问题。我比较诧异啊,居然还有人想试用这东西,说实话现在这边的状况是,尽量快点甩手,从此解脱。我早就不胜其烦,厌倦了没完没了在上面投入。那位主管说得很有理,说这东西做好了很有价值。这个我当然也知道,如果做好了,当然有价值,关键是上头的决心有多大,愿意投入的成本有多少。一直就是我一个人在折腾,一个人折腾么,给我足够的权力和资源也好,偏偏也没有,要指手划脚地作些不合适的决定。 今天我突然想到,要是早知道会拖到5月底这么久,早期的设计就可以做得好一点,2个月有2个月的做法,3个季度有3个季度的做法,唉,这应该可以算是一个失败的案例了。 回顾检讨一下失败的原因:1、前期的规划没做好,开始以为时间不足,就迫使强制采取了些不良设计;2、用户需求一直不明确,以及用户需求实现比较困难;3、我做为唯一的开发人员,心理上有所抵制,积极性不高;4、开发编码工作没有计划和任务跟踪;5、缺少测试支持等额外资源的投入;6、现在看来,因为其他因素的影响,似乎开发投入人力也不够。 暂时只想到这几点,不过也很难过了,唉!
有些问题是看不出来的。 今天因为有人提了单,我才下决心去看了一下代码,经过比较仔细的排查,最后结论是,果然是被我改坏了,原来的那种实现方式确实是不会出这种问题的,不过那种实现方式是一定不能留的,一定要被改掉的,只能在现在的基础上进行修改,最后好像勉强可以了,哈哈。 还有一个问题,好久好久了,是以前离职的一个人留下来的东西,交给其他部门人用的工具,现在发现有问题了,原来我看了一下,似乎问题不在工具本身,而在工具调用的底层通信模块上。今天又被人一说,仔细读了一下工具的源代码,再加上和那底层通信模块作者的讨论,最后结果是,确实好像是工具实现得不对。有几行代码一眼看就觉得写得有问题,且不说是否真有问题,首先代码就不应该是那样写的。 另外是这大半年来我陷入其中的工程,今天写用户手册,当然需要演示截图,结果发现了好几个比较严重的问题。唉,我这大半年的投入产出比还真是低,心里有点难过。争取在剩下的3个星期里,把这些严重问题修正了,完善一下用户手册,就彻底交付了,唉,从开始计划的2个月,到现在都大半年了,真是没完没了,还拖累了绩效,不过似乎就算不搞这个,绩效也不会好到哪里去吧,郁闷! 最后提件还算好的事吧,小思宇回深圳了,今天还给我打电话,挺高兴地跟我说“我回来了”,大概是因为彭彭回来了吧。不过她那高兴的劲也短暂地感染了我,让我如沐春风啊,哈哈。
今天考评,结果还是不出我所料,有点麻木地失望。不过这失望不是本篇blog的主题,这里要谈的是目前项目组里的重头项目,那个已经历了超过一年半开发的IDE。 这东西说要重构,我也已经开了个头,现在的情况是,老大说要在VSS上建分支。可是很明显的是,VSS根本就不支持这样的开发方式。这样就会引入一种新的问题,模拟分支,就有两份明显独立的拷贝,如果进行同步。修正问题在原有代码的基础上进行,重构则在新的一份拷贝上进行,以后合并代码对于现在的几个人来说,估计是个挑战,但我猜更多可能的直接是个灾难。 其次是架构和代码实现。现有的架构方式已经寸步难行了,但还是要在那个基础上继续进行。现在我是切实地体会到,编码产量高的,一点都不稀奇,相对来说架构设计则真的重要得多。一个文件,一个类实现,用C++代码实现,居然有18000行,这样的实现,功能确实做出来了,但后续的工作却举步维艰。一点小的修改,一点小特性的增加,都会牵扯到很多地方,可能引发很多问题。模块间的交互耦合,都没有经过良好的设计,都是觉得怎么容易实现,就怎么写,结果一堆一堆的重复代码,一个个超大的文件超大的类。 再次是加入特性没有经过认真评估,加入了一些完全不实用,花里胡哨的东西,而真正有用的功能并没有加入或增强、完善。比如about对话框,居然是一个视频文件,直接调用MCI接口播放实现。视频的周围则是一张背景图,背景图上的文字都是在图形处理程序中固定写死的,这样在以后每次显示信息修改的情况下,凭空增加了图片维护的工作量了。另一个是状态栏上的动态新闻,嵌入IE直接显示远程服务器上的内容,程序内部截获打开链接操作。大概是实现方式有问题,如果远程服务器宕掉了,则在程序启动时试图连接时,花费好几秒时间在那里阻塞等待。诸多问题,恕不一一列举。 最后是没有好好利用持续集成。虽然装了个CruiseControl,却只是为了实现点个按钮进行编译,连“持续编译”都算不上。一方面,没有实现“持续”,都是在需要时,手动点击一个按钮,进行force building;另一方面,只有编译,没有其他行为,比如代码度量、单元测试、打包发布等等,完全是个空架子。 其实回头看看这些问题,我觉得都是管理上的问题,单纯从管理层的角度出发,就能解决绝大多数。 总之,我对那东西很失望,因为管理者如果没有意识到问题根源,将在以后的很长很长一段时间一直存在,并继续恶化。而我能做的,大概就是假如有机会,把编辑器部分做完善点,在我能顾及到的范围内,实现一个类似Eclipse的扩展机制,仅此而已。因为今天听说,有人对编辑器评价很高,有人甚至就因为这个功能,就想把这东西拿到家里去用,这是我唯一的动力了。
今天又整理了一下代码,又把初始化部分移出来了,居然相关的代码超过1100行,也算是神奇了。现在主要是把相对独立的功能剥离出来,所以并没有仔细地考究里面的代码细节是否写得完美。而且,总感觉现在的结构还不是我理想中的那种样子,但到底做成什么样,我自己也不知道,我想不明白怎么做才能做好。 另外在看代码的过程中,发现其中有一些是重新发明轮子了,其实有直接简单的实现,却因为对系统的不了解,而自己实现了一把,如果不考虑性能等方面的因素,只是关心代码的整洁清晰的话,当然不要自己的实现了。 还是要去整那一体化平台,心里总有种抵制的感觉。想去做图形编辑,想实现一个足够灵活的插件框架,唉!
今天决定开始对代码审查辅助工具动手,结果发现这个代码写得太复杂了,彻底晕死!本来看起来似乎是个很简单的小程序,功能也算比较简单,就是能添加一些信息,把这些信息保存到一个文件,到需要时能从文件中读出这些信息,另外一个功能是能把信息输出到Excel文件中,或者以一定规则输出到Lotus Notes中。 结果发现,为了跟Excel和Lotus Notes交互,必然使用到了COM接口,然而奇怪的是,原来那个作者把对Excel和Lotus Notes的操作简单地用VBS封装了一遍,结果是另一种脚本COM组件的形式出现,再在MFC程序中调用这些脚本组件,实在是不必要。 其次,因为本程序设计的是能在Source Insight中激活并添加信息,所以需要Source Insight的扩展来支持,也许是Source Insight的宏能力比较弱,原作者就设计成在C盘根目录下放置一个很小的cmdline.exe,让宏直接把所有信息当作命令行参数传入给这个小程序,通过它来调用主程序,于是为了在不同进程间传递数据,便把这个主程序设计成了一个进程外组件了。唉,又是COM,烦死人了。我也要把它改成不用COM的,用Event、File Mapping、Metux、Command Line Parameter应该能解决这个问题。 再次,界面上有个TreeView,TreeView的Data域不知道绑了多少数据上去,晕死!关键是不要绑MSXML的COM接口指针上去啊! 最后,我要在这个基础上重构的话,工作量比重新做一个大概少不了多少了!
今天组里几个人突然谈论起组织结构调整,然后我们现在做的东西命运怎么样,我们将来的命运怎么样,最后一个结论是要让我们做的东西成为精品,这样我们才有可能不被人随便摆布,不被拆散。 然后就说到重构当前这个项目的代码。说来说去,我还是去做图形编辑这块,同时兼顾文本编辑器的重构。这是我最希望的情形,对于代码编辑器,我一直有不少想法需要付诸实践,现在说起来要让这个工具能大规模被推广应用,就需要各方面都做成精品(也许这也只是我们的一厢情愿而已)。我能做的大概就是在代码编辑方面努力做好,简单说来就是能让开发人员也能用得顺手,让Source Insight从这里消失吧。目前的状况是,Source Insight缺少代码折叠、Tab标签浏览、中文支持不佳、外部接口不方便这几个大缺点,对于基本的语法着色、自动完成、语法参考还是不错的,速度也挺快的。如果把Source Insight的这些缺点补上,再加上有它的那些好用的特性,还愁不让它消失么!
简直想吐啊,太无聊了,又完不成任务,要求那么多,根本是浪费时间嘛。有空写个程序来自己搜简历得了。大概的想法就是调用IE的接口,几乎所有的IE页面上的元素都可以通过COM接口访问到,除了验证码不能自动识别外,其它部分应该都可以用程序完成。另外还有个问题是,输入email和手机号后,要点击一个按钮看是否重复,这时它会弹出一个MessageBox,这该如何处理,我猜IE也是有接口可以屏蔽掉这个alert的,或者说可以直接把整个javascript脚本都替换掉,不过也仅仅是猜想而已。最熟悉的做法是在后台开个线程,监视是否有MessageBox弹出,然后自动获取MessageBox上的内容,再自动点一下那个确定按钮,呵呵。 不过想法虽好,到时候极有可能就不了了之了,这写个程序还是挺花精力的,呵呵。
经过不短时间的调试,下午终于可以显示出一个虚线画出的矩形框来了。虽然还只是一个虚线框,不但大小改了,位置也没计算好,而且还把连接线都丢了,但是总算是出来了。这一小步,对这个东东的进程来说,其实也是一大步。接下来就是计算一下连接线的位置,就差不多了啊,吃晚饭时那种喜悦放松的心情真是很久没体会过了,呵呵。 调试过程还是比较让我觉得痛苦的,首先是我的机器上Office 2003装好后,居然在我的程序里通过COM接口运行Excel时说注册码不合法,晕死,这可是公司大企业客户版啊!同事丢给我一个算号器,发现有两个Office 2003,用了不同的序列号,晕,另外一个怎么也找不到在哪里,今天上午一气之下把所有的Office这个字眼沾上关系的全让我卸载了,然后装了个Office 2007,偶然发现不再提示注册码不合法了,呼呼,真是玄乎呀。 不过后来发现,有一个函数用来把Excel里的图形复制到系统剪切板中,然后再取出来存成GIF格式,当时一直在2003下处理,用了个魔鬼数字,直接取出指定编号的那种类型的剪切板数据,现在发现那个索引下的不是GIF格式数据了,呵呵,还意外发现了这么个bug呢! 另外还发现个有趣的问题,因为调试经常把Excel整死,若干次后,它居然弹出个对话框说Office似乎经常崩溃,什么深表歉意云云。 终于快要脱离这个苦海喽,回头是岸?
看了一点SciTE的代码,因为从SciTE可以看到Scintilla控件的各种使用方法,说起来Impeller也使用的Scintilla,但是总感觉很弱,比如SciTE可以同时直接支持UTF-8和ANSI编码的文件,而Impeller就不行,一个时刻只能支持一种,另一种编码的文件打开时,如果有中文之类的多字节编码符号,就会显示成乱码。 似乎我是不会被调回去做编辑器模块的工作了,可能要我去做图形编辑方面的事了,版本计划中下个大版本需要加入像Rose那样的UML类图编辑功能,不禁要感叹,他们的野心还真大,唉,Visio这样的工具全世界也没有几个呀! 我现在是陷入项目泥潭了,正是有这样大野心的领导,才会让我等小兵异常痛苦,尽提些高难度高技巧的需求,还总以为很简单很容易实现,却并不考虑用户可接受程度。又听到一个新的需求,说是要求所有工具都能自动安装到部门每个员工的电脑上去。那要是人家不愿意呢,又该怎么办!技术上是没有多少难度的,关键是使用者的抵制情绪如何抚平。 想想我转去做图形编辑方面的工作对我自己来讲是件大好事,本来对文本编辑部分已经有了一定的基础,以后就是自己钻研扩展了,现在趁工作的机会再学习图形编辑,对我以后极有好处啊。刚开始听到这个消息时,心里还略有点失落的,现在想起来,觉得这简直是上天对我的恩赐啊,哈哈!
当时还为自己的设计沾沾自喜、得意洋洋,觉得这样的想法、这样的灵感、这样的架构简直就是神来之笔,谁知结果带来的是无休止的崩溃,找不到原因的异常! 因为需要对流程支持历史版本,也即如果新的流程里删掉了旧的里的活动,但活动里又有关联内容时,流程图在显示的时候,需要把表示活动的图形也显示出来,而boss又认死了excel这个东东,所有流程图的内容都要在Excel中编辑完成,可Excel里又没有记录修改动作历史,于是乎,我的设计隆重登场了。我先把Excel中的内容转换成XML保存下来,然后当Excel有了变化,再分析一遍转化成XML,跟原来的XML比较合成一把,这样似乎就能在那么丑陋的设计中以自以为比较优雅的方式实现这个需求了。结果问题也来了,原来的数据表结构要修改,需要为每个流程记录增加一个存放这转化后的XML内容的字段,而恰好MS SQL Server 2005中有那么一个叫XML的字段类型,于是欢天喜地、兴高采烈地用上了,于是又花了一天才勉强做得像以前已经完成的那种程度。因为XML里可能有各种字符,而且可能非常非常长,所以用合成SQL语句来insert、update、select是很难受的做法,又出于我对ADO的不熟悉,好不容易找到设置Field的Value属性的方法,结果在存放、获取XML数据里花了我今天近一天以及之前的那些时间! 在写入XML时就陷阱重重,第一条xml处理指令的存在就很可能引起崩溃,简单说来,我保持了GB2312的编码方式,里面有中文,它就不让我写进去,一update就崩溃,现在想来,也许用UTF-8不会有这样的问题,嗯!但我还是作了个很恶心的决定,要写入之前,跳过前面的这条指令!接着在取出时,总是会在后面加入一堆乱七八糟的东西,又花了好多时间,最后决定,自己在字符串中查找结束标志,之后的全部丢弃,才好不容易让MSXML的DOMDocument接收了,而且是不能让它直接load文件,得自己把文件里的内容读出来,加上那个xml处理指令,再loadXML,晕死! 不容易啊,不过也算是经验教训了,下次再遇到这样的事就应该能省很多时间,不过我猜下次的机会不多了,不已经烦透了,我要去做其它的东西去。可能还是会让我去做Impeller的部分工作吧,我要让它支持灵活的外部扩展,我要让Source Insight消失!
有点像标题党,呵呵,如果这样的东西放在csdn之类的地方,说不定会引来一大堆人的口诛笔伐,不过这真是我今天的感受啊! 早就烦透了用C++通过COM接口使用ADO来操作数据库了,不得不为那些先人们的艰苦生活感到可怜了。如果没有ADO,我的生活肯定不知比现在悲惨多少倍呢! 但是现在我也是感到苦恼气愤,为什么SQL Server会有这么多不同的字段类型,却使用了同一套表达能力极为有限的API和SQL语法。今天也就只花了一点时间来写代码,结果全都花在这个引起的问题上去了,而且到现在都没解决,郁闷! 恶心死啦!
这个想法有好几天了,在网上搜来搜去,也没找到多少有用的东西,不过今天晚上加班,还是弄到基本可用的程度了。 首先需要明确一点是,所谓的RubyGem服务器其实是一个非常普通的http服务器。在公司里那台公用服务器上,自动化组的人用ruby发布包里自带的gem_server.bat运行了一个脚本,提供gem服务。打开这个bat文件看看,其实是个Windows批处理脚本和ruby脚本混合的东西,它开头一条语句将处理流程跳转到最后,运行ruby.exe来执行自身,中间则是一段一段的html代码和ruby代码,最主要的是最后一段ruby代码,通过WEBRick包提供的功能,在本地开设了一个http服务,并动态处理远程连接的http请求。其中最重要的是yaml请求,远程客户端请求yaml文件,其实它是一个对服务器上所有的gem包的索引,有了这个索引文件,客户端知道服务器上有效的gem包版本和具体路径,然后同样是通过http协议下载需要的gem包,并安装到本地。 有了这些基础,接下来的就好办了。Apache随便哪里都能弄到,基本配置也非常简单,就是改一下端口,设置几个别名,把gem服务器常用的几个目录添加上。一般需要/、/gems/、/doc_root/、/yaml这4个路径,其中/gems/和/doc_root/就是ruby在文件系统目录的直接映射,/和/yaml要通过脚本刷新,脚本不用自己写,只要拿gem_server.bat改一下就行了,原本它是直接生成字符串返回给http客户端,这里就改成把生成的字符串写入到文件就行了。试了试gem install命令,可以用,解决! 最后再来啰嗦一下,为什么要用Apache来作为Gems服务器。因为那个gem_server.bat用ruby来启http服务器,却有非常严重的内存泄漏问题,只要客户端连接稍微多一点,内存占用就直线飚升,随随便便就能到1.5G,所以,就是不能用它!
我会让后果很严重的。 凭什么要强迫我们免费奉献业余时间去吼那难听到死的歌。
被叫去又讨论了一把什么鬼需求,被郁闷了一把,这鬼东西太烦人了,最后我们老大还问我有没有不能实现或者实现特别困难的,我只能麻木地摇摇头,我已经没语言了,上次已经有过经验,就算我说哪里哪里实现很困难,那大boss也会说,这有什么难的,不是很简单嘛,然后不着边际地给你做一堆设计。 回到办公位,我是茫茫然而毫无头绪,稍微整理了一下讨论的内容,然后就向老大去请假,出乎意料地顺利,这样我就决定2月1日回家啦,哈哈。 还有个郁闷的问题是,不知道为什么,我的双缓冲就是不起作用哈,拖动一个图形时,另外的图形都会闪烁得非常严重。不过根据现在讨论的结论看,我是暂时不用做这编辑器了,因为大boss明确表示不要做编辑器,这编辑器是专有的,我们要用通用的工具,这样即使在某种特殊的情况下,我们没了这工具,还是可是使用这套东西。真tmd奇怪理论,什么时候会出现这种情况,又要没有工具,又要能完成什么什么功能。反正很早就开始无语了,我还想再过两年呢,这样弄下去我可坚持不了了。
已经有好几次了,在比较重要的时候,总以为自己能很快处理完。这次也是,但从今天的进度看来,总的说起来比自己想像的要慢一点,不过基本还算是正常的。 今天遇到一个很奇怪的事情,主要还在于自己对MFC架构了解不够。在Doc/View架构中,Doc类有一个方法用于串行化,我就想当然地以为将数据保存到文件中时,应该在这个方法中添加代码,但没有用它提供的串行化对象,直接获取到文件名,就一古脑儿地把所有数据写入到文件中去了。可是却发现,执行完后,文件却是空的,并且怎么也找不到原因,单步调试的时候发现,写入文件的代码是正确的,数据确实是写入了,可是后来不知道哪里又被清空了。最后很无奈,在默认的OnSaveDocument调用完后再来用我自己的代码写文件,就没事了,既然最终目的是达到了,我也就没去深究原来的方法为什么有问题,据我现在的猜测,可能是要把在那个串行化的方法中把数据输入到那个串行化对象中,之后MFC会自动把该串行化对象中保存的数据写入到文件中去,当然这只是我的胡乱臆想,呵呵。 自我感觉这次做这个特性代码结构是我个人有史以来水平较好的一次,不知道是不是真的是因为代码写多了,不知不觉就会水平有所增长,总感觉现在这个架构,层次划分,类的设计,都很让自己满意,呵呵。我觉得我就是不会那啥瀑布模型,就是不适应,那对架构设计要求太高了,对architecture的抽象能力要求也太高了,我就只能适合用一下像XP那样的方法,一边写一边重构,但是我又不用TDD,所以还是很奇怪的。 再感叹一下,强大的Boost,不用白不用!
我最终决定要自己做一个简单的流程图编辑器。改呀改的,就是怕时间不够,如果能慢慢任我做出来,应该也是有点儿成就感吧。 感叹一下,C++里一定要用STL,用了STL就一定要用Boost,呵呵,还是喜欢C++,可以泛型,可以面向对象。
今天只是加了隐藏进程的特性。这是一段从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图片不放呢!自己做个编辑器,跟研究一套还不知道能实现多少效果的东西,需要的时间差别应该不大吧。时间其实都是在这种犹豫不决、优柔寡断中浪费掉的。 总之,我很无语。
本来老大说要跟大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崩溃了。看来还得改呀!
上午去演示了一把这几个月来在弄的那东东,仔细看功能,似乎其实并没有什么特别重要的功能,而且有好几个在他们口中是很重要的需求并没有实现,这让我觉得很沮丧。从11点开始,一直到快12点半了才完,心情低落到了谷底。下午的时候,也没有心情做事,一直坐着发呆,先跟老大大概汇报了一下演示的过程和结果,然后讨论了一会儿之后要怎么做。接着就是出神,心也不知道飘到哪里去了。 主要还有2个大需求尚未实现,一个是流程变更后的自动更新问题,灵活绘制流程图的要求再次浮出水面,还是那个老问题,对于已经删除掉的节点,如果下面仍然挂有内容,则需要以虚线框表示出来。另一个是流程下需要能挂接子流程,这样就可以通过一个主流程一路找下去,找到任意角落里的东西。 第一个需求在我看来,似乎是可有可无的,而且从我程序实现的角度看,代价比较高了。第二个倒是感觉有点道理,似乎有点意思,虽然可以一次性在开始就把所有可见的流程都列出来,就像现在做的那样,但多加这么个功能,感觉更符合平常人思维习惯。 另外还有一些小需求,比如能支持其他来源的数据,像notes数据库中的内容等。 然后下午的时候,有人告诉我,这东东通过审计了,所有与会的人一致拍板同意通过这个project。我其实根本不知道这个的意义何在,审计是为了什么,这么小小一东西。 当然这就意味着至少在年前,我是无法从这里抽身出来的,那边什么编辑器,模拟器之类的东东,就暂时没法投入其中了。
接了无数个电话,当然人家也是打了无数个电话。也许换位思考一下,或许人家更烦一点,那种完全寄希望于别人,自己毫无掌控之力的无力感、恐慌,也许比我的心烦意乱更不爽吧,哈哈。 现在的问题大部分是由于程序运行环境变化,考虑不周引起的。开发环境毕竟是最不容易出现问题的了,呵呵。 下午去参加一个测试行业TMG的会,看到一人介绍了一个叫iTEST的工具。据说这是一美国公司,有80个人开发的,还是基于Eclipse的RCP,看功能似乎比较有趣,说起来没有什么核心技术,但是能解决一类问题,每个license要20000USD,还真是贵呀。其实是一基于录制、重放技术的自动化工具。它的不同点在于,它本身支持多种终端协议,通过它来进行输入,对远端操作,它自动记录下所有的操作,并自动将操作转换成TCL脚本,之后就能重用这些操作序列,进行自动测试。跟平常的Robot之类的自动化体系工具理念不同的一点是,它一开始没有定义为一个自动化工具,只是作为一个操作终端,所以不需要进行测试设计,自动化设计,脚本编写等传统的自动化流程阶段,它的定位在于保存历史操作记录,并在需要时重用这些操作。想了想,似乎有些地方,跟TDL有点点像,因为TDL宣扬的是脚本就是用例,用例就是脚本,有脚本就可以直接手工测试,也可以直接通过Impeller来自动化测试,从人工介入的行为上看,似乎很相似。回来跟同事一说,他们似乎觉得很不屑。再想想也没什么的,他们就那脾气,觉得自己多牛x似的,会点MFC和COM外,也再不会其他什么了吧。 另外,负责那Impeller工具开发的同事还在担心,到时候一季度这套体系推广不了,这个项目就要解散了。我倒是觉得没什么的哈。只是我还想做着玩玩,除了那查找替换部分要重构之外,剩下的网元模拟器、图形化配置环境以及脚本扩展编辑器,都是比较感兴趣的,呵呵。
那36字节的内存泄漏似乎是在Boost里的,昨天从CodeProject上下了一个跟踪内存分配情况的代码,放在工程里用了一下,看到走到Boost.system里去了。这让我觉得有点泄气,对Boost对崇敬的心情啊!不过想想,这36字节一直存在于整个进程的始末,也许它像个普通的singleton一样是不需要释放的呢,而且说不定release就没问题了呢。 MS SQL Server居然不支持双引号,晕,Access就好好的。气死人了。 问题太多了,改来改去整出一堆一堆的问题。下午的时候都烦死了,于是在那里抱怨,当初决定用Excel来作为流程文件格式,根本就是一个错误的决策。因为用户在用Excel编辑的时候,我的程序是跟踪不到各种变化的,最大限度的只能了解到变化前后的状态。今天又偶然发现另一个让人头疼的问题。本来那图形通过Excel的自动化接口直接Copy到系统剪贴板中,然后再从剪贴板中取出存成一个图片文件。但在Copy时有一问题是,它并不从Sheet左上角(0,0)位置开始,而是从所有Shape的最大边界值开始,而我关心的只是Rectangle、Ellipse等几个图形,对于Line等都是直接丢弃掉的。另一方面,Copy图形时,是会把所有Shape都选进去的,这样当有line是在rectangle之类的最大边界以外时,就不能再计算出定义精确的位置偏移了。为了这个问题,跟同事讨论了好一会儿,也没有人根本性的从技术上解决的方案,最后我灵机一动,说不如我们定个模板,该模板固定在左上角(0,0)处开始有个Shape,放个logo上去,用户的流程文件只能从该文件修改而来,这样就保证能获取不用计算偏移的图片了。说改就改,我都为我的灵机一动感到犹如神来之笔啊,哈哈! 还有很多易用性的问题,确实,最早的时候自己也觉得易用性太差,后来根据同事意见,作了一定的修改,易用性有了一定的提高,今天得到一些意见,果然易用性还是太差,嗯,写程序的人确实很难去理解最终用户的使用习惯,这是一大弊端啊,要改要改! 这样弄得心好烦啊!两年计划真的能好好实施下去吗?我不知道,我太懒了,所以我不敢拍胸脯。
今天专心把几个比较严重的问题整了一下。 首先是程序在退出的时候,全弹出出错消息框,我都不清楚这个问题是什么时候开始有的,无奈之下,把那些遗留在那里的,暂时没用上的,准备以后有机会用的代码绝大部分都删掉了,最后发现是由于文件系统实时监控引起的。 我估计是因为一个驱动器一个线程来监视,最后程序退出时没有让线程自己返回,而是强制结束,可能就会有问题。于是我就在OnClose时向每个驱动器都创建个临时文件,这样ReadDirectoryChangeW就会返回,线程就有机会主动退出了。试了一下,有时候还是不正常,通过打印消息看到并不是每个线程都能正常退出。后来通过在线程中打断点试了试,发现好像其它线程还挂在EnterCriticalSection上了,就是说还没主动退出就被强制结束了。于是我通过减少临界区的执行时间,暂时解决了这个问题。我猜,也许在OnClose中每创建个临时文件后加入一点延时,也可以达到目的吧,不过仅仅是猜测罢了,呵呵。 解决了这个崩溃的问题后,转向内存泄漏问题。本来一开始是只有一处36字节的泄漏,一直没找到原因。后来不知道加入了什么代码,有七八处不同大小的泄漏,这让人看了觉得很不爽。通过在程序开始处加入_CrtSetBreakAlloc语句,可以让程序在启动时如果分配了指定序号的内存块时自动断下。马上发现有一处是因为一个singleton没有在退出时主动delete,加上就行。后来,又发现其他几处是因为UDP服务器端的问题,该模块基于asio写成,调试器自动在io_service相关的代码处断下了,看了看代码,我估计是退出时服务器没有释放必要的资源引起的,确实,当时因为不熟悉asio,也不熟悉socket,所以都是胡乱拼凑的代码。再看了一下asio自带的那些例子代码,在退出时主动关闭socket,内存泄漏果然都消失了。 只是最后还是剩下那一直以来的36字节泄漏,调到晚上还是没找到原因。尝试用Windbg,还是没解决,不过我确实也不会用Windbg,郁闷!
今天看到什么代码圈复杂度度量的理论和工具等等内容,找个Source Monitor对我这两个月来写的一体化平台的代码嚼了一遍,发现我基本上写了约20000行代码,当然,包括注释和空行。无心算了一下,以一个月20天计算,两个月来我平均日产代码500行呀!有种说不出的感觉,没想到我写代码是这样的。光是看数量20000行似乎并不多,前不久数的时候才14000。但从日产量看,这个数字太高了,我自己对自己的要求是有200就不错了。然后从Source Monitor的分析数据看,有不少地方写的复杂度高了点,最高的是21,从公司的宣传ppt上看,大概4、5之类的比较合适吧。不过我顺便让它分析了一把Impeller的代码,那编辑器模块一初始化函数,复杂度是137,哇哈哈,真吓人,还有好些八九十的。不过这也不能说明多少其它的含义,最多只能说,也许我这点代码的可维护性比Impeller中的要好一点点。那也是归功于doxygen的推动和促进,如果不是因为一直想着要留一份可以生成良好文档的代码,我也不会写那么多注释了。当然另外一部分原因是,对Boost库的逐渐了解和熟悉,在Boost的帮助下,有不少代码可以简化。 明后天就要把这两个月来的东西拿出去见人了,希望一切顺利啊!
调了一会儿,用tcp连接还是有问题,无奈之下放弃了,想想用udp试试,只是发个消息而已,为什么会这么困难。没想到udp不但代码简单,而且效果上也达到我希望的要求了。我只能说,我真土,真的,到现在也没搞明白为什么用tcp的就不行呢,晕死了。 点对点通信基本稳定后,心里突然就轻松了很多,仔细想了想剩下的事,虽然还有不少,但是心中还是很高兴。
不过boost真的是个好东西,很多库很有用,呵呵。
自从写完那段代码,一直以来都有问题,服务器端读内容时,总是返回一个错误码,结果什么都读不到。都不知道是服务器端写得有问题,还是客户端的代码有问题,仔细看了看asio带的那些个例子的代码,尤其是里面的http服务端和客户端以及chat的服务端和客户端,下午在那里找原因,一会儿以为是服务端的问题,一会儿又以为是客户端的问题,结果到最后还是没找到具体原因,郁闷。 看来一个好用的调试工具是不可少了。但是用Wireshark抓包的结果看,客户端是确实把内容发送过来了,只是看netstat看连接状态立马变成CLOSE_WAIT,然后连接消失,现在我又怀疑是客户端的问题。
今天把Icon Overlay改了改,很奇怪的是,代码跟昨天的一样,今天把图标放到DLL的资源中,就可以显示了,晕。 上午改了Icon Overlay后,下午就集中精力搞P2P通信,还真是比较费时间哦,以前写的操作数据库的代码就有不少问题,另外就是,std::map在不同的线程中操作好像就算没有同步的问题也会直接崩溃,郁闷,于是换成std::vector,当然调试的时候也陷入到了一个陷阱中,明明是要主动发送个消息给对方,再等待对方的回应,可是调试的时候有一段时间不知道为什么对方会不停地发送回应回来,所以我都没给对方发消息,结果这边的状态就没准备好,晕。 因为要调试Socket,所以不得不用于抓包程序,装了个Ethereal 0.99版,里面带的是WinPCap 3.1版,装了后找不到网卡,于是没办法,换用Wireshark,里面用的是4.0版的WinPCap,很好,很强大,还支持表达式的filter。
把Icon Overlay的扩展做好了,这样Shell扩展组件基本上能满足需求了,虽然离我自己的要求还有点距离。奇怪的是,MSDN说,图标可以放在标准的EXE、DLL里,也可以是一个ICO文件,可是实际上我只能放在ICO文件里才会真正起作用,看看TortoiseCVS和TortoiseSVN也都是放在ICO里的,不过看Windows自己的就应该是放在DLL里的,看看共享文件夹的样子,再看看Shell32.dll里的图标资源,大概就是某些属性之类的还有点问题吧。 现在还剩下P2P通信、文件系统监视、流程图显示,这三块了。争取一周搞定一块,这样12月份就能完成了。
本来以为今天可以把所有的功能都串起来了,之前是一个一个零件,今天就到了把零件组装成完整产品的时候了,结果还是比自己预计的慢了点,最重要的点对点的文档下载部分没有调试。 我最担心的就是服务器的负荷能力,以及客户端间点对点通信的可靠性上。 唉,下周一上午好好把点对点间的调试一下,就可以完整地开始让人试用了。虽然还很不完整,但至少是可用了,花点时间可以稍微修改一下,把shell扩展部分做好了,就看起来易用性要好不少,至少是能在资源管理器中直接看到某个文件是否跟某个流程中的某个活动关联。 突然想起来,老大要求的图标也要有个overlay的扩展,这个一直没顾上做,晕!! 有一点很让我觉得自豪的是,在CruiseControl中配置好了,人家可以直接在上面点个按钮等个多少分钟,最后生成一个客户端的安装包,这太安逸了。 我要快点在家里把那个SocketHelper弄出来,至少功能部分要弄出来。昨天经过仔细排查,最后还是看了看附带的一个例子,一下就解决了,在MDI界面拆分窗口的Tab页中,如果是焦点落在CView,就会没有标题,花了两个晚上的时间去找办法,最后发现只是2行代码就能解决,晕死!
今天本来打算把几个功能串起来调试一番的,谁知道只是为了找出最开始的一个bug都花了近一天的时间,SQL Server的字段类型太多了,同样是为了存放一段文本,就有好几种看似都可以的选择,结果在用ADO操作的时候,死活就是抛异常。同样的代码,跑在Access上就好好的,到SQL Server下就不正常,真让我郁闷死了。花了好多好多的时候,排除了各种可能的因素,最后发现有两个字段只要select了就会异常。后来终于想到,会不会是字段类型的问题,尝试着改了几种不同的字段类型,终于有一种就顺利pass了,唉! 另外还遇到一个很恶心的问题,当时根本没想到。Excel在打开文件后,什么都不动直接关闭,文件也会被修改!这就让我的基于hash的机制几乎彻底瘫痪,郁闷。老大给我想了个办法,每次在程序中打开之前,先把文件设成只读的,关闭后再改回去。嗯,这样在我的程序里至少是暂时没什么问题了,不过我心里还是觉得很不爽,这个基于Excel的方案从一开始我就觉得很反感,可是时间不够啊,不然我肯定更乐意自己定一种格式,做一个编辑器。
今天上午,一个同事打电话,问些关于某个名义上由我维护的工具的事情。问题的缘由是,该工具现在使用的时候有些不正常,于是我就推脱说现在忙于另外一个项目。最后她就生气了,其实我心里也不爽。下午的时候去看了看现象,其实我觉得不一定是工具有问题,可能工具使用的机制就是有问题的,如果是机制有问题的话,就一时半会儿也不好解决了。这个工具说原理,其实并不复杂,无非是个函数hook,只不过同我们平常接触到的不一样,它是针对运行在单板上的软件的,单板运行VxWorks操作系统,使用PPC的CPU,用Tornado(其实是GCC 2.9x)编译,应用的典型场景是,在运行Windows系统的PC机上写好代码用Tornado编译一把,然后用这个工具把编译好的东东上载到单板上,并通过用户操作给指定的函数hook一下。有了hook,当然是有unhook操作,问题是有些情况下,unhook不成功!据了解,出问题的情况是分hook什么函数而定的,有的函数hook了就很容易直接宕掉,我粗略估计了一下,这些函数很可能是因为被调用得太过频繁,有些操作来不及做,就阻塞了,比如要把消息发回给PC上的显示终端,于是很可能就宕掉,但这也只是我的猜测。 另一方面,现在手头的这个项目,渐渐时间少起来了,我要争取本月底前拿出一个基本可用的但可以很不完善的原型出来,至少可以让那些头头们不要总在那里烦人。不过真的动手的时候才发现,其实有不少问题是很花时间的,当时的构思是不够仔细的,不够推敲的。 有点烦啊! afei打电话来说下周就要出去了,估计走之前也没时间再出来了。
早上起来玩电脑,卡巴杀出一个病毒,把shdocvw32.dll给删了,重启后就进不了explorer了,调出Firefox来上网查了一下,都说只要把shdocvw.dll复制一份就可以了,可是我这里就死活不行,还把注册表里的也都改过了。郁闷,只好备份了一下C盘的东西,然后索性恢复到出厂状态。这时间比重装一次还久,IBM做软件真不行啊!起来后,是个全英文的界面,中文的软件界面上显示的都是乱码,开始连资源管理器里显示文件名都是乱码呢!装了五笔加加Plus也是界面,还不能用,倒是sogou和极点是可以的。最后上网看了看,果然是只要装个中文补丁包就可以了,加上打安全补丁什么的,一天就过去了。其它那些软件都没装,本来还想写几行代码的呢,唉!
我迷惑了,到底是为实现需求不择手段好呢,还是中规中矩的好呢! 照我的想法,这个东东,应该如果按传统的做法,是自己做网络底层通讯,然后自己定义通讯协议,再实现各种交互功能。可是今天,老大在那里一讲,写个COM,做成COM+,再做个分布式的ATL Server,然后所有的交互可以直接像调用本地函数一样来实现,而对于传输文件,则在中央服务器中开一个可读写的共享文件夹做中转,这边写上去,那边读出来,虽然丑陋,但很简单。我迷惑了!照另一个同事的说法,这样下来,一个星期就能做完了。我不知道这个方案的可行性,分布式COM对大规模连接数量的响应不知道如何。
公司里那个东西是停滞不前了,我都无所事事了几天了。都不知道这样长长的一天都干什么去了,确实都发呆出神消磨完了吗,奇怪。另外一个东西,什么软件故障注入测试平台,简称SFIT,不过好像全称(Software Fault Insert Test)是写错了的,本来是由我们组的人给另外组的人做的一个小程序,能对VxWorks平台上的软件打函数级的补丁,现在那边又提出需求来,希望能把这东东做成一个通用的测试工具,还应可以应用在Linux和Windows平台上。这我就觉得有点难做了,因为PC平台上的开发平台太多了,特别是Windows上,同是以C/C++开发环境还说,最流行的就有MS、Borland的方案,还有次流行的MinGW、DigitalMars等等,除了C/C++,还有Delphi、VB、Java等,太多了,就算是同一种编译器,不同版本的差异都可能很大哦。 今天才意识到,我应该试图努力去找一种我自己感兴趣,别人也感兴趣的东西来做。想起公司里那个东东,要写客户端和服务器端,这样的网络通信程序,调试可能比较麻烦,尤其是当两个都还没有时,开始做其中一个,就交互协议方面的调试就有点困难了。 用Codejock的解决方案,做起界面来也不含糊哈!
这两天总是被老大训,真郁闷。昨天就又挨批了,当然老大有老大的理由,静下来想想也是想得通的。后来晚上跟小妞小思宇一起去百草园后面的甲秀楼吃饭去了,贵州风味的酸汤,不过我好像并不是很喜欢吃哦! 今天就照老大的意思,拆分成n个模块,每个模块提供什么接口,各个模块之间是如何交互的都写成文档。我的服务器端相比客户端非常简单,只是接收客户端的消息,操作一下数据库,再把结果返回给客户端。而客户端则相对要复杂不少,首先是要有比较易用的界面,其次它又当服务器端又当客户端,而且它还要负责向shell扩展等外部程序提供服务。服务器端的部分基本写完了,还剩下客户端的慢慢写了,反正老大要求是下周三拿出来看,哼哼!
真是让我觉得很郁闷,领导的想法真是千奇百怪啊。现在想想可能就是画图部分有困难,其它的应该没多少障碍吧。也就是计算一下文件的hash,操作一下数据库,用网络传输一下数据,以及从excel里读些数据画个图出来。 《程序员密码学》中说MD5已经是不安全了,确实,几年前山东大学的女教授王小云就发表论文破解了MD5和SHA-1了,Gentoo是用3种不同的算法来唯一确认一个文件的,所以我应该看一下Crypto++或LibTomCrypt,自己写一下几种SHA也不是不可以。
今天总算写了一点代码,画图部分,不过效果果然如预期的那样不好,是一定要换用双缓冲才行的啊,不然那么多个对象在那里重绘,闪烁是让人不能容忍的。不过放假前还有3天呢,应该能完成的吧,我没做过复杂的程序,所以没做过设计,也不会在写代码前就做设计,现在突然要写点复杂的了,就觉得很多地方是原来就想不到的,就被遗漏了。 可以用Boost真是爽啊,虽然网上也不乏有人在那里批判Boost哪里设计得不好哪里太花哨哪里不实用,但对于我等来说,Boost真的是有点神化的东西。 疯丫头不知道是不是真在那里那么忙哦,昨天发的邮件,今天才回,总算看到了,估计把她急坏了,哈哈,我就是要这样逗她玩,现在要抓住所有我能发现的机会来这样逗她,嘿嘿。 晚上吃完晚饭,出去压了一会儿公司的路,回到办公位的时候已经7点40多分了,就被同事们笑了。呵呵,最搞笑的是,有一个同事连续两天晚上看到我跟mm在外面走,真是有缘呀,哈哈。 把Impeller的代码下下来,但是编译就不过,本来是用CruiseControl来弄的,连哪里出错了都看不到,而我的机器又不能用VC来打开这个解决方案,只好换用那老爷机2003来打开,发现还是编译不过,不过总算大概知道哪里出错了。我想的是要自己整个私有版本,可以像SourceInsight那样以工程方式管理和浏览代码,初步只要能简单地支持C/C++即可。这是基于ctags来完成的,现在想来,要把ctags部分封装一下,改成一个dll,生成的tag信息经过简单的处理要写入sqlite数据库中,以后可以随时更新查询。既然是私有版本,就应该能把没用的东西都除掉,比如那些跟支撑的绑定等等,增加了体积不说,不稳定性肯定也是随之增加,还拖慢了速度。
那就是谋杀, 时间就是这样流逝的, 我被人慢慢地谋杀, 我慢慢地迷失在无尽的虚无缥缈的沉闷和忧郁中。
丢失的自我何时才能找回, 消逝的罗盘不知现在何处。
半夜,肚子真他妈的饿啊!~
MoveFileEx似乎要在同一个分区里才能移动当前运行的Exe或Dll文件,于是我只好在本地目录再新建一个子目录。还有个问题,用NULL参数登记系统重启后删除,不知道为什么不起作用,该不会是只有在临时目录下的才能自动删掉。 再抱怨一下asio,吞吐率并不高啊,不知道是不是哪里用得不对,而且太占CPU了,很介意这个事啊,要是到时候同时有几个人从这里请求文件传输,岂不是卡死了,郁闷,这是无论如何都不能接受的。 还有个界面刷新的问题,在回调函数时加入Invailidate(FALSE),就能看到进度条在那里动了,当然还要在下面加一句PumpMessage,不过还有一点点问题,如果界面被遮盖住过,再切回来是没有显示的,只有鼠标再点一下界面,才会恢复显示。 今天又被叫去讨论了一下,真是烦死人了。还要用Excel来画流程图,画完了还要用程序来解析图的前后继承关系,烦啊!
今天接着做升级程序,本来以为大部分的技术问题都已经解决了,实际上,还是很花了不少工夫,有些问题想都想不到。 通过http下载昨天就差不多搞定了,今天发现,用asio来下载,很占CPU啊,全都占满了。以至于,好不容易通过boost::function把进度回调加进去后,界面不能得到及时的刷新。 还有,因为我想看起来更人性化一点,就希望是一个文件一个文件地下载,然后替换更新,也就是如果是exe或dll文件,在运行时,也是需要能不动声色地把它替换掉的。依靠以前的一点点模糊残缺的记忆,MoveFileEx可以达到目的,它可以把运行中的文件移动到其它地方,还可以登记让文件在下次系统启动时被删掉。不过中间遇到一点问题,怎么也移动不了一些文件,后来发现只要该文件长度为0,就不能移动,真是奇怪。不过还好,这个情况在实际应用中几乎不会出现。 现在,几乎所有的技术难点都差不多搞定了,只是要实现好,还是要花些时间,精雕细琢嘛。看来这周能把这个升级程序整完就不错了。
今天上午,经过仔细的检查,终于能在右键菜单上显示并正常工作了。有几个关键点,首先,注册表中的项要正确,其次,类厂的QueryInterface要完整,再次,实现类的QueryInterface要完整。这样就基本上应该能正常工作了,我开始总是弄不出来,一是类厂的实现可能有问题,二是实现类就有问题。另外想抱怨一下,ATL来写IShellExtInit接口映射怎么老是编译都不能过。还好,我不是很排斥用API写东西,今天还被老大说了,说我什么东西都喜欢从头从底层重新搞起,应该充分利用现有的资源。我说主要是我特别讨厌COM这套东西,他问我为什么,我说我觉得COM调试起来特别麻烦。 下午整了一下自动升级程序,因为星期天听帽子说,腾迅提倡XP,没有文档,所有的东西都放在服务器上,发现问题可以随时修改升级,我觉得挺好的,于是我要让我这个小东东也可以随时自动升级。想了几个简单的方案,最后决定用http来发布更新。开始研究了一下MFC的WinINet类,MSDN里说得太简单了,不会用。最后只好改一下asio的那个例子程序,勉强能用了,呵呵,不过还有不少要做的,比如我想要有进度报告。 这样说来,白天还是有些收获的。不过晚上就比较郁闷了,本来情绪就有点低落,就想利用一下晚上的垃圾时间,写一下老大要的那个宣传胶片吧。结果,首先是机器有问题,PowerPoint不能即时保存,然后然后然后,居然突然停电了,好像有两页内容没保存!无奈啊!无聊啊!无助啊!
再次说回来公司那个东东的自动完成功能。 本来只有简单的关键字提示功能,因为关键字不多,而且要提示的都只有长度超过3个字符的,所以很简单,把关键字排好序,放在配置文件中,每到3个字符时,show一下那个字符串就行了。后来提出了更多的要求,要能尽量联想一下类名啊、方法名啊、变量名啊等等,于是动用了数据库,把所有的库中的类名、相关的方法名等信息都存放到一个数据库中,必要时从数据库中检索出相应的内容,再组合成一个字符串,show出来。 Ruby语言有点奇怪,不知道是不是大部分现在流行的脚本语言都有类似的情况,因为一直以来我都只接触过C/C++,像Delphi这些语言也是静态编译的,所以几乎都是强类型的。但Ruby不同,它的变量的类型是随时可以变的,不过这个问题对于实现解决自动完成功能时并不是特有的困难,而是所有的语言都可能会有的。要扫描所有的代码,然后确定某个符号是什么类型的。 当前项目中使用的方法,现在想起来,当时做的时候几乎没做什么设计,直接想到一个解决办法就拿上去用了。每次打开一个文件的时候,就扫描一遍文件,把几种特定形式的语句用正则表达式匹配一把,然后记录到一个map中,key是变量名,value是类型名,到时候就查找这个map。这个方案有一个很严重的问题,就是打开大文件时,会有很恶劣的性能问题,可能过了几十秒钟,那个文件还没有show出来,而是正则表达式一直在那里匹配计算,而且正则表达式有好几个,需要匹配好几次,每次都可能花费大量的时间。另外还有一个问题,就是不能很好地反映代码更新的情况,比如一开始打开时已经定义了一个变量,后来在编辑时,修改了变量所属的类型,而我现在只有在回车换行时,才扫描一遍当前行的内容,是定义了新的变量等等,如果用户只是改完内容后直接用方向键移动了,或是用鼠标直接跳离了当前行,就不能得知修改的内容了。 因为没有这方面的经验,也没有看到其它多少可以参考的项目或资料。依稀觉得Source Insight的解决方案比较适合应用到我们这个项目中。Source Insight具体工程的概念来管理所有的源代码文件,新建一个工程后,把所有的源代码文件都添加进来,然后可以由用户手动触发扫描所有文件,建立一个符号表数据库,或者是程序自动在后台,慢慢建立一个数据库,但不会影响前台功能的使用。再一想,我现在用的正则表达式匹配的方案实现很落后低效,再怎么样,也可以依赖于像ctags这样的工具建立索引。我其实并没有仔细地研究过Source Insight的建立索引的机制,只知道它的速度确实很快,而且准确性也基本能符合用户的要求。 另外,我现在几乎不能再大动干戈地改动那一块的设计了,所以表现上不会有质的飞跃了,真是略微有点点遗憾啊。这些想法就只能放在自己现在搞的这块来实现了,要做一个类似Source Insight的通用代码浏览、编辑工具,编辑功能应该是强于Source Insight的。然后针对几种语言做IDE,除了要能浏览、编辑代码,还得跟编译器(或解释器)有良好的交互功能。初步计划是针对D、Lua、TCL、Python、Ruby、Perl、PHP这几种,因为这个市场还没有被什么寡头垄断,还有机会插一脚,哈哈。
晚上又跟小思宇去吃肥牛府了,两个人点了好多,最后浪费了好些菜,肉硬是全让我消灭了。然后两个人慢慢走回百草园,我再走到百草园门口坐车回家。 无聊的时候,就静静地躺在床上,发一会儿呆,把所有的不快都抛得远远的。 今天在公司里也无聊了一天哦,我觉得领导们是存心不想让我按时完成那个项目了,需求不停地讨论、确认、修改,不就那么小小一个文件共享软件吗,如果不是因为想用类似Google桌面搜索那样的界面,我可能两个星期就能做完了。 无聊的时候,就偷偷幻想一下美好的未来吧,有的人有的事,真的不用太在意,有时候我觉得我太有责任心了,都让自己变得很下贱了。
今天上午调了一上午,总是有个异常,说没有可用的终结点了云云,最后无奈把UDP换成TCP的,还是有,但用netstat命令看,确实已经打开了端口在监听了,只是不知道怎么把它绑定到特定的IP上去,用它默认的是全0的地址,不知道其它机器能连上来不,唉。 真怕到时候完成不了啊,还真的有点烦呢。需要asio带了不少的例子,但我对它的使用方法还是不清楚,到底各个类都是什么作用,相互之间有什么影响,是怎么联动的。 另外想想,既然都已经决定用Boost了,就索性用彻底点,有Boost能提供什么样的能力,就尽量用Boost的封装来进行,比如下午看到Boost::Thread,似乎还是很简单易用的。
今天去讨论了一下,居然提出可能要做个流程文件编辑器,彻底晕倒!其实这一点我应该早就预见到的,而今天他们说用Excel来让用户自己编辑,你说如果只是一两个人来编辑一下倒也就忍了算了,我自己也可能会省事儿点,但是现在要求是可能每个人都会改一下,让每个人来改那Excel里面,自己对应前趋后向的关系,还要不出错,不是逼他们发疯吗!唉,估计我这套东东弄出来后,没几个人愿意用,太无聊了!不如我赶紧在里面加入些新奇有趣的特性进去,不过有人敢玩吗,呵呵。 晚上回来上网,看了看Linus那段对C++的放炮闹得好惨烈。呵呵,如果不考虑库的因素,我个人也是更习惯用C的,现在这个项目一边用MFC做框架和界面,另一边用Boost做业务逻辑,两种截然不同的风格,不知道以后我这代码的维护者看到后会是什么样的心情,嘿嘿。
今天老大来跟我讨论那东东的设计方案,居然说要用PHP/ASP之类的东西做个网站,把我郁闷了一把,不过好在我最后发现用这样的设计是无法比较方便地实现P2P文件传输的,最后老大只好同意照我的想法来实现了,真是有点庆幸,不然我就要郁闷了!不知道为什么他那么喜欢Web的东西,而不知道为什么我那么不喜欢Web的东西!而且那帮人真的是COM/DCOM技术的狂热爱好者,只要搭得上边的都想用这个来做,真是晕倒,而恰恰我是一点都不感冒,如果有可替代的其它技术,我就宁可不用的。有些地方不用COM实在没有其它方便的方法了,也就没办法了,比如Shell扩展之类的。 除了把设计方案讨论了一下,今天都没怎么做,还在担心那个流程图怎么画,昨天后来想了想,光是Graphviz还是不够的,Graphviz只是根据依赖关系自动给出图形,但具体的节点处于什么位置,却好像没有提到。 另外,又学到一个东西,在HTML页面中表单内容通过URL传递时,像中文之类的非标准ASCII字符,会先经过编码,以ASCII可见的方式传递,开始我看asio那个例子里面的代码,只是简单的转换,后来我把Google桌面搜索的页面改了一下,发现就变了,最后发现人家是用UTF-8编码来转换的,经过反复的试验,最后得出结论,IE打开的HTML页面如果是UTF-8保存的,就会把表单传递的内容也以UTF-8格式转换,如果以ANSI格式保存的,则也以ANSI格式转换。如果要从UTF-8转到ANSI,可以用Win32 API MultiByteToWideChar先把UTF-8转成UNICODE的,再用WideCharToMultiByte转换回ANSI就可以了。
我等不下去了,今天先自己写了点代码,把asio那个http server的代码copy过来用了用,效果很不错啊,哈哈,仰天狂笑三声先! 现在是很确信这个东东的最大难点是流程图的自动构成,再生成带有热点链接的html页面。跟老大稍微讨论了一下,他提到我们可以让用户自己填一个规定格式的表格,我们再从表格中生成流程图。这确实也是一种解决问题的思路,而且让我突然感觉眼前一亮,似乎这个问题也不再是不能解决的了。老大提到可以用VML这样的东东,我没听说过,不过却知道有Graphviz这个东东,似乎可以解决我这个问题。 看起来业务逻辑相对是一个很简单的任务了,但如果确定要用Graphviz的话,还得学习一下它的dot语言,虽然我可能最后只用到它很小一个功能子集。时间只有3个月,11月底就要有可用的版本来试点,可能会有点紧哦。抓紧时间,争取快点把那些不是很困难的部分早点完成,然后来攻关这个流程图生成、html页面生成问题。 晚上afei打电话来慰问了一下,应该是xcc跟她说了我的事。然后谈了一会儿关于工作的事情,心里又舒畅了不少,等这个项目完成了,如果没有什么大意外的话,我一定要走了。
真是不爽,还在郁闷,快半个月了,总是提不起精神来。晚上在食堂拿了一盘面,最后剩下快有2/3吧,连食欲都没了。真是没用啊,就这样被打败了。 下午又去讨论了一下需求,然后想到下周开始就要投入到这个里面去了,还可能有不少困难呢!现在粗略地想想,大概的难点在于,灵活的界面,极强弹性的可扩展性,以及从实现角度讲,现在还不确定自己建一个本地的http服务器有多少困难,如果想加入自己的扩展,又有多少困难。 白天给工具加了保存成HTML、PDF和RTF格式的功能,不过有bug,PDF对中文直接就乱码,RTF遇到中文,用写字板打开还能正常显示,如果用Word打开,也是乱码,晕!
这周又过了大半了,真快啊!明后两天要加油把帮助文档解决掉,真是个麻烦事,我总觉得一个编辑器没啥好说的。不过很让我高兴的是,功能上基本把最紧要的部分都完成了,今天又加了几个特性,换行符转换、括号配对高亮等。不过今天去找人玩的时候,突然发现有一个很重要的方面居然一直被忽略掉了,那就是对代码审查(或用例评审)过程的支持。如果能做成像Source Insight那样强大的引用、跳转,就太完美了,不过我不打算继续下去了。那个脚本适配层还需要进行一些改进,原来想得太简单,而且被人看到了那个Panel。要给它们添加自定义快捷键的功能,这样就需要一个额外的文件来保存对应的快捷键信息。另外还有一个可能是,应他们的要求会需要能让外部执行器来运行脚本。
从网上down了几十个文本处理的程序下来,我的主要目的是研究一下目前Windows平台下好用的编辑程序,从中汲取一点有用的想法。其实看了看,发现超过一半的编辑器质量很一般,有的简直可以用粗制滥造来形容,只有不到一半的比较成熟。这里先排除像Word这种富文本编辑器,因为我只是为了Impeller来寻找竞争对手和学习对象,所以是纯文本编辑器才列入其中。 Emacs和VIM暂时也不说,感觉这两个从*nix发源起家的,风格完全与Windows平台下的不同,可比性并不大,当然这两个的极强的可扩展性是很值得学习的,VIM了解得更少,Emacs的之前用过一段时间,确实可以说是功能多得变态,这一方面得益于它的灵活的扩展性外,另一方面当然是几十年发展积累下来的众多fans开发的插件,看似很朴素的界面下,甚至可以玩俄罗斯方块。 之后剩下可以参考的,其实就是目前最流行的几款了,如UltraEdit、EmEdit、EditPlus、PSPad、Notepad2、Notepad++之类通用文本编辑器,Code::Blocks、Visual SlickEdit、Source Insight之类具有工程概念支持的代码编辑器。一般说来现在优秀的通用文本编辑器都会支持编程语言的语法高亮,有的还有代码折叠,集成一定程度的文件管理功能,支持外部脚本扩展、宏功能,其它的主要是一些锦上添花的辅助功能,比如支持外部程序调用,各种插入功能等等,看来看去,我觉得Impeller的编辑器功能上除了不支持列模式外,其它的基本上都有了,甚至有的方面还可能略强于那些编辑器。但与那些代码编辑器来比的话,还欠缺一些很重要的元素,比如定位为一款IDE来说,重构是现代IDE必要的功能,以及Source Insight具有的引用、跳转功能也是强得很有特色,作为一款代码浏览器是很需要这样方便的代码导航能力的。 在这个8月里,我大概只能做到完成外部工具调用以及留下外部脚本扩展接口为止了。其它的想法,留给自己的CodingTool来实现吧!
经过今天近一天的奋战,参数列表的提示功能基本也完成了,顺便发现了一个较新版Scintilla中存在的一个bug,自己动手改了重编译dll,解决。 不过今天为了完成这个特性,还是费了点精神的,字符串指针乱飞,真是头也昏了。有时候我就会想,其它语言没有指针,都是怎么操作字符串的哦,哈哈,越来越井底了。 在完成这个特性时,又顺便发现,可能可以通过从数据库中记录下相关的方法返回值类型,更加智能地进行自动补全。 下周重点是先把胶片和帮助写完,然后把其它模块要求提供的支持做好。
可以动态地提示关键字、已定义变量、类名、类方法的自动完成了。其中,用Greta写了个变量声明的扫描器,其实是全文匹配一把,速度挺慢的,于是只好做成多线程的,现在的处理是有隐患的,以要改。另外顺便让我确认用CppSQLite这个封装类在MFC程序来操作SQLite 3.4.x版本也是基本没有问题的,有了封装类,编码真的变得很简单很容易,完了,我已经没能力自己写代码了,全是拿别人写好的代码来拼凑一下。这样一个工具,大概拿出去卖,也是能卖的吧,呵呵。 剩下就是要做函数参数列表的动态提示了。 做完这两个特性后,就去做外部工具和脚本适配层,然后改一些问题,完善一下GT3000的封装,写一下帮助和宣传胶片,这个8月就这样过完了。 不过在业余时间,还得研究一下asio以及它自带的httpd的例子,写一下设计需求一直到概要设计为止。
编辑器重构昨天就基本已经完成,今天好像没做什么事,就是讨论了一天各种事务。其实对于编辑器,我还是有很多想法的,看到SciTE和notepad++的表现,还有UltraEdit,就想把它们有的,都做进来,前两者就是Scintilla控件的最好功能展现。尤其是下午看了一下8月份的《程序员》杂志,刚好有个专题介绍现在流行的几个RoR用IDE,心更痒了,想把所有好的东西全加上去。至少,能用脚本进行扩展是我特别想要的,我甚至想做个DLL做个适配层,工具可以动态地加载该DLL,该DLL可以接受各种外挂的脚本解释器,这样没有这个DLL工具还是能正常工作,除了脚本扩展。另外一个想法是,好像Greta这个库有点点问题,也不知道是不是代码写得有问题,所以我又想,能不能做个正则表达式库的适配层,这样也可以挂接不同的正则表达式库了,比如除了Grata外还有用于C/C++系的boost::regex、ATL::Regex、PCRE等等,这样就像UltraEdit一样了,用户可以选择自己习惯的那种。 现在最大的问题是,语法解析,我要做一个动态提示功能,这需要随时知道一个变量的类型,而这对于Ruby这么动态的语言来说,真是太难了。SUN为Netbeans专门开了个代号为Schliemann的Generic Language Support Framework项目,它可以动态地通过由用户自行添加正则表达式和语法规则(现在流行用巴科斯范式吗?不清楚),来动态地增加对新语言的词法解析和语法解析,这比Scintilla现在的做法要更灵活,不需要编译器,有个文本编辑器写规则就行了。我当然做不了这么好,所以现在只能依赖SciLexer.dll或者另寻出路,看了一下ctags,好像对Ruby的支持不如对C/C++的好,它解析不出变量的最初定义的地方,难道自己写一个简单的够用的,因为目前面向的用户应该绝大多数情况下只会用到Ruby语言中很小一个子集的特性。 早上去讨论了一下另一个任务的需求,果然我最开始的想法是正确的,看来老大的理解能力或者是个人喜好影响了他的判断力啊!今天讨论了一下,老大出来就有点惊奇地说,看来要做一个像电驴一样的东西了。呵呵,其实我当初最早看到这个很原始,未经过整理的需求时,就已经断定会是这样的结果,只是当时老大一心想用Sharepoint,我也不好多说,还似模似样地给他用SharePoint Service3.0建了站来看看,当时转项目部1个月,全在看这个资料了,呼呼,浪费好多时间。 现在就要来网络通信了,一个支持P2P的东东,可以做的事情真是太多了,呵呵。一个集中式服务器只提供索引及账号管理功能,其它的都在客户端完成。我有点想试一下Google桌面搜索的那种界面,在本地建一个http服务器,然后用IE跟用户交互。不过生成HTML页面有没有现成的办法呢,还有HTML的表现力是强,但如果要让用户输入很多零散的信息,这样也很难处理哦。至于http服务器,记得boost的开发邮件列表里有提到过一个基于asio的项目,一时找不到URL了,可能可以用一下。先分解一下设计需求吧,反正有一个季度时间来做,这个东西有点感兴趣哦!
一直以来都存在着这个问题,当时大概看了一下Scintilla的源代码,也没有找到哪里注册处理了这些快捷键,想不到好的办法,于是就临时处理了一下,自己截获这些快捷键,发现一个截获一个,本来以为可能截获得差不多了,结果前些天发现还有没有拦截的,于是觉得有点郁闷,决定要彻底解决这个问题。 又稍微仔细地搜索了一遍Scintilla的源代码,发现确实好像没有注册这些快捷键,然后到maillist上问,作者Neil Hodgson也真的挺热心的,每封邮件都回了,由于时差的关系,加上我白天在公司不能上网,这些天我都是晚上回家写邮件,描述问题,第二天早上起来收邮件,看看他的答复。这样持续了几天,终于今天早上看到回复后,搞清楚了问题的本质。 我照他的办法在ScintillaWin.cxx的WM_SYSKEYDOWN/WM_KEYDOWN里打了断点,然后跟踪,发现这时按到那几个快捷键都是直接传给::DefWindowProc处理了。这开始让我觉得有点走不下去的感觉,后来往上看,有WM_CHAR消息的处理,于是也打了个断点,发现每次按了快捷键后,就会收到WM_CHAR消息,而且参数就是这些不可见字符的ASCII码值。Neil说这是Windows发的。我用SDK写了个小程序试了试,果然发现这是Windows的默认行为。Neil说这只能自己在程序里处理把所有这些快捷键都屏蔽了。于是我就又郁闷了,我怎么知道到底是有多少控制字符被绑定到什么键上去了。上Google搜索了一把,发现一个列表,呵呵,刚好列出了所有的VT100和VT220键盘的控制字符绑定。 中午的时候想了想,我不想在程序里处理拦截所有快捷键,不如直接改Scintilla的源代码,在WM_SYSKEYDOWN/WM_KEYDOWN里记录一下是否按下了Ctrl,在WM_CHAR里判断一下这个标记,如果标记置位了,并且刚好这次得到的是个控制字符,就直接退出,这样就看起来解决了,至少Windows平台上似乎没什么问题了(注:Scintilla是直接多平台的,包括Windows、MacOS、以及通过Gtk+支持的平台等)。 Neil Hodgson是个很有毅力的人啊,这东东从1998年做到现在,越来越完善,而主要作者却一直是他一个人,当然也还是有很多人为之作出了贡献。
但今天却心情却不知所以地有点好。虽然问题数没怎么减少,但自我感觉是越来越好了,总觉得随着不断地改进,这个小工具已经比较好用了,我还额外地做了些增强易用性方面的工作。但有些东西,从架构开始,到最后的可利用资源,都限制得很难再继续发展下去了。代码重构是很急需的一件事了。 今天和晓妮mm一起坐班车,晓妮mm说又和我坐同一辆班车了,呵呵。刚来公司的那一年,我住三楼,她住六楼,虽说是同一栋楼,但正如她说的,当时我们最不熟,其实当时我跟测试组的同事都不熟,我很少跟同事说话,在食堂吃饭也是一个人很快地吃完就走。晚饭的时候经常是坐一在边等小妞过来,或者就出去4个人一起吃。搬了个家后,一切都变了。人是会变的,这是一件值得庆幸的事。昨天室友说起一件事,我说,我都已经原谅我自己了,原来我是很自责,我是很深刻地认为我错了,我也希望能弥补,但既然过了这么久了,还是没有丝毫的希望,我也放弃了。我无力改变别人,就改变自己,我不想继续活在内疚和悔恨中,我已经原谅我自己了。就算是真的触犯了原则性的问题,但人是活的。换了一种生活方式,我没有觉得丁点不好,感觉反而是一种解脱。至少对于我来说,是利大于弊吧。
坐旁边的女同事昨天填完离职申请后,今天就没再来了。又见一个旁边的人离职,不过已经有点麻木,没什么感觉,只知道有一天我也是走这条路的。 今天把输入法的源代码和打包好的安装程序都发到五笔爱好者论坛去了,本来还多大的目标的,没动力了。
好累,好想休息哦! 晚上又加班了,改了一点问题,静不下心来了,于是收拾一下,就走了,去找人玩去。 实在无聊啊,怎么会这样。真想请几个星期假休息一下啊! 一堆事情积在那儿,可是我又懒。 问题又涨到20多个了,真是郁闷,怎么这么多问题。从SciTE里抄了一段打印的代码,居然能用,哈哈。 很多地方的代码写得很低效,有很大的改进的余地。还有很多会崩溃的问题,要解决。
终过连续几周的奋战,到今天下班前,基本把编辑模块相关的问题解决完了,新的需求能加的也都加上了,不过真的从开始设计就遗留下来的通用性问题,实在是一个很烦人的事情,从程序结构上就限制了它的灵活性和可扩展性。今天还是很高兴的,因为把注释块折叠的问题搞得差不多了,昨天的解决方案今天被彻底废弃,因为它会引起一些很奇怪的问题而不容易解决。今天从Scintilla内部着手,修改了一小点代码适应自己的需求。下周就要开始把GT3000升级了,把相关的部分也跟着修改一下。那个模块经过几次几乎是推翻重来的过程,真是气死我了,一方面也确实是自己当时没有考虑到后续的维护和扩展,另一方面不停地修改原有的需求,导致我刚刚开发完一部分特性就被告知需求的变更,就需要重新来过。这回我索性就把这模块的问题先挂在那里,先从相对稳定的不容易频繁变更的做起。
老大又提出一个怪想法:为了测试,让原本不支持COM的程序支持COM。在我看来,这是一种非常古怪的想法。而且他一来就说要注入,而我一开始并没有觉得注入能带来多少好处,或者说对于我们现有水平,现在掌握的技术程序来说,注入可能没有多少优势提升。后来经过稍微的讨论,我也认识到,注入可以让有些事情变得更简单一点,比如可以把窗口的消息处理过程都替换掉。但老大只是为了自动化测试,有了COM后通过脚本语言就可以直接调用相关的功能,而这个COM组件其实是个中间代理的角色,它接收脚本的测试操作请求,然后对实际的程序做相应的处理,处理后的结果再由它返回给脚本。而现在的问题是,它怎么对实际的程序做相应的处理,比如点击某个菜单项,比如点击某个工具栏按钮,这个如果是用标准Windows控件的话,或许还好办一点,但也就没有注入的必要了,可如果用的是其它非标准的组件的话,即使注入了,能做更多事情了,也还是很难达到灵活控制外部程序的目的啊!
随便翻了下阿菲和小思宇的blog看看,想起自己的blog,都已经被工作和程序吞噬了,几乎没有生活了。不知道这是好事还是坏事。 打到我那里的问题堆积得高居榜首,结果被人说了,说这周晚上应该要加点班,于是今晚就很听话地在那里加班,改问题、写文档。难得又加班一回,就给小丫头发邮件,结果好像还被鄙视了,呼呼。 又多了个任务,不过估计那个任务不会花多少时间的,呵呵。 很矛盾啊,又想赚钱又想玩啊!
今天搞了一天,也没把配置的内容整好,不熟悉是一方面,另一方面是内容太多,很多是体力活。未解决的问题数于是又增长上去了。 快下班的时候,老大又把我叫去跟另一个老大讨论那个需求去了,结果还是要在本地加个小程序,呼呼,这个自由度大了好多,而且可以做得再花哨一点,可以像Google桌面搜索一样,加个Band在右下角,用IE来做界面。还说要有可扩展性,这样如果设计得好,还可以做成一个远程控制客户端,既然都这样了,就像一个木马了,亦或是可以即时通讯,哈哈,这个真是太危险了。不过老大还是有点舍不得SharePoint啊,本来SharePoint对于现在这个项目来说,有一项非常强的优势,是内容管理,还可以全文搜索,如果不需要全文搜索,随便一个C/S的东西就行了,要是需要对.doc、.xls、.ppt等文件进行管理,SharePoint是很强悍的。 昨天上网搜了一些中文分词的资料下来,突然觉得要是通过很好的中文分词,或许拼音输入法就能做得比较好用呢,说不定能提高整句输入的精确度呢。
自从老大一声令下要仔细认真测试,短短两三天时间内,挂到我下面的问题就有近70个,这两天奋力迎战,到今天下班前,还剩下30多个未解决的,其实是暂时不容易解决的。 昨天下午,疯丫头还发邮件问我去不去拿MP3,结果这邮件我都是到下班的时候才看到。大概今天她自己都觉得我可怜了,自己送过来了,哈哈。
项目组组织活动,去惠州。主要是两个项目,先去响水漂流,这个漂流大概2个半小时,因为经验不足,硬是把包带在身上,还放手机在里面,于是,这个跟随我将近4年的Nokia 8310终于由于进水,光荣殉职了!另外一个经验不足的后果是,两条腿都晒伤了,膝盖旁边火辣辣的,没做防晒措施啊,这时我就想,要是有个mm在身边,应该不会有这样的情况出现了吧,呜呜! 漂流完后,去荔枝园自摘荔枝吃。这一吃,让我吃腻了。那里主要有无核红和桂味两种。无核红相对皮较厚,经常形状有点扁,而且味道有点酸腥,但颗粒大。桂味就皮薄,但扎手,颗粒一般小一点,如果是两个并排长在一起,经常是核也很小的,相对来讲,桂味的味道明显要好得多。想找糯火糍,但没找到,呵呵,只吃过干的。很亏啊,以后一定强烈建议别人不要去自摘荔枝吃,因为吃不多!我都没吃多少,就吃得什么都不想吃了,呼呼!
被一个老大叫去讨论什么东西,唉,反正很头大,夹死人的事。结果到后来我也没力气说了,他也小声说了,再后来我走到自己的位子上,发现怎么天都黑了,我都还没反应过来,看看周围也很安静的样子,也还是没反应过来。同事们见到我很奇怪,还以为今天有什么事,我才反应过来,已经7点多了,我还没吃饭。 今天就觉得很丧气,觉得自己挺可怜的。然后想着随便找个人一起过,就这样庸庸碌碌过一辈子算了。
今天我们谈起怎么调错跟踪,说到用日志,老大说不行,不能在程序里做这样的事,要调错就在这里把所有的bug都清掉。我觉得很不可理喻啊!另外两个同事也觉得有点郁闷。想想大型的软件系统哪个没有日志记录啊,而且说起影响性能,其实这个开销是微乎其微的,看看我们公司产品,里面不也加了黑匣子吗!再说了,怎么可能把所有的bug都清掉,这是违反自然规律的。倒是把日志系统做强大了才是应该真的好好考虑的一件事。后来那两个同事偷偷说,不管他了,我们就那么用,反正他也不知道,晕!老大的有些想法比较怪啊,他还不让用Boost,如果能允许用Boost的话,有些事情可以变得简单一些呢! 功能基本上是都实现了,至少代码是写了,很多整理工作要做。
今天好像把那个东西做完了,只剩下一些细节优化和问题修改了,大事化小,小事化了真是一种行之有效的方法,想当时一头雾水,毫无思路,现在几乎是做完了,想起来觉得有点不敢相信啊!不过VSS操作的那些标志位,看得我想吐啊,有些就是不知道它在讲什么,呵呵。但是估计那些零碎的活也是很花时间的,想想那个GT3000的部分,到现在也没做到尽善尽美啊。版本最终发布时间是6月底,我的进度很宽裕啊,哈哈,想起来就觉得开心。如果时间多,可以做些自己感兴趣的事啊,真期待啊!
晚上坐公车回家,又遇上堵车,气死人了! 今天把昨天弄的SPS页面给老大看了一下,老大是高兴得眉开眼笑啊,真是让人觉得很不是滋味。似乎现在我只要做这个东西就行了,不过另一边的东西我还是没放下过啊,说是15号前要做出来。我想15号肯定功能是可以做出来的,大不了bug多点罢了。而且今天又把其中一些特性思路整理了一下,豁然开朗啊,原来我要做的事情真的很少很少啊。估计老大很是担心我的能力,所以尽量分少点,或者分些他认为不是很难的任务给我做,哈哈,并且他给的期限不是15号哦,而是6月底,哈哈。不过再回头一想,我总算是没在5月底前完成自己定下的目标。
下午去了一下公司,把SharePoint Service 3.0装在了服务器上,机器配置好就是爽啊,关键就是内存大,2GB啊,我都从来没用过这么大内存的机器呢,之前那段时间在一个128MB的破机器上装SPS,还装MSSQL Server 2005,真是可怜那台老爷机器了,也居然能装上,只不过就算只是试图通过IE打开首页,那台机器的硬盘就要狂转几分钟,然后很艰难地显示出来,呵呵。现在这个就基本上不会有这样的现象了,大部分情况下,用内存就够了,哈哈,开心。不过有点问题的是,默认用80端口的话,是一切正常的,但如果改到其它端口的话,它就不能自动找到default.aspx页面来显示了,不知道怎么改得好。 回来后,心情就感觉舒坦很多啊。回来上网也是一身轻松啊,哈哈,在网上乱逛,发现一个blog写了好多Boost应用相关的内容啊,虽然大多是些介绍,但涉及的面真是广啊,好多库都讲到了,也算是小牛一个了,哈哈,我一直不也是希望自己能那样吗,至少是要了解每个库能做些什么事情的。加油加油! 公司里一个同事给了个Intel C++ Compiler的license,花了几天时间在eMule上拖了个9.0版的下来,今天装上试了试,居然还能编译WTL的工程,而且原来用VC7.1建起的工程,在Release模式下编译有链接错误,用Intel C++ Compiler也是一样的错误,我都比较怀疑了!用PEiD查看了一下,报的是VC5.0,哈哈,有趣有趣! 小妞在车上的时候还用手机发到我QQ上来,说俊英去山东叫人空运樱桃过来,问我要不要,我当然要了,哈哈,然后就想,有钱了,玩浪漫的方式都可以不一样啊!
又瞎忙乎了一天。上午先搜简历到10点,然后开始整代码,把VSS接口部分的模块和GT3000接口模块完善了一下,其实就是增加了几个方法。下午没做什么事,只是增加了个花哨的工具栏,并且借此机会,让右键菜单也可以有图标了,图标都是从其它程序里抠出来的,哈哈。主要是找了好久都不知道怎么给菜单项加关联图标,只好通过工具栏来实现了。加了个工具栏,还发现个问题,突然发现鼠标移到工具栏按钮上去时,界面刷新挺慢的,后来发现原来是我的代码里有问题,每次刷新都会调用那个函数,那个函数会不停地输出日志信息,于是我把打印日志的语句都删掉了,还以为会快起来了,结果还是慢。最后才发现,原来是有一个要判断GT3000是否登录的动作,会每次都要调用GT3000的COM接口,它又是个进程外组件,效率当然低了,改了后,效果就差不多了。 还有两天这周就结束了,我给自己定下的目标能完成么!加油加油! 好好整一下那个日志库,再看一遍《应用密码学》,写个库来玩玩。
虽然需求写得是把每个要做的方面都考虑到了,但实现的时候,突然发现一团乱麻啊!还是得好好设计一下才行,两个交互模块都得写一堆代码啊! 今天无聊的时候,用工具统计了一下我写的两个cpp文件,注释率超过40%啊,哈哈,平常自己在家里写着玩的,基本上都是不写注释的,在公司全是因为有了那几个宏,可以一下生成一片一片的注释块,哈哈,而且很有趣的是,在公司基本没怎么写特别长特别复杂的函数过,都是一小段一小段的,然后每个函数前面都有一块说明性注释,稍微长一点的函数里就有一块一块的注释,也是用宏生成的,就这样,注释率就上去了,哈哈。 争取这周内,应该把主要功能都实现了,之后只是做些修饰润色补全工作。越来越喜欢用VC了,说实话,MFC真的还算好用的,呼呼,尽管不喜欢它会增大文件体积。 那个花里糊哨的日志类也是比较有趣,针对当前的项目改了一下,还可以再改进一下的。不过对于那回调功能需要Boost::function支持,这比较要求高,今天尝试把那部分自己来改一下,结果没弄出来,我的泛型程序设计水平太低了,需要继续努力学习啊!
上午搜了一个小时简历,好多公司的人啊!然后开了两个小时会,讨论了些最近的工作上的问题,我基本上没有说话,确实没什么好说的。还决定周末搞活动,去爬南山,然后吃饭。 下午基本也没干什么事,就是把日志部分替换掉了,没怎么花时间。最重要的是,把之后要做的那东西确认下来了,可以开始做了,我突然都有点怀疑自己这次怎么条理这么清晰,头脑这么清楚,把原来看起来乱糟糟的一堆需求整理得有条不紊的,自己都佩服自己了,哈哈。而且老大问我做不做得完哦,6月30号前,我很小心翼翼地说,不完善点的话,功能部分应该能实现吧,其实我心里想的是,6月1号前我就能把它做出来吧,顶多就是bug多点,容错部分考虑不全罢了。老大很是替我担心,说先把重要的几个功能实现了吧!我当然点头称是,下班前把像以前用BCB时一样,先把界面整出来,然后照着界面把后台功能实现,我把视图上的右键菜单项都添加上了,发现要做的事情就是这些了,把这些功能整出来就行,还暗暗地想,要做的真的不多哦! 还是像往常一样,吃完晚饭就回家了。上codeproject看了看,上面好多好东东啊,于是down了一些WTL的文章和代码下来。大部分是些讲做界面的,因为用VCL的时候,从来没想过界面是怎么用代码来实现的。最近可是懒死了啊,在家里怎么都不想动手。想了想,那个要做完全灵活的插件扩展的平台,可以由主程序提供界面,做成MDI的,就可以有多种界面了,比如TreeView、ListView、WebBrowser、Edit等,然后把这个Handle传递给插件按约定导出的函数,插件就可以为所欲为了,对于DLL类型的插件,当然可以直接调用Win32 API来做,对于脚本插件,看来是应该有一个简单的操作Win32 API的函数集才行。另外,不同的界面还需要定义些各自的事件,让插件在事件触发时能做相应的动作,比如鼠标点击等。这种约定后具体实现的函数名可以通过配置文件来指明,这样就比较自由。当然最大的自由应该是能在插件之间的相互调用,通过组合插件的功能来实现更强大的功能,就像Eclipse一样,那才是我想要的东西。
最近一直过得很忙很累啊,搞得每天回到家都不想动了,只是点点鼠标发发呆了。今天还算比较有成果的,把需求整理了一遍,写了个word文档,给几个相关的人看了下,基本上是pass了,接下去就可以照着这个文档做了。下午就是在画UML图,写概要设计。前些天看以前的《程序员》杂志提到,这是传统的瀑布模型的软件开发流程,如果用TDD,是可以省掉概要设计和详细设计的。哈哈,我回想一下我平常自己写着玩的代码,虽然不是TDD,但也是遵循TDD的原则啊,每次都增加一点功能,让这点功能能正常工作了才开始下一个功能,这样看来原来就是这样,所以我从来没写过概要设计和详细设计,也能整出些小玩意儿来,不过就是从来没有重构过,所以代码一般只有一个版本,之后变得很难看也从来不管,如果要我从头来过,我太懒了,基本上不可能,看看那个到现在还歇菜的LLYF Spy。下周争取努力把那个需求实现了,然后就到了6月份了,剩下的时间里就用来查错、纠错和优化吧!还有另外一个任务呢,唉,真烦! 今天提到了日志,我顺便自告奋勇要改进一下项目中的日志部分内容,要好好研究一下怎么做一下好用又强大的日志系统。今天提到一个需求是,应该能方便地进行过滤。 跟妈妈打了大半个小时电话,说着以后找什么样的老婆,找了老婆怎么样,使劲yy了一把,呵呵。
VSS提供的接口使用起来还是比较容易的,今天大概用了一下,可以把里面的内容都列出来了,估计其它的什么checkin、checkout、get latest version等也不会很复杂吧,不过没找到怎么get某个特定版本的方法,难道是从version的接口中去找?其它时间还是都花到改bug上去了,得好好研究一下需求才行了啊!另外整了一会儿日志部分,把日志输出到一起去了,当然原来的部分还是简单了点,我自己的难用了点,但信息可以多一点。 又大概看了一下Boost.Log的文档和代码,觉得这个库还是挺不错的,在网上看了maillist上的存档,原来当时是作者自己要求不要被accepted的,因为他觉得这个接口看起来不舒服,他觉得抽空从头再设计一个新的日志库,当时说的可能需要半年或更多时间,现在半年过去了,他果然还没有什么新的东西拿出来。 我准备自己设计一个日志库,初始目标是完全依赖STL和Boost,先能支持标准C++的输出,和Windows环境下的输出,并针对VC编译器,加入遍历堆栈的特性!然后从Booost wiki上取一些需求。最好是能不编译就可以使用,而且不依赖那些需要编译后才能使用的Boost库,比如date_time、threads等等。其实做个简单的,花不了多少时间的。 跟小丫头打了一个多小时电话,小丫头懒洋洋的,真可爱,呵呵。
手头的工作算是可以暂时告一个段落了,但不知道为什么,也许是不够自信吧,总觉得会有什么bug突然冒出来,然后就得一把屎一把尿的debug。其实大概想想,大多数会蹦bug出来的地方,基本上在前段时间做demo的时候发现并解决了的,这几天也就是把原来那个demo的代码合并到他们的代码库里,并改一下界面上的一部分代码,加了个用OLE实现的拖拽,这个拖拽效果比直接判断鼠标动作来实现的效果好看多了。给TreeView加了图标,感觉就是爽很多啊! 用了几天MFC后,突然觉得其实MFC挺好用的,甚至比VCL还好用-_-b说这话真是很冒风险,会被人口水淹死的。不过呢,可能是我自己的问题,用了几天Xtreme Toolkit Pro后,迷上了这样的界面库。说起来其实它也没有什么创新,都是模仿的别人,大部分是MS的,MS就是牛x啊,Shell、Office、VS等等等等推陈出新的界面风格,引得无数Windows桌面应用软件竞相模仿。 另外一个让我觉得使用MFC好过使用VCL的地方是,自从VC7.1出来后,VC已经成为众多C++程序库兼容的首要需求了,确实让人感觉,它的编译器已经比Borland的要好了。 再回来说在公司整的那玩意儿,我负责的模块其实真的是很小很小的一个模块,总的代码量大概就是几百行吧!今天下午感到无所事事了,还改了一下输出Debug信息的类,让它能根据宏定义分别实现向文件输出,向OutputDebugString输出,向那个程序的输出窗口输出。昨天看了下boost-consult上的vault,有个logging,想做个日志库合入Boost,看过代码后,觉得以这样的水平,是肯定不会让Boost接受的,一个小小的日志库,居然还要求Boost::thread和Boost::date&time,而这两库都是需要编译后才能使用的,这就对人们使用logging造成了巨大的障碍!另外,代码实现的风格已经库的使用等编程手法上看,目前也不是很细致,远称不上大师水平。最后就是,现在它实现的功能也挺有限的!看过ACE的日志功能的介绍,觉得功能还比较强大,曾经也想过自己写个日志库,现在想来,日志库的实现可能比较麻烦,至少功能上应该达到ACE的水平,不过如果真要静下心来慢慢写,也不是不可能完成的。
上网聊了一晚上天,也没做什么事,现在体会到软件架构设计的重要性了,也体会到为什么会有人去发明什么UML了。 现在觉得似乎用VCL还是得用第三方控件啊,尤其是界面方面,装了几个控件包,试用了一下效果还是挺满意的。不过我最喜欢的界面控件应该是像VCLSkin或XPMenu那样,用原生VCL控件画完后,只要放上这样一个第三方控件,就能直接把界面效果改掉了。而现在看到的BusinessSkinForm、DynamicSkinForm、KSDev、Raize这些都是把一个一个控件自已实现了一遍,如果原来已经画了界面的,就很麻烦了。 VCL是不能跟Boost很好地混用的,因为Boost中大量应用的模板技术,泛型编程,很多都极度依赖C++的语法,比如回调,用()来调用可调用体,用Object Pascal写成的VCL可能就不行了,所以尽管我没真的试过,还是放弃这个念头了。要有Boost就老老实实地只跟纯C++程序一起用吧!
真是难得啊,久违的感觉了。回到家,打开电脑,上几个常去的网站看了看,没什么新鲜的,收了下邮件,也没什么新鲜的,看了几分钟书,不行了,只好趴到床上去。 从公司的图书馆借了本《深入解析ATL》和《Programming Ruby》中文版,其实照以往的经验,这样的大砖头我一般到期了我都不会看几页,只是觉得或者有必要放在身边,以备不时之需。一直在整GT3K那玩意儿,还是有点麻烦啊,要在TreeView中显示,同时要在具有可读性的显示名字以及具有唯一标识性的URI之间来回转换,没有一个好的设计看来是不行了,代码越写越多了。ATL是个好东西啊,里面提供了一些好用的工具类(比如注册表读写类)、宏(比如宽窄字符转换宏)等,只要包含特定的头文件就可以了。今天基本上完成了早上给自己定的任务,争取明天也能完成自己预定的任务,这样五一就可以玩得更舒坦更轻松。他们不用Boost,实在是一大遗憾啊,有些工作不得已只好自己操刀了。
今天开双周例会,结果发现人力不够用了,而我作为最近才加入组的成员,已经肩负重任地看了3个星期的资料了,而且光看资料不说,连个屁都没放出来。于是老大发现这么个人力虽说浪费了也不是很可惜,可惜的是当前那些任务是进度越来越紧张,交付日期可谓近在眼前,让交付件能顺利产生可谓迫在眉睫啊!然后,突然给了我两项任务,我瞬间晕倒。这样下来我真要变成一个复合形人才了,又能做嵌入式软件开发,又能做Windows桌面应用软件开发,还会用SharePoint做Web开发! 照阿菲那颇具讽刺意味的话说,这下不无聊了撒,不会浪费时间了撒。我于是奋发图强,决定天天晚上加班,因为那些任务我好像似乎一点都不知从何下手。经过大致的跟人讨论、自己看文档,又突然发现,晚上加班也是徒劳的,或者说,其实我真的很自大很高估自己,我压根就是觉得不用晚上加班,那点事情也许也是能搞定的,并且如果真的晚上加班,实际上也没有多少意义。唉!
真郁闷,新老大喜欢Web、脚本之类的东西,而我对这些基本一点兴趣都没有,无聊死了。他宁可去申请新的服务器,去装一堆D版的各种服务器软件,然后叫我这样一个不但没有一点经验而且没有一点兴趣的人去搞这玩意儿。组里的其它人大致分成两拨,一拨写Ruby脚本,另一拨做相关的辅助工具,唉,不爽不爽不爽……又无聊了一天啊,而且这边居然都不填工作日志,甚至好像连PBC计划都没有?明天还是带些相关的资料去看看吧,也当是打发一下时间。 昨天晚上一边看《Hunter X Hunter》,一边把CodeGear Delphi 2007 for Win32装上了,其实这东西我也只是图个新鲜,装上了根本不会去用它,就像当年装Delphi 7/8/2005一样,大概所有用Delphi的次数加起来都不会超过5次吧! Google也出了个拼音输入法,不过我觉得一点都不好用。大概是当年拼音加加先入为主的缘故吧,我总觉得,一个输入法,无论是拼音还是五笔,要是连加加系列有的特性它都没完全模仿到的话,它就不是一个好的输入法,我就不会去用它。所以无论它的什么整句输入准确率达到多高,只要不是100%,它连候选窗口弹出的速度都这么慢,它连左右Shift选第二三个候选字的功能都没有,干吗要去用它。所以我至今都只能用着五笔加加的衍生版,所以对于拼音输入法,我只会考虑安装输入习惯像拼音加加那样的紫光或sogou,呼呼。 唉,我的占有欲太强了,这是不对的。我似乎只喜欢享受那个过程,到快要有结果时,却退却了,不愿意了,然后一个人在黑的夜里独自舔着伤口。
今天下午正在电脑上看小说,上面的大老大拍拍我的肩膀,吓了我一跳。叫我出去谈一下,我就已经意识到是这个事情了。果然最后还是如我以前估计的那样,我被释放到系统技术组去了,说得倒是挺好听的,还说是为了发挥我的专长,那边的老大也很期盼,而且为了能让我去,还特地释放了一个原本在那个组的人到其它地方去了。晕倒,我这样是不是罪孽啊!其实我真的对去那个组不是非常感兴趣,经过在公司的这么一年半时间的磨合,我已经如现在的尹老大说的那样,放到哪都是一块砖了。而且像在现在这个组里,还能学到流程方面的东西,而这东西是我觉得在公司里最值得学习的了。去了那个系统技术组就应该在这方面弱化了,照尹老大的说法,那里是偏开发的。可偏偏还是测试部的旗下的,所以不伦不类的,说不定再给我分些奇怪无聊的事情,就真的郁闷完了。再加上,我真的不认为我写代码方面有什么特长,只是刚好这边的同事们大多在这方面没有研究,然后就看起来好像我很厉害似的,真是心虚呀!
帮别人写的那个可以在Navigator上用的脚本差不多可以用了,费了好多工夫啊。本来是上周五就想做完的,结果因为设备类型不同,上面的命令也不同,甚至同样的命令行在不同设备上返回结果的格式都会有点区别。结果就拖到这周,昨天一天,还是有问题,今天也是有问题,上午还在开会,别个就打我手机,结果我说要开一上午的会。下午的时候,经过几番曲折,终于勉强可以用了。在4.0和5.0以上两种平台上,涉及产品类型超过3种,都可以pass了。却一点高兴的感觉都没有,只是觉得稍微松了口气,希望不要再有啥问题。我真的是个害怕承担责任的人。 本来想今天回来先去剪个头,再捣弄一个我的方块。结果,因为同事帮我买了两包吃的枣,所以下车就不方便拿着去理发店了,我又懒得再出去。然后,因为另外一个同事要我帮忙想想一个程序问题,所以就只好先不弄我的方块了。 技术案例已经提到二级审核那里了,呵呵,感觉C++真是个博大精深的东西啊。RubySuck、LuaSuck是之后2个要做的东西,一方面,因为Lua是要嵌入到我的方块里的,另外一方面是想学习一下Ruby,估计明年2季度开始公司普及Ruby后,这方面的研究也是有一定意义的吧。 想换用Outlook来做为邮件客户端。本来是用Outlook Express的,以前也试过Foxmail,还有DreamMail和KooMail这些,结果还是觉得Outlook好用。一方面,Outlook Express是可以直接支持新闻组的,而另外几个不行;另一方面,Outlook有方面的行程管理功能,另外几行不行;还有一方面是Outlook里可以直接使用Outlook Express的新闻组浏览功能。所以其它的第三方邮件客户端软件就不装了。
Category mm
这个月总的说来过得很开心,进展很大,当然前些天也一度出现很灭世的事,甚至为之放声大哭。
一个人的日子果然非常无趣,于是马上回到了用物质享受来麻痹精神的状态,买了一个BlackBerry的PlayBook,一个HP的TouchPad,总共花掉2600块钱,这个月就开销就这变大了。
之后一段时间最主要的两件事,一是找工作,二是写程序。有很多程序要写,现在由于Qt的lighthouse在4.8版本的比较成熟的运用,使得它在QNX,Android,iOS平台上都能进行可以发布级别的移植了,甚至webOS上都可以用了,除了据说虚拟键盘会弹不出来,这样在Pre2/3上应该是没问题吧,虽然我最想的是在TouchPad上用。不过iOS上那个Qt4iOS是要付费的,而且不卖license给个人用户,估计是因为太贵,作者觉得个人用户承受不起,郁闷!
昨天下班后去浦东机场接了小咪,感觉她跟中学时的长相差别好大,看照片中学时要清纯漂亮很多。回到小区是21:39,然后去对面的接头暗号吃肉,不过好像有点吃坏肚子了,晚上2点多起来拉肚子。后来醒来很多次,7:15时醒来打电话喊人起床,再一直迷迷糊糊睡到10点多,发现小咪已经起床了,再起来两人收拾收拾,去老街吃东西。每当有人来这里,我都是带人去老街吃东西,哈哈。不过小咪没像其他人一样吃汤圆,而是去吃了小笼包。吃完就把她送到虹桥高铁站送走啦!
从高铁站回来,又把别人托小咪带回来的东西送到人家手上了。
哈,好像没什么可以写的了。
今天木耳手机被偷了,中午吃饭时还看她在4sq上check in酸奶店,吃完饭回到办公位上看了一下timeline,就看她在说手机被偷了,现在的小偷真是无所不偷啊,那么小屏幕的,成色也不新的手机也偷,真是穷怕了。据说还是在她学校门口,买酸奶,刚刚还在GT聊天的,一秒种就没了。
然后木耳回家了,貌似没带电脑,于是突然好像人间蒸发了。
下午突然想暂时不移植Ninayan到Android上去了,深入研究下LaTeX吧,对自己无语了。
小妞在新浪上说,看到毛家的牌子重新打了出来,还以为他们家真的重开了。跟谭同学杀过去,以为能吃到久违的青椒焖大虾,结果根本就不是那一家!极其失望。特地at了思思玉玉和我。我看了一下下面跟的评论,有句话真是太适合我的心情了,回不来的始终是回不来了。
这两天跑到杭州去玩去了。本来还真没这个打算的,一开始计划顶多是在绍兴随便逛一下,然后到上虞随便逛一下。后来甚至有点想放弃这个游玩安排了,不过嘛…反正是有点被人推着走的感觉,1号晚上才决定去杭州,2号下午才决定要玩两天。
昨天早起,匆匆吃完早饭,然后开车到绍兴文理学院北区西大门,等了一会儿,我一眼就认出樱子来了,她好像也是一下就把我认出来了。樱子脸蛋比我想象的可爱,大眼睛,圆脸,齐刘海,长直发。然后呢,还发现芭比的寝室的4sq点,哈哈。
先走的国道,再走的高速,进了杭州市区果然堵得一塌糊涂,跟去年到杭州的体验一样,这是我最讨厌杭州的原因,没有之一。先到了浙大玉泉校区,说是看看订房间,结果好像是太贵,然后折回余杭区的亲亲家园速8酒店,这个酒店大概是因为地处偏僻,是在网上能查到的在杭州的速8酒店唯一有空房的。
放好东西,去酒店附近一家快餐店吃了午饭,嗯,吃饭都2点多了,然后直奔灵隐。灵隐寺其实我没什么印象,而且实际上我基本是个无神论者,尽管一直有点幻想其实是有神的。她们三个倒是有点虔诚地拜了好多菩萨,我就一直在旁边看。之后是爬了飞来峰,爬上去一看,什么都没有,有种被坑爹的感觉,今天回来跟我妈一说,她居然老早就知道上面只有一块大石头而已,囧。
从飞来峰下去,有点迷路了,找车子一直没找到,最后一个热情的大叔把我们带到了停车的地方。然后开赴清河坊街,结果呢,笨蛋导航再一次发挥了它的坑人本领,把我们带到了杭州火车城站,我靠。好在目的还有个名字叫吴山广场,离得不远。
晚餐一起的还有嘘嘘和芭比,也是第一次见他们,也正是因为要见他们,我们才决定把游玩地点移到杭州的。嘘嘘比较清瘦,五官有点小帅,芭比则真像她的昵称一样,长得很可爱,声音也可爱。是在沸腾鱼乡吃的,感觉味道还行,但量太少,六个人吃了550多,我感觉大概就7分饱吧。
吃完后,6个人一起逛河坊街,这条街是仿古的设计,各种食物、手工艺品等等,其实没什么想买的,就是随便逛逛。樱子跑来跟我说,发现一家哈根达斯,于是我进去问了一下提货券能不能用,居然可以,好开心,于是我请大家吃。偏心了点,我跟樱子吃的是浪漫之舟,他们都吃的是单球,嘿嘿。吃完哈根达斯,就跟嘘嘘芭比分别,各自回住处了。
每次住酒店,我都不敢关灯关电视睡死,还不敢裸睡,真是没有安全感啊。
早上5点多就醒了,然后看动画片,直到快8点时又睡了半个小时回笼觉。9点多时樱子发短信叫下楼,退了房,去沙县吃了早点,开始今天的行程。
比较搞的是,她们说在网上已经订了西溪湿地的门票,要去西溪游客服务中心取,至于那个游客服务中心呢,是在一个叫天目山路的周家村路口处,没有门牌号的,然后呢我们就先跑到天目山路,然后一路张望寻找那个游客服务中心,那三个丫头还说昨天去灵隐时看到过的,是在那条路线上的,导航和谷歌地图上都找不到这个周家村的地方,很是郁闷,沿着天目山路瞎开了一会,趁红灯时问了一位的哥,终于跑到西溪湿地了,最后才知道这所谓的西溪游客服务中心就在西溪湿地里面,我艹,你丫不会就直说你们在西溪湿地里面啊,业务水平太差了!
西溪湿地其实就是坐了坐船,有个高庄可以进去看一下,说是康熙时代一汉人高官的宅子,其他的就是一些吃的。用樱子的话说,如果叫嘘嘘来,说不定会觉得这坐船很好玩,像我们这种从小就在类似的环境中长大的,其实感觉很一般的。
两天的杭州之旅结束了,身体和精神上都有点累,不过现在回忆起来还是觉得有点小开心的。
昨晚打电话,语气之冷淡之客套,太让我失望了。最卑贱不过感情,最凉不过人心。
给自己算了一下,我每天有12个小时不是在上班就是在上班路上,剩下12个小时里8小时要睡觉,剩下4小时里1小时用于洗漱清洁,剩下3小时里有2小时要去阿玛尼或原力健,最后剩下1小时要追小说。确实没时间做其他事啊,这样的日子难道我要一直过下去,直到垂垂老去?太可怕了ヽ(*。>Д
感觉我现在有很多想要做甚至必须做的事,可是很杂乱,我觉得我需要把这些事情理一理。首先,需要定好目标,而且目标是按时间来排序的,半年后一年后两年后三年后五年后需要达到什么目的。然后根据目标制订计划,为了达到这些目标,需要做些什么事。这样可以把现在想的那些杂乱无章的事情都填进去。
自从开始用Google Calendar后,感觉还不错,关键是除了web界面外还可以通过MS Exchange协议同步到手持设备上去,而且跟联系人和邮箱绑定,很方便,之前用doit.im其实感觉也还可以,但是它不能同步到我的C7上。不过Google Calendar貌似只能同步一个Calendar到iOS和Anna上,不知道Android上什么情况,真想弄个Android机玩玩。
早上惊闻木耳的twitter账号注销了,倒不是非常意外,微微失落之余,反而隐隐有点高兴,这丫头终于有多的时间可以用来复习准备考研了。
晚上回来,习惯性地打开木耳的页面,居然发现这丫头还是跟平常一样在唠,看了一下才发现原因,打电话确认了一下,真是替她感到高兴。
不过也有难过的事,居然说我变心快,这丫头就是疑神疑鬼太厉害了,都半年了一直这样。倒是我想回敬她这句话的。怎么她这个白羊女跟双鱼男一样的严重缺乏安全感啊。别说快了,明明连变都没有变,明明是我这两个月来精神被折磨得支离破碎。
我以前都说过了,我总是爱屋及乌恨屋及乌并夸大影响,但人们都只注意到了前一个词,却不留心我特意加上的后一个词。
好好赚钱,好好享受,一定要记住这黎明前最黑暗的日子。
当意识到两人因为价值观的差异而常常意见相左,甚至引发更大冲突时,就会觉得这世界啊,挺没意思的,这人生啊,也挺没意思的。
每个人都常常只认定自己是对的,也许会出于客套听人说人家善意的意见,但心中也许就是不屑。
其实啊,真的挺没意思的。
因为出没于深沉的夜里,没能在自己的黑眸上映上无数朵美丽的桃花,如此已然被自伤,被自悲……
我终于能隐约体会到那天那个并不熟悉的mm跑来在网上找到我,说“我好难过”时的那种感受了,我甚至能想象到屏幕后面她那张挂满泪水的脸。
女巫说我的运气总是差一点。从过往的无数事实确实证明了女巫的专业。
好难过啊。
读到她昨天深夜写的那篇日志,我的心已经泪流满面,距离才让彼此欣赏,真残忍的标题。读了一遍又一遍,反复揣摩她真正想表达的意思。我不敢确定她是不是写的我,开始有点希望是我,后来却又极其害怕真的是我。如果再要有人给我发好人卡,我一定要歇斯底里地大声告诉她,我他妈的真不是好人,我他妈的从头到尾都没好过!
我真不想给你任何压力,不想给除自己以外的任何人压力,我也一直努力试图可以避免着给人压力。可是我不知道,我真的不懂,我可以做些什么,我应该怎么做。我发自内心地希望可以凭自己的能力对你好,温柔地照顾你,体贴地关心你,你开心我就跟着你一起开心,你不开心我也希望可以分担一点不开心。可是在你的心紧紧对我关闭时,我做对了,给你的是压力,我做错了,难道对你来说就是解脱?
我靠不近她的心,她却闯入我的世界肆无忌惮。很多人说感情没有谁对谁错,以前我也基本认同。现在我却发现自己其实并不赞同这个观点,如果真没有谁对谁错,哪会有那么多错过的人,那么多后悔的事。那都是在不正确的时间固执地认为自己没有错,实际上可能旁边的人都可以看出来,或者自己在以后回头看来,却是错得离谱。我怕再错过,所以我愿不顾一切地投入其中,哪怕是沼泽是漩涡。
知道的越多,苦恼越多。无知的幸福。每当提起这个,我就会想到大学校园里那个据说考研失败最后变成傻子的人,他总是在我们从教学楼到寝室的路边坐着,对着我们笑,他什么都不知道吧,却能笑得那么开心!
你说自己明明已经放下了,可我看出那语气却是将信将疑。你在不自觉地欺骗自己,历数他的种种不好,然后断然结论已经没有以前的感觉了,却不经意间流露出对那丝回忆的甜蜜憨笑。也许真的是你自己也不知道、没察觉吧,或许真的已经放下那个人了,却仍放不下抽不干最后那一丝感情。那细小如丝的感情,缠绕在你的心头,阻挡着其他人的进入。
我曾自以为对待感情,我已经可以做到理性成熟。可是等到真正面对的时候,我却再次沦陷。我的心如此脆弱,如同风中的蒲公英,一吹就散。但是,我愿化身飞蛾,扑向那飞舞跳动的火焰,因为我以为穿过火焰的中心,就能到达我一直向往的光明的新世界。
我只不过就是想要有这么个人,她只需要站在我的背后,让我知道她的存在,在我困倦了疲劳了迷茫了无助了失落了焦虑了不安了烦躁了的时候,让我知道她仍然站在我的背后,那就足够了。人生就是一场战役,由无数的战斗组成,而战斗,正是为了保护自己爱的人,让爱的人站在自己的背后,那是我战斗的全部理由。
我不知道该给这篇文章取个什么题目,半个小时前,是先想好题目,然后决定要写这篇文章的,可是当我开始写的时候,觉得那个题目不合适,不能完全表达出我的心情、我的感受。
昨天从家里出发的时候,我看了一眼时间,那是清晨的8:14,当时只是为了计一下时,看我全程需要多久。最后停在上海的小区楼下时,时间是11点半左右,我没记清,我当时发出两条短信,分别给我当前我以为应该是对我来说最重要的两个女人。一个是我妈,还有一个……是她,因为她,我才决定来上海。
这是一个还没有开始,就已经曲折的故事。
我和她认识有5年半了,那这5年多来,一直只是在重要的节假日时互相发个祝福短信。直到今年元旦,她又发来祝福短信。然后很偶然地开始在网上聊天,真的很奇怪,为什么在那5年中,我们就没这么聊过。在网上,我们聊得很开心,至少我是非常开心。于是渐渐地,我沦陷了。我已经不能忍受没有她一起聊天的时光了。
我鼓起自己所有的勇气,我决定向她表白。那是愚人节后的第3天,那天她从上海回家去。本来说好是我去接她的,结果被她姑妈接走了。在那天晚上10点多的时候,我终于忍不住了,我一直认为表白应该是当面才显得有诚意,但是我已经没有办法继续等待,我在电话中跟她说,我喜欢她,请她做我的女朋友。无论是表白的场景,还是表白后的各种情况,都被我在脑海中预演过很多次。但果然现实是没有在我的预料中的,她说太突然了,都没有过渡的,感觉我像在开玩笑。我有点小郁闷,觉得委屈。我都已经沦陷在其中了,为什么仍会被说成像开玩笑。最后我实在没办法了,就说你就考虑下吧。
那是一个奇怪的情景,双鱼的优柔寡断从此可见一斑,于是她说就考虑下吧。挂掉电话,我觉得我应该再做些什么,躺在床上,最后想到一个很老土很容易想到的事情——写情书。恨当年,没多读些诗词古文,挖空心思总算花了一上午时间凑出几百字的小文,通过email发了出去,并用短信叫她去检查一下邮箱。她一直没理我。直到那晚上,才用短信说了下她在干吗。
之后的两天都是在浑浑噩噩中度过的。直到她要回上海的那天下午,我直接告诉她我去接她了。在车站,我们还是像往常一样的聊着,我仍然不敢在聊天的时候看她的眼睛。我像一个羞涩的小男生,我鄙视自己。送她上车后,她发短信给我,说要真实地相处一下,才有真实的感觉,嗯,我华丽丽地在真实的感觉前露出了原形。
因为要真实的相处,要真实的感觉,所以我决定,我要尽快到上海去,这样才能更多地和她在一起。我跟她约好,周六我去上海找房子,她陪我去找。那一周时间里,我觉得像是煎熬,双鱼的多疑充分发挥,我觉得她开始与我保持距离。
好不容易周六了,我乘长途汽车到了上海,然后坐地铁,直到淞鸿路跟她会面。我觉得我熟悉的那个她还在,她仍然对我很热情。我们在永和豆浆吃过中饭,开始去中介租房子。这是悲剧的开始。因为又要价格实惠,又要装修不差,这要的房子不好找,我们跑来跑去近一个下午,最后总算是搞定了。后来回忆中间的一些细节,我发现我经常会有些得意忘形。这是一个很不好的习惯,男人需要沉着并内敛,但我经常忘记,所以我不够成熟。具体一点的事说来,她总是为了房子中的各种设备、条件跟房东、中介讨价还价,而我却不时地打断她,说些不合时宜的话。照一个推友的说法,我的情商够低的。
后来晚上又让她陪着去逛了一些地方,直到晚上10来点的时候,她说膝弯的地方痛得不行了,说下午找房子的时候就已经开始痛了。我说我没感觉呀!她回到屋,我躺在酒店的床上给她发短信,我说如果明天还痛,我们就不走了,找个地方喝喝茶聊聊天。她却说,相信睡一觉会恢复的。
第二天10点钟,我从她小区等她出来,一起去买导航。我只是单纯想要买个导航,却没做过任何前期的调查工作。她问我有没有事先看过要什么牌子的,我说没有。然后两个人像无头苍蝇一样到处乱转。最后看了两家后,导航是买好了,时间也不早了,雨下得很大,我们就在一旁的真功夫吃了,然后她送我到长途汽车站。
回到家,我发现她对我似乎更加冷淡。每一天,我都试图给自己找些事情,填充自己的大脑,转移注意力。一旦停下来,又会想她为什么会这样。我回忆着我在上海时跟她一起的每一件事情,尝试从中找出一些蛛丝马迹。但是成效不大,我很无奈,我不知道我哪里做错了。父母得知我周六就要搬到上海,浓浓的不舍之情从言语、表情和行动上不停流露。我狠下心对自己说,我要勇敢,我不可能一辈子生活在父母的羽翼下。每天早上,我都是在焦虑和不安中醒来,为事业,也为爱情。她说觉得我浮夸,夸夸其谈,不踏实。我很难过,但我想知道我哪里做得不对,我问afei和王同学,结果吃惊的是afei说我对人不真诚。afei告诉我,跟人说话的时候,眼睛不要乱飘。我知道了,我跟她聊天的时候不敢看她的眼睛,以后跟她说话,我一定会注视着她的双眼。其实我经常反省自己,却发现自己仍然经常高估自己的能力,低估现实的难度。
昨天,就是我来上海的日子。来上海,我不迷茫,却充满了不安。我想我太理性,做一件事情总是会试图量化其成本和收益,从而判断是否值得。但是双鱼的感性,让我实际上做事往往只凭着一时冲动。我到达后发给她短信,却一直没收到回复。我是有点生气的,虽说是我在追求你,但你回条短信应付一下也是可以的吧。把东西都拿到屋里后,一件一件发出来,才体会到“儿行千里母担忧”的心情。我忍不住有点痛恨自己,想想我这二十几年,过得实在太失败了,既不能呆在父母身边敬孝,又没能力让父母在物质上过上比较富足的生活,甚至连传宗接代这种事都要父母操心着急,我真太没用了。
晚饭是一起吃的,还有她的室友。我在阿玛尼店门口见到她,一个陌生的她。我的心有点凉。吃饭的时候,我竭尽所能地表现得风趣幽默,结果是个杯具,一个上面刻满了“自以为是”的杯具。
今天她在网上问我,昨天为什么要讲那些恐怖的事情。我说我的出发点,是为了让你们平时多注意安全。她说,谢谢,我们会注意的。很平静,很客套。我的心很凉。她说她不能接受一个麻木的人。我理解,很理解。但我不愿放弃。我求她给我机会,让我慢慢改好,给我表现的机会。她说她是个被宠惯了的人,上次找房子和买东西,让她很无语。她还说我是被女孩子们照顾惯了,不懂照顾人。我很委屈,我打电话告诉她,这些我都会改,但得给我机会,还得在适当的时候提醒我,哪些地方做得不对做得不好。
是的,我真的从没这么委屈过,但所谓一物降一物吧。既然我决定投入了,就要认真地走下去,也许那条路有坎坷,但我仍要继续走下去。也许我会被摔得鼻青脸肿,甚至遍体鳞伤,但等以后回头来看,至少会少些遗憾。
故事已经开始,期待结局的圆满。
早上去食堂,看到江江,就想跟她打招呼,可是隔得远了点,人也多声音也嘈杂了点,她硬是没看到了,于是我一边回头看着她,一边往前走,没走几步,结果整个人撞在石柱上了,头上撞得最厉害,好痛,搞得我头昏眼花。我知道后面一两米的地方有一个人跟着在走,觉得特别不好意思,头也不敢回,连忙走掉。丢人丢大了,想起之前也有一次是在食堂跟小妞挤眉弄眼的,结果连人带托盘撞在悍超身上,昏!
中午离12点还差10分的时候,突然接到疯丫头的电话,叫我拿100块钱去给她。翻出钱包才发现,空空如也,急忙问旁边的同事借了100块钱,又急忙坐电梯到1楼,还以为这样会比走楼梯快一点,再急忙坐穿梭巴士,巴士开得慢悠悠的,我急不可耐地让司机可不可以开快点,不得地看时间,好不容易在6分钟内赶到A10,进了大门看到一着正装的MM站那儿,本还打算上去问一下她101房在哪里,走近一看才发现,这正装MM居然就是疯丫头,哈哈,她也会有穿得这么正式的时候啊! 差不多有一个月没见过她了吧,跟着她领完东西,刚好就是吃饭时间了,于是去A8吃饭。路上偶然发现,她左边下巴上的那些东西还没抹散,呵呵,这个丫头这一上午走来走去,不知让多少人偷偷笑过了。 A8的饭菜感觉就是比F2的要好吃,我还是打了两个素菜。一边吃,她还一边给我讲她新岗位上要做的事,现在在客工部实习,下午就要去接待客户。像以前一样,我很快吃完了,看着她吃,互相讲些自己最近的情况。 吃完饭,慢慢走回来,她就回G1去了。她还说,如果干几个月,觉得不好干,就辞职。我猜,可能还有其他原因吧。唉,人就这样一个一个都走了,我的心就是这样一点一点被敲碎的。
有些问题是看不出来的。 今天因为有人提了单,我才下决心去看了一下代码,经过比较仔细的排查,最后结论是,果然是被我改坏了,原来的那种实现方式确实是不会出这种问题的,不过那种实现方式是一定不能留的,一定要被改掉的,只能在现在的基础上进行修改,最后好像勉强可以了,哈哈。 还有一个问题,好久好久了,是以前离职的一个人留下来的东西,交给其他部门人用的工具,现在发现有问题了,原来我看了一下,似乎问题不在工具本身,而在工具调用的底层通信模块上。今天又被人一说,仔细读了一下工具的源代码,再加上和那底层通信模块作者的讨论,最后结果是,确实好像是工具实现得不对。有几行代码一眼看就觉得写得有问题,且不说是否真有问题,首先代码就不应该是那样写的。 另外是这大半年来我陷入其中的工程,今天写用户手册,当然需要演示截图,结果发现了好几个比较严重的问题。唉,我这大半年的投入产出比还真是低,心里有点难过。争取在剩下的3个星期里,把这些严重问题修正了,完善一下用户手册,就彻底交付了,唉,从开始计划的2个月,到现在都大半年了,真是没完没了,还拖累了绩效,不过似乎就算不搞这个,绩效也不会好到哪里去吧,郁闷! 最后提件还算好的事吧,小思宇回深圳了,今天还给我打电话,挺高兴地跟我说“我回来了”,大概是因为彭彭回来了吧。不过她那高兴的劲也短暂地感染了我,让我如沐春风啊,哈哈。
中午疯丫头跟我说,明天她就去那边了。不免有点失落,以前测试组的同事一个一个地全都调走了。虽然早就知道她一直忙着调动的事情,忙着去那边面试,忙着跟这边的领导周旋,直到前不久,大概也是因为正好赶上了产品线整合以及部门整合,领导也变动,终于同意放她去marketing那边。今天还偶然看到她居然,有纹身,而且不是在很明显的部位,呵呵,还骗我说是贴纸贴上去的,太假啦!
昨天听小妞说的,小思宇前天去领了证,昨天就去公司请假,下周就休假一周,过甜蜜生活去了。时间过得真快呀,想当时我们4个人一起住的时候,还都是小孩子,不时地还会谁跟谁怄气一下,然后剩下两个人要么不知所措,要么就去劝架,呵呵。转眼间,小思宇就已经是已婚妇女了,哈哈,再过不了多久,小妞也要嫁作人妇了,呼呼。 祝小思宇彭彭幸福!
这个称呼我觉得肉麻了一点儿,呵呵,不过就是有几个同事喜欢这样叫。中午在食堂见到她时,还是被吓到了,怎么变成这样儿了,这个脸是怎么了,跟毁容一样了,变成一麻脸了,本来多好一姑娘啊。排队打饭的时候,她站在旁边一排,我就在那儿喊她名字,然后她说我瘦了,呵呵。宣宣就在那里说,以后千万不要走女强人类型。吃过饭后,她走的时候还叫我们注意身体,我心想,你才是最应该注意身体的人呢。真是变化太大了,才大半年时间啊,怎么就变成这样了呢! 这女人啊,还是得保养啊,曾经有光网第一美女已经不在了,只存在于一些人的记忆中了!
早就听小妞说起过,市民中心那边的韩国料理不错,想去试试。今天就稀里糊涂刚好说要去那里吃韩国菜。不过我不认识路,疯丫头也不认识路,只凭着小妞说的几句话,就兴冲冲地找公车坐去了市民中心。市民中心是个很空旷的地方,下了车,找不到什么有可以吃的痕迹。于是打电话问俊英,结果说不是市民中心,而是会展中心旁边。问了几个在市民中心的保安,好不容易穿过几条地道和马路,最后终于找到了俊英说的大中华喜来登。在喜来登的一边,果然看到了小妞所说的家乐福。但是在家乐福外面是看不到那家店的,在外面能看到有必胜客、星巴克、巴西烤肉等等,还有个意粉店,在小妞的电话远程指挥下,终于在意粉店旁找到了那家光阳烤肉韩国料理。 走了不少的路哦,再一次深切地体会到自己有车的重要性。 不过,那里的东西味道还真是不错。点了个蘑菇烤牛肉、八爪鱼拌饭和三色五花肉,还送了些小菜,两个人吃还真是有点撑。最后218元,跟小妞说的差不多,嗯!有钱真是好哇,只可惜照我现在的收入水平,这样的地方只能偶尔来来了。
下午的时候小思宇突然发个邮件说好想吃孔亮火锅,然后小妞就叫上俊英下班载我们去。说实话,孔亮火锅的味道确实比其它地方的稍微要好一点点,那油碟的味道就能比较出来。一边吃,小思宇和小妞就一边怀念学校的生活,倒是我却没什么怀念的,我的心一直是漂泊的。小思宇真的要离职了。
昨天是月末的最后一个周六,所以还是要上班,这是很让人不爽的。白天出神发呆无所事事了一天,其实事情还是挺多的,只不过状态不好,就是不想干活。下午下班的时候,一个人慢慢吞吞地走去食堂。快到食堂的时候,疯丫头从后面叫我,问我去哪里,我说去食堂,她说去梅林吧,于是我犹豫了一下就跟着她去了。 这些天,中午在食堂都吃素,晚上就跑出去吃肉,照大牛的说话,生活真happy啊!周四跟小妞去万科城的一家韩国烧烤吃的,周五跟小妞小思宇去吃的小肥羊。昨天那顿开始没想好要吃什么,疯丫头说去吃韩国烧烤,我说我周四才吃过,后来我就随口说了个漓江又一轩。 到了店里,看到有特价的大闸蟹,10元/只,我们要了4只,又点了一个酸菜鲈鱼和一个田螺鸡锅。这几个菜的味道都还不错,不过有点奇怪,她好像真不知道吃螃蟹哪些是不能吃的,我看她是除了外面的硬壳,其它的全吃下去了,晕,而且照我们那边的吃法,这样的清蒸做法在吃的时候一般都会蘸醋,为了防止吃坏肚子,而她也什么都不蘸就吃了,昏!她说,今天点的都是你喜欢吃的。我说你不喜欢吗。说实话,我除了知道她喜欢啃猪脚,喝雪碧,吃冰激凌之外,还真不知道她喜欢吃什么其它的菜。像我的特征就很明显,尤其是小思宇她们,当年刚来公司,还在大队培训的时候,吃食堂饭时,她们就总结出来,说我喜欢吃各种水里游的东西,而当时我们也是到了公司才开始接触,一起吃饭。上次在宣宣家吃饭时,小思宇还在那里跟人讲我喜欢吃鱼啊,虾啊,田鸡啊,呵呵。 大闸蟹确实好吃,以至于疯丫头说我们再要几只吧,这个丫头,还真疯,不过我说下次再吃吧,毕竟眼前还有另外两个菜,而且份量都比较大。 吃完后,慢慢晃出来,逛路边的小服装店,也有趣呢。
小思宇从百草园的七座搬到八座,我就过去帮忙。其实东西也不算很多,只是几个箱子,而且还不大,虽然3个人,加个小推车搬了2趟。 在百草园遇到小玉玉,没有说话,她只是低下头走过,我也没出声。小思宇问是不是很尴尬,还说我脸都红了。我都会脸红,呵呵。唉,这是注定要遗憾一辈子了。
下午跟她发短信说起换工作的事,她说她这次杀气太大了,面试她的一个ppmm好像不喜欢她,我说好想见识一下这杀气呀,哈哈,她说没机会了,我就威胁说,要是没杀气的话会经常被我欺负的哦,呵呵,结果她却出乎我意料地回了句“没杀气你也不会欺负我的”。我有点惊愕,因为在记忆深处,不刻曾经是哪个mm,在类似的情景里,很俏皮地说“你舍得吗”,我还以为她这次也会这么说,可惜我猜错了。我突然有种很感动得有点想哭的冲动,我怎么会这么心软哪!
今天晚上跟小思宇小妞一起去万科城的湘聚缘吃饭,结果那家店的上菜速度实在让人受不了,于是小思宇就怒了,开始闹,有个上菜的小弟还不知好歹地说什么什么,小思宇就更怒了,当然我和小妞也是很生气的,只不过没这样破口开骂,hoho~~~ 但菜还是好吃的,因为我们三个人后来都不怎么说话,埋头使劲吃使劲吃……
昨天早上还是很早,大概是7点多就醒了,起来开电脑,无聊,然后熬了一会儿,去洗澡收拾,弄得自以为比较干净整洁的样子。还是比较早,就写了一会儿代码,好不容易熬到10点半,出去坐车,本来以为之前已经千叮万嘱过了要准时,别让我等的。结果到了那里,还是等了20分钟,当时心里还是挺有点生气的,不过见到人后,突然就觉得生不出气来了。而那边阿菲则不停地发短信问我到哪了,我则只好很无奈地说,还没上车呢。本来说好11点准时坐车走的,结果已经是11点一刻了,那公车站又等不到能到南山天虹的公车,只好打了个车。打车就快多了,大概半个小时就到了,不到50块钱。在车上时,她悄悄问我,是不是等了20分钟,我说,如果只是我一个人等是无所谓的,等个一两个小时也没关系,关键是现在那边还有人,我不好意思。 到了天虹,进去略微看了看,感觉跟华强北那个气氛很像,乱糟糟的。约好是在二楼的雨花西餐厅,她又闹着要上洗手间,还以为很急呢,结果是整了下头发,带了个发夹。在餐厅里看了一会儿菜单,阿菲她们来了,帽子还背着个guitar,很酷啊,有时候真的很羡慕这样有一技之长的人啊!6个人随便点了些东西,我点了个羊排,阿菲在那里说我,本来想给我省点钱的,现在自已都不给自己省。于是我大声说,你们要少吃点啊,啊! 一边吃一边帽子马上就问起工作上的事来,说起来还真是比较困难,我又想工作轻松,又想钱不少! 一直吃到1点半,帽子还要去排练,说是马上要去比赛了,于是匆匆地走了。剩下几个人,她说要回去,我也觉得没事无聊,还是回家休息一下,晚上还有一顿呢!阿菲说去K歌,我说不去了,还是回去了,于是就跟她一起走了。跟阿菲她们分开后,她问我晚上几点钟吃饭,我说大概六七点吧,她说还有好久呢,不如她陪我玩到6点再走。我说还是回去吧,她说要陪我逛,我说这样我也逛不安心啊,她说那就逛一个小时再走。走出天虹,对南山这带非常不熟悉,不知道可以逛什么,就又折回天虹。 她说要帮我挑衣服,我的衣服太少了。衣服少倒是事实,不过我确实很不习惯让别人来帮我挑,除了我妈。然后两个人在4楼逛来逛去,试了一些西服、休闲装,衬衫、T恤、针织衫,牛仔裤,发现大多数的只要尺码合适,我穿上还是比较好看的,于是心里很是暗爽。其实也不是暗爽,每次她说挺好看的,我就说不是衣服好看,而是衣服架子好。嘿嘿!这点我自己也很早之前就知道了,我穿衬衫西服的样子真的还不错,如果身高能再高个二三四厘米,就更好了。后来在Benbo里,她趁我在试衣间里时,就叫人开单了一条牛仔裤和一件T恤,晕! 又试了几样,无聊了,她说要帮我去选耳环。走到1楼的珠宝专柜,没有男式的。倒是我想起我妈说要项链,于是我说要看项链,那些服务员可热情了,以为有生意来了,哈哈。让她带了两条试试,没什么感觉,而且我妈那么胖胖的,而她又是瘦瘦的,完全想像不出来带上去是好不好看,只好作罢。她就很遗憾地说,买不到耳环了,只好去些路边的小店了。先去把那单买了,结果刷卡的时候,她用她自己的卡刷了。当时我的心情,都不知道应该怎么形容。说高兴吧,肯定是有的,但除了高兴,还有很多很多其它的感觉,说不出的感觉。不知道为什么她要买衣服给我呢? 从天虹出来,天下起雨来,她拿出伞来,不好再去其它地方逛了,看看时间4点,离吃饭时间尚早。但最后还是决定去坐车回去,等车的时候,她问我她回家了我怎么办,我说我随便哪里玩一下呗。她说到时候我可以去家乐福玩一下,等到晚饭时间。我也不好再说什么,心里虽然有点点沉闷。这时想起xcc他们在哪儿了,就打电话给他,他说在晾衣服,再过半个小时出门,我说我在南山天虹呢,于是他说再等一会儿等他出来。刚好发现公车站后面有家KFC,就进去,一人要了一个饮料,另外她要了一对鸡翅。她还在那里很兴奋地跟我描述,抢到这个四人的座位是多么的不容易,呵呵。我就一边吸着可乐一边看她啃鸡翅,最有趣的是,两个鸡翅她都啃了几下就掉了,让我想起星期六才看的Kanon里那个变身成人类女孩的狐狸在生命渐渐衰弱时,吃饭时拿不稳筷子,一连要掉几次,呵呵。 xcc来了,坐着聊了一会儿天,xcc的gf也来了,然后4个人坐车。车上的人越来越多,下车的时候我踩到一个女孩,我反而只是瞥了一眼就下车了,那女孩就在那里喊,连一声对不起都不说。我才不管呢,当年就是这样人很多很挤的时候下车,才把钱包挤掉了,虽然后来找回来了,但我却从此再也不管别人怎么样了,自己安全才是最重要的。她下车来还笑了我,我就顺便语重心长地教育了一下她。在路口分手后,xcc问我怎么不送她进去,我说要是里面有个男的在等着遇到了,岂不是很尴尬。xcc也只好干笑一下,然后扯起另外一些事。 3个人来到八仟馆,等到doggy来,4个人慢慢吃了一顿,但我还是没什么食欲。不过能跟朋友们一起聚聚,还是很开心的,我是很怕孤独的。吃完后,9点过了,随便爬上一个公车,跑回家,觉得好累好累,怎么都不想动了,下了好大的决心洗了个澡,倒头便睡!
梦中无数次出现她那羞羞答答用手压着嘴唇跟我说的情景。我使劲儿安慰自己。这是第一天,这样的日子还会有多少。
居然接到luolu打来的电话。正在看小说的我,先是看到一个看不到号码的来电,接通后断来,后来是一个很奇怪的号码,还在那里用普通话问我知不知道她是谁,我一开始当然听不出来了,毕竟也是好久了嘛,于是老实地说听不出来。好像前一次打电话是我刚来深圳不久,她刚好回国,我就打到她家里,到现在也近两年了。而且这些年来每次只能通过电话才会听到一下她的声音,每次听到的声音好像差别又都挺大的。不过几句话下来,还是猜出来了,我马上说,这么多年了,我哪会这么容易能听出来啊。并且我真的挺意外的,因为从来没想过她会打电话给我,我也一直在疑惑她怎么会知道我的手机号的,而她却说是我以前在QQ上告诉她的,晕,我自己是一点印象都没有了。其实这么多年不见,真的能说的话题已经挺少了,她说知道hw死了人了,来慰问一下,居然连她这个身处异国他乡远在欧洲的人都能知道这个事,这个影响真是太坏了。顺便还问我结婚没,我说你都没结,我哪会结啊,然后问我有GF没,很惭愧地告诉她,本人魅力不够,还没有,唉,刚刚正在郁闷着呢!另外又闲扯了几句,问她回国之日之类的,实在没什么话题可以说的,最后她就说,多联系啊,只是她在上班,不能开QQ,不能开MSN。然后我说用邮件就行了,她说她是小女孩,当然我要主动写给她先,呵呵,能这么跟我说话的,大概也只有她了吧,呵呵。
虽然早已隐约感觉到了,但是亲耳听到从她口中亲自说出来,还是觉得挺失落的。虽然一直以来都告诫自己,动什么也千万别动感情,可是我还是一步一步陷入了自己造出来的那个泥潭中去了。细细数来,这样的情况已经不是第一次了。总是一开始自己装清高扮酷,然后等日子长了久了,自己慢慢投入进去了,而人家却已经要离去了。 快下班的时候,小妞和小思宇突然发邮件说一起吃饭去。我真想说,你们是我这颗漂泊的心避风的港湾啊。吃饭完,三个人慢慢走回百草园,我什么也没跟她们说,但心里觉得比较安稳。回到家,给xcc打了个电话,倾诉了一下。xcc还是比较会安慰人的,分析形势,价值取舍,说得头头是道的,真的很让我觉得舒坦。 失落过后,接着的是解脱,因为可能会面临的很多困扰都没有了,大概我的食欲也会慢慢好起来吧。至少我很孔雀地感觉到她还是比较在乎我的,或者说曾经在乎过我的。 让人不能自拔的,除了牙齿,还有爱情。
今天觉得特别郁闷,于是约了小思宇和小妞一起去吃饭。反正就是特别郁闷,不过下班后,见到小妞,心情就不自觉地好起来了,三个人在肥牛府小小地吃了一顿。她们的战斗力下降,而我最近的食欲一直不好,所以只能说是小小地吃了一顿。小思宇说了我两次,说看到我偷偷在笑,问我在笑什么。我说见到你们心里高兴啊。她们肯定不信,呵呵。 后来她们两人谈起结婚的事来,两个人看样子都是要么赶在今年年底,要么就要等到后年了,突然我觉得自己很迷茫啊,我什么时候结婚呢,谁来跟我结婚呢。 今天疯丫头要我去打听些事儿,于是回到家给xcc打了个电话,大概了解了一下,然后给afei也打了个电话,又了解了一下,其实内容都差不多,毕竟在一个地方的嘛。不知道疯丫头最后会怎么样。从疯丫头跟我说要去问这些事时,我就开始想小丫头那时候的那些事儿。
上周就听说她要过来了,今天快下班的时候看到她从旁边走过,刚好有另外两个领导在,她就只能跟我笑笑。下班后,教授埋单,去湘江老厨吃了一顿,说起来我们几个人很久没有一起出去吃了。高导还是很爱搞笑,真是个有趣的人。一年啊,就这么快过去了。 吃完饭,要走回公司去坐班车。今天很失策啊,没预料到会遇到下雨,还下得很大啊,结果和疯丫头两个人一把小伞,一人湿了一半,还差点没赶上班车,真悬啊。 还以为工具快忙完了,今天才发现,还欠下好多账,唉!不过易用性方面真的也改进了好多,只是我觉得这工具,我们现在花了这么多精力,到时候人家用不用,能用多少,觉得好用不,还一切都是未知数呢,不过就当是给我自己一个锻炼的机会吧,至少是了解了一些MFC编程的东西,以前可是几乎一点都不会MFC的呀,而现在几乎都不想再用VCL了,越来越不喜欢C++Builder了,感觉VC真的太好用了。
今天小思宇突然给我发了个邮件,说她可能要离职了。我也没怎么想,直接说,支持她。记得刚进来的那一年,我们都是互相安慰互相鼓励,这样坚持过来的。后来问了问大概什么时候,她说可能最快9月份,那时跟玉玉一起。我也不好再说什么,水斗新村新阳丽舍新雅阁301就这样彻底散了,以后要见面也不知道是什么时候了。 一天都在整一个外部工具对话框,完全仿VC来做的,不过工作量还是有点大的,或者说我的效率着实很低。在这个8月里,我要把编辑器相关部分想好的都实现了,尤其是要留下接入后门,以后可以在不修改重编译工具源代码的情况下,给工具增加新特性。
昨天又早早地醒来,然后开电脑,写了一会儿代码,估计了一下时间,洗澡,出门,坐391到图书馆,错误地估计了路程,到得太早了,于是进去里面的阅览室看了些杂志,大概过了半个小时多吧,才等到人。还好我已经很习惯等别人了,在以前多次的等人过程中磨练出来了,哈哈。 从图书馆出来,在旁边的餐厅里吃了个咖喱鸡饭,味道不错哦,鸡肉比较嫩,只是量太少了,想起上一次吃咖喱鸡好像是我生日的时候请xcc和afei,在万象城后面的泰国餐馆芭蕉叶里吃的,记得那次的量比较大,呵呵。 吃完饭后,两个人想不好去哪里玩一下,最后说起去看电影吧,于是绕了点弯路去坐地铁,又一个路盲mm,呼呼。到了购物公园Coco Park,里面有个百老汇电影城。我在深圳2年,还没去过电影院呢。mm说没看过变形金刚,看了一下时间,10分钟后就有一场,只是没有好的座位了,只有前三排的了。买了一大桶爆米花,一人一杯可乐加冰。电影院的效果果然就是好啊,连脸上的根根胡茬子都能清楚地看到。 看完电影,她有个师兄打电话约她去K歌,于是于是,俺就也厚着脸皮去蹭了,哈哈。打的到华强北巴蜀风旁边的星期8,好多人在等,看到一个精瘦的小男人,好像比较内向的样子,过了一会儿,又来了一个mm,4个人坐着无聊,斗了一会儿地主,终于有房了。还好几个人都不是很拘束,我也觉得奇怪,以前跟小思宇她们一起玩的时候要是遇到这种场景,我肯定是很自闭的,现在却几乎已经克服了那种心理问题了。 7点半,从卡厅出来,去找吃的,本来说的是去吃小肥羊,后来被我带到小肥羊旁边的华神火锅去了,哈哈!点菜的时候我正给妈妈打电话,打完电话人家已经点完了,mm说,不知道我喜欢吃什么,只记得我很喜欢吃田鸡,于是帮我点了份田鸡,呵呵。 开心!~其实人是很容易改变的,嗯嗯!
真是赶啊,下班就忙不迭地跑去生产中心坐班车,跟估计的差不多,开了45分钟到了莲塘,然后又走了五六分钟路,才赶到吃饭的地方,xcc和他gf已经在了,4个人喝了一顿粥。
中午还在睡觉,她就发短信来,说要我晚上请她吃饭,我想到她大概来出差了。和另外两个同学,去蜀味轩吃了一顿。打折好少哦! 见到小玉玉了,我们果然一句话也没有说,唉。 今天突然公司的那个VC2003不停地崩溃,都不能用了,一下午就浪费在重装上了。
话说昨天晚上才知道她也来这边大队培训了,于是两人约好今天中午一起吃饭。当然是我跑去培训中心找她,虽然两年没见了,但她的样子还是没变,一如既往的漂亮,皮肤之好,典型的重庆美女啊!两人一起吃了顿自助,也算是见过面了,拍了照,在主培楼外面晃悠,雨下大了,于是各自回自己该回的地方去。她还带给我一包重庆产的牛肉干,呵呵。 今天在公司,又发现一个严重问题,还是因为BSTR内存分配的问题,以前虽然也有些比较奇怪的现象,但一直没重视,以为是其它原因,今天才知道是这里错了。纠正一个大bug的感觉真爽啊,不过好多地方我都没有怎么仔细考虑容错处理,要写出一个强壮的程序来,还真的不太容易呢! 另外,那个日志类啊,一拿到公司里去用用,发现好多不对的地方,实在是经不起实践的检验啊,而且实在很难用,风格也很丑,怪不得boost一直没有一个日志库,要做好一个日志库也很难啊!
今天小思宇说她爸妈定了12号回去的机票了,于是我问她晚上有空一起吃饭不。最后定在万科城的关东风饺子馆,跑上跑下去借张优惠卡,结果到买单的时候才知道,预订桌席的就已经有八五折了,晕!小思宇长得跟她爸很像哦,照小妞的话说,她爸长得很可爱,一看就是很慈祥的,呵呵。不过今天小妞好像状态不好,战斗力下降,而小思宇则更不行了,柳妈妈也是只是稍微动了一下筷子!
在梅林吃了2顿,就像当时我请客那样。中午小肥羊,下午打牌下棋,晚上吃竹筒饭。 早上9点不到就睡不着了,于是起床玩电脑,把csdn上的blog内容用LaTeX做成PDF格式保存起来。过了11点,出去坐328,居然遇到教授,在梅林街道办下车的时候才11点40,觉得太早了,于是跟教授去逛了一下金帝巧克力吧,教授买了一盒外包装是心形的巧克力。然后2个人慢慢吞吞走过去,到了小肥羊门口还是不见什么人,我和教授说,会不会被人晃点了呢,我们要反晃点。于是我先给疯丫头打电话,说教授被车子擦了一下在医院,要交2千元押金,快点送来。疯丫头半信半疑给教授打电话,教授说在她家楼上,要她去接。这时疯丫头已经一个人跑到小肥羊店里来了。非常不巧的是,悍超这时候也来了,疯丫头便要他一起去找教授,我和教授看着他们2个进去店里,以看他们要出来了,连忙分散躲起来,看到疯丫头在给教授打电话,我便给悍超打,没想到他竟然走过来了,我就被发现了。于是我们3个人上包间里去等教授,教授只一小会儿就也来了,呵呵。要不是悍超,估计疯丫头就真的去找教授去了。 后来陆陆续续大家都来了,教授和疯丫头出去买饮料。疯丫头打电话给猫猫,说没带零钱,要猫猫去接。猫猫说教授已经去了呀,于是还打电话给教授。我们使劲劝猫猫不要打,人家肯定是在一起,串通好的,可是猫猫这人就是不听,还硬要打,打完教授还要打疯丫头的。过了一会儿,教授满头大汗的样子一个人空手回来了,说是没找到疯丫头。猫猫急了,我们剩下的人就说,快去找吧。于是猫猫真的出去了,一出去我们几个就笑起来,一边吃火锅一边看着疯丫头和一脸无辜的猫猫回来了。呵呵,猫猫也真傻,但为什么不肯听别人的劝告呢。 吃完火锅,先去了一下梅林那边的一个基督教堂。差点出不来,里面人很多,都很有心得地讨论各自的遭遇和体会,但不好玩,我们又都不信教。然后我们又去了上次去过的茶艺馆找了个大包间3个小时。其它的人都打麻将去了,我则又跟疯丫头一起下五子棋,下得头昏脑胀的。一直到7点才出来,找了家湘菜馆,各人点了个饭,吃了便回来了。 总之,这样出来玩,还是多开心的。
早上很早就醒了,然后在床上赖到9:40起床玩电脑,10点半的时候开始收拾,准备出门。跟阿菲一起坐302到万象城,逛了一小会儿,两个这样的组合的人似乎是没有逛这种地方的闲情逸致的,只是买了点曲奇,然后就直接去吃饭的地方了。这是家泰国菜馆,里面的咖喱是阿菲叫我去的主题。等了一会儿,去把xcc接来,这次聚餐的全部主角都到齐了。这两个人,一个接完电话另一个接,都是处于热恋中的,手机必须保持随时能接听的状态,这样他们的另一半才能随时定位到他们的行踪,呵呵。随便点了几个菜,也不是很贵,三个人也就吃了103块钱,每人平均还不到40块。每次我们三个在一起的时候,聊得最多的就是各自工作的问题,以及对以后的展望,呵呵,展望说不上的话,至少可以说是想法吧。阿菲总是说叫我年轻人去做国际售后技术支持。其实我是个懒人,我又怕吃苦。于是跟阿菲说,我想做SOHO,或者等SOHO到一定的收入后,可以找个轻松点的工作。但这样说是说,什么立足点都没有,何况我现在在公司就很轻松,就是嫌钱少了。聊了一会儿后,xcc说要去接一个高中的同学,于是先走了。阿菲要我陪她去买移动硬盘,于是坐地铁到华强北。 到赛格,又到那家买了几块硬盘的地方去了,一个日立80GB的笔记本硬盘,加上一个仿冒的三星硬盘盒,好说歹说讲到470块。刚买完硬盘要下楼,阿菲突然说眼睛很黑,人很不舒服,头晕。我还以为是暂时性的头部供血不足之类的,结果阿菲拉着我的衣服说要打车回家,拉着我的手,走路很慢,说话也很轻声轻气了,我才想到,这下有点严重了。打了个车,在车上,阿菲已经几乎没有力气了,车子转弯时的倾斜,都把她甩倒了,我只好抱着她。阿菲靠在我胸口,我看着她虚弱的样子,想着人无助的时候是多么需要有个人能在身旁,靠一靠也好啊,又联想起某某人来。到了她家,给她倒了杯水,我就出来了。一边走一边想,我真是不会照顾人,就这样走掉了,因为我完全不知道我留下来能干什么。虽然看了很多动画片,还想自己也做一个很温柔的男人,这个时候我才意识到,我骨子里是做不成那样的男人的。大概曾经在我怀里依偎过的女人,没有哪个会有过安全感吧!我不懂温柔,我不够成熟。 再回到华强北,几经抉择,买了套微软的无线桌面套装,380大洋,买了10张DVD刻录盘,买了个小挂饰,去编了个手绳。加上这两天吃饭的,一共1500多就这样花出去了。花钱的速度远远快于赚钱的速度啊。
找了个机会让小妞敲诈了一顿,呵呵,好久没和小妞一起吃饭了,下班后去F1大堂门口的她,然后两个人就说去吃火锅吧。走到肥牛府一看,没有好的位子了,于是走到隔壁的童子羊,点了9个菜,狂吃一顿,一直吃到快9点。撑啊,我们两个的战斗力还是不错的,呵呵。之后小妞说要我教她怎么刻录,于是去了她屋里,欣赏了一下她在阿尔及利亚的照片,呼呼,这丫头,连撒哈拉都去过了,还看了地中海,真让人羡慕。七整八整就弄到了10点半才出来,呵呵。
呵呵,今天在食堂吃晚饭的时候,我们美女老大说我眼光高。这点我承认,好多人已经这样说过我了,我自己也觉得。难道真的是因为美女看多了,不知不觉就把要求提高了? 其实,说不定,哪天,心血来潮,就随便找个女人过了,哈哈。现在一直觉得还年轻,可以拖几年,混点资本,到时候再找个。很盲目,呵呵!
今天偶然看到某人也有blog了,这让我有些许的诧异。因为一直以来,都以为是个对网络不怎么感兴趣的人,仅有的用处大概就是下碟,当歌,聊QQ吧。不过,也许是因为不够了解,也许是因为人会改变。毕竟,这半年来,我自认为也改变了很多了,甚至是换了一种生活方式,一种生活态度。可能是一直以来,自己的处世方法有问题,对人对事总以一成不变的眼光看待。有句话说得好,可能最值得庆幸的是,人是会改变的。但是不能改变的是曾经,是历史。有些事情,是永远没有挽回的余地的。因为我的愚蠢,我的冲动,我的情不自禁,我的不可饶恕,一切已成为过去。 也许,某些人对于一个人来说,都只是漫长生命旅途中的匆匆过客,某一刻,某地,稍作停留,又继续上路,剩下的只有那回眸一笑的皓爽回味,亦或是横刀相向的痛苦回忆。佛曰,上天尚且不完美。凡人何必要追求事事无憾。 只为了那逝去的友情,追忆曾经拥有的快乐和酸楚,永远记住那个被我深深伤害的小女孩。对不起!
一盏离愁孤灯伫立在窗口我在门后假装你人还没走旧地如重游月圆更寂寞夜半清醒的烛火不忍苛责我一壶漂泊浪迹天涯难入喉你走之后酒暖回忆思念瘦水向东流时间怎么偷花开就一次成熟我却错过
谁在用琵琶弹奏一曲东风破岁月在墙上剥落看见小时候犹记得那年我们都还很年幼而如今琴声幽幽我的等候你没听过谁在用琵琶弹奏一曲东风破枫叶将故事染色结局我看透篱笆外的古道我牵着你走过荒烟漫草的年头就连分手都很沉默
一壶漂泊浪迹天涯难入喉你走之后酒暖回忆思念瘦水向东流时间怎么偷花开就一次成熟我却错过
谁在用琵琶弹奏一曲东风破岁月在墙上剥落看见小时候犹记得那年我们都还很年幼而如今琴声幽幽我的等候你没听过谁在用琵琶弹奏一曲东风破枫叶将故事染色结局我看透篱笆外的古道我牵着你走过荒烟漫草的年头就连分手都谁在用琵琶弹奏一曲东风破岁月在墙上剥落看见小时候犹记得那年我们都还很年幼而如今琴声幽幽我的等候你没听过谁在用琵琶弹奏一曲东风破枫叶将故事染色结局我看透篱笆外的古道我牵着你走过荒烟漫草的年头就连分手都很沉默
三天的假期感觉好短哦。 1号睡得多了点,下午跑到华强北买衣服去了,真是贵呀,实在不好找。后来还是在茂业买个件外套,去买了个洗衣袋。买了东西就没事做了,发短信问一下雨烟在干吗,说在买手机,于是跑去找他们。然后她和小于陪我去曼哈打了个耳洞,¥44呢,还是人家算错钱了,哈哈。心里感觉怪怪的,就这么一下,身上就多了个洞。之后3个人走到巴蜀风去吃了一顿,也不是很贵,三个人¥102。 2号早上7点多就醒了,因为心里总是惦记着小思宇说早上要过来,就翻来覆去不怎么敢睡了,结果本来说8点就过来的人,一直到8点45过后才给我发短信说才出门,晕,起床收拾了一下,等她过来。然后跟她一起出去,到小区对面吃了早点。好像我跟她都没一起吃过早点哦,以前大队培训的时候,她总是不吃早点,后来虽然一起住,也是到各自所在的区域的食堂吃的,周末一般都是睡过去了,起来后最多找些零食来充饥一下,呵呵。送走小思宇,我便坐317跑到笔架山公园,和同事们爬了山,下来打了一下午牌。之后转去华强北吃自助烤肉,从没去过那儿,在振华路口,叫酋长的地方。一边吃一边玩杀人游戏。居然一把杀手都没当过,不过我自己都觉得奇怪,怎么在猜杀手的时候,我的判断力会这么好,以前跟小思宇他们那帮人一起玩的时候,没这么准过呀。不过有点气人的是,猫猫和雨烟两个家伙,就知道瞎起哄。 3号,没什么事做了,呆在屋子里,看《天使心》,就是《城市猎人》的续集,还是比较合我口味的,看了一天!今天是妈妈的阴历生日哟,妈妈生日快乐!
下班了雨烟问我不去她们那边了呀,我说我同学单位有活动了,我就不跟他去吃饭了,雨烟就说去我们家吧。感动啊~~ 坐班车到了梅林,三下两下到了雨烟家里,小于已经做好了扇贝,准备好了所有的吃的,幸福ing的雨烟!我们一起涮羊肉,肥牛,还有好多好多各种各样的鱼丸肉刃蟹肉饺子等等等等,吃得好满足啊!生菜烫一下吃也是多美味的,hoho~~~ 雨烟说,冬至要吃羊肉,吃饺子。我都吃到了,哈哈。吃饱喝足了,我们谈论起以前江江洗碗的事儿,没想到提醒了疯丫头,这次也硬要洗碗,呵呵。雨烟好可怜,吃了后就开始闹肚子,不一会儿上了两次WC。 雨烟和小于都是好人!嗯,疯丫头也不错,还会刷碗呢,真是疯丫头不可貌相,海水不可斗量呀,嘿嘿!
昨天晚上小妞上QQ了,说起她今天要去阿尔及利亚了,圣诞也在那里过了,还似乎很高兴地说,那里圣诞是要放假的。我说我送你一张电子贺卡吧,她说不干,去年我都是送了她们每人一条围巾的,呵呵。我说这次见不到你了呀,她说春节之前要回来呀。磨不过,呵呵,我说那我留着给你当惊喜吧,嘻嘻。实际上我也不知道送小妞什么东东好呢。 今天整了一天的用例,花了很多时间在写脚本,写一点改一点试一下,其实大部分的工作都是交给脚本去完成了。重复的劳动如果让人去做,很容易使人情绪烦躁并且容易出错。这样的经历让我觉得编译原理和人工智能这些学科很值得学习一下,让我想起网上一部幻想类小说《编出来的幸福》。
hoho~~~这就是传说中的疯丫头,啦啦啦啦~~~
快下班的时候,xcc就给我打电话,说是一起吃饭。于是和雨烟和疯丫头一起坐班车,本来还以为糟糕了,堵车了,还好只是在高速路出口处稍微慢了一点点。到了老地方,xcc在买东西,星期天就要出差去南京了,看他买了个吉利和一包湿巾。xcc女朋友管自己玩去了,就剩下xcc一个人了,我问他去吃什么,他说韩国烧烤吧,疯丫头就很高兴地说,真有品味,晕~然后三个人去吃烧烤了。 中午在食堂吃完饭,去还餐具的时候,只顾着跟小妞打招呼作鬼脸,没看到前面贝克汉超已经停下来了,就一下都撞上去了,被人笑话死了,只顾着看美女去了,呵呵。小妞还在邮件里说我一定很懊恼,呵呵,怎么会,这么有趣的。
中午在公司吃饭的时候,骗了疯丫头一瓶卡士,顺便帮小妞也骗了一瓶,哈哈。 总之,雨烟和疯丫头都是很有趣的人,呵呵。
Category Emulator
终于把这篇也整了,原文在这里,同样,还是有些没懂起的。 游戏驱动by Aaron Giles 可能关于MAME怎样工作的最常见的问题是:我应该怎么编写驱动?为了理解怎么编写驱动,你需要理解驱动是怎样连接到MAME中去的,以及众多的驱动相关的难点是什么。这篇文章向你提供在从最顶层的,驱动需要些什么的概况。以后的文章会讲述这些以外的细节。 开始,你得先看一下driver.c里的代码。实际上这个模块做的,只是生成了MAME支持的所有驱动的指针的列表。问题是每个驱动,需要选声明一下:extern struct GameDriver driver_puckman;extern struct GameDriver driver_puckmana; ... 然后所有的驱动被声明了,我们要这样声明一个驱动的列表:const struct GameDriver *drivers[] = {&driver_puckman, &driver_puckmana, ..., 0 }; 使用C语言来做这事很烦人,因为它需要我们为每个驱动添加2个东西到driver.c,在顶部的一个声明和最底部的列表中的表项。实际上,在用一些好用的预处理魔法去简化这些事情前,我们已经这样做了好多年。如果你是一个C专家,你可能会指出来,也可能不会,没关系。重要的是,要把驱动添加到主列表中,你只要用特定的DRIVER宏这样声明一次就行了:DRIVER( puckman ) DRIVER( puckmana ) ... 这样把表项插入到列表中,和其它表项一起,你的驱动就已经可以被MAME通过主驱动列表正式引用了!当然,这也是说你实际上需要一个GameDriver对象,用在MAME其它的地方,用相同的名字,用于成功地连接到应用中。那应该怎样正确地定义一个游戏驱动? 基本的GameDriver结构非常简单。它提供一个很基础的信息列表,关于这个驱动的,记录了绝大部分的描述性数据(游戏名,制造商,年份等)和指向其它用于描述游戏使用的硬件的结构的一些指针。比起你自己定义和使用GameDriver结构,你应该简单地使用宏来填充所有的细节内容。如果你看一下驱动目录中任何一个文件的底部,你会看到大量的这种宏用于描述驱动:GAME( 1980, puckman, 0, pacman,...
有好些地方看不懂,晕,凑合吧,以后如果明白了,再来改吧!更让我郁闷的是,自己的英语水平真是不敢恭维啊!其实Aaron Giles已经写得很简单了,几乎没有长句!唉! MAME的CPU调度by Aaron Giles 第1部分 MAME中多CPU游戏是以循环的方式进行调度的。循环执行的顺便在机器驱动中根据CPU的顺便严格定义。没有办法改变这个顺序,然而,你可以通过挂起CPU或调整调度粒度来影响调度。那部分内容会在第2部分讨论。 调度器依靠定时器系统工作,定时器系统知道什么时候下一个定时器被调度。所有调度都是在定时器被触发时发生。类似的,当CPU运行时,定时器从来不被触发。这点很重要。 调度器查询定时器系统,找出什么时候下一个定时器被触发。然后它轮循每个CPU,计算CPU需要多少个时钟周期才会到达那个时刻,再运行CPU那么多个时钟周期。当CPU执行完后,CPU核心会返回实际上执行了多少个时钟周期。这些信息被累计,并转换为“本地CPU时间”,这是为了统计是否多用了CPU核心时间,或者过早退出CPU核心。 例如我们说CPU #0是14MHz,CPU #1是2MHz。我们还说我们从0时刻(对两个CPU来说都是本地时间为0)开始,有个定时器在150ms后触发(time=0.000150)。 循环逻辑会启动CPU #0,计算它需要多少时钟周期才能达到0.000150时刻。我们从0时刻开始,我们至少需要运行150µs。0.000150 × 14,000,000 = 2100时钟周期。它就调用CPU运行函数执行2100个时钟周期;当函数返回,它知道多少个时钟周期实际被执行了。我们假设它返回它实际运行了2112个时钟周期。(CPU核心一般会过量使用,因为很多指令会占用多于1个时钟周期。)2112个时钟周期转换为CPU #0的本地CPU时间是0.000150857(2112/14,000,000)。 现在轮到CPU #1运行。0.000150 × 2,000,000 = 300时钟周期。所以我们调用执行(300个时钟周期)并返回300个时钟周期。CPU #1的本地时间现在是0.000150。 现在,两个CPU都已经执行过了,它们的本地时间都大于或等于目标时间0.000150。所以调度器调用定时器系统让它处理定时器。完成后,它再次查询什么时候下一个定时器会触发。假设它很精确地在150µs后触发,time=0.000300。 再回到调度器,我们再次启动循环。CPU #0需要运行(0.000300 – 0.000150857) × 14,000,000 = 2088时钟周期到达本地时间0.300。注意我们统计了上次执行过的所有时钟周期数。所以我们调用执行(2088),然后返回,是2091。这时本地时间就是0.000150857 + 0.000149357 =...
打算研究一下MAME,所以先研究一下Aaron Giles写的几篇文章,英文的看着不是很舒服,所以草草地翻译了一下。这次放出第一篇《Resource Management in MAME》,原文在这里。
MAME的资源管理by Aaron Giles
如果你在写一个驱动,或者给驱动添加状态保存功能,这时了解MAME是如何管理资源的就很重要。 以前,MAME根本不跟踪资源的使用情况的:如果你调用了malloc(),你就需要free();如果你调用了timer_alloc(),就需要调用timer_free()等等。因为标准命令行版本的MAME一次只运行一个游戏,所以当你退出时即使留下一堆已分配的资源也没有什么实际影响。当然,那些移植版本如MacMAME―允许你在不退出的情况下停止一个游戏开始另一个游戏―会因为内存不足或其它资源分配后却不回收等问题引起程序崩溃。 在内核中使用优秀的资源管理有很明显的理由:它只使用不多的代码,并且不会很快地改变。而,在几百个驱动中用好资源管理,简直是个噩梦。驱动通过提供回调函数hook住主系统。下面列表中是一些通用驱动回调函数: DRIVER_INIT VIDEO_START/VIDEO_STOP MACHINE_INIT/MACHINE_STOP 大多数的驱动在MACHINE_INIT和VIDEO_START中分配资源,并且理论上假设它们也会在MACHINE_STOP和VIDEO_STOP回调函数中释放这些资源。实际上,这并不是一定的,这让人很头疼。而且,一些系统会在DRIVER_INIT中分配内存,但却没有比较合适的地方可以释放这些内存。我假设我们应该添加个DRIVER_STOP回调函数,但是最后却是另外一个不同的方案被采纳了。 如果你从逻辑上考虑一下,99%的情况下,你会希望在MACHINE_STOP释放在MACHINE_INIT中分配的资源。类似的,你想要在VIDEO_STOP中释放所有在VIDEO_START中分配的资源。所以,相比要求每个驱动去编写代码完成释放资源,为什么不由内核来简单地跟踪资源分配,并在适当的时候自动释放呢?这样确实可以工作得很好。 如果你看一下这些回调函数的调用顺序,它应该像这样(用伪码表示):init{DRIVER_INITVIDEO_STARTreset:{MACHINE_INITrun-the-game-until-exit-or-resetMACHINE_STOP}if we-exited-due-to-reset thenloop back to reset:VIDEO_STOP}exit
你应该会注意到我在上面的伪码中使用了一组花括号。这会给你一点提示,应该怎样自动跟踪资源的分配-这很像在C/C++中使用局部变量。当离开这个作用域,所有被跟踪的资源在该作用域中被分配的应该自动回收。当你运行到MACHINE_STOP和VIDEO_STOP间的闭花括号,内核会释放所有从前面的开花括号以来分配的资源,包括所有在MACHINE_INIT中分配的东西,同样也会回收内核在那段时间分配的资源。类似的,当你运行到第二个闭花括号时,所有被跟踪的在DRIVER_INIT和VIDEO_START中分配的资源都会被释放。请注意我说的被跟踪的资源。只有有些资源是被跟踪的,另外一些需要显式释放。例如定时器,总是被跟踪的。任何时候你在MACHINE_INIT中分配了一个定时器,它会在你退出内部作用域时被释放。实际上,通过这种方式来跟踪,定时器是不需要显式调用timer_free(),你需要依赖于资源跟踪来处理。 最明显的不被自动跟踪的资源是内存。原因是当调用malloc()后,当离开该作用域时还是有可能需要保留该内存不被释放。你可通过使用auto_malloc()替换malloc(),手动使MAME跟踪内存。auto_malloc()像malloc()那样工作除了它会在离开当前作用域时自动释放。这里你必须小心点,因为如果你在MACHINE_INIT中使用了auto_malloc()并保存了该指针在一个全局变量中,当游戏重启时MACHINE_INIT会被重新调用,那块内存会被释放。你的全局变量仍然是相同的指针值,但内存已经不存在了。正确的作法是不要使用保存在全局指针中的值,而只要简单地每次在MACHINE_INIT回调函数中都调用auto_malloc()就可以了。 另一种通用资源需要被手动跟踪的是位图。有个叫auto_bitmap_alloc()的函数可以创建位图,并在离开当前作用域时回收。 最后一种被跟踪的“资源”是新近才加的:保存状态注册。根据最近的系统的修改,你可以只注册数据到需要被保存到外部作用域(DRIVER_INIT/VIDEO_START)。这是因为如果你点击F3重启游戏,MACHINE_INIT会被调用多次,而保存状态系统不能处理重复注册(我知道,这并不难,但有其它一些更复杂的东西)。为了管理这些,当你退出一个作用域,所有你在该作用域内注册的保存的状态数据会丢失,意味着你需要再注册一次。像大多数情况下,你在MACHINE_INIT回调函数中注册,当游戏重启后你会被再一次调用MACHINE_INIT,这并不是说你需要做什么特别的,只要简单地像什么事都没发生过一样注册一遍,它就能工作得很好。 在之后的文章里,我会讲到关于保存状态的系统的更多细节,所以如果上面这些听起来有点迷糊,很快就能得到更多的认识。
Category Execise Outdoor
今天是重阳节,据说要登高,这个习俗我是去年才知道的。突然想起去年的情景。 去年十一的时候嫌无聊,开始参加网上组织的户外活动组织,一个月要出去2-4次,而像重阳登高这种是纯娱乐休闲级别的,那次是下了班转了几次车最后还是打车去的集合地点的。 时间过得真快啊,就这么一年过去了!
今天去溯溪了,在一个叫马峦山的地方,早上7点半起了床,出门大概8点,之前想得好好的,到梅林关去坐车到银湖汽车站,再转车到小梅沙,可是到了出门了,就突然改变主意了,觉得转车两次也太麻烦了。于是直接到小区对面坐380B,可以直达目的地小梅沙海洋公园。以前没坐过,对需要多少时间也没有什么概念,但总觉得保守估计也是2个小时应该绰绰有余了。结果实践证明,大约1个半小时就够了,可能是因为早上路上车少人少开得快的缘故吧。 大概提前了半个小时就到了目的地,倒是在车上遇到2个同事,他们本来是参加另一个户外团的活动的,就是出来晚了,人家已经出发不等他们了,于是就让他们加入我们的团。 最后出发的时间基本上比预定的晚了近20分钟,唉!这次溯溪路程不长,而且人太多了,中间遇到好几个其他的团的人。这次大概就走了2、3个小时就到了吃饭的地方,结果等到吃饭的时候,又是差不多3个小时后了,而且最最重要的是,味道实在不咋的,而且7个菜,最后还要平均每人25元,划不来啊! 下山就快多了,不过真的是上山容易下山难,路比较陡,而且很滑,得非常小心!比较累,呵呵。
这次是从西涌到东涌这样的路线。以前听很多人说过,就是自己没去过,这次可是切身体会了一把。 本来自己的负重差不多,不会让自己太累到,结果出发前有2个mm把一些水和水果放到我包里了,结果真的重了好多。 今天才知道,原来东涌和西涌也就是两处海滩游泳场,穿越就是沿着海岸线从一端走到另一端。 沿着海岸线很不好走,大半的是礁石,剩下小半的路程是在山上爬,真的是爬哦,我还带了跟登山杖去,没用上,太难走了。中途一mm要虚脱了,于是我发扬不怕苦不怕累乐于肋于舍已为人的国际共产主义绅士风度骑士精神,帮忙背上她的包,果然又重了很多! 非常不幸的是,在从一高处跳到低处时,左脚踩到一块不平的石头上,于是扭伤了。不幸中的大幸是,已经离终点并不远了,咬咬牙总算也坚持下来了。 拍了一些照片,总的说来,海景很不错,怪不得总会有拍婚纱照的要去海边,今天就碰到两对,呵呵。
昨天又跑出去玩了,玩得太high了,一直到后半夜1点多才回到家,对于不久前的我来说,这简直是太让人难以置信了,我不是应该是个宅男么,不是很不喜欢跟人出去high的吗!但事实就摆在眼前,我跟着一群不熟悉,甚至不认识,很多还是第一次见面的人一起出去玩,而且玩得那么晚! 早上像平时上班一样的时间起床,收拾了一下便出门了,先坐317,到了市二医院转58路到武警医院,太早了!当时上了317我就想,这次应该会提前很多时间,果然,317坐了15分钟,58路坐了10分钟,总共半小时不到就到了集合地点了。本该9点才是出发的时间,结果8点10分就到了。 爬山,仍是主题。这次爬山路线就比较隐秘了,那些路应该都是之前爬山的人走出来的,并不像莲花山、梧桐山、南山这种有专门修过的登山道,而且更陡!不过相比那次爬梅林后山,速度要慢一些,而且这次我为了防止重蹈上次梅林后山的复辙,背了双肩包,装了3瓶共1800ml的佳得乐,1包摩卡蛋糕,1包萨其玛,6个桔子,尽量最后没有用上多少。 我们在差不多山顶的地方进食中饭的,我其实没吃自己带的这些东西,倒是吃了别人的一些枣,挺甜的。有3个mm还带了盒饭,式样全都一样,太可爱了。无聊时,杀人游戏是个老少咸宜的活动,但是和不熟悉的人玩,而且玩的规则也不是我喜欢和熟悉的那种,让我捉襟见肘,屡屡失误。 众人都有些疲乏,便不再爬山,直接下了山,快到山脚时,进入了一片高级住宅区,别墅区,里面的保安还不让我们借道,我们只好从外边再绕出去,搞得另一边的保安们也很紧张!下来了,就是银湖公园了,那里没什么玩的,于是众人商量了很久,走走停停商量着,最后决定到八卦岭去吃饭,如果有玩的就顺便玩一下。 结果是到了八卦一路的一家叫大骨仔的店,离吃饭的时间还早点,就几个人打麻将,几个人打拖拉机,然后吃饭。吃饭倒没什么值得讲的,跟所有下馆子吃饭都一样,喝点酒,吹下牛。 吃完饭,人就先散伙了一批,有人说要去洗脚,哈,这是我很喜欢的一种放松方式,就留下,点一下人,刚好4男4女,不过形象真的不好,全身汗臭,背个大包,着装也不整洁。进了一家叫一方山水的店,装修倒是还可以,不过技师水平不怎么样,而且收得也贵点,38一个人,不过有茶和奶茶喝,成本也是这么高上去的。 洗完脚,叫淡蓝色的mm硬是要叫人再去KTV玩,特别是威逼利诱群主,哈哈,开始群主还是很强硬的样子要回家,最后还是经不住淡蓝色的软磨硬泡,于是8个人再赶到华强北欢唱100,同样,装修不过,包间里还带卫生间。几个人唱起了歌,我就跟淡蓝色几个人玩起骰子,不过我玩不过她,郁闷,开始单玩的时候还好点,有个更差的人垫底,后来分组玩的时候,就惨了,不停地输,不停地喝,喝得我撑死了。 大概high了3个小时吧,终于决定回去了,毕竟第二天还有些人要上班的,包括我。打车回家时,我身上的现金已经不剩下多少了,还好是与人拼的走的,可以不用付这全程的价钱,回到家,1:14!
本来没打算去的,直到今天中午的时候还没想要去的,结果下午的时候偶然发现飘飘在QQ上,就聊起来,于是被她鼓动了。 下了班,匆匆去取了点钱,然后先坐车回家换衣服,飞快地再坐小巴到梅林关转车。结果给飘飘打电话,说还没出门,晕,于是我只好自己一个人先去了。爬上370,到北大医院下车,在附近转了转,没发现可以吃饭的地方,于是只好在莲花山公园入口处的书报亭买了包豆干来充饥。还没看到大部队,于是在门口随便吃了起来,几下就解决掉了。 过了没多久,看到阿金,于是走过去,倒是认出几个人来。爬山之前等了很久,因为有很多人一起来。 莲花山本来是很矮的,一小会儿就爬到顶了,所以估计也是出于这个考虑,我看领队的故意绕了好些路走,直到我出汗了,说起来今天还是很凉快的,而且结果我的那瓶脉动被飘飘解决掉了。 还是很快,就到了山顶,人山人海啊,我直到今天才知道,重阳节是要登高的,汗!人太多,只是拍了几张照片,便下来了。到中途吃水果,似乎是有吃西瓜的习惯的,连拍照的时候喊的都是“西瓜甜不甜”,呵呵。 吃完水果,因为时间、天气等原因,安排到公园门口集合,然后要吃饭的一起再去腐败。那一带我不熟,被他们带去一个湘菜馆,吃的当然是最普通的湘菜,当然吃什么不是最重要的,重要的是认识一些人,大家互相介绍一下,我还是第一次这么庆幸当然给自己取了这么一个特别的网名,哈哈!
今天是我第一次出去参加这种社会性质的户外运动团活动,吃了没经验的亏,当时没有准确估计行程,只买了一瓶脉动便跟人上山了。当时也是不了解,单纯地以为只要走个十几二十分钟路就可以了,谁知是足足4个小时,从上午10点开始,一直到下午2点,可怜我连早饭都没吃,到12点多时,那瓶水就喝完了,然后就又饿又渴又累地翻山越岭,又不好意思开口向别人要水,毕竟是不熟悉的人啊,忍了近2个小时! 到下午2点过一点点的时候,终于到了吃饭的地方,最急着解决的事便是解渴,跑到自来水笼头那里,估摸着那水是山水,确实没有那种自来水出来的消毒水味道,大口喝了好多,还是不解渴,又买了2罐百事,没办法,没有其他适合的饮料。 那些菜的味道倒真是不错,那汤也好喝,就是量不多,也过钱也不多才一人给了25块钱。到下午4点的时候就出发返回,这次走的路就没有之前那么困难了,都是平缓的石板路,跟着几个人一边走一边聊,还没觉得不适,前面那段路上我都没怎么说话,连拍照都只是照了几张风景,返回的时候倒是拍了些人物的。 我还是内向了点,不知道怎么能挑起话题,唉!
说起来真是惭愧啊,去年办的一张半年卡,到现在为止5个月了,总共去了不到10次吧,就算是10次,也是很亏啊,¥120/次,真是奢侈啊。今天一天都在屋里度过,室友问我去不去健身房,我想再不去人都要发霉了,于是说吃过晚饭过一会儿再去。 晚饭是在屋里做的,我只负责用电饭锅做饭和生炒了个青菜,很简单的类型,呵呵,吃完饭后就觉得困了,然后就坐在椅子上睡着了,一直睡到8点半,才动身去健身房。 很久没去了,身上肥肉又长厚了一层,跑了15分钟,累得要死。
昨天算是项目部年终活动吧。 上午跑去南澳打野战去了,是用激光感应的那种,不过感觉不好玩,对着打都没反应,一点真实感都没有。中午在那儿吃饭,说实话,饭菜的味道也很一般,倒是那儿的风景还真怡人,很适合像我这种人偶尔去去,放松一下心情,拍了一些照片,可怜我的T200当时买得也太冲动了,不但贵,还浪费资源,总是闲置着。 下午跑到海滩边搞拓展训练。说是训练,其实娱乐成分更多一点。先是让我们在10s钟内尽快拍手,我当时还估计大概能拍25下吧,结果实际上好像是拍了75下,大大地出乎我的意料,还有人声称自己拍了八九十下的,应该也是有可能的。还有个活动是看4个人光是用各自双手食指,就把1个胖子顶起来,也是很让我吃惊,很多时候只要方法得当,看起来不可能的事情还是被很轻松地完成了。接着我们18个人玩盲人方阵游戏,要求是所有人在30分钟内在蒙着眼的情况下,用2根绳子分别围成一个正方形和一个内切圆,并且要求正方形各边上的人数对应。结果据说我们是用了31分钟完成的,看完成后的效果似乎还不错。中间有一段混乱,也是必然的,缺少精细而有效的计划,并且缺少强力的领导。不过总的说来还是完成了,那教官还说我们是他看到的这么多HW队伍中最出色的了。我现在想想,觉得这也是可能的,我们算是测试的人,很多人却做些开发的事,所以两种人的特点都会有,对于发现问题、解决问题也就更可能会有直接快速的观点和方法了。再后来,就带我们去高空断桥,也就是八九米高的地方,从一边跨到另一边。我是第一个上的,当时隐隐有点儿兴奋,到了上面,架子晃起来了,就有点儿怕,于是不管三七二十一,就跨过去了,到了中间那段,晃得更厉害了,直没站稳掉下去,还一个劲地想站稳,结果还是不行,最后忍不住了,不稳也冲过去了。后来看别人跨的时候才意识到,这种事情应该是一开始就一鼓作气一路冲过去,在还没意识到恐惧之前,就已经完事了,呵呵。像我这样晃了好久,还试图让它不晃,根本就是白费力气。 这拓展训练,还是略有收获的。
上周六下午无所事事,就跑去健身房耗了一个小时,本来只是跟以前一样踩一下车,跑一下步的,后来去做了几个仰卧起坐,要求是做4组,每组15个,结果我只做了2组就做不下去了,后来好不容易又死撑了10下。当时就觉得挺虚的,就偷偷逃回家了。过了一晚上,腹部上的肉疼得站直不了了,像是要被撕开一下。今天还是痛,虚啊,听室友说他上次这样痛了3天才好,晕!
今天就为了要不要去健身房,犹豫了好久好久,一会儿决定去,一会儿又想不去了,一会儿又决定去,最后终于还是去了,实在是不好意思哇,哈哈哈哈。 早上去上班的时候,下了车居然看到疯丫头,这世界真是乱了。原来她早就搬到F3来了,只是我不知道而已,呵呵。
我怕我会坚持不了几天的,呵呵。还是比较累的,不知道消耗了多少卡路里,很少出这么多汗了,还说我脂肪多,这好像是事实,看我腰腹部的赘肉就知道了。
我真是头脑发昏心血来潮,居然会去办健身卡。光是看我长的这模样,健身这种事情怎么想都联系不上来,但我真的真的去办了张健身卡,半年的无限次数卡,1180元就这样花掉了。现在花钱越来越大手笔了,可是赚钱的能力却不见提高,反而是同类中最差的。 在健身房称了一下体重,据说是72KG,昨天晚上吃过火锅,去小思宇屋里称,是71KG,反正无论哪个准一点,比起过年刚来时,都轻了,我就天真地认为这是近三个月来吃素减下来的。 顺便说一句,这个健身房的女经理身材好好哦,不知道是不是练出来的,是我见过的人中唯一可以和疯丫头拼一下的了,当然疯丫头那应该是天生的,瘦出来的,应该没练过吧,呵呵。
没有艺术细胞呀,四肢僵硬呀,肥肉丛生呀! 摇滚步,战斗舞,排腿,结束动作,hoho~~~
Category gfw
使用CoreDNS有不短的时间了,之前也通过自己编译修改版CoreDNS来解决DNS污染的问题,不过后来因为没解决好go module依赖的问题,在官方CoreDNS某次commit后修改版就编译不过了,这样持续了一段时间,直到前几天,我又偶然尝试修改了一番,终于又可以编译过了,于是动了继续增强CoreDNS功能的念头,经过几天的尝试,目前有点小成果。
之前提到科学上网为不同目的IP走不同的线路,导致加了16000多条iptables规则,太大的iptables表将会导致路由器性能下降。
前段时间路由器莫名其妙起不来之后,折腾了一下tun2socks,虽然在macOS和Windows上都能勉强工作,但总觉得操作麻烦,有一天我在MBA上用完后没有恢复路由表,第二天家里妹子就告诉我好像网坏掉了(手动狗头。所以最终还是需要在路由器上解决这个问题。
本来由于使用网关的方式进行科学上网一直工作得比较稳定,所以很久都没折腾科学上网相关的东西了。前不久用了几年的Banana Pi突然连不上了,通过socks5+pac的方式也勉强应付了。今天回到老婆娘家,发现两个月前还工作得好好的树莓派不知道什么时候已经点不亮了。不禁感叹ARM板似乎不太耐操啊,以后还是尽量只用x86的工控机之类的吧。
我之前整理过在国内搭建无污染DNS的一些方法,github上各种轮子也层出不穷,但基本原理几乎不变。自从半年多前开始用CoreDNS,我觉得可以不用dnsmasq/overture/chinadns这些轮子了,CoreDNS完全符合我的需求:
昨天在喵帕斯tg群里看到一张HAProxy的截图,经过了解,原来是梅林固件自带的,真是不错的想法。
DNS污染主要是两种,一是丢包,二是抢答,两种方式基本上无规律出现。做纯净DNS解析基本上就是为了解决这两个问题,现在主流的方法大体有以下几种:
今天回老家了,老家用的是便宜的移动宽带,之前用着也没多不爽,因为也一直没怎么用,就是用来看小说了,虽然也发现移动的墙要高一些,但也凑合着过了。
悲剧地发现10多个SSH全都挂掉了,包括一个付费的,虽然这个付费账号是别人送的,超期用了一年多了。于是只好另想办法。GAE是用得很多的一个免费方案,goagent也听得多,看了一下项目主页,惊讶地发现它居然支持Windows/Mac/Linux/Andorid/iOS这么多系统。
部署过程不复杂,连建了4个id,修改hosts把域名指向一个国内的IP,速度也不错,看youtube很流畅。我的iTouch和iPad上都是用GFWInterceptor的,基本够用,于是暂时不去折腾它了。
所谓道高一尺,魔高一丈。虽然blogspot.com不停地被GFW封掉,但当时还有pkblogs.com和inblogs.net来作转向。可是现在,连它们两个也惨遭毒手了,GFW真是越来越过分了。不过它没有过分到像几年前那样,把google也封掉,所以为了突破GFW的封锁,在 google上搜了一遍,还真找到一些方法。 这些方法的只限于如何访问blogspot.com,因为实际上,后台blogger.com好像一直没被限制。其实比较好的方法是,自己弄个域名来转向。还有个方法是,用BloggerSpaces的服务。不过有更简单好用的方法。一个是利用 google的translate服务,先翻成繁体中文,再翻成简体中文,损失不是很大,只是要用一个长长的URL,以及对用非中文表示的文字,中间的空格都会被删掉,影响原意,还有个缺点是,当鼠标光标移动到文字上方时,会自己选定一段文字,弹出一个消息框来,比较烦人。再有一个方法,就是改浏览器设置。先把这段代码保存到文件(假设为c:\proxy.pac): function FindProxyForURL(url,host) { if(dnsDomainIs(host, ".blogspot.com")) { return "PROXY 72.14.219.190:80"; }} 以Firefox为例,打开Firefox,依次点击Tools->Options->Advanced->Network- > Settings...->选中Automatic proxy configuration URL,在下面填写:file:///C:/proxy.pac。这要,就可以直接用missdeer.blogspot.com来访问啦。如果是IE,也是类似,Tools -> Internet Options -> Connections -> LAN settings -> Use automatic configuration script, 再指向文件,要填成file:///C:\proxy.pac。 唉,不过这样的方法都只有我自己知道了,真是悲哀啊,只能自娱自乐了。...
Category Reading
前几天粗略翻阅了一下《七周七并发模型》,这是本从v2ex上收来的二手书,虽然算上快递费也并没比新买一本便宜多少,但是知识是无价的,呵呵。
有个同事,平时看我在公司里用手机连公司的WIFI,很是眼热,一直问我怎么用。我就告诉他,要装个ProxyDroid,而且手机得root先。这样持续了将近1个月,今天他突然跑过来对我说,都怪你都怪你,现在我的手机刷得只剩下闹钟了。原来他的HTC G12昨天被他用什么一键root软件强行root,结果不能启动WIFI了。于是今天中午和另一个同事一直在OF外面折腾这手机,希望能恢复WIFI。结果还是没有什么进展,而且最后从网上看到,似乎他的G12是所谓的木马机,笑死了。
今天看到,豆瓣推出阅读器了,除了Web版和iPad版,毫不意外地有Kindle递送服务。说起Kindle,之前有一段时间我非常想买一个电子书,当时只考虑了1000出头的Kindle3和500左右的Bambook,不过好在每当一有这种强烈的购买欲望时,都有一股理性的声音说,你不是个爱看书的人!然后就拖到现在也没有买。自从上次去上海图书馆,亲自把玩了一会儿Bambook,非常庆幸自己没有一时冲动买了这么个设备,这页面切换的速度太慢了,效果太难看了,版式也很丑,啧啧!不知道Kindle到底怎么样,得找个地方也亲身去体验一下,才能决定到底能不能符合我的要求啊。
自从两年多前从老东家辞职以来,这是第一次进图书馆吧。
交了100元押金,办了张普通的借书证。用RFID技术的整个图书馆流程上基本可以做到无人值守也能很方便地运作。
去一楼的中文图书外借馆里看了看,书并不很多,甚至感觉跟以前我读的那大学,以及以前那那东家的图书馆里的藏书差不多多。可能这里的特色是古籍,珍本,孤本什么的收藏多吧。另外,几个阅览室里的座位也并不多,而且无一例外的是没有空位的。
总之,比较失望。
辞职前,还计划在到年底前的3个月里好好读一下买来的那么多书,可是事实是回来这么些天了,还是没什么动静。 那时的计划是要读一本市场营销原理的书,一本经济学原理的书,一本心理学原理的书。之后再是读一遍已经买的“图灵”系列丛书,主要是想把实现模式、设计模式、面向对象程序设计以及重构这4方面的内容结合在一起,以提高自己的水平。 近两周来,我没基本看过一本书,我觉得应该调整一下,慢慢地看也好,每天看一点点,但要做笔记,或者写心得。这是最近让我觉得比较迷惑的地方,前段时间要写重构相关的幻灯片,可是虽然我读了《重构》,但在写幻灯片的时候却只能抄书上的内容,这是让我觉得很不爽的一件事情。我觉得心得,主要应该是自己结合原书内容得加以扩展、延伸的内容,而我现在却写不出什么东西来。在之后的读书过程中要努力改进啊!
看到一篇义愤填膺的博文,正气浩然。又看了一下文中的链接,一篇广告帖引起的口水仗。不过倒真是看不惯那作者的作法,死不认账。又看到其他人的跟帖,我不禁庆幸,幸亏我不是做网页的! 不过说到底,我的专业领域C++方面,应该也是有这种问题的,不过我自己没怎么接触到而已。在我准备大举进入本行业之时,有候捷在那里做了不少出色的教育和科普工作,从此弯路就极少走了,想看的书,基本都是挑公认的最顶尖的专家写的最优秀的书籍。而过了那么一小段时间后,自己也基本上具备了识别并挑选出优秀书籍的能力。 不过今天看到那些讲什么ASP、AJAX、JS的书,我还是很庆幸,那个行业似乎比C++的混乱多了啊!
书在桌上摊开好几天了,不过一直没有投入进去用心读。今天似乎也有点闲了,于是认真地看了一会儿。这本书在去年《软件调试》上市做宣传的时候就已经听说了,还花了点时间去网上找过英文的电子版本,尽管后来发现公司网上很早前就有人发过了。找来英文电子版也就纯粹是满足一下心里那种奇怪的怪癖吧,而从来没有开始看过。 今天读来,发现《Windows高级调试》和《软件调试》基本上两本没有交集的著作,但在一定程度上却是互补的。《软件调试》着重的是原理和底层设施的介绍,而《Windows高级调试》则注重实践,应用各种现有的软件工具,调试各种软件问题。由此联想到另外一本书《Windows用户态程序高效排错》,该书则是案例形式,内容显得比较零碎,不如《Windows高级调试》那么系统化。 最近几个月来,在负责项目组内的core dump文件分析工作,由此才对该领域开始重视。一直以来,都是依靠WinDbg的!analyze -v命令进行分析,如果它能打印出最后的调用栈,而且调用栈又能比较明显地指出出错的源代码行,我才能连猜带蒙地得出一个定位结果并以此指导问题修改。但这样的好事并不多,大概还有3层左右的core dump直接靠!analyze -v是得不到那么明显的信息的,于是对这方面的技能要求就高了。 今天又从一个同事那里得到一个ppt,里面是公司一个传说中的core dump分析组的演示,原来还怀着比较崇敬的心理希望能从中学到那么一招半式的,结果从头到尾翻了一遍后,发现他们就是直接调试的debug building,让我比较失望,同时更是有些不屑,不过如此嘛! 最终还是得靠自己呀,总之看了《Windows高级调试》一书中对于“栈”的调试那部分后,我隐约觉得,在这书的指导下,加上这么多的实践机会,应该能让我在分析core dump的能力得到很大的提高。
这两天闲暇的时候,翻起Kent Beck的《实现模式》。Kent Beck也算是世界有名的编程方法论方面的牛人了,这本薄薄的《实现模式》买了几个月了,这回翻起,才明白过来“实现”二字的含义,这不是一个动词,而是一个名词。与设计模式相对应的,有设计,然后有实现,既然设计可以有模式,那么实现也可以有模式,原来是这个意思! 不过我仍然没有耐着性子把书看完,只是快速浏览了一下目录以及前半本的内容。书的主题不是一个新鲜的话题,但它的切入点却是比较新鲜,居然也套上了“模式”,倒也是一种可尝试的方法。这书的目标是为了帮助程序员可以写出美观优雅,易读易懂的代码。作者把这个主题分成7部分来讲,每部分是一个大的分类,各自包含一些模式。从我自己对已经读过的部分来看,大体上作者的目的是能达到了,至少有不少条目我看了就觉得很有道理,心有共鸣,而且相比GoF的《设计模式》来说,这本《实现模式》无论是语言表达,还是技术内容,都要浅显易懂得多。 觉得有点缺憾的是,该书中例子代码实在太少了,而且缺少对各条目的应用场景,作用,使用限制等方面的描述,不过如果加上这些内容,也就不是这么薄薄170多页可以解决了的。
这书买了有一段日子了,但一直没有拿起来读过。几年前,也从公司的图书馆里借来过,好像那时候还在测试组吧,只是网上吹得厉害,于是就好奇地借来看看,结果完全不知所云,还暗骂网上吹的人不厚道。直到最近,一个同事以为自己把图书馆里借的那本搞丢了,在那说说,于是我又好奇心起,拿来翻了翻前面几页,发现讲得真好啊,原来以前是自己水平不够才看不懂的,于是上网买了一本。 我有这样的坏习惯,书借来的时候觉得挺好挺有用,于是自己去买,买了来就丢一边了,好像里面的知识已经掌握了似的。这次也不例外,但是昨天不知怎么的,拿出来,以最近最认真的状态看了两章,有些收获,只不过,这一年多来,沉迷于网络小说,实在静不下心来认认真真做些有意义的事呀!
这两天都是干点儿活,看两眼《Exceptional C++》,看得我异常郁闷!这是一本老书,讲的内容也都是我没关注过的,可能也正是这个原因,使得我看起来非常吃力,老是觉得不知所云,偶尔看到一些似乎有点儿明白的“原则”之类的tips,也是翻过一页立马就忘了,而更多的时候是不知道为什么要这样。 极度郁闷啊!
几天前突然想起Intel似乎是在网上可以直接申请指令手册的,大学的时候就申请过,不过都没看直接在毕业离校看给一个老乡师弟了。现在想起来可能会搞点跟汇编、CPU、指令集相关的东东,所以又想弄一套来。 先在Intel的网站上找了一下,没找到相关的链接,于是google一下,还真能搜出来,以前可以直接在网站上填张表格就申请好了,现在是只能发邮件。于是照着示例写了个邮件,马上就有一封回信了,大致意思说是申请已经提交了,等fedex寄出后,还会发个邮件。结果等了好几天都没什么邮件,还以为中途出问题了。又等了几天,收到一个邮件说7月7日就已经寄出了,但我去fedex的网站上却查询不到。 今天公司里,收到一封邮件,说我有快递,我猜也就只可能是这书了,跑去投递中心一看,果然是,好大一箱,比上次的还大,有点儿重。回家拆开看看,每本都是厚厚的,但重量却比想像的要轻不少,都是一棵棵的大树啊! 估计我还是不会怎么去看的吧!
心血来潮地翻出照例买来即束之高阁的《C++网络编程》,尘封不止一年了,只记得还是在测试组时买的,而且确实连目录和序都没看过,汗! 这次也是因为项目里用到了ACE,看了一点《ACE程序员指南》(所谓的红宝书)中关于reactor中的一点内容,似乎勉勉强强可以凑出一个能用的系统了。才偶然想起,仅有的3本讲述ACE的翻译成中文的书我都有了。拿出这卷1和卷2,发现封面都泛黄了,这日子过得还真是让人哭笑不得! 不负责任地说一句,这两卷《C++网络编程》其实是套讲设计的书。书中以网络编程这个话题为目标,用C++这把究极神兵,辅以设计模式这高等心法,大刀阔斧地讲述怎样设计,为什么这样设计,最后凝结成ACE这套演示成果。 所以在我看来,这两卷最终成为学习使用ACE的入门及进阶的参考书籍,这样的效果只能说是原本功能的副作用而已。
从china-pub上买了本《软件调试》,厚达1000多页的大砖头。开始拿到的前面有8页是空白,到china-pub上去说了一下,该书的责任编辑通过email跟我协商,最后又快递了一本正常的过来,我再把有问题的那本快递给她,如此服务质量,也让人称心满意了。 难得原作者用中文写成,这样就可以让我们中文读者第一时间可以读到如此重量级如此深度的精品专著。 该书从CPU(Intel x86系)对软件调试的支持、操作系统(Windows)对软件调试的支持、编译器(MS VC)对软件调试的支持三大方面进行了讲述,中间结合VC、WinDbg等实例进行讲解。 昨天晚上躺在床上,快速地浏览了一遍,让我深深感叹Windows,噢不,应该是微软的强大。微软从操作系统到开发工具,都为软件调试支持了极其强劲而且方便的支持,窥斑见豹,微软做软件是多么认真,多么负责,微软帝国的崛起除了机遇外,其自身实力和不懈努力是起主要作用的。 翻完这本书,我禁不住想自己写一个应用层的调试器,像OllyDbg那样的。粗略想一下,一个调试器需要具有的最基本的功能:反汇编、CPU寄存器读写、内存读写、单步、断点,以及跟系统相关性比较大的装载模块、内存映射、符号信息读取。这些在Windows上绝大部分都有现成的API可以完成了,除了反汇编比较麻烦点(看看IDA Pro做成什么样了,当然动态调试器是不需要这么复杂的),其他的至少从原理上看,是很简单的,困难的是细节。 嗯,WIND Is Not Debuggger……
今天上午连续接了两个奇怪的电话。已经有几次了,打到什么布吉五金商行的,结果打到我们这个座机上来了,不过有趣的是,这次这个家伙没有直接挂掉,而是跟我扯起来,说什么交个朋友,有没有兴趣出来干,呵呵,感觉像是个人贩子似的。好不容易挂掉电话,马上就有另外一个人打进来,听背景声音跟前面一个是同一处,但听口音,明显是两个不同的人。这次这个也比较有趣,问我们公司现在招不招人,有什么岗位,待遇如何等等,还说是不是研发的都是高学历的,水平很高的,呵呵。又是好不容易挂上电话,手机又响了,这次是当当网送货的了。蹭蹭跑出去,发现居然是在岗亭门口的一个小角落里,而且看货有好几箱,而送货的只是一辆小自行车,真不知道他怎么把这么多书载过来的,混口饭吃也不容易啊。 打开看了看,建筑类的几本书的纸张质量还真是不敢恭维。《Head First Design Pattern》外面有一张塑料纸包着,好厚一本,拿回家翻了翻,有点后悔,价格定那么高,里面的篇幅实在没多少,很多的插图,很多的空白,浪费啊,看来我还是习惯那种适合苦读的典型的中国教科书啊。《建筑模式语言》有上下两册,精装的外壳,很厚很厚,但里面的纸张远不如《Head First DP》,《建筑的永恒之道》不是很厚,而且不是很大开本,不过奇怪的是,想不到建筑类的书居然也定价那么高。
还是没干什么事,看了一阵书,话说昨天把《设计模式解析》第二版还掉了,其实旁边的同事又马上借回来了,于是乎我就拿来看看,看得囫囵吞枣的,不过也比直接看GoF的要省力得多。其实一直以来我都很少会认真仔细地从头到尾看完一本技术类书籍,很多书甚至是只看了前言、序,或者目录就直接丢到一边了。虽是这样,就算没完整看完一本书,像那种武侠小说中描述的那样,像我这样的小虾,向大师学习时,能领悟到个一招半式也是受用无穷的了。 到今天为止,大致了解了Adapter、Facade、Bridge、Strategy、Abstract Factory这几种模式。简单地说来,Adapter是为了转换接口,Facade则是为了封装并简化接口,Bridge说是把抽象和实现解耦,在我看来,实际是把几种不同类的概念分类,避免组合爆炸,Strategy是为了封装算法,Abstract Factory则是封装一系列相关的类的实例化过程。在阅读《设计模式解析》的过程中,我还发现一个比较明显的现象,有些模式,或者说有些解决问题的方案,其实都是通过将问题细化,将较细粒度的变化进行封装来实现的。比如书中讲述Strategy模式时,一开始例举的是直接继承,在论述了该例的缺点后,才抛出新的方法,其实就是把更小更精确粒度的变化提取出来并进行封装。在讲述Bridge模式时,也有类似的倾向和做法。再回想《重构》一书中,作者Martin Fowler则是更激进的做法,如果要给一段代码添加注释,则把这段代码提取出来,用有意义的函数名来阐述代码的作用。这从另一角度促使了小粒度代码段的生成。 《设计模式解析》一书的写作风格也是让人比较舒服的。作者会花一些章节进行理论或实际例子的讲述,再用一些章节描述模式,再讲述一些通用的理论,如此穿插的作法,反正我书看得少,正是第一次看到,感觉比较容易让人接受并领悟。
我就是缺乏定力,就是忍不住去做些无聊的打发时间的事情,就是不愿意去做些有实际意义的事情。早上起来就觉得很烦躁,也不知道是哪里出问题了,仔细想想好像也没有什么重要的事情,但总是静不下心来。 白天在公司里糊里糊涂地过了一天,看了一点书,《设计模式解析》,书写得还是比较合我的口味的,不过下午的时候去图书馆,把这书还了,因为快到期了,以前没怎么看,后来觉得有用的时候,却是借期快满了。虽然只看了前半本,但也觉得略有斩获。前半本有不少内容是通用性的概念,有些概念我一看就觉得就是这么回事,不过自己却肯定总结不出这么精辟的来。
《重构》中文版一直都放在公司电脑前,随时读上几页。有时不觉会为其中的精妙之处深深折服,大呼过瘾。看着一种一种的重构手法,该手法的使用场景,不时会有深有同感的感叹。 有些情况下,自己写的代码,写着写着,自己都觉得很不爽,但不知道问题出在哪里,功能是可以实现,但总会觉得不舒服,又不知道如何改进。在读《重构》时,就很可能能遇到甚至一模一样的所谓bad smell。 今天偶然跟同事谈起,我已经不再喜欢看跟语言相关的书了,同事就略带玩笑的语气说,这是架构师才会做的事。确实,我已经不再满足于那种与特定语言相关的奇技淫巧了,我更关心的是如何写出更少bug,更多弹性,更易理解,更好维护的代码。 但是在读这些书的过程中,我还深深地体会到熟练掌握并运行设计模式的重要性。现在的我,对设计模式几乎一无所知,能产出的代码也是最简单的过程化结构,往往能在最早期的时候快速写出一些代码,但后续的维护和扩展却越来越困难。从读《重构》一书中,体会到,也许只有设计模式,才能解决我目前所遇到的这些问题。不然,即使能看出问题所在,但不能运用正确的解决方法,依然是毫无用处。
这两天在看Martin Fowler大牛的《重构》,之所以不写是《Refactoring》,是因为我看的是jjhou和gigix的翻译版。《Refactoring》我已经买了两年了,基本上没拿出来瞟过一眼,也幸亏没瞟,前些天偶然拿出来翻了翻,发现里面的用语太偏了,n多不认识的单词,汗颜!不像《C++ Templates》,当年每天早上翻几页,居然也看了十几章。 《重构》一书由jjhou和gigix来翻,质量上基本还是可以保障的,反正感觉比较信得过他们两人,至少应该极少可能会出现翻错的情况吧。也幸亏是看这本中文版,让我对那些个古怪的名称有了比较感性的认识。 Martin Fowler大牛在书中罗列了几十种所谓的坏味道(bad smell),然后简洁地描述了一遍针对各种坏味道可以采取的措施。我现在也才看完这部分,但马上发现,要能在项目进行时重构,在个人技能上需要能嗅探出坏味道,在工具支持上需要有像VAX这样的辅助,在开发方式上还需要有TDD之类的有效质量保障体系支持。第一项,通过对该书的学习,以及之前的积累和以后的长期坚持,应该不成问题。第二项,现在新版的VAX都是有支持的,以前用VAX基本只是用了它的自动完成提示功能,现在才发现这个Refactoring菜单项的功能是多么强大多么好用。第三项我就有点迷茫和动摇了。其实有时候我也想用TDD的,可是一方面总感觉信心不足,写Test case本身就是一件很花时间的事情,我不敢保证这个投入是否值得,另一方面我现在基本全是用C++/MFC写程序,绝大部分代码都紧紧地跟界面耦合在一起了,要用CppUnit来还真不容易,除非先重构一遍,把所有业务逻辑都提取出来,再用CppUnit来进行测试,但是如果真要通过UI来跟用户交互的怎么办呢?这个我暂时不知道应该怎么做,但如果不用TDD来进行重构,感觉有点形似神不似,而且重构后的代码质量也不好保证,所以还是得尽量往那个方向走。
这几天回顾了一下,发现自己兴趣转移了,对那些重构、敏捷开发、设计模式这类主题感兴趣了,反而对以前似乎很有兴趣的纯语言技巧之类的东西没什么兴致了。本来我也不会注意到自己有这样的变化,只是最近在找书看的时候,不知不觉地不想看那些语言的高阶技术书籍了,也许是自己写代码的数量到一定量的时候,就会有这样的转变吧,就会潜移默化地开始关注设计问题了。 今天先在图书馆网站上看到有《重构》中文版了,马上跑去,终于借到了,哈哈,真开心啊!简单快速地浏览了《重构》的目录,发现这书很值得从头到尾细细看看,里面讲述了各种类型的bad smell,还有几十种相关的refactoring方法,我自己觉得对于我现在的水平应该有很大帮助。今天又发现,VAX1559版里已经集成了比较实用的重构功能了,真是太好用啦,原来只是用一下它的rename,今天才明白,其余的这些功能都很有用,大大简化了重构操作。配合Source Monitor的度量功能,重构简直是一种享受! 看了几页《重构与模式》,很遗憾地发现,要先懂重构,懂设计模式,再来看这本书才能有所收获,不然就是一头雾水啊。所以,先好好看《重构》,还有《设计模式》和《设计模式精解》,这就作为最近一段时间的学习计划吧!
春节放假前就在看了,这书我早就买了英文版,那时意气风发,还以为自己能忍住煎熬看完的,结果没看几个字就束之高阁啦。这回从公司图书馆借来的中文版,居然还能坚持下来看,真是书非借不能读啊,哈哈。不过我也没有全部仔细看完,只挑了中间自己现在感兴趣的,有点关注的主题看了看。总的说来,这书对我的启发意义还是有点大的,对于程序设计方法,软件架构等都有不少的教育意义,觉得还是多有收获的,呵呵。 这书完稿于2003年,所以今天看来,有少许内容有点过时,没有及时刷新,但这并不妨碍它在总体上成为一本好书。最后几章的内容我就没看,看了一下标题,觉得没多少兴趣。 最近对程序设计方法、需求分析之类的主题比较感兴趣啊。接下来要看看重构、测试驱动开发、设计模式方面的书啊!可是可是,我那本《敏捷软件开发》被老大拿走了,他怎么能这样呢!
不容易啊,看网站上说1月15日就全国同步发行上市了的,结果我天天逛那些个小卖部,还去其它卖书的地方看,就是没看到。今天中午吃过中饭,跟疯丫头去食堂一个平常都没去过的小卖部,偶然发现那里居然有卖了,不禁有些欣喜。现在定价是¥45,在我的意料之中。想都没想就刷了卡,买回来随便翻了翻,发现这次的合订本纸张质量很差,闻一下味道也不好,没有那人让人心旷神怡的墨香,感觉像是盗版的,晕死,不过看那附着的DVD,觉得应该是正版的,呵呵,盗版的也不会这样明目张胆地放在公司小卖部了。 快速浏览了一下目录,感觉没什么特别感兴趣的内容,不知道是我自己的品位发生了变化,还是这个杂志确实做得越来越不对我的口味了。不过我也不是很放在心上,反正平常确实也都不买月刊了,最多拿别人的看一下,或者索性在小卖部里看,呵呵。
Category Driving
国家大力推广不停车支付过路费,虽然我高速跑得不少,但我一直嫌麻烦没去安装ETC,从新闻上看到有些省份已经试行微信支付和支付宝支付了,像上海的虹桥火车站、机场停车场我在支付宝上绑定了车牌后,也可以自动感应支付了,结果到现在也没等到这两家侵入到这边的高速公路收费站,倒是等来了年底普及ETC。
中秋回家的时候闲得无聊玩手机上百度地图,偶然发现8月份居然突然多出10次违章记录,几经查询确认,是那段时间经常早上上班时顺便往那边买早点然后走到单向行驶的路上逆行了。如果不是闲得无聊,怕是要这样被抓几百次了!
昨天跟小师妹约好的一起回去,今天早上8点半到了她楼下等她,结果居然电话都关机了,幸亏知道她同屋的室友的电话!原来小师妹还睡着,囧,睡过头了。幸亏我买早点的时候也买了她的份,等她下楼下已经9点半了。
不知道是不是因为放假的第一天,在上海的第一个收费站那里就慢慢吞吞地堵了大半个小时,真是烦躁。我们是要去杭州市三医院的,不过很郁闷的是,在高速杭州北路口拐出去后,就找不到方向了,导航也太蠢了,老是指向不知道什么地方。问了收费站的工作人员市区怎么走,好不容易到了市区,但又不知道怎么往市三医院方向走。在高架上走了一阵子,太堵了,小师妹很生气,后果很严重。我毅然决定下了高架,问了一个的哥,结果的哥居然说走高架本来是可以到的,不过好在他又帮忙指了另一条路。后来又问了个的哥,终于找到了市三医院,没想像的那么大,还找不到停车的地方,更郁闷的是停车的时候又刮到了,唉!
从医院出来大概是一个小时后了,即使有导航,还是有点提心吊胆的,不过这次似乎没怎么乱指,上了高速就好说了,但又有了另外一个问题,油不够了!小师妹说,怎么跟我出来尽是遇到意外情况啊。终于熬到绍兴界的服务区,加了油,之后总算是熟门熟路了。送了小师妹回家,我再自己回家,到家的时候已经快7点了。一天开了8个多小时,还真是累啊!
刚才有那么一刹那,突然很害怕,不知道今天做了什么,几秒钟后反应过来,今天出门了,去办入沪车辆通行证了,现在这记性,真让人无语。
总的说来是比较顺利的,昨天在网上看过大致的要求,今天先跑去东关派出所,这是离我们家最近的派出所了,顺便试了试前天买的导航,除了我们村认不出来外,其他的都不错。到了东关派出所,结果被告知,因为车主是我妈,而我妈的户口是在百官的,所以得去百官派出所办,而且因为授权给我开,所以我得有临时居住证。有点出乎我的意料的是,临时居住证的办理非常快捷,只要填一张表,交两张一寸照就可以了。而我没有一寸照,就跑到东关街上那家主人本来是棉纺厂里跟我们是邻居的照相馆里立马拍了照。话说现在的拍照也太方便了,拍完后直接拷到电脑上用Photoshop改了一把,再用打印机打出来就行了。然后再折回派出所,那里的姐姐动作麻利地把其他事情一会儿就搞好了,临时居住证也是从打印机里打出来的。接着就直奔百官派出所,这时导航就比较傻了,我估计是地图没有更新,一直指向另一个派出所了。到了百官派出所,人也不多,那里的mm拿出三张纸来让我填,然后去旁边的复印店里复印了一下相关证件,就被告知等3天后就可以取到入沪通行证了。还是很顺利的啊!
我真的投入进去了,不顾一切地投入进去了,不怕遍体鳞伤,不怕鲜血淋漓,为了爱,我要勇敢!
因为前些天小师妹在网上跟我说,喝豆浆养肠胃。嗯,我肠胃不好已经很久了,我爸妈的肠胃也不好,所以我觉得买个豆浆机很有必要。
今天去4S店拿行驶证和发票什么的,昨晚聊天太晚了,今天老是走神,真危险呀。看来开车是个很耗体能和精力的事情,以后在前夜一定要保证精、气、神的良好状态!
吃过中饭去一百,先看到美的,看了一会儿,抬头看到九阳的柜台,于是直奔过去,买了个很便宜的,不能打冷饮的,呃,反正现在只是想喝豆浆而已!
买车已经一个多月了,还没有上牌,如果早知道买个车有这么多烦人的事情,我真的得考虑一下这个付出是否值得,本来想有个车,是为了方便,结果到目前为止,有的更多的是,则是烦心!
今天去绍兴上牌,起了个大早,嗯,辞职以来还没这么早过!匆匆忙忙吃过早饭,赶到4S店里。等了一会儿,售车的小姐说了相关事项后,我就先出去加油了,毕竟到绍兴有不近的路呢。结果加完油出来,明明我横插着已经过马路一半了,有辆车硬是从我前面飞过,结果擦到了!那车都没看清,就直接跑掉了。我就下了车看了看,心疼加恼火啊,一新车,连牌都没上,已经有两处被擦坏了!如果有一天让我遇到那个人,我tmd撞死他!
后来也没听到什么说话,上牌的车队一声不吭就开走了,我还以为不是我要跟的队,傻乎乎地等了一会儿,就打电话给带队的人,结果说就是那队车,郁闷了,我连路都不认识,只好沿着大路追上去,一直没追上,倒是自长训后,第一次飚快车,当然其实没上100码的。
带队的人结果只好在一个要拐弯的地方等着,他却开得更快,大概是为了追前面已经去的车队吧。不过这也有好处,至少让我明白一个事,车子在高速的情况下,确实很难刹住的。路上看到一队大客车,同一款同一色,也是去上牌的,真壮观呀!
好不容易到了车管所(?),好多车排除,现在买车的人果然多了,唉!想起那些人,一方面叫嚣着要劝人们出门多坐公交,少开私家车,一方面却仍做着那些不经过大脑的事情,就说我们地的公交车吧,已经稀疏地半个小时一趟了,还会不时地有翘班的,除了这些,有很大杀伤力的是,有个严禁超载的规定,一辆中巴能坐几个人呀,不到20吧,往往在那等几个小时也上不了车,这大冷的天,或者以后大热的天,不逼着人省吃俭用自己买车吗!
再扯回话题,好多车,慢慢排进去,几分钟才会移一个车位,过了不知道多久多久,终于到了车检了,我还真有点慌如果让我自己过那条道的话,呵呵。车检过了后,绕到后面,然后就是无休止的等待,排了个号,前面还有37个人,到12点时,前面还有18个人。出去走了快半个小时的路,找到一个地方吃快餐,好咸的大排!然后又走回去,要到1点半才开始下午的,无所事事地等了半个小时,开了门又无所事事地不知道等了多少小时,好不容易认证好手续。
最后是最重要的选号,嗯,这里我又算是被忽悠了!原来这里是分两种的,但是没人跟我说过!一种是八选一,一种是个性号码。八选一的话,当场可以拿到牌,我不知道啊,只是乐呵呵地报了个号,结果就成个性号码了,还得再等三四天他们寄过来!这其实也没多少个性,本来还想选2216,就跟家里的电话号码一样,结果2215和2217都有,就唯独没2216,唉!选好号码后,带队的人问临时牌照到期没有,是否需要再打印一张,一张5块钱!我艹,怎么以前就不知道有这回事,以前的临时牌照都是4S店里卖我车的那个女人跟我打的,我连忙打回电话去问,居然说需要再打一张,我说那你再帮我打一张不就得了。她说,一辆车只能打三张,我以前已经领完了!这明显是他们的问题啊,当时就是他们说等几天就可以在上虞上牌的,我才一拖再拖,搞得现在连3张临时牌照都用完了,而且我事先还不知道有这规矩!我实在是比较愤怒,以后再买车,绝对不会再去那家店了!
另外,我还得强烈谴责一下那些电视剧和小说,上面怎么全都是直接跑到4S店里,交了钱后什么手续都办完了的,完全是欺骗观众和读者啊!
就当吃一堑,长一智了。这辆起码车,就当是学费了。下一个目标:3到5年后,换个60到80万级别的车。
其实上周五的时候,晚上我在外面吃饭,手机没电了,回到家充上电,就发现江江发给我短信说驾照已经拿到了。反正我是懒得跑去F1那么远,就为了一个驾照,于是拖到今天,江江自己给我送过来了,不过相应的是我付出了几块德国巧克力的代价。宣宣还在那里告诉江江,说昨天她好求歹求了好久,我都不肯给她巧克力,哈哈。 有了驾照,却没车,真是个头痛的事情啊!不知道半年后,假如有了车后,我还敢不敢开上路。
仰天长笑三声先,哈哈哈…… 中午吃过中饭,便和江江一起坐车到四季花城门口,教练早就等在那里了,加上另外一对小夫妻,一共4个考生,那男的还教过我练九选三呢。到了车管所门口,4个人各绕着考试路线开了2圈,基本熟悉了一下路线。到考试的时候还是有点紧张的。我是4个人里最后考的,这是我最不喜欢的顺序,我一般倾向于占在最先的位置。不过没办法了,因为不好意思说。第一个GG很正常的地pass了,第2个mm紧张过度,第1次时低头看了一眼,便挂了,车停在路中央,考官立马说开始第2次,结果那mm更加紧张,一下挂了个倒档,车往后一溜就挂了。到了江江的时候,她真是好运啊,上车开了大概10来米吧,到红绿灯前停下,我还以为至少会让她过了这灯吧,结果考官说换人。郁闷,我紧张兮兮地等过了1个灯,转弯,考官就在那说挂二档,挂三档,三档减二档,车在挂二档的时候猛抖了几下(其实我压根都已经忘了这情节了,是江江后来提起来的,我又模模糊糊有点儿这个印象,就当是真的有这回事了),有惊无险地pass了! 从此,这多年前已经流行的三大件技能我都勉强算是都有了,哈哈哈哈!
长训回来了。昨天去的时候,我第一个开,除了经验不足,有些时候有点手忙脚乱之外,自我感觉还是不错的,主要还是靠熟练,多开开,也就会了,就像带路的教练说的他有个学员,九选三之后就去自己买了个车,等到路考的时候就已经开了5000公里了,其实如果只是单纯作为代步工具来说,开车一点技术含量都没有,全靠熟练。 今天早上回来的时候,还是我第一个开,路上目睹了一起车祸的现场,面包车与摩托车,一个人已经脑浆涂地趴在路上,估计是那个开摩托车的,人的生命是如此脆弱。 之后就是赚点钱,过个半年自己买个车了。
学个车还真是麻烦啊,这回要跑去韶关,来回需要两天,于是明天又要请一天的假了,想起来上周四下午请的假还没有填请假电子流呢,记性真是越来越差了,难道真是因为没有休息好。 上路也才练过一次,还是跟江江两个人轮流开了一个小时,我总是集中不了精神,眼睛看着路,思想却不知道飘到哪里去了,于是车就方向乱转了,于是被教练骂了,于是我郁闷了! 也不知道路上会遇到什么,教练说那条路上车很少,就算是学员也可以开得很快。我没有什么想法,只是觉得这考个驾照怎么有这么多事啊,过了这趟,下次还要再请假去考路考,烦死人了!
周五的时候才知道,原来我报的是6月30日的考试,一直都以为是7月10日的,所以一直都不怎么着急,还觉得练车次数太频繁,殊不知是30日。周六吃过中饭,正在睡午觉,教练还打电话叫我下午去练一下车,我说不行,要5点半才下班,然后拖到周日上午。今天又是6点半就起了床,匆匆赶到训练场,跟江江一起练了一个半小时,单边桥的我老是右边上不去,教练说不要紧。 说好11点集合,还有2个小时空闲,于是无所事事地到百草园去,江江趁这个空隙跑去体检了,我就只好无聊地看看网页,偶然发现blogger又解封了,像是重刑犯放风一样。到10点半的时候去百草园对面吃了一碗炸酱面,太多油,腻死我了。刚好11点,教练简单讲了一下考试时的注意事项,然后把我们带到接送车的地方。 12点半不到就到车管所了,一直到大约2点半的时候才轮到我们考,当时我还多紧张的,可是抽到的是3道,除了定点停车和侧方位停车外,另一项是所有项目中最简单的直角转弯,真是太幸运了。一上去就忘了起步打左转向灯,心里顿时瓦凉瓦凉的。好在后面的都冷静沉着地正常发挥,不但是我,连电脑也是,一点意外都没有,一次就pass了,心中那块石头放下来了。 九选三,pass!
考倒桩去了,有两次机会,第一次在最后倒车时,右边的观后镜刮到桩了,第二次就提前打方向盘了,有惊无险,呼呼,困死我了。
晚上去练车了,这是我第一次摸车,比较不习惯,总是记得一头忘记另一头。比如想着踩离合器和刹车的时候,就会忘了摆方向盘,或者又不记得挂档了。 据说天黑是不能练车的,因为看不到桩。确实,如果没有灯的话,我连边线都看不清,有双夜视的眼睛该多好呀! 一般说来,习惯成自然,只是平时没有碰车的机会。要流畅熟练地手脚并用,还需要多多练习。 因为是第一次,所以只是教了下怎么挂档,怎么用离合器控制速度,怎么摆方向盘,怎么前进倒退。除了我,还有另外一个人一起,两个人轮换着控车,大概总共搞了1个小时多一点点吧,不过瘾啊,要攒钱自己买台车才行,呵呵!
今天去理论考了,考前还是有点担心的,因为感觉准备不充分,本来打算上周日好好看看书的,结果经不住诱惑去看小说了,还看得天昏地暗的。昨天晚上看完一遍,今天早起又开始从头开始看,在公司里也看了一上午,一直到11点半,才跟江江一起出去。先去四季花城,吃了顿快餐,凉拌的牛肉做菜,味道还不错。吃完看时间还早,便又在花城里面的椅子上坐着看书,有点大学里的感觉,平时不努力学习,到考试前夕就着急抱佛脚。 然后去花城门口等,等了一会儿接送车来了。在上面随着车的颠簸,有微微开始有点困意,确实本来这几天就因为看小说而睡得不多,加上一直来这个时候就是午睡时间,困是应该的。看江江也是眼睛一闭一闭的,呵呵。 一觉醒来,发现已经到车管所了,醒得还真是时候。上楼,签名,验指纹,排队等候。这是一个exam pool,一个人考完出来,交了座位牌,外面等的一个人才能拿着座位牌进考场。江江进去没几分钟,我也进去了,不过我不知道江江坐哪里。我拿着1号的牌,略带紧张。 每个座位左上方都有一个监控摄像头,座位之间都有挡板分隔。没有键盘,只有一个显示器和一个鼠标。我飞快地答完题,虽然还是有几题拿不准,不过我猜应该能pass吧,1分1题,最多允许错10题呢,拿不准的大概也是10题左右,再怎么也是有蒙对的吧。结果第1次交卷还太早,一定要开考后15分钟才能交,于是又把选择题看了一遍,再提交,有点紧张,94分,万幸,呵呵。 拿了成绩单,走下楼,江江还没出来,于是等了一会儿。江江出来时看到我还有点奇怪,说没听到我的名字,呵呵,她考了96,果然比我好呀! 到接送车的地方,开车的司机说要等到3点半,看看时间还2点半都不到,于是我和江江决定去外面自己找车走。刚走出,就遇到一帅哥问我们是否一路,于是又找了一美女,4人在路口等了好一会儿才拦到一辆红的,真的是,太少的士了。一直到公司,我拿了35块钱出来。 爽啊,就等上车了。
年前就想去报了,结果被小破江江一直拖到现在。真是后悔当年在学校没去考,当时只要2000多RMB就可以了,今天就刷掉¥4080,心疼呀! 计划着是到周末的时候去学一下,据说一次才学1个小时,这么少时间!等到半年多过后,差不多就能拿到驾照了,争取有足够的钱去买个车,呵呵! 不过要学个车也麻烦呢,要交十多张一寸照,要填好几张表,还要3份身份证复印件,甚至还要体检证明!还要去理论学习,还得是工作日去,还得请假,还得有几次考试,还得都是工作日的,还得都请假,真是烦啊,还好还有几天年休假! 加油加油,赚钱赚钱,呵呵!
Category Mobile
周四周五的时候妹子跟我说她的Nexus 5屏幕在抖动,当时我也没放在心上,只想着可能是系统或某个app的缘故,等抽空把数据备份一下,然后还原出厂设置试一下。结果拖延症一拖也就过去了,昨天妹子出去参加什么沙龙去了,晚上回来手机已经抖得几乎没法用了,我就着急想把数据备份一下,主要就是(垃圾)微信聊天记录,照片以及通讯录。结果一插到电脑上,干脆花屏了!然后妹子就大发脾气。
之前给avege的DNS解析功能加了黑名单白名单,然后就直接部署在家里的树莓派上了,昨天晚上突然发现妹子的Nexus 5和我的Nexus 6全都连不上WIFI了,右上角的WIFI图标一直显示着感叹号。换热点,重启路由器,重启手机WIFI开头都没有,我想了想这两天来做的事情,基本确定是因为avege的DNS解析功能导致的。
iPad Mini和Surface都快要发布了,各种消息满天飞,我最关心的当然是价格了,因为作为当今世界上做软件系统最好的两家公司,他们的产品足够吸引我的注意力!
不过iPad Mini最低配的价格貌似还可以接受,Surface的就远远超出我的预期了。叹气啊!但是很可能过段时间仍然咬咬牙上了,再托阿菲帮忙从美国带吧,估计Surface至少比国内买行货少花费500人民币吧。
有个同事,平时看我在公司里用手机连公司的WIFI,很是眼热,一直问我怎么用。我就告诉他,要装个ProxyDroid,而且手机得root先。这样持续了将近1个月,今天他突然跑过来对我说,都怪你都怪你,现在我的手机刷得只剩下闹钟了。原来他的HTC G12昨天被他用什么一键root软件强行root,结果不能启动WIFI了。于是今天中午和另一个同事一直在OF外面折腾这手机,希望能恢复WIFI。结果还是没有什么进展,而且最后从网上看到,似乎他的G12是所谓的木马机,笑死了。
今天看到,豆瓣推出阅读器了,除了Web版和iPad版,毫不意外地有Kindle递送服务。说起Kindle,之前有一段时间我非常想买一个电子书,当时只考虑了1000出头的Kindle3和500左右的Bambook,不过好在每当一有这种强烈的购买欲望时,都有一股理性的声音说,你不是个爱看书的人!然后就拖到现在也没有买。自从上次去上海图书馆,亲自把玩了一会儿Bambook,非常庆幸自己没有一时冲动买了这么个设备,这页面切换的速度太慢了,效果太难看了,版式也很丑,啧啧!不知道Kindle到底怎么样,得找个地方也亲身去体验一下,才能决定到底能不能符合我的要求啊。
一直想弄个Android机玩玩,虽然说很多厂商都在做,但一直只想过HTC或Nexus系列,现在看Nexus S不到2000块,还有4寸屏就很心动,纠结了几个星期了。周一的时候自以为搞定了那个bug,心情很好,打算好好犒劳一下自己,晚上回来就上淘宝拍了一个。直到周四才收到快递,昨天晚上回来把它root了,然后装了GAEProxy,装上了几个Twitter客户端。
只用了一天,给我的感觉不是很好。周四晚上突然就有点后悔,我哪有那么多时间来折腾这个玩意。在屋里联通的信号很差,对WIFI的接收能力也不怎么样,默认还没有设置Proxy的功能,需要root后装第三方软件才行,屋里那个无线路由器的信号时断时续。流量跑得飞快,昨天晚上到现在10个小时左右,WIFI流量跑了30MB左右,3G流量跑了20MB,这好像是因为用一GAEProxy的缘故,昨天白天10来个小时没用GAEProxy也差不多走了20MB流量。很多app运行了就不能退出了,即使强行杀进程,它也会自动再启动,囧了。
好吧,其实各有各的优点的,比如这样后台Gmail、Google Reader、Twitter等的推送就感觉不错。
盼Qt移植到Android和iOS上是有点盼不到了,尽管都有开源社区的人在进行相关的工作,但实在进度太慢,等不及了。还是老老实实去学JAVA和Android SdK,Objective-C和Cocoa Touch吧。
昨天花了半个晚上,在Windows XP SP3和Mac OS X 10.6.7上配置好了Android开发环境。安装配置的过程非常简单,基本上每本讲Android开发的书上都有会那么些篇幅讲这些内容,而作为开源工具集合而成的开发方案,能做到这样程度的方便,已经相当不错了。而且Android开发环境中有一点我觉得非常厚道的是,它的emulator可以直接安装正式发布的app的apk包来运行,这给开发者带来极大的便利,可以直接体验别的app,而且不用担心有害代码。而无论是iOS还是Symbian都不行。
今天下午在网上找了一下Xcode4版本无证书进行真机调试的信息,还真的找到一篇文章,操作也不是很复杂,最后在我的Xcode 4.0+Mac OS X 10.6.7+Touch 4.3.3环境中实验成功,真是开心啊。
这样基本上解决了Android和iOS开发的绝大部分问题,至少deployment是基本解决了。开始移植Ninayan吧。
回家了,可能还是因为长假的缘故,两个收费站都堵了好久,几乎每个服务区里加油的车都是排长队的。
下午又看了一遍goagent for iOS的wiki page,然后开始折腾。花了约2个小时把touch装上了goagent,感觉就是速度似乎比GFWInterceptor要慢,其他没什么区别。晚上又折腾了下,把iPad也装上了goagent,这样Flipboard可以添加上Facebook账号了。好像换了goagent唯一的好处是可以比较完美地上Facebook了,囧。嗷嗷嗷,更想去弄个Android机了!
让我觉得比较郁闷的是,在Mac OS X上用goagent,似乎添加的SSL证书不起作用。于是Ninayan在Mac上就不能连接Twitter了,纠结了。
昨天又不甘心,在网上一通乱搜,终于找到一个英文固件刷中文的方法,在dospy上有一篇帖子比较详细地介绍了整个过程,还是比较简单的,今天晚上回来搞了一下,其实就几分钟的事,终于搞定啦,内牛满面啊,然后发现Gravity已经过期了,我要去买么,唔。
这些天发现可以通过MS Exchange把Google Calendar,Google Contacts和Gmail同步到iOS设备上,还可以同步到Nokia C7上,于是一直在折腾。
有时候同步会有延时,还有,发现如果Google Contacts里的生日只填月日,不填年份的话,貌似不能正常识别并使用,比如在iOS上会把联系人的生日那天在Calendar上标记出来,但没有年份的话是不会标记的,因为压根没有从Google Contacts同步过来。
除了联系人和日历外,邮件也是很有用的,用Exchange在线维护感觉很好,不过本来想的是Gmail可以通过pop3来收取其他邮箱的邮件,但是很头痛的发现它连接不到网易邮箱的pop3服务器,总是报连接超时,但连接hotmail没有问题,而用hotmail通过pop3连接网易邮箱又是可以的!这谷歌和微软在对华公关上做得差距有点大,当然可能是因为微软是得罪不起,而谷歌没这么不可或缺。于是只好先用hotmail把网易的邮件收下来,再用Gmail把hotmail都收过来,然后根据收件人把邮件打上不同的label。
另外有个问题是,我在电脑上,无论是XP还是Mac上都配置不好客户端的Exchange连接,Outlook 2003,Foxmail 7.0以及Mac Mail,都说连接不上m.google.com,这就很头痛了!要继续研究下。
昨天下午收到了Nokia寄过来的Qt Ambassador Kit,4张Qt的贴纸,2张Qt Ambassador的贴纸,一件黑色的T恤和一部C7手机。从包裹外包装上看,用的是一家叫TNT的快递公司,以前都没听说过。
之后就一直在折腾手机。居然没有说明书,但是有贴膜,显然是被拆过封。接着发现不支持中文,以为要刷机,头痛。后来在dospy上看到如果只是为了支持中文的话,只要装入兼容的字体文件就可以了,终于搞定!
现在我也是有WIFI手机用的人了,啊哈哈!
今天突然在推上看到Nokia N9的消息。搭载了MeeGo 1.2版本,已经很新了。
下午收到了Qt Ambassador的邮件,邀请为N9开发app,还可以申请N950用于调试和测试。可以使用Qt为N9开发应用,对我来说,实在是欣喜,至少Ninayan要移植过去应该障碍很少了。
上官网看了一下大概的情况,官方指导价550欧,有点贵,不过它有3.9英吋的屏幕,而且看截图,真的有点心动。
感觉N9会是一个好玩具。
前天上午在淘宝下的单,昨天上午快递就到了,这次网上购物经历是耗时最短的一次了。
买的是iPod Touch4。我是差不多去年这个时候知道有Touch这东西的,那时也在为一个女子纠结,然后听了一个师姐的建议,买过一个Touch3。不过自己没怎么玩,转换了几集《Friends》存进去,就送人了。这次买Touch4也是犹豫了很久了,一方面以为这会是个好玩具,另一个方面是决定转做iOS开发。
比较悲剧的是,Touch4到手后,玩了不到一个小时,新鲜感就过了,实在算不上一个好玩具。装了几个app,都感觉如果不是靠了iOS本身的设计规范约束,应该是很渣的。跟小言@ninayan交流了一下看法,后来小言也基本赞同我这观点。
就以拿各种微博客户端上微博来说吧,输入法不好用,客户端操作不方便,如果是上Twitter的话,没有VPN就没辙。越狱后,装个第三方输入法用用,再想办法折腾下SSH,倒是能用一些需要翻墙的Twitter客户端了。但总的感觉体验是远不如在我的Nokia 5230上通过Gravity使用百度五笔输入法上的舒服。
算了,就当个开发用机吧。
诺基亚与微软合作,以后放弃Symbian,在高端机型中使用Windows Phone7系统,而一直在大吹特吹的MeeGo将只作为一个实验性的作品,这消息发布后,网上就像炸了锅。
我个人表示很无语,感觉我期望的那个诺基亚已经远去了,那个Elop简直就是微软派去的卧底。关键一点是,以后也是使用微软的开发工具,最近两年那些开发出Qt、QtCreator、Qt SDK的人的工作,几乎等于打了水漂。不可否认微软的IDE很强大很好用,但它的框架(类库)我却是相当不喜欢,而且我现在觉得Qt实在是个有希望好好跨平台的方案,但这些大厂商硬要自己搞一套,实在烦人。Windows Phone开发用C#,Android开发用JAVA,iOS开发用ObjC,而Symbian/MeeGo开发用C++,这是让人非常纠结的事。而因为Qt的存在,让我曾经幻想,可以在WP、Android和iOS也使用C++/Qt进行开发,如今看来,毕竟是我贪心了,叹气。
现在网上都在说,以后就进入三足鼎立的时代了,要我选择的话,如果苹果的品质没有大的变化的话,我会首选iOS的,然后是Android,最后才会是WP。
我的N73是2007年6月买的,由于一直把它装在一个硬质小挎包里,从去年开始,键盘上的按键就开始一个一个掉落了,最开始是5,最中心的一个,然后沿着这个5把4,7,8,*,0都掉了,今年5月买了个5230后,就让N73光荣退役了。
从上海回来后,就一直把N73丢在书柜上,前天突发奇想,在淘宝搜索了一下,果然有N73的键盘卖,想去年去深圳华强北的电子市场找了半天都没找到。于是马上订了一块,定价20,快递6块,从广东寄过来。今天早上有电话打来,是申通快递,说是我填的那个地址他们不送到,要我自己去取,好远的,一直在汽车西站再过去几百米的地方。自己开车都20多分钟,不过倒是通过电话指引找到他们的分拣处了。
拿回来后,照网上的拆机视频,用一张硬质的卡,可以是各种商家的VIP卡,也可以是IC卡或银行卡,将前面的面板拆下,把新键盘装回去,再将面板盖回去,哈哈,又跟新的一样啦!就给我妈用吧,原来她在用的那个Nokia不知道什么型号的电池鼓起来了,不好再用了。
今天跟公鸡去华强北看手机,主要看了iPhone,让老板拿出真机来体验了一把,还真是爽。爽的有几个原因,一是屏幕特大,这就让看惯了小屏幕手机的我觉得特别大气,虽然在很多机器里N73也不算小了,不过到了iPhone面前还是小巫见大巫了。二是里面的应用程序比较丰富,多媒体娱乐上网等功能都有现成的程序。三是界面比较漂亮,这是苹果一贯的作风,不过也确实漂亮,弄得我曾经把N73上的主题都换成iPhone的了,呵呵。四是它支持WIFI,这样就可以通过我的无线路由器直接上网啦,不用什么GPRS了,不但省了钱,也许速度也更快呢! 除了这些吸引我的特点以外,还有其他特性也是很安逸的,比如据说苹果将在3月份发布官方的SDK,这样就可以自己写程序来玩啦,这点也许是本质上最吸引我的吧,虽然我可能实际上永远都不会动手去写它的程序,但这样官方的支持,对于第三方应用软件的发展,是极有利的,不难想像将来iPhone上的应用程序将遍地开花,呵呵。 因为iPhone并不在中国大陆上市,所以在华强北看到的都是水货,今天问的价格最便宜的,8G存储容量的3750,真是太有诱惑力了,实在有点忍不住想买的冲动啊。不过最近手头太紧了,已经快要去喝西北风了,呵呵。
因为想要把CodingStudio移植到Mac,于是就想先编译下wxWidgets 2.9试试。结果在Windows下用VC9倒是正常编译通过了,用MinGW 4.4最后链接的时候报wxScintilla里一些符号找不到,真头痛。
后来就想试试Qt吧,找来QScintilla最新的稳定版本2.5.1,编译倒是基本上没问题,可是自带的那个example在一启动就崩溃。
在Mac下编译wxWidgets 2.9倒是正常通过了,而且确实是使用cocoa 64bit port,试了几个sample也能正常运行。
头痛。
wxWidgets本身支持对未处理异常引起崩溃的拦截和后续处理,从它的官方文档中可以看到,只要在wxApp::OnInit()中调用::wxHandleFatalExceptions(true);然后覆盖wxApp::OnFatalException函数,可以比如遍历当前进程的堆栈什么的。
还有种处理这种未处理异常的方法是在程序启动时(一般就是在wxApp::OnInit()中)动态装入exchndl.dll文件,接下来该dll会自动拦截未处理异常,并在崩溃的时候自动在exe文件所在目录生成一个与exe文件同名的.rpt文件,里面以纯文本记录了进程上下文等现场信息。exchndl.dll可以在这里找到,可以看到其实它是配合一个叫Dr MinGW的现场调试器使用的,这是MinGW的方案。
如果是用MSVC编译器,那么有更好的方案,那便是google breakpad,它实现了Windows、Mac OS X、Linux等多个平台的dump,并且除了未处理异常,在MSVC2005之后的编译器中还包括了纯虚函数调用和CRT函数调用参数错误的捕获,另外提供了文件上传等服务,具体的编译部署可以参考这篇还有这篇文章,不过我的实际使用gyp经验是,应该在breakpad的gyp所在目录开始运行python.exe yourpath/gyp --no-circular-check breakpad_client.gyp,不然会报递归溢出。之后就只要在程序运行范围内创建个google_breakpad::ExceptionHandler对象就可以了,它有各种选项,提供了很多功能,可以通过阅读google breakpad的源代码获得详细信息。
值得说的是,这两种接管未处理异常的方案可以同时使用,但就我个人意见是,如果是用了MSVC编译器,配合PDB文件进行dump文件分析得到的信息已经足够了。
最后提一下另一种拦截未处理异常的方法。除在前面提到两种方法外,e使用了另一种方法,它没有在wxApp::OnInit添加任何代码,而是自己添加了一个WinMain函数,是的,MS官方文档给出的Windows程序的入口,在该函数中调用::wxEntry即可,在该函数后面添加IMPLEMENT_APP_NO_MAIN(CXXXApp)而不是平常用的IMPLEMENT_APP(CXXXApp)。这时,WinMain中就可以为所欲为了,比如e是自己写了__try{}__except(){},也可以根据自己需要,用google breakpad或者exchndl.dll什么的。
这两天想试一下把手头这个用wxWidgets开发的工程移植到Linux和Mac,不过遇到了些困难。
该工程使用wxWidgets作为主GUI Framework,又嵌入了Lua解释器,将一部分界面和逻辑使用Lua脚本实现,而Lua脚本大量使用了wxLua以及诸如LPeg之类的第三方库,除此之外,主程序还使用了Boost、wxFlatNotebook、wxScintilla、wxPropertyGrid等第三方库。
主要的困难在移植到Mac上。目前我使用的wxWidgets是2.8.11版本,该版本在Mac上只有32位Carbon API版本,而编译Lua和其他第三方库默认出来的全是64位的,wxWidgets官方的消息是2.9.x版本有64位Cocoa API版本,但现在不稳定,还没正式发布。于是我无奈了!试了一下2.9.1的wxMSW,编译wxFlatNotebook和wxPropertyGrid都不能通过,懒得折腾了,打算等3.0版本正式发布了再说吧,说是希望2010年底前发布,鬼知道到底什么时候能出来啊,现在越来越觉得wxWidgets不给力了,各方面的!
至于移植到Linux上,以及将其他的Lua第三方库编译出来这些事现在倒是可以做。
突然想再整一下wxMac,之前曾经编译过,也编译出静态链接和动态链接的库了,记得也生成samples的可执行文件了,今天找了一下,那些samples的可执行文件找不到了,随便敲了下make,发现连头文件都没有找到,应该是wx-config没正确执行。然后好奇看了一下readme,赫然发现wxWidgets/Mac doesn't come with any guarantee whatsoever. It might crash your harddisk or destroy your monitor. 这个太夸张啦,不敢用啦,甚至开始觉得是不是以后别的用wxMac开发的程序也要先检测一下然后不用了呢!那个杯具的CodeLite和Code::Blocks都是用wxMac的呢!反正我是不想再用了。
下午尝试给CodingStudio加入命令行打开文件的功能,可是怎么整都是搞得程序启动就崩溃,郁闷了!
于是很有些后悔当初采用了wxWidgets,而不是Qt。但是想想以当时的情况,确实再来一次,很可能还是不会用Qt。当初对Qt很是不满意它对所有控件都是自绘,而不是native的,而且觉得Qt需要moc一下很无语。最关键的是当时参考了大量CodeLite和Code::Blocks的源代码,没办法啊,对于一个新接触的GUI framework,这是最直接有效的办法了!
哦,对了,今天的消息,国人得到Nobel Peace Prize了,具体情况,咳咳,不明真相的童鞋,需要当一回红杏。
昨天完成了自定义快捷键的特性。该特性在配置对话框中实现与用户交互。
首先,在程序启动时,装载所有菜单项时,把所有菜单项的ID、标题、快捷键信息记录下来,作为缺省的配置。将缺省配置保存到文件中,然后查看是否存在保存了修改后配置的文件,如果存在该文件,则装载该文件的配置,应用到程序中。应用过程分两步,刷新菜单显示和设置快捷键表。
接着,处理在配置对话框中的用户交互响应。在对话框初始化时,加载当前正在使用的快捷键配置。用户可以修改其中任意一项的配置,当用户选择应用修改后的配置时,就将当前配置保存到文件中,以便下次程序启动时可以装载这个修改后的配置。
基本处理流程就是这样。用wxWidgets实现时,也是比较容易的。wxWidgets提供了快捷键相关的几个类和方法,相当方便,包括wxAcceleratorEntry、wxAcceleratorTable、SetAcceleratorTable等等。
这里不得不抱怨一下,wxWidgets对于一些明明日常需要使用的类和方法,竟然没有文档进行说明。另外还发现个问题,wxAcceleratorEntry有个ToString方法,当其中的Key Code是除了字母、数字外的其他的可打印字符时,会断言失败,太Orz了,只好自己写代码转换了。
Relation视图可以算是完成了,至少是处于可用的状态了。基本原理就是调用cscope这个程序,本来这个程序是开源的,而且是用BSD许可的,比较干净的做法是把代码拿来编译进自己的工程里。不过我懒得研究那个代码怎么编译了,直接调用现成的可执行程序,通过管道获取其输出,然后自己解析一遍输出内容,显示在relation视图上。这样看来这该是个很容易实现的功能,但是实际上我却花了不少时间。原因是我一开始考虑得过于简单,把所有工作都放在一个singleton中完成。既要生成新进程,又要获取管道输出,同时还要兼顾老进程没有结果又有新进程的请求到来。于是总是在同时有多个进程时崩溃。后来把新老进程调试和获取管道输出分别放在两个类中实现,就都好了。
另外还有个问题是用gcc编译。现在这个版本基本上也到了收尾的阶段,我也买了个Mac Mini,希望能把它移植到Mac OS X上。Mac OS X上可以用gcc,于是我就先尝试在Windows XP上用gcc编译这个工程。这些天一直在折腾这事,总是由于这样那样的原因失败。到今天为止,终于可算是正常通过了,有几点需要记一下。我一直用boost svn trunk中的代码,绝大多数时候,用VC编译链接都是没问题的,可是这次用MinGW中的gcc 4.4.0把boost.thread链接到工程中时,仍然会报有几个符号找不到,如果是用正式发布的1.43.0版本的Boost,是可以正常链接通过的。gcc不支持在函数体内定义结构体(类),VC9是可以的。gcc在用boost.lambda时有些情况会编译不通过,就是几个结构体内的成员被lambda bind后再进行比较的情况,但是VC9是能编译通过的,而且也不是所有这种bind并比较都不能编译过,具体的还得继续研究一下。总的说来,gcc对类型检测比较严格,呃,说难听点,是比较死板,不如VC那么智能。还有种情况是gcc编译wxString::Format时,如果第二个参数开始传入的是wxString,运行时会出错,但它又报不上来,基本上就是直接崩溃,VC在这方面又做得好得多,不过这点我估计是受不同编译器对对象内存布局不同引起的,所以也许gcc真是无能为力,VC那样可以用算是歪打正着吧。
好吧,总之最头痛的两件事算是解决了。
今天看到推友@liancheng说Mozilla/WPF/QT/GNOME3都同质化了,大体的意思是指这几种方案都把表现层和逻辑层分离得很独立,复杂的,高度重用的,平台相关的部分,用C/C++之类的语言实现成组件,表现层用XML描述界面,用CSS之类的样式描述skin,再用如JS之类的脚本语言描述运算逻辑粘合组件和界面。
我最早了解到这种架构是几年前Firefox开始大肆流行,网上这类技术文章也大量涌现。当时也是很惊叹于Firefox的扩展机制如此灵活,却对它的开发环境很是鄙视,而且用于表述逻辑的脚本语言是用JS这个我完全没了解过的东西,所以看过介绍后,就丢到一边了。后来也偶尔听说WPF、XAML之类的东西,但对.NET一直没啥好感,于是也没研究。最近几个月跟个网友讨论,提到QT的界面方案,大体上也是知道QT也采用这种架构了,而且也确实一直计划着做完眼前的这组东西后,以后全面转向QT了,但仍一直没抽出时间来研究。
今天看到@liancheng的讨论后,让我有点儿沮丧。我现在用C++/wxWidgets做主框架,好不容易设计并实现了一个并不精巧的插件机制,用Lua来编写逻辑,还总是有这样那样的限制,这不就是典型的重新发明轮子么,而且发明的是个不咋样的轮子。唉!
今天粗略考察了一下Code::Blocks/CodeLite/notepad++的配置功能,发现需要做不少工作。
和外部工具特性一样,配置功能也需要一个用户界面,但这用户界面却更复杂,因为配置选项有各种不同的应用场景。总体上看来,我比较喜欢Code::Blocks的那种配置对话框,最上边是一个static text控件,中间是一个listbook,最下边是几个标准按钮。查了下wxLua的文档,这种界面效果用wxLua基本上可以实现。从代码中可以看到,Code::Blocks是用XRC这种协议实现的,这样的好处是界面和逻辑代码分离,我也一直觉得通过完全通过代码来构造用户界面实在很土,效率又低,但我又不知道有什么工具可以方便地进行用户界面设计并生成XRC,特别是其中有自定义的控件。不过现在既然是决定用wxLua实现,也没办法了,就继续用代码生成界面吧。
我要加入配置功能,主要是为了支持用户可以自定义编辑器的各种设置,特别是各个lexer的风格,于是又看了一下那三个软件的配置文件的存储格式。前些天我一直在想的是,用sqlite3数据库来存储配置内容,今天看了看boost::property_tree,觉得这个库似乎不错,接口使用起来也还算方便,而且屏蔽了底层存储格式细节,目前可以支持INFO/INI/JSON/XML格式,于是我又想把这个库的一些常用接口封装一遍给Lua用,但是又有点担心这些格式在存储时有大量冗余信息,不如sqlite3格式紧凑,而编辑器的风格定义又会有很多信息,所以还得仔细考虑一下,明天就先尝试把编辑器风格定义都用XML描述一遍看看效果,如果实在是冗余信息太多,再用sqlite3吧。
这个特性以前就实现过一遍,那是在MFC+Xtreme Toolkit Pro下做的,想起当时的情形,完全没有任何规划和设计,真正的quick & dirty。这回是用wxWidgets实现,总的说来要比上次方便一点,但也方便得有限。
此特性分为两部分,一部分是配置用户界面,用户可以实现添加,删除,修改等操作。另一部分便是菜单项以及响应。
配置用户界面是一个对话框,我这里用wxLua实现,代码量不大也不小,总之最近总是觉得用wxLua不是个好选择,一方面似乎不稳定,另一方面开发效率不高。用wxLua最大的好处在于字符串处理方面借势Lua,还算比较趁手。
菜单项和响应部分就比较低级了,基本上都是在宿主中用C++实现了接口,然后供Lua调用。其中比较重要的是创建进程部分,以前用MFC时,这种功能都是用Win32 API写的,现在用wxWidgets了,好在wx中有这样的封装,不过感觉并不方便,但也勉强能用吧。
这个特性原本还以为半天或一天就可以完成了,现在已经大约3天了都没完成,唉,明天争取把剩余部分搞定,然后实现编辑器scheme!
宿主程序提供了界面国际化,那么插件不能提供国际化就说不过去了,至少得有这样的机制以供支撑该种需求嘛。 得益于wxWidgets对国际化的良好支持,要让嵌入的Lua解释执行的Lua脚本也能根据宿主程序的本地化信息进行正确的处理非常简单。wxWidgets中对要进行国际化的字符串用_()进行包裹,其实这是一个宏,用于调用真正的翻译功能,比如wxGetTranslation。所以在嵌入的Lua中将wxGetTranslation函数注册到Lua中即可,然后在Lua脚本的最开始处将该函数换个更简单的名字,比如_,这是最好的名字了,哈哈。这样就可以在Lua脚本中对需要进行国际化的字符串也用_()进行包裹,它会调用wxGetTranslation函数。 GNU的国际化方案套餐中,提供一个叫xgettext的工具,可以从众多编程语言的源代码文件中提取出字符串,生成po文件以供翻译生成mo文件。比较不幸的是,xgettext不能支持Lua语言,同时由于我这个项目中使用的插件描述信息中有一部分界面信息是在xml文件中的,这也是一种自定义的格式,所在很不幸地xgettext更是不能处理啊!所以我在想,我是否要先写个可以支持Lua和我这种xml格式的类似xgettext的工具呢?Poedit太扯蛋了,居然只能认它自己生成的那种po格式的文件,稍微改一点就报错了!
上午整了一两个小时,在wxWidgets程序中使用第三方库wxPropGrid,结果发现在VC2008中链接时有几个warning,虽然看起来刺眼,但似乎是可以正常运行的,也没有很在意。然后用MinGW编译链接,最后链接不通过,报未定义的符号,而这些符号是之前用VC2008时报warning的那几个,这就说明不是库编译得有问题,就是本身程序编译得有问题。 我先把焦点放在库上,wxPropGrid是编译成静态库的,这不但编译链接选项不同,连有个宏定义(静态库是WXMAKINGLIB_PROPGRID,动态库是WXMAKINGDLL_PROPGRID)都不同。我仔细观察了该宏定义对源代码的影响,并参考了wxScintilla的做法,发现区别很小,基本可以忽略。于是我琢磨着如果实在不行了,把wxPropGrid编译成动态库试试。正在这么打算的时候,突然想起来,这个宏定义在主程序中没定义啊!一定是这个原因!于是修改了主程序的配置,加上了这个宏定义,重新编译,发现果然有效,VC中也不报warning了,MinGW中也可以链接通过了! 其实这是个老问题了,只是平时很少遇到这种情形,一时没想起来。
不知从什么时候起,程序退出时,VC的输出窗口中就会打印一大片内存泄漏信息。开始还没怎么在意,认为只要程序功能正常,有点儿内存泄漏实在不是什么大不了的事情。最近随着代码的增长,似乎打印出来的内存泄漏数量也随着增长了,我仍然有些想逃避,安慰自己说不定是wxWidgets的问题,其实用膝盖想都知道,这种可能性太小啦! 晚上实在忍不住,或许真是只是想证明,确实是wxWidgets的问题吧,决定看一下到底是哪里泄漏的。因为程序使用嵌入Lua,很多功能都通过脚本扩展实现了,C++的代码量不多,基本上只剩下一些主框架界面的创建和消息响应转发的工作,所以没花多少时间,通过分段屏蔽代码来检测内存泄漏的源头。 最终发现有3处,而且确实都是我自己的代码有问题。 首先是有个singleton在程序退出前没有销毁掉,好像在GoF中还是《Modern C++ Design》中说的,这种情况的singleton销不销毁影响不大,不过用Loki中的Singleton是不会有这种问题的,所以还是为了美观起见,主动销毁吧。 然后,稍稍花了点时间,发现有一处new了一个对象后把指针插入到std::map中,却发现new出的对象个数最后比map中的元素个数多几个,那么最后通过迭代map销毁这些对象时,就有几个漏掉没销毁掉了。我一时间还没想明白怎么会出现这种问题的,后来想起来,有几个对象插入时估计是使用了相同的key,于是只能在map中留下一个。程序运行表现倒是没错,这是一种奇怪的现象,但在这里是合乎逻辑的,但仍然要改掉。 最后,发现是new了wxFlatNotebook后,就有泄漏。照理说,这种有父窗口的子窗口对象创建后,wxWidgets是会负责销毁的。所以估计是wxFlatNotebook有什么特殊的要求,从sourceforge上找到它的页面,有SVN下载选项,最近一次更新是2008年的事了,估计是不会更新了。它的作者居然就是CodeLite的作者,但我发现似乎CodeLite本身就没用这个组件,作者又自己实现了一套标签系统,不过都放在CodeLite里没独立出来。对比了一下我使用的wxFlatNotebook的版本,应该是2.1版,跟CodeLite代码里放的那份是一样的,SVN trunk中的至少是2.2以后版本了。于是下载下来,还有sample,这才是最重要的,看了一下sample在主窗体的析构函数中调用了一下wxFNBRendererST::Free()。把这条语句加到我的程序中,真的没有泄漏了! 现在舒服了,不报内存泄漏了,能这么顺利地解决3处内存泄漏问题,跟程序架构有很大关系啊!
昨天偶然发现一个超级严重的问题,程序运行一小会儿就会自动退出,什么提示都没有。至于没提示,这已经有一段时间了,照理说,内部状态、逻辑不正常么,可以给个Windows的崩溃报告嘛,可是它偏偏没有,弄得我要跟着崩溃了。 后来在代码中加入一些跟踪语句,发现出错的原因跟我的猜测一致,内嵌的Lua解释器栈溢出了。这是个很头痛的问题,以前听人说过,如果没有sandbox,插件运行环境是不可靠的,呃,最出名的是chrome的架构,经典的sandbox。但是我这个程序跟它的情况有点不同,在主窗口和子窗口上都有大量的用户交互操作,以及主窗口和子窗口之间大量的交互,子进程间的通信会很复杂。而且现在引起崩溃的,都是主窗口中的逻辑,所以还是会导致整个程序的不可用。 昨天晚上调试了好久,发现只要更新工具栏按钮或主菜单项的界面状态的响应函数打开后,过一会儿就会退出。所以最后可以把范围缩小在C++调用Lua函数的那一块代码上。我不怀疑Lua的代码有问题,凭我现在对Lua的了解,即使真有问题,估计我也是束手无策的。既然是栈溢出,而且时间不长就可以重现。我仔细地看了那块代码,又看了Lua manual和PIL,以及Luabind Documentation,发现我一直忽略的一个问题,在调用Lua的C API出错后,Lua经常会把出错信息压入栈中,而Luabind可能会直接将其封装为luabind::error类型的异常抛出,然后我就只是看一下那个字符串内容,却没其他处理了。这是一处错误,应该在提取字符串后,将其弹出。另一处错误是,我这里调用Lua中的函数,都是存放在一个表中的,所以中间无论哪个步骤出错,都应该把先前压入栈中的东西弹出。还有一处错误是,最后我从Lua栈中获取到函数后,用luabind::object封装了一把,然后luabind::call_function来调用,这时我又直接返回了,却没把这个放在栈中的函数弹出。 昨晚解决了这三个问题后,还以为所有问题都已经修正了。今天又测试了一遍,发现过了约半个小时后,程序还是自动退出了,而且连那exe文件都没了!我要疯了! 唉,这什么都是从零开始的,风险实在太大了。使用wxWidgets是第一次,复杂的内嵌Lua扩展框架是第一次,使用Luabind是第一次,使用wxLua是第一次,把所有东西混在一起用更是第一次!而且很不爽的是,已经用惯了MS的解决方案的我,没有像MSDN这样的大而全的文档极不适应,那些说使用开源的东西成本低的人,不知是真的短视,还是别有用心呢。
描述一下问题,程序主框架是用C++实现的,GUI框架用的wxWidgets,有一部分功能通过嵌入Lua解释器调用Lua脚本完成,如果要在Lua脚本中用wxLua实现个对话框的这种情况下,需要一个父窗口,而最好的父窗口是由C++实现的,现在就需要能把C++中实现的窗口传递给Lua,并让wxLua作为父窗口使用。 问题根源是出于偷懒的考虑,我把C++中需要能被Lua调用的类、方法等用SWIG嚼了一遍,生成了脱水代码。这样用SWIG返回的wxWindow*跟wxLua中的wx.wxWindow就不是一种东西。 解决方案比较quick and dirty,过程略有点曲折。昨天偶然在wxWiki上看到一段文字,描述了如何将MFC的窗口关联到wxWidgets中,我就想如果wxLua是严格移植了wxWidgets的话,应该也很容易实现的。不过很沮丧的是SetHWND、AdoptAttributesFromHWND、Reparent这三个方法wxLua一个都没有实现!于是又去wxWidgets的Google group上找了找,发现一个叫AssociateHandle的方法,可以关联一个原始的Windows窗口句柄。到了这一步,我已经没有其他出路,只好修改wxLua的源代码,在wxLua\modules\wxbind\src\wxcore_windows.cpp这个文件中给wx.wxWindow添加一个新的方法void SetWindowHandle(long hwnd),代码实现可以抄SetWindowStyle的,函数签名相同,里面的步骤也类似。最后要在wxWindow_methods的初始化列表中添加这个新增的方法,就可以重新编译wxLua了。 有了这个修改过的wxLua,再在自己的应用程序中暴露一个方法以便Lua获取主窗口的句柄,接口就可以在Lua中这样使用了: local win = wx.wxWindow() local hwnd = frame:GetMainFrameHandle() win:SetWindowHandle(hwnd) 这个win就可以作为wxLua中创建的子窗口、对话框的父窗口了!
今天整理了一下项目中使用的第三方框架、库的列表,很多,有C++的,有Lua的,突然面临一个迫切需要解决的问题:怎么决定某个功能应该由C++实现还是由Lua实现? 最早决定让项目成为一个由C++构建主体框架,由Lua脚本扩展实现其他的业务逻辑时,只是单纯得想让C++完成一部分最核心的功能。但现在的问题是,怎么判定一个功能是否够核心,以及即使够核心了,还得考虑其他一些因素,包括实现难度,安全保护,代码架构合理性,代码和逻辑共享等。 众所周知,用不同的语言实现相同的功能,难度和工作量可能差别很大。以前听同事和领导不止一次说起过,一行脚本顶得上一百行C++代码。这也许有点夸张的成分,但正好说明差异巨大这个事实。引起这种差异的主要原因就我自身角度出发来看,在于对语言的掌握程度,不同的语言风格就对不同开发任务的适应度,以及可利用的现成的库和代码的丰富度和成熟度。 说起安全保护,是今天看到Lua的maillist上讨论LuaJIT时Mike Pall说起源代码保护时才提醒了我。一般说来,用C++编写的代码,经过编译生成二进制代码,比起用脚本语言写的代码生成的字节码(中间码)反编译要困难得多。而我本来考虑让众多功能都通过脚本实现,这就面临一个问题,如何保护自己觉得重要的代码。最早的时候想用Lua的官方编译器编译一把就行了,现在看来这个保护弱得可以。而最近又面临另外一个短期内不可能解决的问题是,我打算嵌入LuaJIT 2.0的解释器,而刚刚才知道LuaJIT 2.0不兼容Lua官方的字节码,只提供源代码级的兼容,似乎LuaJIT也没提供一个自己的编译器,同时即使有这样的编译器,万一某种情况下需要用Lua官方编译的文件,那么处理就不一致了!Mike Pall的意见是,用个zip之类的东西打包加密就行了,呃,怎么说,确实是个方案,但使得本方案只能自己使用的了,不能让第三方的开发者参与了!所以除非有其他比较完善的解决方案,不然那样的代码只能用C++实现了。 再说架构合理性,总的说来,到目前为止的进度,自我感觉这样的架构还是比较满意的,当然现在只是一个空壳,只能支持让主菜单、工具栏按钮和右键弹出式菜单的构建和触发都是由脚本插件扩展而成,接着就而对的问题是,像配置选项功能要由谁来做,这种功能有一定的复杂性,又有GUI界面,又有后台处理逻辑,是全部让C++做,还是全部让Lua做,或者是各做一点,那又是各做哪些和各做多少呢?几乎所有同时涉及界面和后台逻辑的功能点,都有这样的问题,究其原因在于,用C++实现了主界面,而在Lua中目前并不能很方便地操作这些界面。原本天真地以为,C++用了wxWidgets做界面,那么Lua中用wxLua就可以实现无阻碍互通了。现实是残酷的,现在光是想让wxLua中使用C++中创建的主窗口作为父窗口就搞不定! 最后是代码和逻辑的共享。这个问题不是很严重,如果是纯粹的计算逻辑最容易共享,一些常用的底层功能,两种语言都差不多拥有第三方库来解决。除了GUI,其他的代码(逻辑)要共享,通过luabind和SWIG可以比较方便地粘合起来。如果粘合起来还是犹豫不决,那就是架构合理性的问题了。 想不到这次决定构建一个基于C++的脚本扩展框架的应用程序,会引出这么多问题,大大出乎我的意料啊,我是一直以来对风险的估计不足啊!
今天完成了右键弹出菜单的插件扩展框架支持,基本上没有遇到什么障碍,跟原来想的一样简单。 除了这个,还把菜单、工具栏的插件扩展支持功能的代码重构了一遍,把这部分功能提取成一个独立的类,在类中完成插件扩展的相关功能,只有最终的事件消息响应函数仍然放在界面类中,这是因为才发现不是随便一个类的成员函数都可以绑定成事件处理器的。 顺便说个可能是wxWidgets的bug,动态创建的菜单,动态添加的菜单项,第一个图标总是显示不出来! 再一个是原本用SWIG生成的文件,我把它直接作为头文件,包含在另一个源文件中,而该源文件因为某些原因,经常会被重新编译,而恰恰这SWIG生成的文件体积巨大(超过25000行),所以编译要花不少时间。于是又仔细看了一下生成的这个文件,发现其实最终只是需要一个luaopen_libname的函数,这样SWIG生成的文件就可以作为源文件了,不用跟着其他文件编译了。
今天修改了插件扩展的描述方式,把菜单项、工具栏按钮的标题、路径和帮助文本,工具栏按钮的图片等信息,全都写到xml描述文件中,这样一弄,lua脚本确实精简了很多。到现在为止,已经可以正常地通过插件扩展实现主菜单和工具栏的点击响应了,如果要说更新界面状态,也不是很麻烦,也就是多添加一个消息连接而已。 再说右键弹出菜单,我粗略地想了想,应该不是很麻烦,也就是添加到各自的扩展点下即可。其实直到现在,我才想起来,我这种实现方式,其实应该跟Windows传统的GUI资源编程基本思路是一样的。主菜单用一个编号标识,然后是菜单项信息,需要足够多的信息可以标识出菜单项的位置(路径),然后是给菜单项添加消息响应。工具栏的实现也是类似,所以如果要支持右键弹出菜单,也沿用那套思路就行了。 昨天说到,如果在插件扩展中使用wxLua,那么wxLua不能使用宿主程序使用的wxWidgets二进制文件,于是我今天想用IUP来试试。我从CVS里取出IUP的代码,然后用MinGW编译出所有的dll文件,可是用的时候发现总是报IupClipboard符号在指定的dll中找不到,而我用depends看是有的,郁闷!但是用LuaForWindows里的dll是可以的,可是它是用VS2005编译的,要带一个VC2005的redist,不爽啊! 另外一个问题是,本来以为脚本扩展时用了wxLua,而宿主程序也用了wxWidgets,两个之间可以无阻碍地互相使用各种控件,今天才发现,当时太想当然了。我用SWIG封装了宿主程序中的一些代码,比如wxFrame,在wxLua中是不认识这种封装的,两种不是相同的类型。所以现在只能精心挑选一组必需的,常用的代码来用SWIG封装,现在让它生成的包括scintilla和scilexer以及wxcintilla的声明后,生成的文件有近30000行,编译要花不少时间。说起来,我应该再仔细研究一下SWIG的用法先。 这两天用wxWidgets,有时候感觉它比MFC、VCL要灵活,比WTL要易懂。这也许很偏面。不过我最不满的是它的资料太少,以及运行效率不高。
这两天又用wxWidgets,不得不感叹一下,资料实在太少了,只有一个现成的manual,其他时候就只有看看CodeLite、Code::Blocks的源代码了! 到今天为止,修改了脚本扩展的功能,可以在一个描述文件中定义多个扩展的信息。对于主菜单来说,倒是勉强够用了,不过当时因为想让描述文件中对扩展的描述尽量通用,将其他的信息都写到脚本里去了,现在看来如果要对工具栏也使用脚本扩展,那么这种方式实在太不方便了点,还是应该把这种静态配置信息的都放在xml格式的描述文件中,脚本中应该只有动态的逻辑。所以还需要修改。 今天又忘了,wxWidgets的程序如果使用Lua扩展,而扩展又装载wxLua的话,wxLua的二进制文件不能用和wxWidgets程序相同的wxWidgets二进制动态链接库,不然会出现各种奇怪的问题。这是让我目前比较头痛的问题。我现在是用MinGW来编译wxWidgets和相关工程,那么一来wxLua就只能用VC或其他编译器编译了,但我今天试了OpenWatcom和Borland C++ 5.5,连wxWidgets都编译不过,郁闷!
今天偶然发现在svn trunk中的wxWidgets已经支持Ribbon了。在更新了代码后,我还特地用VC2008编译了一遍体验了一下。总的说来,可以算是Ribbon了,但感觉没有像XTP、BCG或MFC v9.0中的那么舒服。我看的是它自带的那个sample,还带着Windows标准窗口的标题栏,没有左上角的按钮和下拉菜单,也没有右上角的按钮。不知道是sample中没实现,还是wxWidgets本身就不支持。不过我想么,用wxWidgets本身就说明是重点关注它的跨平台可移植性,就不要关注这种平台特定的东西了,包括那GDI+也是。它既然号称look and feel native,那么代价就是界面不容易做得很有个性,就只适合做些严肃题材的软件了,比如IDE。 今天又看了下MSDN中对VC 2008 Feature Pack中对MFC界面增强的介绍,让我有点儿小小的郁闷,之前是过分谨慎,或者说固步自封了,没早点尝试这个增强库,而一直盯着XTP不放。今天看来,绝大部分需要的特性,在这个Features Pack中是提供了的。只不过现在还没仔细看过它的各个sample的代码,不知道它到底可以实现怎样的效果。
之前因为使用wxLua,发现如果宿主exe使用的wxWidgets动态链接库如果和wxLua使用的一样,则不能在Lua中正常加载wxLua。虽然可以通过使用不同的wxWidgets动态链接库文件来规避这个问题,但实在是很丑陋的一件事情。 今天想起来,能不能把wxLua内嵌到宿主exe中呢,这样就都使用同一份wxWidgets了。于是看了一下wxLua的代码,代码文件组织是很清晰的,很快就明白了各个文件夹下的文件是什么作用的。使用wxLua的一种方案是,它最后需要编译生成一个叫wx.dll的文件,Lua中可以直接require这个wx模块来使用。打开它的VC工程来看,也就是那么几个文件编译出来的,直接照它的样子把这些需要的文件添加我的工程中,然后编译,看情况需要修改的有几处:因为我的工程用了WXUSINGDLL宏,但这个宏会让wxLua中的一些类变成dll linkage的,所以要把这几处编译开关修改一下;有一个for wxLua的wxApp派生类,删掉;还有一处最主要的,luaopen_wx函数,有一个wxLuaState的对象,要改成直接在创建对象时把lua_State指针传过去,其他有些分析命令行参数之类的代码也是多余的可以删掉。另外还有个问题,在VC9里cell控件的代码中有一个GetRef方法,链接时报错,很诡异,搞不明白,暂时屏蔽掉那行代码。 经过这么一番折腾,终于可以直接在exe中用内嵌的Lua解释器使用wxLua了!
弄了一整天,插件框架基本上运行起来了,至少主菜单部分能出来了,证明这套机制是没什么大问题了,剩下的没解决的都属性主菜单的问题,而不是插件框架的。 不过之后郁闷地发现,用MinGW编译的使用了wxWidgets的工程,不能使用wxLua,无论是通过C API加载,还是通过Lua代码加载,都不成功。用VC编译的工程就不存在这个问题,如果是普通的工程,没用wxWidgets的工程,也是可以加载的。于是我猜测是不是因为加载相同的wxWidgets而冲突了啊!因为wxLua是用MinGW编译的,还没试过用VC编译来wxLua来试试。开始还怀疑是不是因为路径的问题,或者是用了Luabind的问题,或者是用了SWIG的问题,后来实验发现好像都不是。 用VC编译了wxLua来试试吧,如果还是不行,就没办法了,只好不在扩展脚本中使用wxLua了,唉!本来还以为用wxWidgets的工程用wxLua是绝妙的搭配呢,大不了再试试IUP之类的呗。
半生不熟地用着wxWidgets,全是照着代码改的,勉强能运行起来,不过似乎用gcc编译出来的release版本有时候会报错,不知道是哪里出的问题!可能是哪里资源没正确释放什么的吧! 界面的框架算是搭起来了,排除掉那个报错的bug就比较完善了。接下来完成插件扩展机制,一大块功能就可以用脚本完成了。
因为考虑到要跨平台,所以不能用MSXML了,而且对于MinGW能不能直接使用MSXML我都不抱希望,于是在几个开源的可跨平台的XML解析器中进行选择,并且只能是用于C/C++的。候选项包括expat、TinyXML、libxml/libxml++、Xerces-C++。我不喜欢expat的实现方式,也不习惯TinyXML的只有DOM的解析方式,而libxml/libxml++则是因为捣腾了一阵子还是没能用MinGW正确编译,最后的选择只剩下Xerces-C++。而实际上编译Xerces-C++也花了我一些时间。网站上最新的是3.0.0,倒是有VC7、VC8、VC9的编译好的包,不过我要MinGW的,所以下载下来源代码,看了一下网站上的说明,先装好msys,选好参数运行./configrue,就会生成makefile。而这生成的makefile似乎并不能直接用MinGW的make过,需要稍微修改下,也就是把其中所有的什么dirstamp目录的创建和依赖都删掉,方能编译。 编译wxLua稍微好过一点,不过一开始绕了点远路。从CVS下下来的源代码,到build/msw下找makefile.gcc文件,这个文件少了写了两个编译选项,以致于在生成库时在链接时总是去找WinMain,开始不明所以,硬是把LDFLAGS设为-shared,在编译库时是没问题了,但编译出来的.exe文件就不行了。后来发现只要添加LINK_DLL_FLAGS := -shared和LINK_MODULE_FLAGS := -shared就可以一切正常了。当然wxLua依赖于wxWidgets,所以事先要设置好WXWIN和WXCFG环境变量,而且最后面不能有反斜杠。只要设好了这两个环境变量,用VC9倒是可以很顺利地编译过。 有些时候不免要抱怨一下,开源的东西,易用性可能确实差了点。
今天又看了一下wxLua,其实很简单一回事只要把用CVS下载来的wxLua源代码编译一下,生成一个wx.dll文件(当然是在Windows平台下的),该文件依赖于wxMSW的两个dll,分别是wxmsw28u.dll和wxmsw28u_stc.dll,如果用不同的编译器,或者编译选项,可能会有不同的文件名后缀(注,不是扩展名)。我是用MinGW最新扩展4.3.2 TDM-2来编译的,把编译出来的dll放到搜索路径下,用lua.exe就可以直接运行wxLua自带的几个例子程序了,比如auidemo.wx.lua。 开始时,还在想到底是嵌入一个纯粹的Lua解释器,还是嵌入wxLua。其中的区别就是嵌入wxLua可能会需要多点C/C++代码加到工程中,作为胶水代码连接lua代码和wxWidgets。现在发现,其实不用管这么多了,只要嵌入一个纯粹的Lua解释器就够了,再设定好搜索路径,即package.cpath,就可以自由地装载wxLua了,其他的第三方库也可以用了,比如LuaXML、LuaZip等等。 我仰天长笑,接下来的问题是,如何让外部的Lua脚本识别出各个scintilla控件。MDI界面必定会有多个Scintilla视图,怎么能让脚本方便自主地获取到自己需要操作的那个视图呢?
幸亏有Code::blocks和CodeLite两个的源代码可以参考,可以省事不少,不过还是发现,要像现在用MFC一样的比较熟练地使用wxWidgets仍需要先阅读一些基本的资料,当然wxWidgets的manual也是必不可少的。 学习一种新的GUI框架的使用方式,关键还是在于了解并掌握它的消息处理机制。通常见到的GUI系统都是消息驱动的,所有所有的编程框架都不可避免地要有一套自己的消息处理机制,而且这套机制的设计好处,直接影响到整个框架的运行效率和使用效率。 总的说来,我感觉目前wxWidgets已经有点庞杂,好处是有些问题可以有多种解决方案,坏处是增加了学习成本以及降低运行效率。总觉得它不但最终生成的可执行文件体积大,而且运行效率太低。不过似乎用gcc编译出来的代码,运行效率也不如用VC编译出来的。假设能用Intel编译器来编译,是不是运行效率能更高呢? 现在用wxWidgets来写程序,还有个比较麻烦的问题是,跟用MFC开发相比,缺少一个好用的开发工具。以目前凡事都追求效率的情况来讲,写程序早已不是随便找个文本编辑器就能写代码的时代了,不光要有基本的文本编辑能力,其他自动完成、重构、提示、引用跳转、向导等等,无不影响着程序员的心情,以及开发效率。从这方面讲,目前已经没有哪个环境能跟VC+MFC比了。用vc也能写wxWidgets程序,但跟开发MFC程序相比,它缺了各种向导,比如Property视图,可以直接为各种系统消息、命令ID生成对应的函数声明,还有常用类派生的虚函数实现。 不过,总算起步了!
一直沉迷于网络小说,完全属于玩物丧志的类型!今天无聊完,郁闷完,打开VS来,决定先把框架搭起来再说。 总的说来,这是一个需要用外部脚本和配置文件协同扩展才能让业务逻辑正常运行的系统,而C++部分纯粹是为了实现用脚本比较困难的核心功能。虽然想了很久很久了,但一直迟迟没动手,玩物丧志是主因。 另一个不太重要的借口是,没找到好用的开发工具。微软的一个很好的实践是dogfood,很早以前看《微软的秘密》一书时就知道这个了,前些天听那微软的专家交流时,又看到这个,觉得很有趣。像Code::Blocks和CodeLite都是典型的dogfood,使用自己来做为开发工具。而我目前还处于一片空白的阶段,被Visual Assist X惯坏了的我又受不了其他工具的弱智,于是一直停在那里。今天想通了,就用VS来作开发环境好了,先用VC编译一个debug的wxWidgets,要retail版本时,就写好makefile,用gcc来编译。 这次恢复系统后,只装了个VS2008,这一方面可以让我不至于为众多的选择而分心,同时也减少多版本并存而可能出现的各种奇怪问题。前两天把原本只能用VS2005打开的WIND工程尝试着用VS2008打开,居然没崩溃,高兴之余把用WTL封装了的Scintilla代码也精简了一把,删掉了几千行代码,这下应该更不会崩溃了吧!
今天看了一段CodeLite的源代码,很小一段,从app开始看,到Frame。因为想学习使用wxWidgets,阅读现成产品的代码一种比较有效的方法。我并不知道到底有哪些程序是用wxWidgets的,到目前为止了解到的有FileZilla和Code::Blocks,以及这个CodeLite。 学习的主要目标是掌握如何创建各种类型的窗体,如果为窗体设置消息响应。如果在绝大多数情况下,都能比较快速熟练地解决这两个问题,那么基本上可以认为算是会用这个库了。 wxWidgets的处理形式跟MFC比较相似,都是有一个app类,代表当前程序,然后有frame类,表示主窗体,在frame类中再衍生出菜单、工具栏、状态栏等元素,也包括其他一些子窗体,比如CodeLite中,用到各种Pane,这些Pane通过wxAuiManager来管理,可在主窗体上依靠,或脱离主窗体浮动在外。CodeLite和Code::Blocks都用标签页(Tab)的形式作为主界面,也用标签页的形式做Pane,但两者在实现标签页时略有区别。Code::Blocks用了wxFlatNoteBook这个组件,而CodeLite则似乎是自己创建的一种组件,该组件将标签页头和页内容分成两个wxPanel来实现,标签页头部分又在这个wxPanel上使用Tab来展现出页头的效果。这样的好处是标签页头相比wxFlatNoteBook有更多的可控制选项,坏处则是需要自己写不少代码。 现在我最大的困难就在于,还是没有完全搞明白,这个界面是怎么创建起来的,一旦这个框架建立起来了,那剩下的业务逻辑部分都是比较清晰明了的,至少知道大方向上应该怎么走了。
虽然打算使用MinGW+wxWidgets来写程序,似乎是可以抛弃VC+MFC或者BCB+VCL这类商业软件了,但是,实际上我发现我根本离不了VC,主要是离不了VAX,这个超级好用超级变态强悍的VC助手。 早先的时候,只用到VAX的智能联想提示功能和跳转到定义或声明的功能,自从看了Martin Fowler的《重构》,VAX的诸多重构功能也成了我目前最常用的功能,日常工作写代码,离了它简直痛不欲生。 写代码最好用的是VC+VAX,但看代码最好用的,个人感觉还是Source Insight这个虽然不思进取,但基础确实不错的东西。Source Insight也可以用来编辑代码,不过比起VC+VAX来还是弱太多了,而且它也是要买license的,最关键的一点易用性方面不足是,多少个版本推出来,还是不支持标签页浏览,真是不可理喻,而且对中文的支持也是一直都没任何改进。 所以最好的工具是能集VC+VAX代码编辑功能和Source Insight代码浏览功能于一身的。但是目前还没有找到能达到这种效果的软件,从免费到商业的,都没有。回到最开始提出来的,要用MinGW+wxWidgets来做开发,还是比较困难的,比较折中一点的办法是,先在VC里做debug版进行开发和调试,定期用MinGW生成release版本进行测试,先打造一个好用的CppCoding工具。
总觉得心事重重,走在路上焦躁不安,忍不住安慰自己“熬过这个六月就好了”,心里刚刚默念完,突然觉得这句话很熟悉,似乎以前自己说过。不过要说真的说过的,那肯定得是一年前才可能的事了,去年的六月我又在烦些什么呢!确实好像这一年多来,一直过得很不顺心,每次都劝自己说“熬过这段时间就好了”,结果这样的时间一段接着一段。 计划有点宏伟,但对于我这么一个懒散的人来说,着实有点困难:WallpaperHelper——VC/MFC;SourceCoding——MinGW/wxWidgets;DCoding——MinGW/wxWidgets;CppCoding——MinGW/wxWidgets;PHPCoding——MinGW/wxWidgets;RubyCoding——MinGW/wxWidgets;PyCoding——MinGW/wxWidgets;LuaCoding——MinGW/wxWidgets;TclCoding——MinGW/wxWidgets;PerlCoding——MinGW/wxWidgets;TeXCoding——MinGW/wxWidgets;XMLCoding——MinGW/wxWidgets;Flowchart——MinGW/wxWidgets;SoftwareDiagram——MinGW/wxWidgets;NetworkDiagram——MinGW/wxWidgets;Go——MinGW/wxWidgets;Chess——MinGW/wxWidgets。
Category WIND
上周基本解决了一个dump文件分析的问题。
一开始,问题没有弄复杂,只是从最后异常看到call stack,大体得出某个类的指针为NULL,却被继续使用,然后fix的话只要在被使用前判断一下是否不为NULL就行了。
不过这个fix有一点没有考虑到,是该方法一开始就有一个分支对该指针进行了判断。所以如果该分支确实成立的话,我的fix就说明有问题了。于是新的问题就成了验证该分支的条件是否成立。
分支的条件是判断另一个对象的每个成员是否为空。本来,这个对象一开始是new出来的,指针是某个方法的局部变量,一般说来是放在栈上的。不过通过call stack切换到那个方法的context后,发现查看局部变量并没有那个指针。通过查看反汇编的代码,才发现原来该指针被优化了,并不存储在栈上,而是存储在寄存器r13上了。于是我就开始想着如何可以查看某一级call stack时的寄存器,一开始我以为每次call指令时,会自动把所有寄存器的值都压栈的,后来发现不是,还特地去找了Intel的指令手册看了一下说明,反正没说有压栈寄存器,大概是我记错了。问了一下那个老外同事,他说没什么办法,只有想办法从栈里找。
这样没头绪了几天,后来灵光一闪,偶尔发现在call stack中使用r13存储指针的方法的下一级被调用方法的反汇编代码中,把r13压栈了!于是只要在栈中就肯定能找到那个指针的值了。至于怎么找那个栈中的位置,从函数的返回地址找!从最后的esp值开始大地址(栈的生长方向是往小地址方向生长)开始搜索那一个方法的返回地址,找到后再往小地址找压入的栈的寄存器值,果然找到一个值,可以通过dt来查看,还可以通过dds该地址的vf-table来查看它的虚表包含的虚函数名称,这样就可以验证是否是要找的那个对象。果然没错!
从昨天下午开始check in,到今天下班仍然没有完成,太囧了,什么乱七八糟的东西,叫了组里最有经验的同事,还有build team里的妹汁来定位,仍然没有搞定,昏特了。
倒是另一个分给我的bug,貌似快要被我搞定了。这次这个bug问题出在C++写的内核里,用Visual Studio 2008调试经验死掉,于是刚好用WinDBG来调,除了有点不习惯,其实WinDBG好像稳定多了,也快多了。其实一般在Visual Studio里调试,也就用到断点,单步,查看变量这三板斧,即使一点没有WinDBG的基础,也可以很快transfer过去。然后用Source Insight看代码写代码,好happy!只是如果仅仅用WinDBG做这些事,有点暴殄天物了。可是我不会其他高级用法,唔…
话说上周五的时候让我给team里的人做WinDBG的training,然后我就随便写了几页ppt,忽悠了50分钟,只提到了怎么用WinDBG实现VS中的那些常见的调试任务,至于WinDBG最擅长的memory corruption,resource leak和postmortem debugging全都没提到,然后老大很不满意,唔,其实我这是故意这么安排的,虽然我自己确实对后面三个topics也没有研究,但要循序渐进嘛!
今天终于从服务器上找到几个没因为too old而被删掉的core dump文件,于是祭出WinDBG进行分析。
最大的障碍还是对WinDBG不熟,以及对常用的分析方法不了解。
不过发现一个奇怪的事情。程序是在Win API里崩溃的,该API接受两个字符串作为参数,所以一般说来我们可以认为是作为参数的字符串有问题。通过call stack终于找到最早的这两个字符串的出生地,是两个std::wstring,被const_cast强行对.c_str()的返回值进行转换然后传递出去。所以说,如果call stack没有问题的话,应该是这std::wstring对象的问题了。因为从dump文件中看到TCHAR*的值确实是指向一个不知道什么地方的地方,反正dd是看不出来的,于是dt -r查看这两个std::wstring对象,发现其中的其中的ptr域确实就是指向不知道什么地方去了。好了,奇怪的事情被我发现了,这个函数里,有两个std::wstring对象占用的是同一个内存地址!一开始我的直觉是这不可能,难道是dump文件的问题,或者是release buiding优化后就读不到正确的内容了?我看了一下代码,发现这两个对象是存在于不同的scope中的,有不同的生命周期,嗯,这是从C++对象模型的角度的说法,但实际上编译器会怎么实现,我是一点都没头绪的。我跟老大说了一下,他也认为是dump文件的问题,然后我打开第二个core dump文件,发现了同样的问题。于是虽然老大仍然坚持他的意见,我已经有点动摇了。
好奇怪呀呀呀!
第一次知道google-breakpad这个东西,是一篇讲chrome使用的开源库的文章,当时也只是一带而过,心想这功能也能做成多平台的? 最近还是因为项目的需要,原本已经有一个这种实现的,是从FileZilla的2.x版本中抠出来的,不过有些时候会生成不了dump,让人觉得诧异,还有一些是生成了dump,但最后发现栈回调的信息太缺乏可参考的价值了。我估摸着,这可能跟如何使用dbghelp.dll里的函数的方式有关系,而这google-breakpad在我看来可能是当前功能实现得最好的一个了,就打算好好了解一下。 从svn里取得到的代码,解决方案是用于VC2005的,大概google内部VC都是用的2005吧,看到好些它的开源项目都是。直接用VC2008打开,自动转换版本后,也可以直接编译。主要看src\client\windows\目录下的代码就可以了,一般而言可以用到的有3个lib文件,分别是crash_generation.lib、exception_handler.lib、crash_report_sender.lib。如果用户程序只是为了能生成minidump,直接链接exception_handler.lib就可以了,crash_generation.lib已经被它包含了,而crash_report_sender.lib顾名思义是可以将文件发送到某个地方的,从代码上看,是通过http的上传功能来实现的,不过还没研究。另外还有一个GUI的演示程序,crash_generation_app.exe,可以测试除0异常,CRT函数参数无效异常以及纯虚函数调用异常。 通过阅读crash_generation_app.exe的代码可以大体上了解google-breakpad的使用方法。google-breakpad将这么一个小功能分成几部分来实现,首先,它分为服务器和客户端两部分,这两部分都可以生成minidump,但应用场景不同。用户程序出现未处理异常时,被ExceptionHandler捕获到,该模块会根据当前进程是否已连接到一个服务器,来决定由谁来生成minidump。在crash_generation_app.exe中默认是会去连接一个服务器的,所以如果服务器没有问题,则是由服务器来生成minidump的。而且服务器生成minidump不限于当前进程,它通过Event得到客户端的dump请求,通过管道进行其他数据的传递。使用C/S结构的好处是,可以尽量减少对被dump进程的影响,代价则是大大增加了代码实现的复杂性。如果没有可连接的服务器,客户端也可自己生成minidump,这部分的实现上网上的所有有关这个主题的代码,基本上都是相同的。唯一有点区别的是,网上其他的代码一般只接管了未处理异常,而google-breakpad则还可以接管CRT函数无效参数异常和纯虚函数调用异常。 在crash_generation_app.exe的实现中,使用服务器dump的方式,最后返回的结果总是说没成功,而实际是dump文件是生成了的,这应该算是个bug吧。还有个问题是,如果一开始尝试连接到服务器后,后来服务器又被关掉了,那之后的dump会全都失败,这可能是因为演示的缘故,没有仔细编写这种异常流程的处理代码吧。另外,算是小瑕疵吧,用google-breakpad默认好像是不能自定义dump文件的名字,只能指定个保存路径,最后的文件名是随机生成的uuid。 总的说来,对于有这方面需求的应用,使用google-breakpad是个不错的选择,它做了不少工作。
今天花了近一天的时间,重新写了一遍自动分析mini dump然后将分析结果提交到wiki上的程序。通过这次实践,也确认了我原先的想法是可行的,内嵌一个IE,然后通过它暴露的COM接口,进行一些基本的操作,主要有遍历已有元素,填充TextArea,提交。只是发现这些操作,全都不是阻塞的,所以具体应用的时候还是得留心一下。 晚上加班,看了一下一个公司的人写的ppt,介绍Erlang的,看得让我觉得有点不舒服。按我的理解来看这ppt,似乎他的意思是公司目前使用C/C++来开发电信类软件,而且有那么多的问题,而Erlang从语言的机制上就提供了不少的保障机制,可以写出更快更稳的程序来。让我感觉他在鼓吹这就是银弹。就我以为,写这个ppt的目的就不明确,或者说就算明确了,也是动机不纯,我们应该立足于眼前,如何提高公司开发人员的设计和编码水平,而不是考虑着换一种语言就妄图可以解决一堆问题。 不过总的说来,我看了《Erlang程序设计》中的前面一两章后,就觉得这是我真的需要的一种东西,也许它在保证并发上,或者FP编码风格的处理上并不完美和彻底,但就目前看来,它应该是比较适合我的需求的一个选择。
事实证明,x和dt偶尔还是有些用处的,有几个core dump记录,经过分析后,嗯,是x或dt后,发现就是在倒数第二次或倒数第三次调用某个对象的方法时崩溃的,而崩溃的原因就是因为那个指向对象的指针其实是个0,只要调用的方法引用了什么成员变量,那么对不起,保证完成“死给你看”的任务。想来,在知道用x和dt前,那些问题我估计是分析不出什么结果来的。 今天,抱着试试看,用VC9重新全部编译了一下Scintilla,发现真可以用了。在这之前的几天里,偶然发现只要向Scintilla发送什么消息,应用程序就会崩溃,还以为是CVS里的代码有问题。 这软件的问题啊,真是个很缠人的事啊!
那些个core dump,都是我抠了FileZilla早期版本中的源代码出来,利用DbgHelp.dll的功能整出来的mini dump,本来有点迷惑的为什么查看变量内容时,老说访问内存错误,又翻了一会儿书才偶然发现,原来是这mini dump本来就只保存了寄存器和栈回调的信息,这也可以理解了,不然加上完整的内存dump,怎么可能只有几十KB大小。于是只好很沮丧地得出一个结论:对于mini dump,除了!analyze -v外,还真的什么都不行。
今天发现,对于core dump文件的分析,除了!analyze -v外,还可以.frame一下,再x或者dt一下的。不过也就只能这么一下了,而且不知道为什么,那时x或dt出来的对于之前调用栈中的内存,显示都是读取错误,而且有时候看地址似乎也真的不对。 由于发现了x和dt这样的命令,于是今天在分析core dump时也稍微卖力了点,不过最后我却又不得不怀疑我这样的理解是不是正确的,因为有两个core dump到最后分析出来都是因为类指针为空而对它进行提领,而看代码实现是很不像会出现这种指针为空的情况啊!我大汗! 还是得继续学习啊!
上午花了两个多小时,嗯,确实是两个多小时,写了个小程序,每隔一段时间扫描一下指定的文件夹下所有core dump文件,和历史数据库中的记录进行比较,如果历史数据库中没有记录,则认为是新追加的文件,一边将其添加到历史数据库中,一边则使用cdb.exe通过命令行进行分析,最后将分析结果连同那个core dump文件一起通过SMTP协议发送到notes邮箱中。 其中遇到不少奇怪的问题。本来是打算cdb.exe将分析结果重定向到文件后,自己读一下这个文件的内容,把这个内容作为邮件的正文发送的。结果首先是发现,使用system这个CRT函数,其中是调用了cmd.exe /c这个命令行,所以如果传给这个函数的参数如果同间有空格,是要用双引号包括起来的。尤其要注意的是,如果打算执行的是一个带参数的命令行,得从头到尾一起括起来。接着我就想用ifstream的方式把文件内容读出来,然而很诡异的是,直接将其输入到一个stringstream时,只有一小部分内容读出来了;通过getline一行一行读出来后,本来打算全部追加到另一个string中去的,但是就是追加不进去,最后想使用API吧,直接CreateFile,再ReadFile,内容但是全读出来了,最后通过SMTP发送这部分正文时,依旧只能发送前面一小部分。放弃了,本来就昆个Quick & Dirty的东西,于是还是直接把这个文本文件作为附件发送吧。也不知道是不是那个SMTP类本来就有问题,运行的过程中时不时弹出个出错信息来,什么delete指针时错了呀,堆被破坏了呀,等等等等,不一而足,实在无语得很! 不过尽管还是会弹错误框,但手工点一下也不麻烦,先这么着吧,至少可以当成一个监视器用了。 这两天我一直在想一个问题:是不是mini dump只有一个用途——!analyze -v?没有找到答案,但翻遍所有的能找到的参考资料,似乎这个猜想是真的!
昨天又看了一下《Contributing To Eclipse》,思路有点清晰了,应该有一个任何地方都能访问到的地方,Eclipse中叫插件注册表,存放着所有插件的描述信息,这样无论是核心还是插件,都可以随时读取到与自己相关的插件的所有必要信息,实现相应的功能。 之前还疑惑,与界面相关的插件处理流程会自相矛盾,现在看来应该能解决了。首先需要确认一点,暴露被扩展点的,无论是核心还是插件,都可以从插件注册表中读取扩展的信息,比如菜单项名称,这样就可以添加一个新的菜单项,以及维护一个处理关系,Eclipse中有个某某proxy的机制,这形式不重要,关键是暴露被扩展点的那个部分应该在添加了新的菜单项后,能在菜单项被点击时,准确地知道哪个菜单项被点击了,并依赖插件注册表找到对应的处理流程,以我目前的情况而言,即对应的Lua脚本文件,Lua脚本模块名称,以及处理函数名称,然后将这些信息提交给插件运行模块来运行,插件运行模块则又要与插件装载模块合作,如果运行时发现没有对应的模块或函数,则要先装载对应的脚本文件到解释器中。
本来想用VS2008来写WIND的,但是这两天遇到几个问题,不得不降到VS2005来用。 首先是装了Refactor!Pro,在VS2008编辑器变得迟缓无比,敲几下键盘,就会死半分钟,这是无论如何不能忍受的,于是在Refactor!Pro的配置项里改了一番,卡死的情况有所好转,但仍然处于不可用状态!而且在退出VS的时候,会写一个巨大的cache文件,工程中没有多少个文件,都会写入100多MB,估计随着代码量的增加,这个文件的体积也会不断飚升。 其次是,我从PN中抠出来的Scintilla相关的代码,一添加到工程中后,VS2008就会updating intellisense,而且只updating到半途,VS就崩溃了,屡试不爽,无论是从命令行打开该工程,或者是从界面上打开该工程,都会updating直到崩溃! 于是,我万般无奈下,尝试用VS2005。降级倒是很容易,直接用文本编辑器打开.sln和.vcproj文件,把里面最开头几行中的版本号改小就行了。再用VS2005打开工程,写几行代码,编译一把,似乎倒是没有在VS2008中的那些问题,只好先用VS2005来写了,生在中国可真幸福。 这倒都只是IDE的问题,我猜如果只是直接从命令行来编译整个解决方案的话,应该不会有问题吧,而且升级也方便,只是改几个版本号。只是是否有这个必要,一定要用VS2008来编译。以后再说吧,本来最主要的也只是为了体验一下Refactor!Pro重构的快感。
有点受不了MFC那比较累赘的几个在超大dll,同是Windows平台下做GUI开发,我只好选择了WTL。其实我已经比较习惯MFC那套东西,并没有发现多少网上说的种种使用MFC的不爽,相反我觉得还是挺安逸的,甚至对于使用了四五年VCL的我来说,MFC也没多少不方便的,虽然相对于VCL来说,MFC根本算不上可视化,但我也不清楚为什么自己仍然能这么乐于退回使用这种原始的framework呢!现在唯一让我觉得不爽的竟然是它要拖几个dll文件,也好,刚好学习一下WTL。对于目前我的状态来说,最大的困难是可参考的资料过少,市面上还没发现哪本图书是讲怎么使用WTL的,唯一的一份教程则是CodeProject上那流传甚广多少年前的那几篇文章。 之前也用过WTL写过一个对话框程序。还有一个输入法辅助程序,本来期望是用它来做皮肤生成器的,结果和众多其他我写的程序一样,只是开了个头,然后就丢下了。如今要写一个比较大的程序,我自己也估计不好规模会有多少,猜一下大概C++代码行会过万吧,另外我希望大部分逻辑都是使用外部脚本扩展来完成。 虽然几乎一点经验都没有,但还好有现成的代码可以参考,特别巧的是,我那程序中也需要一个代码编辑功能,本来就想好是用Scintilla的,但是我不懂如果在WTL中使用这种自定义的窗口,刚好就可以抄袭那些代码了,哈哈! 编辑器能正常显示出来了,接下来要把TabbingFramework和DockingFramework加进去,之后再考虑其他问题!
以前对这方面没有多少关注,只是偶然看到LuaEdit用了个叫madExcept的库,可以让Delphi程序在运行时如果崩溃了弹出个看起来比较牛的对话框,显示一些当前进程和当前系统的相关信息,并可以让用户选择是否将这份报告通过email发送回开发者。当时很好奇这是怎么做到的,很希望在自己的程序中也集成进这个功能,但很遗憾地发现,这个库只适用于Delphi,而我偏偏就不是用Delphi的。 后来,偶然,没错,以是偶然,看到公司网上有人说FileZilla有一部分这种代码,于是找来看了看,才大致了解了基本原理,并直接把这段代码抠出来用在了项目中,但到目前为了,这个功能虽然加进去了,却还没有发挥实际的功用。因为这段代码针对使用VC编译的程序会生成一个dump文件,该文件需要配合编译时的源代码以及编译器生成的pdb文件协同工作才会有实际用途,而我们的项目没有一个良好的机制把各个发布版本配套的源代码和pdb文件归档。 这些天看了《软件调试》,稍微了解了Windows的错误报告机制,觉得这是一种能很好改善用户体验,帮助开发团队改进软件的方法。 前段时间读Code::Blocks和CodeLite的源代码时,发现在Windows平台下编译时它们都动态装入了一个叫exchndl.dll的动态链接库,却只是装入,没做其他任何事情。根据代码注释中的只言片语,加上后来去down了Dr.mingw的源代码,发现这个dll就是做了捕获未处理异常,生成报告的工作。 于是,我就有了现在这个想法,也许这个想法就是微软的错误报告机制的简装版。首先,确定这套机制由三大部件协同完成:1、未处理异常捕获;2、反馈崩溃信息;3、分析处理崩溃信息。在具体实现时,可按这三部分分别处理,未处理异常捕获,就像exchndl.dll一样,只需要提供一个dll,应用程序只需要装入后,什么也不用管了;反馈崩溃信息,可以另外再写个客户端,将报告信息(文件)传送给服务器端;分析处理崩溃信息,也就放在服务器端了,可以自动作些简单的分析(像WinDBG那样的,配合对应的源代码和pdb,可以找到引起崩溃的代码行),根据这代码行,可以给用户显示个html页面,说明一下崩溃原因等等,当然这需要一定的人工介入,而且也是三部分中最复杂的。这些工作都可以通过微软提供的技术来实现,但还是有不小的工作量,比如像WinDBG那样结合pdb和源代码分析dump文件,这都是调试器的一部分功能了,另外再显示html页面,肯定是需要有先例通过人工编制一个页面。 而且这套机制似乎有个最大的不足,是只适用于VC编译的程序。也许其他的编译套件(Borland、DigitalMars、OpenWatcom、Intel……)也提供了类似的机制,但可能没有VC的完善,不需要人工分析即可定位到源代码行,这是何等方便啊!
从china-pub上买了本《软件调试》,厚达1000多页的大砖头。开始拿到的前面有8页是空白,到china-pub上去说了一下,该书的责任编辑通过email跟我协商,最后又快递了一本正常的过来,我再把有问题的那本快递给她,如此服务质量,也让人称心满意了。 难得原作者用中文写成,这样就可以让我们中文读者第一时间可以读到如此重量级如此深度的精品专著。 该书从CPU(Intel x86系)对软件调试的支持、操作系统(Windows)对软件调试的支持、编译器(MS VC)对软件调试的支持三大方面进行了讲述,中间结合VC、WinDbg等实例进行讲解。 昨天晚上躺在床上,快速地浏览了一遍,让我深深感叹Windows,噢不,应该是微软的强大。微软从操作系统到开发工具,都为软件调试支持了极其强劲而且方便的支持,窥斑见豹,微软做软件是多么认真,多么负责,微软帝国的崛起除了机遇外,其自身实力和不懈努力是起主要作用的。 翻完这本书,我禁不住想自己写一个应用层的调试器,像OllyDbg那样的。粗略想一下,一个调试器需要具有的最基本的功能:反汇编、CPU寄存器读写、内存读写、单步、断点,以及跟系统相关性比较大的装载模块、内存映射、符号信息读取。这些在Windows上绝大部分都有现成的API可以完成了,除了反汇编比较麻烦点(看看IDA Pro做成什么样了,当然动态调试器是不需要这么复杂的),其他的至少从原理上看,是很简单的,困难的是细节。 嗯,WIND Is Not Debuggger……
Category PSP NDS
昨天小妞给介绍我玩了一个PSP上的方块游戏,规则很简单,只要把4块或更多的同色方块组成正方形或扩展的长方形,就可以消去这些方块。这个游戏的很美妙的背景音乐,还有绚烂的动画。在小妞屋里玩了差不多一个小时,虽然规则简单,但要玩好实在不容易。 于是回到家,我自己去网上搜索了一下,原来叫《音乐方块2》。它由Q Entertainment公司门户的水口哲野出品,可玩性角度讲很适合mm玩,嗯,这也跟实际相符合,毕竟就是小妞介绍我玩的。 在家我也玩了一阵子,感觉比我原来PSP中已经安装的那些游戏要吸引我得多,看来PSP也不是一无事处啊,哈哈,原本都只是在像候机之类的时候打发无聊游戏才玩一下的。最近拿出PSP也是上次小思宇来这儿过夜,她拿来玩了一会儿炸弹人,后来还说搞得她一晚上没睡着,哈哈。以后得多多发掘一些有趣好玩的游戏啊,包括NDS上的。
周日头脑发热,去买了一台PSP2000和一台NDSL,总共花掉2700大洋,我哭丧着脸跟同事说,半个月工资就这么没了。同事则也说还好呢,才半个月工资。我说难道是要想想那些花掉2个月工资的。 买回来,其实没玩多少,因为对我来说,还是有很多方法打发时间的,消磨时间并不是我买它们的主要原因。为了省钱,我没买那些数据线,所以也不能自己下载游戏来玩了,都是铺子里给我装的几个。 简单玩了一下,发现NDS这个机型的机能不足了,确实只能从游戏性上下功夫了。有一个Mario篮球游戏,通过触笔来控制人物进行各种篮球运动中的动作,比如运球、传球、射篮、抢断等等;有一个养宠物狗的游戏,可以通过触笔来做手上的动作,比如挠痒、抚摸等等,还可以通过语音来实现命令的下发,比如呼唤宠物,让宠物做动作。总之,因为有了麦和触摸屏,游戏的方式就改变了,虽然它的色彩不如PSP丰富,运算性能没有PSP强大,但它的游戏趣味性和多样性可以做得比PSP好很多。 PSP的屏幕分辨率高,上面的游戏画面效果真是令人震撼,当然这也跟它的处理能力强悍有密不可分的关系。当然有点让我觉得无趣的是,PSP除了可以玩游戏,还加了太多其他功能上去了,看视频什么的,我觉得完全没必要嘛!
Category CodingStudio
在Visual Studio 2008里打开solution,都不知道从哪里下手了,囧。
这些天一直在写爬虫,但是进展极其缓慢,大概是由于对这个东西没兴趣吧,尽量可能很有用。
心不在焉啊。因为某人的一句话,第二天心里美滋滋地乐了一天,尽管那句话并不能代表什么。又因为一句话,开始低沉压抑,觉得人生了无乐趣。很无力啊。
昨天看了一下Archlinux,仓库里有现成的wxWidgets 2.8.11和boost 1.46.0,在Archlinux上写程序和发布程序应该是很幸福的事,需要关注第三方库应该是所有系统中最少的了吧。又看了下Fedora14,也有wxWidgets 2.8.11和boost 1.44.0,而Ubuntu里的boost是1.42,这个太老了点。
我琢磨着等爬虫写完,把Ninayan加上Facebook、Google Buzz和Google Reader的支持后,再回头来更新CodingStudio系列,这个系列反响不好我一直心有不甘。一个大的计划是把CodingStudio移植到Mac和Linux上跑,这个其实在最早做计划时就有的,但是后来只顾着在Windows上的效果,用了一些影响跨平台的方案,于是就搁置了。现在有了Ninayan的一点点跨平台经验,再来做CodingStudio应该会好一点了。要去掉wxLua的依赖,因为wxLua的实现不让人满意啊,而且我用的还是自己稍微修改过的版本。但CodingStudio现在已经有了大量代码用到了wxLua,于是这件事可能会花不少力气吧。甚至还想去掉Lua的依赖的,但那样变化实在太大了,而且有不少事情放在Lua里做确实方便不少,就留着吧。
再说吧。
这两天想试一下把手头这个用wxWidgets开发的工程移植到Linux和Mac,不过遇到了些困难。
该工程使用wxWidgets作为主GUI Framework,又嵌入了Lua解释器,将一部分界面和逻辑使用Lua脚本实现,而Lua脚本大量使用了wxLua以及诸如LPeg之类的第三方库,除此之外,主程序还使用了Boost、wxFlatNotebook、wxScintilla、wxPropertyGrid等第三方库。
主要的困难在移植到Mac上。目前我使用的wxWidgets是2.8.11版本,该版本在Mac上只有32位Carbon API版本,而编译Lua和其他第三方库默认出来的全是64位的,wxWidgets官方的消息是2.9.x版本有64位Cocoa API版本,但现在不稳定,还没正式发布。于是我无奈了!试了一下2.9.1的wxMSW,编译wxFlatNotebook和wxPropertyGrid都不能通过,懒得折腾了,打算等3.0版本正式发布了再说吧,说是希望2010年底前发布,鬼知道到底什么时候能出来啊,现在越来越觉得wxWidgets不给力了,各方面的!
至于移植到Linux上,以及将其他的Lua第三方库编译出来这些事现在倒是可以做。
之前我说过,作为一个文本编辑器,一个IDE,不能通过命令行参数打开一个文件,是很说不过去的。前面试图加入这个功能,结果遇到了些问题,经过昨天和今天的奋战,终于搞定了。
其实就是发现用wxWidgets的IPC机制怎么都不能正常运行,于是最后我想到了直接用Boost的InterProcess库,这个库也是跨平台可移植的,基本处于符合我的要求的范围内。
昨天还一直没死心,希望能用wxWidgets的IPC类搞定,结果果然无论是用DDE还是用Socket,都有问题。今天下定决心,先看了一下Boost的资料,发现其实很简单,InterProcess只是实现了共享内存的部分,再加上一点同步相关的机制,用于通知,于是只要在最老的进程中启动一个线程无限循环等待其他进程的通知,有了通知就从共享内存中读取文件路径信息,然后就可以打开了。
顺便说一下,Boost.InterProcess的共享内存类封装得比较底层,有一个类是纯粹的对系统的C API用C++类包装了一下。另一个稍微高级一点,但也是C++语言层面的高级,感觉缺少对现实世界对象的抽象。我有点奇怪自己现在怎么会考虑到这个层面的东西,大概是因为看了一段时间的Qt的文档和代码,Qt在这方面的工作确实做得很好啊。
还有个之前说到的,在wxApp::OnInit方法中,创建完主窗口后,直接打开文件也崩溃的问题,其实是当时测试的时候没有把配置文件放在正确的配置目录中,这个功能其实是没多少问题的。
总之,现在就是可以通过命令行参数指定文件打开一个文件了,然后又实现了单一进程实例,后面再要通过命令行参数打开文件,都会通过IPC机制通知最早创建的那个进程来打开文件。基本完美实现预定目标!
作为一个文本编辑器,一个IDE,不能通过命令行参数打开一个文件,是很说不过去的,于是我就想加这个功能,不料却意外地困难!
首先考虑当前没有已经运行的本程序的进程,通过命令行参数指定一个文件后,最wxApp::OnInit的最后返回前,主窗口已经正常创建显示后,可以将文件路径传递给主窗口,让主窗口打开这个文件。照理说,这应该是一个很平常很普通很正规的流程吧,结果不知道为什么,打开文件这个操作会让程序崩溃。
然后考虑当前已经有运行的本程序的进程了,这时如果再通过命令行参数指定一个文件,启动新进程,就需要让新进程通过IPC向老进程发送通知,让老进程来打开这个文件,而完成通知工作后新进程就可以退出了。这也是一个很平常很普通很正规的流程吧,于是我查阅了wxWidgets的关于IPC的文档和sample代码,感觉还是很简单的。在Windows平台上有两种选择,分别是基于DDE的实现和基于Socket的实现,可以用相同的代码,最终通过预定义宏来开关选择,可是最终仍然是问题重重。使用基于Socket的实现,进程在第一次启动时,Windows会弹出消息框询问是否允许该程序在本地打开一个网络端口进行监听,这就已经有点小题大做了。然后当新进程给老进程发送通知时,老进程不是没反应,貌似根本没收到通知,就是崩溃!如果切换成基于DDE的实现,倒是老进程能收到通知,但有个很奇怪的现象是从收到通知开始的那个wxDDEConnection::OnExecute函数开始往下走,wxChar*或wxString不能正确转换为const char*(因为我是使用Unicode编译项目,而字符串要以const char *传递给内嵌的Lua解释器),反正就是无论用wxString::mb_str(),还是直接的wxConvLocal::cWC2MB()都不能正确返回转换后的const char*。试了一下C runtime中的wcstomb函数,倒是能正常转换。但在Lua回调宿主程序导出的函数时,该函数将wxString转换为std::string作为返回值传递给Lua,无论用哪种转换方法,结果也会崩溃!
到此为止,所有尝试均告失败,加入命令行参数打开文件功能仍然没有实现,郁闷!
我一直在寻找,甚至试图自己编写一个Source Insight的替代品,主要看中它作为一个源代码阅读工具,并具有良好的通用代码编辑功能。如果一定要找出同类产品来,还真是比较难,也许Komodo IDE和SlickEdit在通用代码编辑器的范围上可以往上靠,但在代码阅读器的范围内,实在很少见,可能doxygen和understand for C++可以勉强算是一类,但实现方式差别很大。现在有了DForD SourceCoding,总的说来,它是最接近Source Insight定位的同类产品。 DForD SourceCoding具有良好的中文支持,这得益于Scintilla控件的完美实现和ICU的强大兼容性。Source Insight的中文支持一直是其软肋,多年来没有什么实质性的改进,无论是保存项目文件的路径字符,还是文件中的字符,凡是中文,都很有可能出现轻重不一的问题,DForD SourceCoding则完全没有这些问题。 DForD SourceCoding使用Tab栏多文档界面,很难想像如今还有一个拥有大量用户的多文档界面的软件,居然没有Tab栏,Source Insight就是那么一个独树一帜的软件,以至于有牛人通过逆向工程等手段,给Source Insight开发了外挂,通过外挂给Source Insight添加Tab浏览等功能,可谓用心良苦。 还有一个大问题是DForD SourceCoding的代码编辑器是支持代码折叠的,而Source Insight至今仍无任何迹象显示要在这方面有所改进。代码折叠也算是众多Source Insight用户特别期待的一个功能了,对于现在一个完整的代码编辑器,基本上可算是标准配置,可是比较遗憾的是,这个功能似乎连外挂也是不能指望上了。 当然DForD SourceCoding也有不少缺点,比较明显的是,速度比较慢,比起Source Insight不是差了一两个数量级。其次,DForD SourceCoding的代码分析功能相比Source Insight来说,不够精准。DForD SourceCoding直接使用了ctags和cscope来进行代码分析,而Source Insight应该是对cscope进行了一定的改进,而且跟编辑器结合得更紧密。另外,DForD SourceCoding虽然本身是基于一个Lua脚本语言扩展的架构实现,但它并不开放这个扩展构架以便用户进行二次开发,而Source Insight则是向用户开放了脚本扩展的能力。所以说,DForD SourceCoding还需要持续改进,才能彻底战胜Source...
昨天算是发布出去了,这次花了3个月时间。修正了一些bug,添加了一些新特性,修改了一些功能。总之,现在回头看来,不那么令人满意。
没有UT是最大的问题,根本不能保证某次修改会影响到什么。这不能再忽视了,test case要开始补起来。
其次是编译器差异和编译模式差异之大,出乎我的意料。好几次都是VC编译出来的正常,用GCC编译的就不正常。或者debug编译的正常,release的不正常。这是因为我离不开Visual Assist,也有点离不开VC的调试器。这点实在不好解决。
再次是Lua开发环境还是不够好用。Auto Completion不准确就不说了,有时Auto Completion出来过后,整个程序就会很卡,不知道为什么。以后要能做到Auto Completion分库,可以让用户随意通过增删文件来增删符号库。
最后一点是对架构的不满意。经过如今大半年的迭代发现,插件扩展架构的可扩展性和可裁剪性不够灵活。这点现在还没有具体的思路,或者说一直觉得实现上也许有点麻烦。
除了这些外,还有许多特性要增加,比如增加几种常见的SCM工具支持,开放二次开发接口,增加插件扩展的开发环境等等。
这是个很简单的功能,但却很有用。SciTE和Notepad++都有一套自己的实现,感觉Notepad++的效果比较好。从它们的配置文件中提取出众多编程语言的注释符号即可。注释分为两类,一类是行注释,另一类块注释。不是每种编程语言都支持这两类注释方式,甚至有的编程语言都不支持可以有注释。当然这个不是很重要,反正所有的信息可以写在配置文件中。
昨天还意外地发现,用boost.lambda对std::basic_string和wxString对象进行==比较时,用VC编译的运行正常,用GCC则一直不正确。一开始还以为是两个编译器对两种字符串对象的内存布局不一样引起不同的结果。最后发现,其实是我自己写的迭代器在std::find/std::find_if中不正常,在GCC编译的程序中,比较谓词根本没有被调用。回想起来当时看到GCC的std::find/std::find_if对于随机迭代器是特化实现的,想想其实我那个迭代器不需要随机迭代器,用双向迭代器就可以了,改了后,一切都正常了!
昨天完成了自定义快捷键的特性。该特性在配置对话框中实现与用户交互。
首先,在程序启动时,装载所有菜单项时,把所有菜单项的ID、标题、快捷键信息记录下来,作为缺省的配置。将缺省配置保存到文件中,然后查看是否存在保存了修改后配置的文件,如果存在该文件,则装载该文件的配置,应用到程序中。应用过程分两步,刷新菜单显示和设置快捷键表。
接着,处理在配置对话框中的用户交互响应。在对话框初始化时,加载当前正在使用的快捷键配置。用户可以修改其中任意一项的配置,当用户选择应用修改后的配置时,就将当前配置保存到文件中,以便下次程序启动时可以装载这个修改后的配置。
基本处理流程就是这样。用wxWidgets实现时,也是比较容易的。wxWidgets提供了快捷键相关的几个类和方法,相当方便,包括wxAcceleratorEntry、wxAcceleratorTable、SetAcceleratorTable等等。
这里不得不抱怨一下,wxWidgets对于一些明明日常需要使用的类和方法,竟然没有文档进行说明。另外还发现个问题,wxAcceleratorEntry有个ToString方法,当其中的Key Code是除了字母、数字外的其他的可打印字符时,会断言失败,太Orz了,只好自己写代码转换了。
Relation视图可以算是完成了,至少是处于可用的状态了。基本原理就是调用cscope这个程序,本来这个程序是开源的,而且是用BSD许可的,比较干净的做法是把代码拿来编译进自己的工程里。不过我懒得研究那个代码怎么编译了,直接调用现成的可执行程序,通过管道获取其输出,然后自己解析一遍输出内容,显示在relation视图上。这样看来这该是个很容易实现的功能,但是实际上我却花了不少时间。原因是我一开始考虑得过于简单,把所有工作都放在一个singleton中完成。既要生成新进程,又要获取管道输出,同时还要兼顾老进程没有结果又有新进程的请求到来。于是总是在同时有多个进程时崩溃。后来把新老进程调试和获取管道输出分别放在两个类中实现,就都好了。
另外还有个问题是用gcc编译。现在这个版本基本上也到了收尾的阶段,我也买了个Mac Mini,希望能把它移植到Mac OS X上。Mac OS X上可以用gcc,于是我就先尝试在Windows XP上用gcc编译这个工程。这些天一直在折腾这事,总是由于这样那样的原因失败。到今天为止,终于可算是正常通过了,有几点需要记一下。我一直用boost svn trunk中的代码,绝大多数时候,用VC编译链接都是没问题的,可是这次用MinGW中的gcc 4.4.0把boost.thread链接到工程中时,仍然会报有几个符号找不到,如果是用正式发布的1.43.0版本的Boost,是可以正常链接通过的。gcc不支持在函数体内定义结构体(类),VC9是可以的。gcc在用boost.lambda时有些情况会编译不通过,就是几个结构体内的成员被lambda bind后再进行比较的情况,但是VC9是能编译通过的,而且也不是所有这种bind并比较都不能编译过,具体的还得继续研究一下。总的说来,gcc对类型检测比较严格,呃,说难听点,是比较死板,不如VC那么智能。还有种情况是gcc编译wxString::Format时,如果第二个参数开始传入的是wxString,运行时会出错,但它又报不上来,基本上就是直接崩溃,VC在这方面又做得好得多,不过这点我估计是受不同编译器对对象内存布局不同引起的,所以也许gcc真是无能为力,VC那样可以用算是歪打正着吧。
好吧,总之最头痛的两件事算是解决了。
把ctags封装了一把,其实是CodeLite中的codelite_indexer,因为它已经把ctags提取出来了,不过是5.6版本,又对C++部分做了些修改,不过我不清楚这些修改有什么作用。有点奇怪的是,如果在Lua中用的话,只能提取一次tags,再试图提取tags的话会出错,就我现在猜测可能是里面有些全局状态,用过后没有恢复。于是我只好用Rings了,这是个在Lua的state里再创建一个state来执行代码,master state和slave state之间基本可以互不影响,但也可以传递些数据。这样我就每次都是在一个新new出来的Rings的slave state里调用一次ctags。在封装ctags的时候发现codelite_indexer没有把gnu regex编译进去,这需要指定几个宏定义,看makefile就知道了。
现在已经可以将所有文件都提取一遍tags,并存入数据库中了。而context视图都是在数据库中查找可能匹配的符号信息的。但这需要保证当前数据库中的符号是正确的最新的,所以一个合适的自动更新符号数据库的机制就很有必要,现在还没想好要怎么弄,既要有及时性,又要求不能影响用户的操作体验。
之后还剩下一个大特性是relative视图了,这个目前有些困难,无论是数据上还是界面上,都没有比较方便的现成解决方案。
有个纠结了几个月的问题,同样的文件,在我的程序里打开后显示的换行符和其他程序显示的不一样!一直想不通其中的原因,总之我是没怀疑其他软件会出错,因为基本上所有其他的软件表现是一样的,只有我的程序跟它们不一样。
今天又纠结起来了,于是一狠心,准备全盘照抄CodeLite的源代码,用Beyond Compare合并了绝大部分代码,最后发现,问题仍然存在。于是我不再怀疑编辑核心的问题,准备从其他地方着手分析。比较有嫌疑的是文件读取的部分,我的做法是用Lua将整个文件使用*a参数全部读出,然后用ICU将其从系统默认编码转换成UTF-8,再将这UTF-8的字符串传给Scintilla显示。我猜测会不会这个转换编码的过程把换行符处理过了。于是再单独的Lua环境中测试了一下,发现是没有处理的,其实稍微想想就知道,这应该是不会变的。既然确认转换编码不会影响这个,那么我就再将焦点往前移,看看读出的文件的原始内容是什么。将读出的内容转换成16进制打出来,发现我的程序确实是按照原样显示的。但是Notepad++/CodeLite/Code::Blocks甚至VS都将一个\r\n处理成了\r\r\n,会多显示空行。这是让我有点迷惑的,为什么就只有我的程序是照文件的原样显示的?
最后还是没有得出确切的结论,据我的猜测,是在文件读取时的方式引起的区别,文本类型的方式在某种读取方式下会多插入换行符?这个可能是存在的,不过我觉得太无趣了,不玩了!
有一做开源游戏的老外兄弟发邮件来说程序在点了try按钮后就崩溃鸟~我万般郁闷滴说,其实我以为不会有这么脆弱滴说,我还以为基本可用滴说,我现在比较失落滴说……
总之我没有充分的测试,这是事实。但我现在也没足够的条件啊,我猜测还是在用Crypto++进行RSA签名验证那段崩溃的,不过这也仅仅是猜测。虽然还存在着各种可能的原因,但基于这个猜测,我目前能做的其实不多。我要换掉Crypto++,这个库从一开始引入我就很不情愿,谁让那个libtomcrypt最初就没好好用成功呢。在看雪论坛上看到过有人说,要加大保险系数,自己写RSA算法实现是必须的,不过我不会啊!我最多可能再去网上找段现成的代码来,或者继续研究下libtomcrypt的使用。
自从那天去了徐家汇后,我就有种想买个组装机的冲动。那天问的说,用次点的集成显卡,2k就能搞定一台了。我想要台多核x64的,最好是4G内存,500G或1T硬盘,这样可以装个64位的Win7,还可以装些WinXP/2003什么的,用来做开发做测试的环境就差不多齐了。如果这样在3k以内可以搞定,就再花个4K多买个Mac Mini,就有了个Mac的开发环境了。比较经济的选择呢!
昨天晚上从微软官网下载了VS2010,今天上午装了后,试着把原本用VS2008编译的各个第三方库都用VS2010编译了一遍。用VS2010替换VS2008比较明显的一点好处是,没有Side by Side的困扰了,CRT库只要把两个DLL文件直接放到系统目录中就可以了。也就是说,开发好的应用程序部署要轻便了一点,不用带个VC Redist包出去了。在这一步中,不得不多谢bjam这个工具,对于换用不同的编译器的需求,适应得绰绰有余。
晚上又尝试把所有插件扩展脚本中用到Xerces的地方都用RapidXML了,这样又可以去掉一个DLL了,想当初一个用MinGW编译的Xerces的DLL就有4MB多,然后是一个Lua的扩展库,几百KB,前些天在宿主程序中去掉了Xerces的依赖后,换用VC编译的DLL,体积减小到1.8MB,而Lua的扩展库也减少到40KB。到了今天,可以把这个1.8MB的DLL也省了。
想想还是比较舒服的,试着打了个安装包,原来是15MB左右的,现在是10MB左右,少了约1/3。
配置功能让我纠结了好些天,现在基本上思路是确定下来了,也已经做了一部分了。
首先想说的是出乎意料的事,当时总以为用XML存储内容会比sqlite3存储内容占用空间大,经过实际测试100KB左右的数据用XML占用空间反而更小,大概是因为用sqlite3的话还会有一些用于索引之类的数据。
接着发现用sqlite3中那种二维表格来存储我想要的那种数据格式不是很方便,还是用XML那种树形结构方便,而且XML可以在同一级层次存入不同含义的节点,这也增强了表达能力。
后来我还是决定有boost::property_tree来操作通用配置文件,结果发现这个官方文档已经过时了,不过好在有人在maillist中提到了,也给出可用的代码了,居然还有人说读库代码就知道用法了,囧。另外想说的是,在存为XML时,没有更多的控制选项吗,没有pretty print吗。这次我倒是没有直接为Lua封装成一个C库,而是直接在宿主程序中用luabind绑定了一个简单的配置文件读写类,省了不少事。
最后想说,这进展实在太慢了,到现在为止,才做完通用配置的读取。
今天粗略考察了一下Code::Blocks/CodeLite/notepad++的配置功能,发现需要做不少工作。
和外部工具特性一样,配置功能也需要一个用户界面,但这用户界面却更复杂,因为配置选项有各种不同的应用场景。总体上看来,我比较喜欢Code::Blocks的那种配置对话框,最上边是一个static text控件,中间是一个listbook,最下边是几个标准按钮。查了下wxLua的文档,这种界面效果用wxLua基本上可以实现。从代码中可以看到,Code::Blocks是用XRC这种协议实现的,这样的好处是界面和逻辑代码分离,我也一直觉得通过完全通过代码来构造用户界面实在很土,效率又低,但我又不知道有什么工具可以方便地进行用户界面设计并生成XRC,特别是其中有自定义的控件。不过现在既然是决定用wxLua实现,也没办法了,就继续用代码生成界面吧。
我要加入配置功能,主要是为了支持用户可以自定义编辑器的各种设置,特别是各个lexer的风格,于是又看了一下那三个软件的配置文件的存储格式。前些天我一直在想的是,用sqlite3数据库来存储配置内容,今天看了看boost::property_tree,觉得这个库似乎不错,接口使用起来也还算方便,而且屏蔽了底层存储格式细节,目前可以支持INFO/INI/JSON/XML格式,于是我又想把这个库的一些常用接口封装一遍给Lua用,但是又有点担心这些格式在存储时有大量冗余信息,不如sqlite3格式紧凑,而编辑器的风格定义又会有很多信息,所以还得仔细考虑一下,明天就先尝试把编辑器风格定义都用XML描述一遍看看效果,如果实在是冗余信息太多,再用sqlite3吧。
这个特性以前就实现过一遍,那是在MFC+Xtreme Toolkit Pro下做的,想起当时的情形,完全没有任何规划和设计,真正的quick & dirty。这回是用wxWidgets实现,总的说来要比上次方便一点,但也方便得有限。
此特性分为两部分,一部分是配置用户界面,用户可以实现添加,删除,修改等操作。另一部分便是菜单项以及响应。
配置用户界面是一个对话框,我这里用wxLua实现,代码量不大也不小,总之最近总是觉得用wxLua不是个好选择,一方面似乎不稳定,另一方面开发效率不高。用wxLua最大的好处在于字符串处理方面借势Lua,还算比较趁手。
菜单项和响应部分就比较低级了,基本上都是在宿主中用C++实现了接口,然后供Lua调用。其中比较重要的是创建进程部分,以前用MFC时,这种功能都是用Win32 API写的,现在用wxWidgets了,好在wx中有这样的封装,不过感觉并不方便,但也勉强能用吧。
这个特性原本还以为半天或一天就可以完成了,现在已经大约3天了都没完成,唉,明天争取把剩余部分搞定,然后实现编辑器scheme!
ZenCoding由2部分组成,ZenCSS和ZenHTML。其中ZenCSS只要简单的查表替换就可以实现,而ZenHTML相对要复杂得多。为了比较完整地给CodingStudio添加ZenCoding支持,花费了我一周时间,当然这一周我也是堕落了,工作时间和效率都很不乐观。
本来我已经发现用LPeg实现ZenCoding将是非常合适的解决方案,但看了一两天LPeg的文档后,还是有点迷糊,再看看ZenHTML的规则很少,硬编码实现也不是太复杂。
首先扫描是否当前表中已经有对应的项,如果没有,则下一步。
匹配E+E,将表达式按+分隔成多个子表达式,然后针对每个子表达式进行处理。
对子表达式匹配E>E,将子表达式按>分隔成多个包含关系的表达式,对各个表达式分别进行处理。
对表达式匹配E#name和E.name,到这步之后,E就可以查表了,而name部分仍然需要继续处理。
对name匹配E*N$和E*N,到这步后,就可以获取到所有信息了,然后向前回溯,组合成最终的字符串。
我这里的实现跟官方ZenCoding还是有点区别,官方ZenHTML是先匹配E>E,再匹配E+E的,我想我还是得照官方的改一下的。
本来这是打算在上周五完成的,结果上周五又开小差搞界面去了,周六周日又跑去魔都了,于是就拖到这周了。今天刚开始的时候还有点惧怕的,怕是实现难点有点高,甚至又冒出过放弃的念头的。后来还是硬着头皮做一点是一点,结果还不错,比想像的要容易一些,已经能达到90%的计划中的程度了,剩下的10%么,从个人感情上还是从策略上,都应该放到后面的版本中实现了。
下面先说一下最终的表现吧。
前一个版本,code snippet使用的展开缩写的快捷键是Ctrl+,,这次把这个快捷键换到Ctrl+;了,那是因为另外又增加了两个操作,这两个操作是正反对应的,于是分别占用了Ctrl+,和Ctrl+.。正常的操作方法是,假设在编辑Lua源代码时,输入for,这时光标停在最后一个字母r的后面,按快捷键Ctrl+,,会自动将for展开为比较完整的for i = 1,10 do…(省略号表示后面还有些内容,这里不影响说明,就不列出来了)并选中for后面的循环变量i。到这步为止,相比上个版本的实现,只是增加了选中循环变量i的这步操作,但也已经方便了用户可以不再手动移动光标位置来修改变量名称。接下了,就是新增的两个占用了快捷键的操作,即Ctrl+,和Ctrl+.,分别是向左或向右跳动选中1和10。也就是说,在这次for展开后,共有3处可能被自动选中,即i、1、10,至于每次选中哪处,可以通过快捷键Ctrl+,和Ctrl+.来修改。这是基于这样的应用场景:在for循环中,基本的循环结构是自动补完了,但实际上循环变量和变量的初始值和终结值是最可能需要根据情况修改的,于是编辑器就可以通过快捷键快速选中这些部分,而不用再通过鼠标或方向键等常规方法移动输入光标进行修改。这就是最终的表现。
接着简单记一下实现的过程。
因为从整个程序的实现架构上的原因,此功能的实现一部分由Lua脚本完成,一部分由C++完成。首先是修改了code snippet的模板,如上例中的for,在模板中的定义是for ${1:i} = ${2:1}, ${3:10} do…(省略号表示后面还有些内容,这里不影响说明,就不列出来了)可以看到有3处用${}包括的内容,这些内容的都用一个冒号分隔,冒号前面是一个编号,冒号后面是最终展开后填入到编辑器中的内容。编号用于按快捷键Ctrl+,和Ctrl+.时进行排序,Ctrl+,则从大到小跳转,Ctrl+.从小大到跳转,初始状态时选中编号为1的部分。在for后展开snippet,是用Lua脚本完成的,那会先从模板配置文件中找到缩写对应的模板,然后将${}部分全都提取出来并替换成冒号后面的部分内容,并根据当前编辑器的插入位置重新计算和修正每个${}的位置信息。这些位置信息用于后面的选中功能。然后把所有这些信息都存入C++实现的编辑器对象中,在C++实现的编辑器类中会有几处事件通知处理。一处是刷新UI时,更新当前光标位置,如果当前光标位置已经不在任何一个${}的范围内,那么本次code snippet展开就算完成任务了。另一处是编辑器内的文本修改,如果有新增或减少文本,那么要修改当前光标所在的${}的长度(这个长度在选中文本时需要用到),并修改该${}位置后面的所有其他${}的起始位置。只有这样,才能在修改了一处${}后,仍能继续正常地在各处${}间来回跳转。好了,基本的思路就是这样了。
题外话,想说一下,在文本处理方面,脚本语言确实比C++要方便一些,比如查找替换${}部分,在Lua中实现的模式匹配就很好用。
昨天偶然发现CodeLite已经升级到2.5版本了,作者还真是孜孜不倦啊。下载下来看了一下,发现最明显的是界面上的变化,工具栏变漂亮了。于是我又好奇心起来了,找来它的源代码看看,原来是用wxAuiToolBar类而不是原来的wxToolBar。于是昨天我先在自己的程序里把主工具栏也换了一下,感觉是很爽。昨天还加了最近打开的历史文件记录和解决方案记录,一直弄到晚上9点才基本搞定,一开始没搞清楚怎么处理2个wxFileHistory对象。
今天开始着手增强Code Snippet。前天已经想通了,现在的插件机制基本上算得上强悍,就不用完全照搬TextMate的Bundle了,只是Tab trigger还是不错的。我的决定只要把code snippet部分做得跟Tab trigger差不多就行了,以后再完善一个插件机制,提供一个插件开发包就行了。
今天写代码,看着焕然一新的工具栏,以及方便的最近打开文件菜单,心情非常好,code snippet的预处理部分基本上完成了,明天只要加上快捷键,可以进行跳转就OK了!后来又觉得应该把TeX的符号工具栏也用新式的wxAuiToolBar,由于它跟wxToolBar的接口有点区别,所以自己从wxAuiToolBar继承下来创建了个新类,主工具栏和符号工具栏都可以使用新界面了,感觉不错!
看来得多找些更新积极的开源的项目,多学习学习那些源代码啊。
想到实现Bundle,是个比较大的挑战,有些部分必然会跟编辑器核心结合得比较紧密,对于我这种直接使用Scintilla控件实现的方式,很有可能需要修改Scintilla的源代码提供必要的支持。今天一想,其实如果基于我现在的Code Snippet的思路做下去,是很难做到TextMate的地步的,因为Bundle能完成的功能很多,输入输出条件也有好几种,而code snippet只是其中的一种而已。如果只是沿着把Code Snippet强化这个方向发展,最多实现到TextMate中Tab trigger的那种地步,而这些正是我之前一直在考虑的以为是Bundle的东西。小瞧了啊!没办法了,一步一步来吧。
昨天在QQ上跟人交流,知道一个诺基亚的手机应用开发大赛,到6月10日截止提交作品,到9月评出结果。现在算来还有足足2个月,不过我并没有好的题材。他是做图像处理方向的,而且是用QT的,所以移植到Nokia的手机上应该工作量比其他人小多了吧。另外他还给我看了一个老外做的画图软件,那界面真是赞啊!如果不是做像IDE这种严肃型的软件,其他的大众类软件真的得好好设计一下界面。
前些天Firefox自动升级到3.6.2后,看到Firefox也用twitter/facebook/blog进行推广了,看来这是大势所趋啊。之前试过几次想创建一个组织型的Facebook账号,结果一直没成功,今天发现原来是创建错类型了,Facebook有专门的为产品/组织等非个人形式的个体创建页面的入口。于是今天就在网站上加了twitter和facebook的链接,至于blog嘛,众所周知世界上最成功的blog营销案例,在软件行业应该算Joel on Software,不过Joel在那篇宣布以后不再写blog的文章中提到过,要靠blog聚集人气,不光要写自己公司的产品,还要写关于软件开发的方方面面,这样才会吸引各种相关读者的讨论。可是,我现在的致命缺陷是,我当前的英文水平完全不够用来写blog,真郁闷啊!
昨天晚上咬牙把所有的图片都修正了一遍,基本处于可用的状态了,终于撑过这段繁琐枯燥的工作了。今天又添加了几个新建项,上次发布的时候把这个忘掉了,这次补上。不过实现得有点儿问题,在第一次显示的list view中只要是有多个图标的,总是会在最开始留出那个数目的图标的位置,真郁闷,心烦意乱地调了一下午,也没进展,先不管了。
接下来的任务是实现一个类似TextMate的Bundles机制,这需要好好设计一下,实现成什么样,怎么实现。最近在纠结的问题是,快捷键要不要换掉。TextMate和e都是用Tab的,而且不支持Shift+Tabe。我在之前的版本实现code snippet时,用了Ctrl+,这组快捷键,而且我觉得支持反向跳转似乎很炫,呃,目前确实只能用“炫”来形容,因为不知道实际使用过程中到底有没有用。
昨天提到从抠图片,到添加到程序中,一共要处理500多个图标,很大的工作量,而且太枯燥机械了。今天看到MiloYip大大的留言,恍然大悟,我怎么就一直没想到把这个过程自动化一下呢!
今天上午的时候还在老老实实地把图标一个一个加入到程序中,这有两步操作,一步是添加XML描述,另一步是添加Lua响应函数。一上午,总共添加了53个图标,到吃中饭的时候自己都觉得效率太低了。在MiloYip大大的提示后,下午用Lua写了几行代码,花了2个小时左右,把剩下300多个图标全都添加进去了。以前真是太傻了,多花了不少时间啊!
剩下的工作就是把那些图标稍微都修正一下。
从这次事件可以看出,我的相关技术敏感性还不够,缺少自我改进意识。
昨天还说今天要写文档的,结果今天花了近半天时间画图标去了,当然基本是抄的别人的,我自己是没这种美工功底的。不过比较欣慰的是,最终的结果还算看得顺眼。
另外,本来运行latex等编译命令是直接让它显示个黑窗口的,后来觉得实在不爽,又看了一下它的命令行参数,发现有一个-interaction=nonstopmode,可以在出错时也不停下来,这个不错,于是可以把黑窗口隐藏起来,同时把它的输出重定向到程序的日志窗口了。
最后,是修正了一个小缺陷,在添加已有文件到工程时,同一节点中添加重复的文件也会成功,这太傻了点,就限制了一下,在添加前先检查一遍。
不行了,这东西已经做了5个月了,效率太低了,明天一定要认真快速地写手册了。
今天看到消息,WinEdt发布6.0版本了,这个软件停在5.x版本长达9年之久,我曾经也试用过,遇到它发疯的时刻,不知什么操作过后,所有的中文字符都会变成乱码,而且在输入时,自动换行很不智能。6.0版本马上下载下来试了试,发现编辑器部分做得更漂亮了些,其他的以前就没深入过,也不知道有什么改进了。
而我的TeXCoding经过今天的努力,基本处于可发布的状态了。现在程序已经能够自己屏蔽没有菜单项的菜单了,在只有TeXCoding的时候就可以没有调试和构建菜单了。所有的,呃,其实是大部分最常用的TeX编译命令已经实现了,当然其实是被我砍掉了好些我觉得可能不那么实用的。这些被砍掉的,以后可能会在后续版本中添加。
明天就开始认真写用户手册了!
前次说到可以做一个TeX编辑的完整工具,于是这两天都投入进去了,AutoCompletion倒是也实现得勉强可用了,自我感觉至少比SciTELaTeXIDE的做得好一点点吧,Code Snippet也实现了,具体配置是抄SciTELaTeXIDE的,还有Outline也实现了,用正则表达式每一行都匹配了一遍,其中对一个大字符串按换行符分割是用Lua自己的string.gmatch的,这个模式匹配方法还是很好用的。今天一天都花在实现LaTeX编译之类的命令上去了,其实就是直接调用TeX系统中的可执行文件,完全的体力活啊,而且有一点的是,我对TeX的了解只是一点儿皮毛,很多命令都不知道的,这就使得我只能看SciTELaTeXIDE有哪些命令了,还剩下一点点,争取明天全部完成,就可以真正开始写用户手册了。
抱怨一下QT Creator,真是比较另类啊,选了用Release方式编译,最后链接仍然是用Debug链接的,真是土死了,还一直没找到在哪里设置链接子系统是用console还是windows,默认都用console了,只好手动修改下它自动生成的makefile。
因为准备写用户文档了,而且是打算用LaTeX编写,最后生成PDF格式,所以要有一个好用的LaTeX编辑器。本来这类工具应该是很多的,但从一开始我就打算是自己写一个这样的工具。当然编辑器仍然是用Scintilla的,只不过,Scintilla中的lexer对TeX的支持并不好,官方代码库中,有两个可用的lexer,一个叫tex,另一个叫latex。但是两个lexer都有比较明显的缺点,以至于根本处于不能用的状态。那个叫tex的,其他表现都勉强可以接受,但是在输入字符时,响应迟缓,不能忍受。而latex则没有支持代码折叠,很简陋。
好在有一个叫SciTELaTeXIDE的开源项目,它是基于SciTE-ru项目的,所以也是用Scintilla的。开发者是向Scintilla贡献最原始的那个latex lexer的作者,在SciTELaTeXIDE中,latex这个lexer已经被修改得比较完善了,同时还增加了BiBTeX和ASY以及metapost的lexer。简单看了一下,要增加这几个lexers,对官方Scintilla代码的修改很少,很容易就合进去了,同时还废掉了官方的latex和tex这两个lexers。
只要再做好Auto Completion,Outline和编译命令,基本上又是一个完整的工具了,呵呵。
今天主要搞定了源代码断点,之前遇到的如果有断点,debuggee启动就会崩溃的问题,其实是通过socket发送命令过去后,debuggee在接收时会把不完整的信息压入到队列中,跟昨天遇到的回应消息不完整是一个道理。
最后我仍然是采用了完全使用debug库的功能实现的方式,这种方式的缺点是调试执行的效率很低,因为每次debug库回调时,都要判断一下是否在当前行有断点。至于之前我想过的那种快速断点的方案,就留到以后版本中实现吧!
今天可算是最近两个月来状态最好一天了,修正了一堆问题,以至于调试器工作得像样起来了,剩下只要完成源代码断点的功能,就接近可发布的状态了!
这里简单记一下这些已解决的问题。
一开始,是有各种奇怪的问题的,比如在Lua扩展中解析XML格式的回应信息时,会报invalid node,有时候又会报call stack节点不存在,有时候在VS的调试器中运行时,会在分配内存的时候异常。这些问题,最终的原因可能是相同的。我的设计是另有一个工作线程通过socket在与debuggee进程通信,它会接收debuggee进程发回来的回应消息,并把这些回应消息压入一个队列中。而界面线程,会在应用程序消息空闲时,从该队列中撮回应消息,并转发给Lua扩展进行处理。这时我犯了一个错误,我会把一个可能不完整的消息结构体压入队列中,而界面线程取出处理时,并不能检测出是否内容完整。而且,我还是通过动态堆分配来存储这些额外信息,在界面线程中又会去释放这块内存,于是工作线程很可能去读写一块已经无效的内存。
另一个问题是,debuggee有时候会启动即崩溃,通过打印的调试信息显示,是boost::shared_ptr的使用有问题。我仔细检查了代码,发现只有两个boost::shared_ptr,还发现,其中有一个是不必要的,那是一个放在线程函数中的临时对象,生命周期只在该线程函数中有效,所以换成栈上创建就可以了。这样一来,后来经过几次测试,也确实没再出现崩溃。
还有问题是,只能调试一次,再启动debuggee就自动退出了,还有调试的时候用户手动停止调试,debugger会崩溃。其实这是没有仔细划分好各模块的职责,没有仔细设计各模块交互的协议。后来总结发现,如果debuggee要退出,分两种情况,即自动运行完退出和手动强制退出,无论哪种退出,都给Lua扩展发送一个通知,然后Lua扩展把调试端口(socket通信)停掉,而这个通知如果debuggee有能力发(手动强制退出),就让debuggee发,如果没能力(自动运行完),就让debugger发。而手动强制退出,则是只要向debuggee发送个退出命令就可以了。
今天心情真舒畅啊!
这两天整调试器,经过不怎样的努力,到现在为止,功能上基本算是具备了,不过就是剩下些bug,主要有:
从debuggee发送过来的信息有时候经过XML解析会出错。
从debuggee发送过来的信息,有时候没有调用栈信息。
断点工作不正常。
有时候刚启动debuggee,debuggee就崩溃。
明后天就集中精力修改这些问题了,哈哈!
我决定,不再盲目赶进度了!
一直以来我都处于一种奇怪的紧张赶进度的状态,每个月都想着能在当月或下月底前release一个可用的版本出来,于是为了达到这个目的,又由于实现中的各种未预期的状况出现,一项又一项的特性被我临时决定砍掉,或拖延到以后版本中实现。
所谓慢工出细活,现在我决定,不这么着了!对于那些基本特性,还是要花时间仔细实现的。所谓基本特性,就是别的大部分同类都有这些特性,假如没有这些特性,用户就会感觉到不习惯甚至诧异。这些基本特性有着这样的定位:在第一个版本应该实现大部分,而且以后版本的维护工作量很小。
对于要缩短每个版本的开发周期,我觉得砍掉特性或安排特性在不同版本实现,是必然可以采用的策略。而只有那种本产品特有的,有极高技术难度的,或单纯为了推广策略而需要分步推出的特性,才可以这样做。
嗯,今天要实现中断构建过程和在文件中查找替换的功能,希望不会有太多困难。
大清早的,被老妈叫起,驱车去4公里外的集市吃早餐。要了一客小笼包子,一碗馄饨,说起来从上大学开始这八九年来,还真很少吃得到这样的早餐。上学的时候嫌贵了,工作了之后就一般只在公司食堂里吃,周末虽然在家,但都睡过去了。偶尔为之,真是享受啊!
昨天突然想起,我的编辑器只能打开ANSI格式的文件,如果是Unicode,UTF-8之类的文件,打开是一片空白的,于是想改一下吧,打开时检测一下文件头部的BOM,用iconv转换一下再显示到编辑器。本来以为这将是很顺便的一件事情,从网上下载了Windows下可用的iconv库和头文件,最后却无奈地发现一个诡异的事情。原本至少ANSI格式的文件中的中文是可以正常显示出来的,如果用了iconv库,无论有没有进行编码转换,中文就全部变乱码了,而且显示乱码后,Scintilla就会报断言失败,然后整个程序就崩溃了。最后我不得不相信,这应该是iconv与wxWidgets或Scintilla配合有问题,至于到底是什么问题,我就不深究了。
没了iconv,于是我只好转投ICU门下了。还有点比较头痛,却又让我觉得解脱的一点是,我C++程序将是用MinGW编译的,而ICU当前的4.2.0.1版本曾经尝试了很久,都只能让VC编译通过,MinGW无奈地败下阵来。这就说明,我这编码转换的功能不能通过C++实现了,也省得我再费心思去琢磨到底把这个功能放在哪里实现了。Luaforge上有个叫ICU4Lua的项目,可以在Lua中使用ICU,这个库我以前也编译过,拿出来试了试,非常简单易用,只好把读取和保存文件的功能也用Lua实现成插件了。
前面提到iconv转换编码搞得wxWidgets写成的程序在Scintilla刷新时崩溃,还以为是iconv引起的问题,于是决定使用ICU。
嗯,结果我错了,用ICU仍然有问题,有相同的问题,尽管我已经把这部分代码放到Lua中执行,对嵌入的Lua解释器,调用ICU4Lua,再调用ICU,仍然是Scintilla直接断言失败,然后崩溃,错怪iconv了!
经过一系列的尝试,最后发现只要把Scintilla的code page设成UTF-8就解决了,真是奇怪,原来设计936照理在本系统上也是正确的,它却仍把中文字符分成2,3部分显示。现在好了,连中文字符都作为1个字符显示了。另外发现,ICU的接口果然丰富呀,可以直接获取当前系统使用的code page,安逸!
昨天本来是想完成编译构建的特性的,结果先去搞工程树视图了,发现了好些工程树视图代码中隐藏的bug。
其中最诡异的莫过于在打开一个工程文件时,读出各个xml的DOM节点,调用另一个函数处理这个DOM节点,总是发现值为nil。搞了老大半天,把代码结构也调整了不少,最后发现是该函数本是个递归函数,在递归调用时居然少写了个参数,于是Lua就主动把后面缺的参数值赋为nil了。人都差点儿崩溃了,开始抱怨Lua不稳定,其实是人不稳定啊,哈哈。这次事件让我再次觉得,缺省参数值这个特性实在是很危险,以前在C++程序中也因为这个原因引起过问题。
在定位这个问题的过程中,还偶然发现,原来Xerces中的getElementByTagName是游走整棵树的,跟我原来的设想不一样,都是MSXML用惯了的后遗症。决定以后就只用Xerces了,无论是VC还是GCC都可以用,以后换个操作系统也可以用,现在Lua中也可以用,彻底告别Xerces,至于它保存成文件时格式不好看的问题,暂时不管它。
Xerces的文档一直没仔细看过,昨天发现,XMLString::transcode返回的字符串,用完后,要用XMLString::release释放,原来我都没这么做!
前两天偶然发现,又有内存泄漏了。昨天仍然在写Lua脚本,于是没怎么管它,今天早上起来wc时,突然觉得这内存泄漏实在是眼中钉,肉中刺,一定要解决。
首先是发现,只有在程序中打开过文件后,才会有内存泄漏,而且泄漏的数量跟打开文件的数量似乎是成正比的。于是开始查看打开文件部分的代码,发现这部分代码实在写得太简单了,几乎不存在泄漏的机会,绝大部分函数都是立马将请求转发到Lua脚本去了,我假设Lua脚本不会出现泄漏。
于是我尝试新建一个文档而不保存,发现果然没有泄漏!这就说明泄漏可能的两个来源,一个是读写文件时,一个是根据文件类型作出不同响应时。接着,尝试打开一个txt文件,也没有泄漏,这说明第一个猜测的泄漏源不成立,那么把注意力集中在第二点上。
我先是怀疑是不是lexer相关的代码引起的泄漏。于是又用程序打开cpp文件,这是一种处于中间状态的文件,程序能认出这种文件的类型,应用相应的lexer对其着色,折叠等,但不做更多的操作。果然也没有泄漏,再打开lua文件,又有泄漏。仔细回忆了一下lua文件和cpp文件的区别,大概最有可能的两处是符号视图和代码片段视图,这两个视图在打开lua文件时是会被操作的,而打开cpp文件则没有。
这时,我先去看了一下符号视图,先把刷新视图的代码屏蔽掉。编译运行,没有泄漏。已经将范围缩小到这个函数内了,再只屏蔽添加新节点的代码,发现又有泄漏了,说明泄漏不在添加新节点的代码上。通过一段一段地屏蔽代码,直到最后发现,是我自己写的Xerces-C++的封装类在从字符串中载入xml文档后,就会有泄漏,所以可以确定问题出在这个载入函数中。
打开这个函数的代码看了看,非常简单,只有3行代码,其中第1行就new了一个对象,后面却没有任何释放的动作。在后面加了一句delete,重新编译测试,确实没有泄漏了!还有一个Lua使用Xerces-C++的绑定库,也要做相应的修改。
解决,安逸!
前几天,把所有的插件以插件为单位打包成zip了。不过不知道wxWidgets中的zip虚拟文件系统如何支持密码,至少是没找到相关的选项。现在的情况是验证了方案可行性,可以确认功能上的不缺失以及性能上的损耗在可接受的范围内,但真正实用是一定要有密码的,也就是为了保护插件中的源代码。以前还以为带了密码就不方便第三方开发插件了,现在想通了,其实只要我提供一个插件开发环境,其中自带插件打包功能,这样就可以用同一个密码了。既然wxWidgets没有简单方便的接口来支持密码zip,那就只好自己写一个这样的功能了,好在zip实在是一个很大众化的格式,源代码很容易找到。
今天在宿主程序中做了修改,并添加了插件,可以在适当的时候触发刷新语法树视图。 刷新语法树的时机其实并不好选择,总的说来,应该在这两个时刻进行刷新:一,文档刚刚打开;二,做出了影响语法树内容的修改。第一点,比较容易做到,但第二点就比较困难了,它包括当前活动文档的切换,以及当前活动文档被修改。切换也是比较容易响应的,但怎样判断一个修改是否影响了语法树内容,就不简单了。我现在的简单做法是,每当有新的行时,就进行刷新,笨了点,但勉强能用。 刷新语法树的方式,也是需要仔细实现的,我现在的做法完全是为了简单起见,先停止刷新窗口,然后清空整个树,再把整个树的内容都重新添加一遍,再刷新窗口。这样的缺点是在刷新时,能明显地看到整个树视图的闪烁。如果要规避这个问题,应该比较当前树视图中的内容和待刷新的数据,在树视图中逐个判断有新增的,或需要删除的节点,这样就比较流畅了。但这个算法就相对来说复杂,而且可能更耗资源。 目前我只是让Lua中的函数定义作为语法树视图中的唯一的元素,目前看来效果还可以。其实单就Lua来讲,还可以添加变量的定义以及表的构造。但是眼前可以预见的问题是,变量可能有很多,全列出来可能干扰视线。而表的构造表达方式可以很复杂,而且表是可以在程序中动态增删元素的,这要如何处理。
昨天偶尔发现,在笔记本上编译的工程在台式机上启动即崩溃。一开始的时候我认为是因为lua装入的一些第三方库dll没有设置好依赖的dll路径和正确的manifest配置,后来发现问题不是那么简单。 首先是我用了LuaJIT的dll,而之后发现LuaJIT要求CPU支持SSE2指令集的,我那台式机是2002年的配置,当然没有。换成官方Lua后,问题仍然存在。 接着发现,安装程序没有把配置文件复制到正确的文件夹下。看了一下安装程序的脚本,果然没写对。但是当把配置文件的路径修改正确后,问题仍然存在。 因为台式机上装了Win2000ProSP4,WinXPProSP2和Win2003,所以当XP上仍然不能运行时,我切换到Win2000和Win2003上进行测试,发现问题同样存在。我考虑了一下两台机器软硬件的区别,猜想是不是仍然是软件配置的问题。于是我在笔记本上用VirtualBox建了个干净的XP系统,第一次运行时,居然报了个错,说ltxml加载不成功。幸好我前天已经自己写了个Xerces C++的绑定,而且用于的地方现在还不多,立马全都把使用ltxml的地方改成用xerces的。之后虚拟机上可以正常运行了。 到了这一点,说明可以排除安装部署的问题。再想想两台机器的区别,台式机上的3个系统都是原生的中文版系统,而笔记本上和虚拟机上的都是英文版的,其中笔记本上的打了个可以处理中文的多国语言包。我有点怀疑会不会是因为这个缘故,但又觉得可能性不大,如果真是这个原因的话就不好处理了。我试着把安装后的那些mo文件都删掉,结果仍然没用。 最后我没有办法了,只好修改源代码,从程序开始处依次加入日志,看到底在哪一步引起崩溃的。经过逐步排查,最后定位到使用Crypto++的初始化RSA公钥的对象构造时崩溃了,连异常都没有抛出。这时我想到了LuaJIT对CPU的要求,猜想会不会Crypto++编译时也受CPU的影响。用CPU-Z看了一下虚拟机的CPU,是跟宿主的CPU几乎相同的。不再继续猜想,直接在台式机上编译了一遍Crypto++,拿到笔记本上可以链接上,再把exe复制到台式机上,程序也可以正常运行了。 至此,问题解决!这时我不禁有些担心,我这样一直用笔记本写的程序会不会都有这种问题,一遇到老机器,就会罢工呢!
昨天晚上,突然发现又有内存泄漏了,我真的要疯掉了。一段代码一段代码地注释掉,来查看到底是哪段代码引起泄漏的,中间又偶然发现有些情况下又没有泄漏,真是太容易迷惑人了。最后发现还是原来那段扫描文件目录并分析xml文件那个函数引起的泄漏,费了老大的劲儿。这是一种比较奇怪的现象,我到现在也没有想明白怎么会有这种情况。本来以字符串作为key插入到std::map中时,如果有重复的key,我会用clock()生成一个数字添加到key的末尾,作为一个新key,以为这样就可以保证都插入进去了。现在发现似乎还是有漏网之鱼,真是太奇怪了。不过我也不想深究这个问题了,索性遇到这种重复的情况,直接在原来的key后面添加一串比较随机的字符,并再添加一个递增的编号,这样再要有重复,我就去买彩票了。 昨天在实现Auto Completion功能,呃,只是Lua编辑时可用。后来发现LuaForWindows中带的SciTE的一个做法可以学一下,就是可以分析出当前编辑器内的所有单词,以这些单词作为Auto Completion的列表源。于是今天想了想,这部分提取出单词的功能应该由C/C++来实现,Boost中有个Tokenizer库,刚好用来作这个事情。看了一下文档,用它自带的一个示例修改了一下测试一番,提取一个828KB的cpp文件中的所有单词,然后用STL的sort算法排序,再unique和erase一把,把重复项去除,最后再用STL中的copy算法复制到另一个vector中,总共这些操作,在VC2008中进行测试。最后发现,在Debug模式中大约在10700ms左右,Release模式则在500ms左右,近20倍的性能差异!我不知道这个比例是线性的,还是指数级的,反正证明一件事,那就是Release的确实比Debug的快很多!
到昨天为止,基本完成Code Snippet的框架,剩下的都是些体力活。该特性要求在点击菜单项时,根据当前光标所在位置的字符串,替换成对应的代码片段。由于菜单项是通过插件添加实现的,而且Code Snippet又根据当前编辑的源代码对应的编程语言不同,也会有不同的处理,所以也是通过不同的插件实现的,这就要求插件可以再次调用插件。好在当初设计插件扩展框架时,已经考虑到这一点,所以虽然有实现过程中有需要慢慢调试的地方,但没有特别大的障碍。 完成Code Snippet后,应该开始Auto Completion特性的开发。该特性是本项目中可算是难度最高的特性之一,同时又有比较高的准确性和运行效率等要求。还有点比较头痛的是,针对不同的编程语言,可复用的东西不多。 此外,还有个功能应该尽早加入,就是处理文件的不同编码。比如通常,尤其是早期的代码,都是直接使用ANSI编码保存。而现在已经比较常用的是保存成UTF-8等编码方式,特别是像LaTeX的一些处理器直接要求输入文件是UTF-8编码。所以应该能在文件的装入和保存时,可以自动处理文件的编码问题,这可以通过iconv或ICU实现,不过问题就在于有了选择,才是苦恼啊!目前我倾向于使用iconv,因为相比之下更轻量,而且够用。 这些天发现,Lua的字符串连接符..效率还真低,怪不得Lua要提供*all和table.concat等设施。 本来Lua中操作XML有几种不同的选择,这跟在C++中情况差不多,我选择的是比较轻量的ltxml。而昨天在Code Snippet特性的开发过程中发现,我把所有的信息都保存在xml中,而每次完成snippet时都从xml中读取,开始几次还是正常的,但只要过一会儿,在调用xml.open时就会报什么试图index一个function值中一个number值,还真是诡异,但调试发现这时无论xml.open还是传入的参数都是正确的,很是纳闷啊。于是只好规避一下,只在开始时读一次,全部都装入到内存中,以后就直接读内存了。 一直以来,都是通过print来进行Lua脚本调试,真是应了那句“一夜回到解放前”。前两天才在界面上加了一个专门的输出窗口用于从Lua脚本打印字符串过来。好比是当年写Windows GUI程序时,用MessageBox调试进化到用OutputDebugStrng进行调试。昨天记起来有LuaLogging这么个第三方库,于是仔细看了看,很简单的功能,只有几个lua文件,可以记录日志到文件、控制台、socket、email或数据库中。于是我参照这些appender的实现,加了一个新的appender,用于将日志打印到宿主的插件输出窗口中,感觉不错。 接着是使用luabind的问题。在网上看到有人说luabind的各个版本都存在指针的double deleting问题,这让我有点惶恐。好在今天看邮件列表时,看到luabind的作者说,这种问题只出现在使用智能指针或类继承时切片的情况,而且要求是Lua的state先于这些对象被销毁,现在没有好的办法来修正这个问题。我想了想,这几种情况我现在都不会遇到,我只有最最简单的嵌入和扩展交互。之后,又发现有人在邮件列表中写了一个luabind和SWIG的性能比较,SWIG的封装比luabind的快一倍。看到这个结果,我觉得是意料之中,SWIG的封装方式比较底层,调用快也是正常的。不过luabind的作者说,他写了些benchmark的测试,在未发布的luabind 0.9中已经有不小的改进,虽然仍然不比SWIG快,但相比0.8.1版本,差距缩小了约一半,期待0.9的发布。 昨天无意中看到云风blog上一篇老文章提到有Lua Ring这么个库,可以在Lua代码中再创建个新的Lua state,让某些代码在这个新的state中运行,从而保护比较重要的核心state。我潜意识中认为,像我现在这个项目使用嵌入Lua来作为插件扩展的运行环境,确实要用一个比较安全的环境,即所谓的沙盒,但这个Lua Ring怎么应用上去,以及能有多少效果,仍然有待考察。 前些天,从SVN上更新的了wxPropertyGrid的代码后,发现用GCC编译不过了,直到昨天仍然不行,实在忍无可忍,真要骂娘了。上它的sf项目见面看了一下,自11月25日更新代码后,估计作者就压根没发现这个问题,于是在上面提了个单。今天发现作者已经回复那个单,并在svn trunk中已经修正了该问题,总算松了口气。 今天仔细学了一下如何让wxWidgets支持国际化,发现非常简单。只要在程序初始化时,自己创建一个wxLocale对象,把mo文件的搜索路径加进去,设置好当前要使用的语言。其他想要被翻译的字符串用_()宏替换wxT()和_T(),如果是个wxString对象,就用wxGetTranslation(),这样在这些字符串会自动从mo文件中读出相应的翻译后的文本,感觉比ini等配置文件,或是国际化资源dll的方案方便很多。不过为了让插件支持国际化,也可以使用类似的方案,但是我有poEdit时发现它只能从源代码中提取出需要翻译的字符串,不能全新的创建一个,这太土了,以后一定要自己写个好用的。 最后的一个问题是,现在的插件扩展机制,容易出现重复代码,比如相同的功能会在菜单中写一遍,在工具栏中也写一遍,这该怎么修改一下呢,呃,得仔细考虑考虑
不知从什么时候起,程序退出时,VC的输出窗口中就会打印一大片内存泄漏信息。开始还没怎么在意,认为只要程序功能正常,有点儿内存泄漏实在不是什么大不了的事情。最近随着代码的增长,似乎打印出来的内存泄漏数量也随着增长了,我仍然有些想逃避,安慰自己说不定是wxWidgets的问题,其实用膝盖想都知道,这种可能性太小啦! 晚上实在忍不住,或许真是只是想证明,确实是wxWidgets的问题吧,决定看一下到底是哪里泄漏的。因为程序使用嵌入Lua,很多功能都通过脚本扩展实现了,C++的代码量不多,基本上只剩下一些主框架界面的创建和消息响应转发的工作,所以没花多少时间,通过分段屏蔽代码来检测内存泄漏的源头。 最终发现有3处,而且确实都是我自己的代码有问题。 首先是有个singleton在程序退出前没有销毁掉,好像在GoF中还是《Modern C++ Design》中说的,这种情况的singleton销不销毁影响不大,不过用Loki中的Singleton是不会有这种问题的,所以还是为了美观起见,主动销毁吧。 然后,稍稍花了点时间,发现有一处new了一个对象后把指针插入到std::map中,却发现new出的对象个数最后比map中的元素个数多几个,那么最后通过迭代map销毁这些对象时,就有几个漏掉没销毁掉了。我一时间还没想明白怎么会出现这种问题的,后来想起来,有几个对象插入时估计是使用了相同的key,于是只能在map中留下一个。程序运行表现倒是没错,这是一种奇怪的现象,但在这里是合乎逻辑的,但仍然要改掉。 最后,发现是new了wxFlatNotebook后,就有泄漏。照理说,这种有父窗口的子窗口对象创建后,wxWidgets是会负责销毁的。所以估计是wxFlatNotebook有什么特殊的要求,从sourceforge上找到它的页面,有SVN下载选项,最近一次更新是2008年的事了,估计是不会更新了。它的作者居然就是CodeLite的作者,但我发现似乎CodeLite本身就没用这个组件,作者又自己实现了一套标签系统,不过都放在CodeLite里没独立出来。对比了一下我使用的wxFlatNotebook的版本,应该是2.1版,跟CodeLite代码里放的那份是一样的,SVN trunk中的至少是2.2以后版本了。于是下载下来,还有sample,这才是最重要的,看了一下sample在主窗体的析构函数中调用了一下wxFNBRendererST::Free()。把这条语句加到我的程序中,真的没有泄漏了! 现在舒服了,不报内存泄漏了,能这么顺利地解决3处内存泄漏问题,跟程序架构有很大关系啊!
昨天偶然发现一个超级严重的问题,程序运行一小会儿就会自动退出,什么提示都没有。至于没提示,这已经有一段时间了,照理说,内部状态、逻辑不正常么,可以给个Windows的崩溃报告嘛,可是它偏偏没有,弄得我要跟着崩溃了。 后来在代码中加入一些跟踪语句,发现出错的原因跟我的猜测一致,内嵌的Lua解释器栈溢出了。这是个很头痛的问题,以前听人说过,如果没有sandbox,插件运行环境是不可靠的,呃,最出名的是chrome的架构,经典的sandbox。但是我这个程序跟它的情况有点不同,在主窗口和子窗口上都有大量的用户交互操作,以及主窗口和子窗口之间大量的交互,子进程间的通信会很复杂。而且现在引起崩溃的,都是主窗口中的逻辑,所以还是会导致整个程序的不可用。 昨天晚上调试了好久,发现只要更新工具栏按钮或主菜单项的界面状态的响应函数打开后,过一会儿就会退出。所以最后可以把范围缩小在C++调用Lua函数的那一块代码上。我不怀疑Lua的代码有问题,凭我现在对Lua的了解,即使真有问题,估计我也是束手无策的。既然是栈溢出,而且时间不长就可以重现。我仔细地看了那块代码,又看了Lua manual和PIL,以及Luabind Documentation,发现我一直忽略的一个问题,在调用Lua的C API出错后,Lua经常会把出错信息压入栈中,而Luabind可能会直接将其封装为luabind::error类型的异常抛出,然后我就只是看一下那个字符串内容,却没其他处理了。这是一处错误,应该在提取字符串后,将其弹出。另一处错误是,我这里调用Lua中的函数,都是存放在一个表中的,所以中间无论哪个步骤出错,都应该把先前压入栈中的东西弹出。还有一处错误是,最后我从Lua栈中获取到函数后,用luabind::object封装了一把,然后luabind::call_function来调用,这时我又直接返回了,却没把这个放在栈中的函数弹出。 昨晚解决了这三个问题后,还以为所有问题都已经修正了。今天又测试了一遍,发现过了约半个小时后,程序还是自动退出了,而且连那exe文件都没了!我要疯了! 唉,这什么都是从零开始的,风险实在太大了。使用wxWidgets是第一次,复杂的内嵌Lua扩展框架是第一次,使用Luabind是第一次,使用wxLua是第一次,把所有东西混在一起用更是第一次!而且很不爽的是,已经用惯了MS的解决方案的我,没有像MSDN这样的大而全的文档极不适应,那些说使用开源的东西成本低的人,不知是真的短视,还是别有用心呢。
经过定位,方法很简单,在有怀疑的地方加入跟踪语句,打印栈大小,发现确实还是在那几个地方,栈中项的数量稳步增加,这才想到,会不会是从表中获取某个元素后,那个表还在栈中呢?看了下文档,也没有相关的说明,只好先作这个假设。在调用表中的函数后,应该弹出两个值,这样修改后,果然过了一个多小时也没退出,而且看栈中的项也确实没泄漏的。 昨天修正了对TeX代码高亮的问题。原本发现有TEX和LATEX两种lexer,如果直接设置好lexer的话,LATEX只能着色,没有代码折叠,而TEX有代码折叠,不能着色。看了代码似乎也都不用设置什么关键字字符串的,没办法只好到scintilla的maillist上问一下,Neil回复说SciTE中用的是TEX。于是我又看了一下TEX的properties文件,发现还有4个专用的property要设置,加上后果然好了。开源就是开源,只有通用的scintilla接口文档,却没有针对每个lexer的文档,唉! 昨天还写了个小程序,用于将原本给另外一个程序用的Scintilla的所有lexer的语言配置文件从xml格式转换成现在正在进行的这个程序可用的 lua脚本。这是个很省事的活,不过这小程序也是花了不少时间修改,因为要生成的lua脚本也在不停地修改。从这看出,xml真是一种存储数据的好格式 啊,可以方便地转换为其他格式。要是SciTE的配置文件也是xml的就好咯,想当初为了把众多lexer的配置从properties格式转换成 xml,可是花了我好几个晚上的业余时间的。 接下来应该要实现其他一些基本的功能,以及好好考虑下如何实现针对不同lexer的各种功能。
描述一下问题,程序主框架是用C++实现的,GUI框架用的wxWidgets,有一部分功能通过嵌入Lua解释器调用Lua脚本完成,如果要在Lua脚本中用wxLua实现个对话框的这种情况下,需要一个父窗口,而最好的父窗口是由C++实现的,现在就需要能把C++中实现的窗口传递给Lua,并让wxLua作为父窗口使用。 问题根源是出于偷懒的考虑,我把C++中需要能被Lua调用的类、方法等用SWIG嚼了一遍,生成了脱水代码。这样用SWIG返回的wxWindow*跟wxLua中的wx.wxWindow就不是一种东西。 解决方案比较quick and dirty,过程略有点曲折。昨天偶然在wxWiki上看到一段文字,描述了如何将MFC的窗口关联到wxWidgets中,我就想如果wxLua是严格移植了wxWidgets的话,应该也很容易实现的。不过很沮丧的是SetHWND、AdoptAttributesFromHWND、Reparent这三个方法wxLua一个都没有实现!于是又去wxWidgets的Google group上找了找,发现一个叫AssociateHandle的方法,可以关联一个原始的Windows窗口句柄。到了这一步,我已经没有其他出路,只好修改wxLua的源代码,在wxLua\modules\wxbind\src\wxcore_windows.cpp这个文件中给wx.wxWindow添加一个新的方法void SetWindowHandle(long hwnd),代码实现可以抄SetWindowStyle的,函数签名相同,里面的步骤也类似。最后要在wxWindow_methods的初始化列表中添加这个新增的方法,就可以重新编译wxLua了。 有了这个修改过的wxLua,再在自己的应用程序中暴露一个方法以便Lua获取主窗口的句柄,接口就可以在Lua中这样使用了: local win = wx.wxWindow() local hwnd = frame:GetMainFrameHandle() win:SetWindowHandle(hwnd) 这个win就可以作为wxLua中创建的子窗口、对话框的父窗口了!
Category Cryptography
我从几个月前开始用acme.sh来自动签发Let’s Encrypt的免费证书,一两个月后,发现它没有renew成功,手动renew发现每次都是报错:
突然想研究一下软件注册机制中使用比较强的加密算法,能带来什么效果。说到比较强的加密算法,用非对称的算法应该是公认的比较好的选择。流行的大概有RSA、ElGamal和ECC了。翻出几本买了好久,都没仔细看过的书,最后发现我的数学基础实在很差,这方面的思维分析能力也很差,最终大致能看懂原理的只有RSA算法。RSA算法的强度建立在大素数因子分解的基础上,只要选择足够大的两个大素数,当然还要受制到当前主流硬件运算能力,就能保证一定意义上的安全。 目前有很多开源的加密算法库和大数运算库,可以提供RSA算法的实现,比如MIRACL、Crypto++、LibTomCrypt等等。结果发现MIRACL只能免费用于非商业用途,而LibTomCrypt的接口让我比较迷惑而不会用,剩下的Crypto++倒是可以正常使用,接口设计得也非常方便易用,缺点是体积大了点,而且很早以前在网上看到过有人说它有些算法可能涉及到一些版权、专利的问题。 最后是使用RSA实现软件注册算法的问题,从书上看到,注册机使用RSA私钥对用户名进行解密,解密的结果则作为注册码,用户拿到该注册码,输入到软件注册界面后,软件使用RSA公钥对注册码加密,能得到用户名?不过我发现,在用Crypto++进行计算时发现,随便取的一个字符串作为密文用私钥根本解密不了啊,会抛异常说无效的密文,其次,使用公钥进行加密时,也有限制,对明文的长度有限制,根本不能对很长的,可能是密文的字符串进行加密呀!倒是用RSA进行签名是可以的,这种签名方式就与MD5、SHA之类的单向散列算法效果类似了,只能确认明文是否被修改过。 不过我到PEDIY的论坛上问了问,其实采用多强的加密算法没多少区别,只要破解者能找到最后判断的语句,找到关键的那条跳转语句,就可以爆破了,前面的那些复杂的加密解密运算全做无用功了。汗!
Category Editor,IDE
这几天突然又想试试C++ Builder,现在最新的版本是12.1。曾在大学时使用C++ Builder 6写过一些小程序,这么多年过去,源代码丢掉了一些,还能找到一些。用12.1是不能直接打开6.0的工程文件的,需要新建VCL工程,再把窗体文件、源代码文件和头文件添加进去,才能编译。12.1的VCL整体上变化不大,主要是字符串类变成了UnicodeString,以前的C++ Builder和Delphi在字符编码方面的支持确实是一大弱项,项目代码拷过来后,主要就是字符串部分需要修改一下。
偶然在Embarcadero的营销邮件中发现现在C++ Builder有Community Edition即社区版可以免费下载使用,想当年从大一买了自己第一台电脑开始,也曾用过6年左右C++ Builder写了些小程序,为了情怀也得试用一下。
本来这是打算在上周五完成的,结果上周五又开小差搞界面去了,周六周日又跑去魔都了,于是就拖到这周了。今天刚开始的时候还有点惧怕的,怕是实现难点有点高,甚至又冒出过放弃的念头的。后来还是硬着头皮做一点是一点,结果还不错,比想像的要容易一些,已经能达到90%的计划中的程度了,剩下的10%么,从个人感情上还是从策略上,都应该放到后面的版本中实现了。
下面先说一下最终的表现吧。
前一个版本,code snippet使用的展开缩写的快捷键是Ctrl+,,这次把这个快捷键换到Ctrl+;了,那是因为另外又增加了两个操作,这两个操作是正反对应的,于是分别占用了Ctrl+,和Ctrl+.。正常的操作方法是,假设在编辑Lua源代码时,输入for,这时光标停在最后一个字母r的后面,按快捷键Ctrl+,,会自动将for展开为比较完整的for i = 1,10 do…(省略号表示后面还有些内容,这里不影响说明,就不列出来了)并选中for后面的循环变量i。到这步为止,相比上个版本的实现,只是增加了选中循环变量i的这步操作,但也已经方便了用户可以不再手动移动光标位置来修改变量名称。接下了,就是新增的两个占用了快捷键的操作,即Ctrl+,和Ctrl+.,分别是向左或向右跳动选中1和10。也就是说,在这次for展开后,共有3处可能被自动选中,即i、1、10,至于每次选中哪处,可以通过快捷键Ctrl+,和Ctrl+.来修改。这是基于这样的应用场景:在for循环中,基本的循环结构是自动补完了,但实际上循环变量和变量的初始值和终结值是最可能需要根据情况修改的,于是编辑器就可以通过快捷键快速选中这些部分,而不用再通过鼠标或方向键等常规方法移动输入光标进行修改。这就是最终的表现。
接着简单记一下实现的过程。
因为从整个程序的实现架构上的原因,此功能的实现一部分由Lua脚本完成,一部分由C++完成。首先是修改了code snippet的模板,如上例中的for,在模板中的定义是for ${1:i} = ${2:1}, ${3:10} do…(省略号表示后面还有些内容,这里不影响说明,就不列出来了)可以看到有3处用${}包括的内容,这些内容的都用一个冒号分隔,冒号前面是一个编号,冒号后面是最终展开后填入到编辑器中的内容。编号用于按快捷键Ctrl+,和Ctrl+.时进行排序,Ctrl+,则从大到小跳转,Ctrl+.从小大到跳转,初始状态时选中编号为1的部分。在for后展开snippet,是用Lua脚本完成的,那会先从模板配置文件中找到缩写对应的模板,然后将${}部分全都提取出来并替换成冒号后面的部分内容,并根据当前编辑器的插入位置重新计算和修正每个${}的位置信息。这些位置信息用于后面的选中功能。然后把所有这些信息都存入C++实现的编辑器对象中,在C++实现的编辑器类中会有几处事件通知处理。一处是刷新UI时,更新当前光标位置,如果当前光标位置已经不在任何一个${}的范围内,那么本次code snippet展开就算完成任务了。另一处是编辑器内的文本修改,如果有新增或减少文本,那么要修改当前光标所在的${}的长度(这个长度在选中文本时需要用到),并修改该${}位置后面的所有其他${}的起始位置。只有这样,才能在修改了一处${}后,仍能继续正常地在各处${}间来回跳转。好了,基本的思路就是这样了。
题外话,想说一下,在文本处理方面,脚本语言确实比C++要方便一些,比如查找替换${}部分,在Lua中实现的模式匹配就很好用。
这两天整调试器,经过不怎样的努力,到现在为止,功能上基本算是具备了,不过就是剩下些bug,主要有:
从debuggee发送过来的信息有时候经过XML解析会出错。
从debuggee发送过来的信息,有时候没有调用栈信息。
断点工作不正常。
有时候刚启动debuggee,debuggee就崩溃。
明后天就集中精力修改这些问题了,哈哈!
用了wxScintilla,我一直试图让其中用到的Scintilla代码保持跟官方CVS中的同步。现在发现,还是合得有问题了,功能没合进来,但是光是看代码,我也不知道到底哪里出错了。具体的现象是,现在官方的Scintilla是已经能直接支持多块选择了,昨天试了试我的程序是不行的。不过这个问题暂时倒不要紧,可以放到以后去修改。
看到SciTE开始有实验性的支持使用Lua脚本实现lexer了,不过接口还没有稳定下来。不过我猜这个特性可能不会合到Scintilla里面去,而且即使合进去了,我暂时也没有这个需求。
自从前些天看到TextMate的Bundles的介绍,以及Zen Coding的介绍,心里一直蠢蠢欲动!VS在有VA强大的智能提示的帮助下,或许可以不用这种方式的支持。但对于已经习惯于UNIX使用文化的人来说,这种自动代码生成方式是很符合他们的使用习惯的,而且同时又能极大地提升编码效率。我就开始琢磨着能不能也实现一下。
Zen Coding的效果看来,主要适用于HTML这种从SGML衍生而来的标识语言,这主要是它的语法,以及它的生成代码上的限制,所以如果不是这方面的应用,可以暂时不管它。
而TextMate的Bundles看起来就很让人心动了,以前只是听说过却没有直观地体验过,所以感触不深,前些天看了一些评论和操作视频以及manual,冲击太大了。当然这种机制在Windows平台上命令行工具并不流行,脚本解释器又不默认安装的环境下,可能不如Linux/Unix/Mac上那么突出,但如果能做成对少数几种工具、脚本语言的支持,也是很有诱惑力的。
大概想了下,如果要实现这套机制,要修改一下Scintilla中对Tab和Back Tab的实现。目前Scintilla中的Tab有两种不同的行为,如果选中整行或多行了,则会对选中行进行缩进,其他情况则是插入空格或制表符。在Bundles中或者说Tab Triggers中,Tab又多了两种行为,一个是缩写扩展,如果同时有多个扩展使用相同的缩写,则要显示AutoCompletion下拉框,另一个是缩写扩展后光标自动跳转。所以我的想法是,要在Scintilla原来的两种行为中增加缩写扩展的行为,并在内部保存一个状态,表示缩写扩展后,所有的Tab操作不再进行默认的缩进或插入空格(制表符),而是在这些时候都给个通知,让宿主程序自己处理这个操作。而宿主程序在适合的时候再发个消息给Scintilla重置那个状态,以便Scintilla又退回原来的Tab处理方式。
算了,不说了,先搞定调试器,再来看这个吧!
Scintilla和SciTE就不多说了,我接触到它并真正用到它,有3年多了,一直跟踪着它的最新发展。发现有几个跟它相关的项目,比如有用(有趣),值得记一下。
第一个要说的是SciTE-ru。这是个SciTE的增强版,大概作者是俄罗斯人吧,所以后面加个ru。SciTE从它本身的定位出发,并不会增加很多强悍的辅助功能,只能说是Scintilla有什么能力,SciTE便有什么功能。而SciTE-ru的出现则试图从第三方增强SciTE的不足之处,并修正了一些在Scintilla或SciTE中存在的小缺陷。如果对SciTE有爱,那么SciTe-ru则会让人觉得更有爱。遗憾的是我不在此列。
接着要说的是SciTE LaTeX IDE。这个项目在SciTE-ru的基础上发展而来,但它的定位是成为一个好用的LaTeX编辑器。作者不但在SciTE在软件包中增加了一些编写LaTeX常用的小工具,还在界面上增加了一批方便的按钮和菜单,更重要的是作者修改了Scintilla官方的LaTeX和asymptote的lexer,却没有合入到官方代码库中去。照作者的说法是修改后的lexer要求太苛刻,会破坏原有的应用程序。我是个LaTeX的初级应用者,确实使用SciTE LaTeX IDE编写过几篇文章,觉得从编辑器的角度出发,已经算是很不错了,但如果定位是IDE,则还是差得远的。
最后要说的是Sicintillua。这是个很有趣的Scintilla/SciTE的fork项目,它移除了所有Scintilla中使用C++编写的lexer,取而代之的是一个叫LexLPeg.cxx的文件,里面定义了两个lexer,分别是null和llpeg。对于各种已有编程语言lex支持都是通过外部的Lua脚本实现,所以用SciLexer原有的标准接口查询和设置的lexer都是llpeg,它又增加了两个接口用于设置直正的lexer。这个fork解决了一直以来就有的Scintilla增加lexer不方便的问题,因为有一拨人觉得,使用C++编写lexer并编译进Scintilla中实在麻烦,确实我也这么觉得,只不过我可以容忍,因为我直到现在都没有自己要添加lexer的需求。我简单地看了一下Scintillua的代码与官方CVS中的代码进行了比较,发现修改的地方不是很多,不过修改了一些接口,我不太喜欢,有可能的话,我要在Scintillua的基础上再出个修改版,能更方便地跟官方代码树进行融合。
Category TeX
今天总算咬牙把手册编造完了,一共22页,包括封面和目录。偶然发现在用Adobe Reader浏览这PDF时,在某几页会猛烈地闪烁,一顿一卡的,除了那几页有比较多的图片外,也没其他特别之处了。而同样的文件用FoxIt浏览,就没这问题,而且似乎连字体都要更清晰一点。
这就让我觉得很费解,很有点不爽,于是我打算尝试一下XeLaTeX。卸载了CTeX 2.4.6,然后装上了CTeX 2.8.0.125,因为这个版本里有XeTeX。简单看了一下网上的说明,要用XeTeX,基本不用修改什么,只是比较重要的一点是源文件要用UTF-8保存,当然这只对中文之类的双字节字符来说需要,我这个文档全是英文的,也就不存在这个问题了。然后直接用xelatex.exe编译,一步生成PDF。不过最后出来的效果,却让我很不满意。具体表现在,所有在figure或figwindow中的图片,都没有进行合适的自动缩放,而这点在LaTeX中是做得比较好的。我不知道是哪里的问题,在网上搜了一阵子,也没有提到只字半语。于是又试了一下latex.exe,好家伙,这个版本看到插入png格式的图片竟然报错说缺少什么RoundBox信息。我没折了,撤!
还是继续用回2.4.6版本的CTeX吧,闪烁就闪烁吧。
Category Life
节假日不用回老家真是太好了,29号晚上才决定去湖州龙之梦乐园玩一下,在网上团了酒店房间,虽然网上都说那边商业化很严重,似乎评价不高的样子,但总归要自己去过才知道到底行不行,反正离得不远,自驾1个半小时就行了。
端午节最终决定去武夷山游玩,对旅游这块确实既没多大兴趣,更没什么经验,都是老婆一手操办下来的。这个决定做的比较晚,导致买高铁票都是老婆花了不少日子靠在app上抢来,好在总体而言还算顺利,叫上两边的老人一起,浩浩荡荡7个人。
昨天是2019最后一天,晚上因为菜比较多,就喝了点红酒。然后跟爸妈视频通话的时候脾气上来了,把我妈狠狠骂了一顿。起因只是白天我妈把自己家里人的一些照片传到某些小程序上做了相册之类的H5页面发到家庭群里,我看到了就叫她不要传自己的照片上去,要保护自己的隐私,现在坏人那么多,谁知道他们拿了别人的照片会用来做些什么事。然后矛盾就开始了,跟我狡辩诸如国家领导人全世界人都知道、只发到家庭群里都是自己人、是她自己做的照片没传出去……晚上视频通话的时候打的我妈的手机,却是我爸接的,聊了一会问我爸我妈呢,结果她说没啥好说的,拒绝接视频。大概是喝了点酒的缘故,我立即语气很严厉地说起来,然后她就哭哭啼啼扯到其他话题上,简直烦透了,我的火气就再大了。最后是我爸说好了好了,才挂断了视频。
家狗昨天早上突然去世了。我妈微信上发来视频,开始我还以为是家狗在玩装死,后来马上我妈说家狗就是去田里找她,然后听到它狂叫了几声,等她下去从草丛里好不容易找到它时,就已经伸伸舌头死掉了,整个过程非常快,大概都不到一分钟。
过去几年每年初都会写个新一年计划,但几乎都没实现过,所以我觉得不要做计划了,也不要回顾已经过去的一年了。活着已经很辛苦了,我只希望亲人们身体健康,希望做事都顺顺利利。
昨天是一年一次的年会,每年的年会都是大大的失望,虽然说没有期望就不会有失望,但是每年都看着旁边的人能抽中各种高低不同档次的奖品,怎么会没有期望呢!
2017年完成了人生中的一件大事。其他的就混过去了。
公司组织的旅游,我报名了日本大阪京都线路,上周四上午出发,这周一(也就是昨天)下午回来。
妹子新工作居然要求自带电脑,然后就报到前一天晚上开始折腾一台老ASUS笔记本,结果折腾得自己改坏了系统登录密码,再也进不去系统,只能重装解决。
这次team building大家投票选出了方案,去江西三清山游玩。本来以为是一条休闲级的线路,结果事实却是疯狂级!
节前请了2天年假,节后公司又比法定多放2天,于是今天仍然在家闲着。
又是新的一年,看2016年1月1日做的计划,除了翻墙网关卖出一份外,其他的全都没有付诸实践,执行实在太差了。
又到年底了,看了下之前的2016年计划,发现似乎一条都没实现,这是多糟糕的执行能力。老话说得好,计划没有变化快,这话尤其适合我这种爱开坑,爱立flag,又爱拖延的人。于是我觉得我仍然得做些计划,不长远,就近期的一些小步子。
我终于也算是出过国的人了,上周四到周日,公司组织的旅游,虽然是报了团,但到了济州岛后是自由行。作为第一次出国的人,很多事情都是第一次。幸亏年初把户口迁回老家了可以方便地拿到户口本,不然没有居住证还不能在上海办护照。上海办护照还算方便,可以在微信里预约,外地人要等大半个月才能拿到。济州岛不需要签证,这也特别适合第一次出去的人。
从淘宝花了几十块钱买了个Nexus 5的尾插排线,然后自己掰开后盖换上,Nexus 5复活了!有点小遗憾是我的手工不好,换上后不是很紧凑的样子。
昨天回了老家,今天一早去了派出所办户口迁入,基本上还算顺利,去街上拍了张一寸照,办户口迁入用。然后身份证又要换过了,这里直接在派出所里拍的照片,这个比较方便,交了20元钱。剩下就是大约40天后可以领取新的身份证了。我又变回浙江人了,哈哈。
今天又到深圳办户口迁出了。有了上次的教训,这次预约的是11点-12点,飞机仍然是10点到的深圳宝安机场,然后打了个车到派出所,花了63元钱。上次坐机场巴士和公交车才花了16元!
最近几个月一直在纠结迁户口的事,虽然一直有点心理准备,但真到了没迁成的时候,心里还是有点愤怒的,不玩了。
这是跳槽后第一次过春节,没想到居然一共放9天假,然后又在节前请了4天年假,前3天带了妹子去我家,初四~初六去了妹子家,初五还去喝了木耳和小句的喜酒。
上周去了一趟深圳。本来这是计划8月份就要去的,结果当时是我不太乐意,后来发现我的身份证都过期了,还必须得回户籍所在地换,于是只能去深圳了,但又因为另一方公司进度拖延,一直拖到11月,还是我不停地催促下才搞定成行的。
最近实在没想到什么值得写的,连流水帐都写不出来了。
本来只是妹子的同学老家产茶,要帮那同学卖茶,但是还没好的包装,所以想着先把店开起来,可以先卖点咖啡,咖啡来源就是喵咖啡了。店在微店和淘宝都有,分别适用手机和电脑两种环境,店铺地址仍然是https://shop.yii.li。
周五下班时打电话回家,我妈突然说周六要来上海,打了我个措手不及,然后妹子开始发脾气。周五晚上一直闹到半夜,好不容易哄停了,然后收拾屋子一直到后半夜2点多。
想要MBP好多年了,一直没下决心买,实在是觉得有点小贵。于是拖了一年又一年,直到现在都差不多已经绝了自己花钱买MBP的念头,最大的进帐也就是去年情人节给妹子买了个MBA。
周末升级了Mac OS X到10.10.3,发现多了一个Photos app,打开一看就是iPhoto的替代品,于是想到把这两年的照片也整理一下导入进去,顺便翻了一下以前导入的老照片。
春节回来上班一周多了。上周六终于把thumbnail service的基本逻辑调通过了,可以work了,不过没有各种容错处理。
今天回老家了,赖床赖到8点多,大约9点出的门,要去建行的ATM取钱,结果跑到常去的那个网点,居然被封了,然后转到另一个网点,因为跟妹子有了点口角,然后包好的红包也没给她。
上周在cloudflare又新建了个账号,记得很多年前我有个账号的,不过忘了密码也忘了注册邮箱,只好再新建个。然后用free plan加了两个域名,其中一个就是现在blog在用的minidump.info,cloudflare除了CDN,还能提供SSL,这点非常赞,于是就加上了。昨天晚上看到有人说自己在github pages上的blog因为敏感词被GFW过滤而reset了某个页面,于是我想不如把整站强制使用https算了。说干就干,因为我用的是Jekyll,只要在_layout的模板中加几行Javascript代码就可以搞定:
2014年这么快过完了,真是有点不知所措,很多计划中的事情依然没有完成,甚至没有开始。
自从上个月突然感觉全身不适,觉得是因为身体肥胖导致的健康状况变差,我毅然决定必须要减肥了。其实我一直有减肥的想法,断断续续也试过一些方法,包括去健身房请私教,去美容院按摩,调整饮食,晚饭后去散步或跑步。但都因为看不到效果而坚持不了多久就放弃了。之前看到一遍文章,有人现身说法,自己几个月时间减了几十斤,方法很简单,就是节食加运动,于是我打算也再试试,没想到这个方法对我非常有效!
妹子生日的时候她表妹送了一个Bridestowe牌的薰衣草小熊给她。当时的多开心的,在电视上看到过某演艺圈的明星就是做这个生意的,在国内受到热捧。前段时间我在淘米的时候偶然发现这才买来没多久的袋装大米里居然有一两只米虫,虽然觉得这种品质的大米里会长米虫很奇怪,但因为小时候自家种自家碾自家吃的米里常常会有大量的米虫出现,多的时候甚至能听到“沙沙”的虫爬的声音,记得那时候爸爸还买来那种杀虫的药粉来撒在上面,所以我也没怎么当回事。前些天妹子突然发现放在床头的薰衣草小熊外面爬了好多米虫,幸亏外面套了个纱袋,才没让虫子大规模分布在整个屋里,但想来已经有一些能飞能爬的跑到外面去了。
早上出门打算开车上班,刚起步就听到有奇怪的声音,像是什么东西卡住了,下车绕着车看了一下4个轮胎,似乎是正常的,再起步,声音还是很大,踩刹车的时候声音特别大,于是只好决定不开车了,等周末的时候找家修车的检查一下,真烦躁!
周一去换了驾照,因为本人去深圳实在不现实,在网上看到可以直接转成上海驾照,于是就这么弄了。花了450元钱,就在车管所对面,一座要被拆掉的小楼里面,很山寨的问了一问“你开车的时候戴眼镜么”,这大概就算是体检了,然后在另一个房间里拍了张照,交了钱把身份证、临时居住证以及旧驾照留下就可以走了,隔一天就会用顺丰把这些证件送过来。明明走正规流程非常复杂繁琐的,只要交点钱就能非常便捷,这就是天朝现状,可谓生财有道!
今天早起送妹子去了火车站,回来休息了一下便出门办事。因为我的驾照快到期了,原本是深圳发的如果要在深圳续期的话非得本人跑去深圳不可,不光是要拍带回执的照片只有深圳的照相馆连得上深圳的相关部门的网络,指定的体检的医院还只有深圳的,所以对我来说成本过于巨大。好在后来网上搜了一下,像我这种情况的人可以直接在上海把驾照转成上海的,只要去指定的地点带上身份证、(临时)居住证和旧驾照,以及几百块钱,当天就可以把拍照和体检等所有手续都办完,顺便续期。因为我的临时居住证早已过期,我今天就打算先去续一下,于是先跑到居委会所在,大门紧闭,一张工作时间贴在门上,只有工作日才开放。怏怏离开,抱着试试看的心理去了镇上的社区服务中心,一问果然还是要居委会开的居住证明。只好下周一请假了!损失真不小啊!
最近在写一个彩票辅助分析程序,觉得研究彩票是个比较有意思的事情,在网上看了很多有根据没根据的文字,想把其中的一部分用程序实现出来,也不知道有没有道理,所以同时想把这些事情记录下来。
这个月总的说来过得很开心,进展很大,当然前些天也一度出现很灭世的事,甚至为之放声大哭。
一个人的日子果然非常无趣,于是马上回到了用物质享受来麻痹精神的状态,买了一个BlackBerry的PlayBook,一个HP的TouchPad,总共花掉2600块钱,这个月就开销就这变大了。
之后一段时间最主要的两件事,一是找工作,二是写程序。有很多程序要写,现在由于Qt的lighthouse在4.8版本的比较成熟的运用,使得它在QNX,Android,iOS平台上都能进行可以发布级别的移植了,甚至webOS上都可以用了,除了据说虚拟键盘会弹不出来,这样在Pre2/3上应该是没问题吧,虽然我最想的是在TouchPad上用。不过iOS上那个Qt4iOS是要付费的,而且不卖license给个人用户,估计是因为太贵,作者觉得个人用户承受不起,郁闷!
昨天下班后去浦东机场接了小咪,感觉她跟中学时的长相差别好大,看照片中学时要清纯漂亮很多。回到小区是21:39,然后去对面的接头暗号吃肉,不过好像有点吃坏肚子了,晚上2点多起来拉肚子。后来醒来很多次,7:15时醒来打电话喊人起床,再一直迷迷糊糊睡到10点多,发现小咪已经起床了,再起来两人收拾收拾,去老街吃东西。每当有人来这里,我都是带人去老街吃东西,哈哈。不过小咪没像其他人一样吃汤圆,而是去吃了小笼包。吃完就把她送到虹桥高铁站送走啦!
从高铁站回来,又把别人托小咪带回来的东西送到人家手上了。
哈,好像没什么可以写的了。
跟樱子聊天,突然又聊到我的blog,从csdn上的开始算起,2004年11月开始到现在,也足足写了7年了,csdn上有127篇文章,后来在blogger上,再后来搬到这个独立blog,也有近一千篇了。想起之前还曾试图用LaTeX整理排版所有的文章的,今天就想到要是把这些文章再整理一下,自己精心排版,最好能自己加上插图和封面,然后找个印刷厂印刷出来并且装订成册,印个十几二十本,贵点就贵点,送给关系最亲近的朋友,会不会很有意思。可是转念又一想,这种东西送人合适么,礼貌么,有人会要么,人家会不会就直接丢掉了。跟小咪说了一下,她也说要一本,呵呵。
其实我的blog内容很无趣的,大部分是在倒苦水,关于工作的、生活的、感情的,基本上是无聊的流水帐。但自己偶尔翻以前的文字,还是会有点心生感慨的,原来当时是这样的生活啊。
就这样吧,争取明年春节后就把这些东西都准备到可以交付印刷的程度。
才发现自己,经常让动力来源于无根据的幻想、对未来的奢望。
时间真的不够用啊,除了需要干活,还需要大把的时间来浪费,一天有48个小时都不够啊。
晚上去原力健跑了一会儿步,速度8.5,坡度4,跑了25分钟居然没啥感觉!记得以前勉强跑个10分钟都气喘吁吁了,现在居然只是回来后大腿有点酸!看来指望跑步能减肥实在不靠谱。
最后终于下决心去拍了一对才379元的音箱,直接支持iPad2/iPhone/iPod插入播放,也支持电脑的音频输出。想想在原力健和阿玛尼几千几千的刷,怎么到这里就抠了,犹豫那么久。马上就可以早上起床刷牙洗脸的时候听音乐了。
要向某人学习,少买书,多读书。要喝酸奶。要每天泡脚。要嘴角习惯性上扬15度。要抗压力耐打击。要会Android/iOS开发。要用WinDBG/GDB调试。要用自己的IDE写代码。要能用英语跟老外对话。要努力赚钱。要心怀梦想。一切都会好起来的。
想起昨天晚上我妈给我打电话,然后我很不耐烦。最近几次都这样,脾气越来越暴躁。因为受其他不相干的人的影响,而让自己情绪恶劣,实在太不值得了,可是我忍不住。好像这些年来,我的脾气越来越不受自己控制了,性情都有了大变化,那天跟阿菲打电话,说起最近我遇到的一些事,然后她就说我变了,以前还至少会怎么滴,现在却是这样做了。唉。
真想带上一点钱,一个人跑到一个从没去过的,没人认识的陌生的地方去。可惜放不下的东西太多了。
10月12日,伟大的C语言之父,UNIX合作开发者,罕见的开发人员获取图灵奖得主,Dennis M. Ritchie去世了,享年70岁。但是从Twitter中文圈的反应来看,这位大神的去世远没有Steve Jobs去世激起的反响大,叹气。
呃,现在应该说是昨天下午,开会一直到6点半,team里的培训计划,让我负责MFC Message Mapping Mechanism,MSMQ,C# event Mechanism,好吧,其实我都不懂,又得硬着头皮上了。其实我倒是对这方面有点兴趣的,我就打算粗略地研究一下MFC、WTL、Qt、wxWidgets的消息映射/处理机制以及C#事件机制,然后进行比较如果可能,得把Gtk+也加上,只不过C#和Gtk+这两个我连使用经验都木有!
上午给实习生培训.NET Data Access和XML去了,原本写了个ppt,还以为就这么点内容讲不到两个小时,要误人子弟了,何况我自己本身就没接触过这方面的内容。好在准备还算比较充分,从书上抄了不少内容当讲稿,然后又抄了不少代码,讲一点就停下问下他们有没有问题,要是他们没问题,那就我问他们,哈哈。最后还真的讲了差不多2个小时。
一觉醒来,最大的新闻是乔布斯挂了。这位跟胰腺癌斗争了多年的天才终于回归星辰的怀抱了。
在这之前,只是看过小篇幅的他的履历,怎么装配电脑,怎么开公司,怎么被赶出苹果,怎么发展NeXT,怎么回苹果,怎么将苹果带回巅峰。
数了一下,我第一次买苹果的产品是2006年上半年去香港,帮小妞带了一个NANO1,下半年我自己买了个NANO2,好像是2008年春节时,给表弟买了个Shuffle2,在2009年下半年买过个iPhone3G,在2010年上半年买过个Touch3送给了小师妹,还买了个Mac mini自己玩,今年先后买了Touch4和iPad2。一直想买个MBP,一直没下决心买,争取今年能入一个。
近一年来我一直把自己定位为一名果黑,但实际上这些普通消费型苹果产品我基本上都体验到了。实际上苹果产品给我的好印象只是工业设计好,它的软件体验其实只能说一般,大概是被果粉吹得厉害,而实际自己体验达不到期望的程度,反而有点失望。
不管怎样,乔布斯回到苹果这些年做出的成绩非常让人佩服。老乔一路走好。
这两天跑到杭州去玩去了。本来还真没这个打算的,一开始计划顶多是在绍兴随便逛一下,然后到上虞随便逛一下。后来甚至有点想放弃这个游玩安排了,不过嘛…反正是有点被人推着走的感觉,1号晚上才决定去杭州,2号下午才决定要玩两天。
昨天早起,匆匆吃完早饭,然后开车到绍兴文理学院北区西大门,等了一会儿,我一眼就认出樱子来了,她好像也是一下就把我认出来了。樱子脸蛋比我想象的可爱,大眼睛,圆脸,齐刘海,长直发。然后呢,还发现芭比的寝室的4sq点,哈哈。
先走的国道,再走的高速,进了杭州市区果然堵得一塌糊涂,跟去年到杭州的体验一样,这是我最讨厌杭州的原因,没有之一。先到了浙大玉泉校区,说是看看订房间,结果好像是太贵,然后折回余杭区的亲亲家园速8酒店,这个酒店大概是因为地处偏僻,是在网上能查到的在杭州的速8酒店唯一有空房的。
放好东西,去酒店附近一家快餐店吃了午饭,嗯,吃饭都2点多了,然后直奔灵隐。灵隐寺其实我没什么印象,而且实际上我基本是个无神论者,尽管一直有点幻想其实是有神的。她们三个倒是有点虔诚地拜了好多菩萨,我就一直在旁边看。之后是爬了飞来峰,爬上去一看,什么都没有,有种被坑爹的感觉,今天回来跟我妈一说,她居然老早就知道上面只有一块大石头而已,囧。
从飞来峰下去,有点迷路了,找车子一直没找到,最后一个热情的大叔把我们带到了停车的地方。然后开赴清河坊街,结果呢,笨蛋导航再一次发挥了它的坑人本领,把我们带到了杭州火车城站,我靠。好在目的还有个名字叫吴山广场,离得不远。
晚餐一起的还有嘘嘘和芭比,也是第一次见他们,也正是因为要见他们,我们才决定把游玩地点移到杭州的。嘘嘘比较清瘦,五官有点小帅,芭比则真像她的昵称一样,长得很可爱,声音也可爱。是在沸腾鱼乡吃的,感觉味道还行,但量太少,六个人吃了550多,我感觉大概就7分饱吧。
吃完后,6个人一起逛河坊街,这条街是仿古的设计,各种食物、手工艺品等等,其实没什么想买的,就是随便逛逛。樱子跑来跟我说,发现一家哈根达斯,于是我进去问了一下提货券能不能用,居然可以,好开心,于是我请大家吃。偏心了点,我跟樱子吃的是浪漫之舟,他们都吃的是单球,嘿嘿。吃完哈根达斯,就跟嘘嘘芭比分别,各自回住处了。
每次住酒店,我都不敢关灯关电视睡死,还不敢裸睡,真是没有安全感啊。
早上5点多就醒了,然后看动画片,直到快8点时又睡了半个小时回笼觉。9点多时樱子发短信叫下楼,退了房,去沙县吃了早点,开始今天的行程。
比较搞的是,她们说在网上已经订了西溪湿地的门票,要去西溪游客服务中心取,至于那个游客服务中心呢,是在一个叫天目山路的周家村路口处,没有门牌号的,然后呢我们就先跑到天目山路,然后一路张望寻找那个游客服务中心,那三个丫头还说昨天去灵隐时看到过的,是在那条路线上的,导航和谷歌地图上都找不到这个周家村的地方,很是郁闷,沿着天目山路瞎开了一会,趁红灯时问了一位的哥,终于跑到西溪湿地了,最后才知道这所谓的西溪游客服务中心就在西溪湿地里面,我艹,你丫不会就直说你们在西溪湿地里面啊,业务水平太差了!
西溪湿地其实就是坐了坐船,有个高庄可以进去看一下,说是康熙时代一汉人高官的宅子,其他的就是一些吃的。用樱子的话说,如果叫嘘嘘来,说不定会觉得这坐船很好玩,像我们这种从小就在类似的环境中长大的,其实感觉很一般的。
两天的杭州之旅结束了,身体和精神上都有点累,不过现在回忆起来还是觉得有点小开心的。
昨晚打电话,语气之冷淡之客套,太让我失望了。最卑贱不过感情,最凉不过人心。
给自己算了一下,我每天有12个小时不是在上班就是在上班路上,剩下12个小时里8小时要睡觉,剩下4小时里1小时用于洗漱清洁,剩下3小时里有2小时要去阿玛尼或原力健,最后剩下1小时要追小说。确实没时间做其他事啊,这样的日子难道我要一直过下去,直到垂垂老去?太可怕了ヽ(*。>Д
感觉我现在有很多想要做甚至必须做的事,可是很杂乱,我觉得我需要把这些事情理一理。首先,需要定好目标,而且目标是按时间来排序的,半年后一年后两年后三年后五年后需要达到什么目的。然后根据目标制订计划,为了达到这些目标,需要做些什么事。这样可以把现在想的那些杂乱无章的事情都填进去。
自从开始用Google Calendar后,感觉还不错,关键是除了web界面外还可以通过MS Exchange协议同步到手持设备上去,而且跟联系人和邮箱绑定,很方便,之前用doit.im其实感觉也还可以,但是它不能同步到我的C7上。不过Google Calendar貌似只能同步一个Calendar到iOS和Anna上,不知道Android上什么情况,真想弄个Android机玩玩。
好像是上个月就开始跟蘑菇在约吃饭了,直到今天才如愿以偿。上午是在床上度过的,吃了一盒趣多多,一盒优酸乳。起来洗了个澡,然后出门去莘庄,每次上下班都经过凯德龙之梦,一直以为是个夜总会什么的,在里面逛了一圈才知道原来就是个shopping mall,除了卖服装,还有各种吃的。蘑菇给我的印象跟网上不一样,网上似乎感觉要清淡冷静一点,现实中还比较热情。一起吃了两个小时下午茶,还算聊得开心。然后刚好一大学女同学打电话来,约好在家乐福见面。蘑菇一直陪我从凯德龙之梦走到家乐福,还一起逛了一圈百盛。
这大学女同学前一次见面时是据她回忆说是2007年,我是记不得具体年份了,只记得我在深圳,她进了HW去总部大队培训然后见过一面。现在她连小孩都20个月了。一起见到的还有她老公和母亲。然后去了她家吃晚饭。好久没吃到这么家常的川味了。然后随便聊了一会儿。时间过得真快啊。
两周的training结束了,唯一的收获是一个教训:英语不好出来混不好。Training的讲师都是从微软总部过来的人,有华人,有加拿大人,还有大概是美国人吧,反正都是说英语的,中国人说的英语打起精神来听,还能勉强听懂大多数,其他人的英语就傻眼了,那些英语是母语的人说得太快,印度人的口音么太大舌头。郁闷死了。
昨天在GT上跟素素聊天说起学英语,然后她发给我一个BBC的链接,说那篇比较简单,让我可以听一下,于是我又华丽丽地被打击了。BBC的语速不是一般的快。
我现在不止是听力不好的问题了,单词量也不够,很多时候要翻词典。我倒是想学英语,可是我能找出一堆理由来证明我没有那个时间。叹气。
Training听不懂,本来对这产品就没了解,再加上英文讲述,于是只好打瞌睡了。无聊的时候,就整理了下Google Contacts,然后发现iOS上的通讯录字段并不能跟Google Contacts完全对应,有点遗憾。
回住处后,从QQ里又找了一遍联系人,把一些QQ号,邮箱,生日等信息也补充了一下。
然后从iOS上看Calendar,有好多生日提醒了。
前些天稀里糊涂被卷进一场很狗血的事件,几乎做了件比拆了十座庙还罪过大的事,不过周日晚上后,差不多抽身而退了。小孩子啊,年轻就是好啊,可以尽情地挥霍爱情。
今天分到一个新任务,关于installation和upgrade,叹气,微软的东西就是烦,很多时候我就在想,这么个特性,那么个需求,也有必要做得那么复杂么!
木耳最近要去北京、厦门研究生面试,如果成功的话意味首明年可能就不在上海了,真是伤感啊。
人生啊,真是没有动力啊。
昨天就说好了的,今天中饭是吃的那小丫头送来的便当,唔,真是个傻丫头,好大的份量,饭也多菜也多,撑死我了,而且还有一盒雀巢柠檬茶,傻乎乎的。
下午4点多,卓越送书的终于来了,4本跟debugging相关的书以及一本《CLR via C#》第三版大砖头。叹气,其实我不会怎么看的吧,而且其实我最想看的内容是怎么进行postmortem debugging,可是……
突然想到《君が望む永遠》了,叹气,是要那么纠结一场才会尘埃落定么?
今天墨墨晓晓和木耳过来七宝,也没有什么玩的。
中午去老街里面吃汤圆,然后回到我住处,4个人这么呆坐了一下午,各自上推,除了晓晓玩了会儿游戏。不是自己的地方,果然怎么都弄不出那种味道来,连电视都没有接有线电视或数字电视。
到五点就去接头暗号吃烤肉,39块钱一人,一桌再加3块钱酱料钱,实在很优惠了。吃了2个小时,撑到了!
然后就送他们到地铁站。
又想起《水果篮子》那句经典的话。
我虽然真有点心急吧,但宁缺勿滥的原则是深入骨髓的。我不担心没有喜欢的人,也不担心没有喜欢我的人,只是担心没有互相喜欢的人。像我这样的年纪的生活能自理的人,至今仍然单身的,一般都是自己心理上的问题。但对别人介绍对象这事,尤其是那种随意介绍,是个母的就介绍过来,还真感觉很耻辱很伤自尊的。
作为纸醉金迷的生活的开始,随便在网上看了一下上海的景点列表,排在第一位的居然是上海科技馆,恰好我也知道它在某条地铁线上,于是就跑过去了。之前就听别人说过不好玩,去了之后才体会到到底不好玩到什么程度。60块门票实在太不划算了,6块钱才差不多。里面多数是小孩,以及带小孩子来的大人,像我这样的实在很稀奇。封杀之~
今天在公司里把AWD的第一部分快速过了一遍,明天继续看第二部分,争取这周把整本书都过一遍,达到可以用windbg完成基本的调试任务的目标。说到底,最终的目标是要能用windbg分析dump file的目的,虽然以前也做过这种事,但都是囫囵吞枣不求甚解的,这次有机会可以系统的学习下很有用。另外,我想在这公司里,估计以后回过头来看,最大的收获可能是英语的听读能力有大进步吧,可能写和说的能力也会有所提高吧,这将是我最高兴的事。
周末无聊,随便算了一下自己每月的固定开销,吓了一跳,居然这么高,这点工资收入实在不够看,要多久才能攒够买MBP的钱呢,昨天从上海科技馆出来后跑到陆家嘴的苹果专卖店,发现13寸的那款只要11498了,以前印象中是13998的呀,好心动,国庆后一定要入一个。也就是说,光靠这点工资的收入是远远不能支撑我日益膨胀的消费能力和消费欲望了,赚外快呀呀~
csdn上的Qt应用开发大赛奖品好少,不过E7很让我眼馋喵,还剩下一个半月,快速写几个程序试一把。先就已经提上计划好些日子的Aokiwen吧,豆瓣客户端,支持Win/Mac/Linux,以及Symbian。qDou其实已经做得不错了,不过它一开始就是为手机设计的,有些方面不是很舒服。握拳!
最近发生了不少事。首先,我找了个工作,在上海,于是又跑到上海来了。这工作倒目前为止给我的感觉应该是比较轻松的。租房子离上班的地方比较远,每天开车来回要2个小时左右。
然后我又如去年那样悲剧了一把,真不知道是我有问题还是对方有问题。上海啊,真是我的哀伤之地。
最后,历经2周,昨天终于把宽带装好了,上海电信的服务实在太差了。这个小区是光纤接入,这上门装的设备还带一个无线路由器。这路由器貌似同一时刻只能有一个客户连接,没找到设置界面,而且touch和ipad连接上后,是上不了网的。换成自己的TPLink后就一切正常了。对的,上周末去败了个最低配的iPad2。
到了上海,算是有了新的开始,终于有机会真正向纸醉金迷的生活迈进了,要好好享受人生啊,人活一世机会难得。平时就好好上班,晚上回来继续搞,嗯,现在不是专职了,只能算外快了,周末就尽量出去玩玩,那些景点要去走个遍。
你也许不相信,我淡推,我不发短信,我不打电话,我不去找你,很大一部分原因是因为我不想打扰你学习,尽管可能是我高估了自己。
话说,大前天收到Qt Ambassador Program的邮件,说是A free Qt Ambassador Kit is on its way to you! The kit includes: Customized Qt Ambassador Stickers and T-shirt, Qt Stickers and a Nokia C7 Phone. 让我激动了一场。不过也不知道他们是从哪里寄过来的,也没有个快递单号可以让人在网上跟踪一下行程,真纠结啊,以前从Intel索取手册还给个Fedex的网址可以随时在网上看到状态呢,而且记得还在重庆上学那回,人家Fedex深圳的人发邮件来说我地址不详细,我回个电话告诉人家具体地址后,没几天重庆Fedex的人就专门送上门来了,这还只是几本书而已。这次可是有个手机的哇,是2000人民币价值的东东哇,唔,心焦。...
清早醒来,看到一条推,于是连吃早饭都没有心情了。
其实吧,长久以来,我都是一直在纠结,为着同一个问题而苦恼。
对于爱情,我缺少在其他方面一直拥有的勇往直前的勇气和信心。
尽管很多时候安慰自己,没有就没有吧,不行就算了,随便吧。可是实际上,每次当确实地看到什么,确信地以为她将远去,心就非常的痛。
每当心情不平静的时候,就什么事都不想做了。连敲键盘的手,都是那么重。
各种的没有动力啊。
木耳这回大概是真的淡推(禁推?)了,真是个努力的孩子。
最近一个月很是懈怠,不过前几天又比较仔细地调整了一下计划,想做的事还是很多的,在doit.im上粗略地添加了任务,把时间也随手定了下,不过实际上这个时间对我的约束力几乎没有多少年来一直是这样的。
除了这个,真的想换一种生活方式,厌倦了现在的这种生活状态,因为已经影响到自己的精神世界。
有点小迷茫,感觉又有点像2007年初那样,很无力。
不过再无奈,也是要面对的,即便把头埋进沙土也是会难过的。其实很多事实是福祸相伴的吧。
勇敢一点!加油!
现在对于这种用于吐露秘密,又不想为人所知的工具(场所?)有了一个新的称呼,叫“树洞”。我第一次知道这个名字是在Twitter看到一个叫“秘密树洞”的服务,后来那个服务被一群人用作YY的场所了,叹气。
我这blog被GFW认证,原本就不高的访问量一减再减,现在也可以看作是一个树洞了,嗯嗯。
我决定了,要工作也找上海的工作,即使薪水低点也忍了,杭州这回就不考虑了。即使是极度缺乏安全感的我,也不是特别艰难的决定。大不了,受伤我来,开心你去,不敢轻易说爱,喜欢就够了。
昨晚上QQ,偶然发现谢巍居然在线,于是聊了一会。谢巍貌似是所有与我相识的人中最关心我个人问题的人了,每当有什么事,总是积极地为我出谋划策煽风点火。
可是感情这事,根本不像其他的事,可以用数字描述,用概率计算。
而且一旦沉沦,但难以自拔。我为什么这么执着,执着着这种痛苦。每天不停地刷新,只为看到一次mentioned。
我只是有点疑惑一切变化得太快。
随缘其实是一种无奈。
我觉得我已经处于崩溃的边缘了。早晨醒来,抓过床头的Touch上Twitter,翻人家的Tweet,然后继续睡。不想醒来,只想一直睡着,睡着就什么都不会想了。
昨天总算是硬着头皮做了点事。硬着头皮的另一种含义是迷茫而不思过。
都说精神病人精神好,弱智儿童欢乐多。可我这IQ不高,却对某些事情偏偏敏感得要死,稍微有点风吹草动,蛛丝马迹就会把事情猜个八九不离十,知道太多事情真不好。除此之外,还要患得患失,还有对世界认知的极度悲观。
好痛苦啊。缺爱的人啊,好不开心。
早上醒来,一阵悲苦,心里莫名的好压抑好沉重好难过。
那边的事算是已经有了了断,照理我的心情应该可以轻松一点,可是没有。
最近总是早早上床休息,其实并不是因为自己需要休息,只是为了逃避一些东西,但是上床之后却仍然抑制不住那股类同于偷窥的欲望,可之后却十有八九让自己更难过。
我不清楚自己在这个漩涡中到底处于什么位置,只知道自己试图挣扎逃离,却仍然越陷越深,然后越来越自悲,越自伤。
我怀疑周围的每个人每件事,渐渐成为一个腹黑却无能的阴谋论者。
感觉自己只是别人手中的牵线木偶、棋子,自己却兴高采烈地扮演着那个角色,偶尔自怨自艾一下。
我是不是真被人诅咒过,被扎过小人,被画过小圈圈。
我好难过。
昨天在QQ上跟小乖说了两句话,我就跟晓晓打电话去了,过了大半个小时再回到QQ上,跟小乖说,刚刚打电话去了,小乖开口就问,是mm啊。我说你怎么一猜就猜mm呢,小乖说总不可能问跟gg打了这么久电话吧。然后我说,我是爱情咨询热线,专业解决各类感情问题。于是小乖说了句“理论派哦”,道尽我一切的心酸与苦楚。
刚刚去吃喜酒了,一个远房表姐结婚,在德国念了博士什么的,然后据说找的老公也是德国人。我是没见到人,也没印象,饭也是匆匆吃了几口,实在没什么胃口,几件事堆在一起,真是烦恼啊。希望明天过后,能解决掉其中的一件事情。不知道会不会把我封印得那么严实的暴戾因子激发出来。
以前看过一小说里说,只有年轻人,比如学生什么的,才会对事情患得患失,叹气,我现在不年轻了,还是这样,就没成熟过。今天又看间客里说,只有宅男宅女,才会对事情瞻前顾后,叹气,我也不想宅啊,恶性循环啊。
继思思之后,王同学也说我留言从来不理,唔,笨QQ!
小妞本来说是昨天的预产期,今天下午给俊英发短信,结果说还没动静,还在家里等呢,我囧。跟思思一样哦,都是钉子户。
其实被墙了也好,有些话,还真只适合在这种环境下说。
那天跟素素聊天,然后说了不少我从没听到过的观点,感觉很新奇,也许很有帮助。可是我现在仍然很无奈。
之前有那么一小会儿时间,我雄心壮志地想,你要是谈恋爱了,那我就等,等你们分手。可是我现在却觉得很无助。
我现在处于一种非常非常尴尬的境地,自身的实际情况跟自己的理念冲突太厉害,而同时改善自身条件的努力一直没有效果。
好难过。
昨天心情糟糕得一塌糊涂,到处找人聊天,想起好久没联系思思了,于是就发了个短信问候一下。结果她说我QQ上一直不理她,冤枉死啦,我都不上QQ的,也没看到她有什么留言。又说是在线微博上,于是我去QQ微博上用她的真名搜索,有13个同名的,貌似都不是,用她的QQ昵称搜索,居然有97个,看了一遍貌似也不是,又看了一遍我的mention timeline,也没发现哪个是,纠结啊。
今天鬼使神差上了下QQ,看到思思在线,于是发了个招呼,结果她带孩子去了,是彭彭,呃啊。然后就随便聊了一下,彭彭现在在迪拜,这次刚好是回来给思思办护照的,大概下半年让思思带小孩子一起出去,呃啊。而且她们出去后,是要一直呆在那里了,除非彭彭工作调动,或者小孩子要上小学才回来,呃啊。
哇哇,去年跟小妞打电话还说我今年去看她们的,结果思思跑到国外去了,我我我……
这些天一直在写爬虫,但是进展极其缓慢,大概是由于对这个东西没兴趣吧,尽量可能很有用。
心不在焉啊。因为某人的一句话,第二天心里美滋滋地乐了一天,尽管那句话并不能代表什么。又因为一句话,开始低沉压抑,觉得人生了无乐趣。很无力啊。
昨天看了一下Archlinux,仓库里有现成的wxWidgets 2.8.11和boost 1.46.0,在Archlinux上写程序和发布程序应该是很幸福的事,需要关注第三方库应该是所有系统中最少的了吧。又看了下Fedora14,也有wxWidgets 2.8.11和boost 1.44.0,而Ubuntu里的boost是1.42,这个太老了点。
我琢磨着等爬虫写完,把Ninayan加上Facebook、Google Buzz和Google Reader的支持后,再回头来更新CodingStudio系列,这个系列反响不好我一直心有不甘。一个大的计划是把CodingStudio移植到Mac和Linux上跑,这个其实在最早做计划时就有的,但是后来只顾着在Windows上的效果,用了一些影响跨平台的方案,于是就搁置了。现在有了Ninayan的一点点跨平台经验,再来做CodingStudio应该会好一点了。要去掉wxLua的依赖,因为wxLua的实现不让人满意啊,而且我用的还是自己稍微修改过的版本。但CodingStudio现在已经有了大量代码用到了wxLua,于是这件事可能会花不少力气吧。甚至还想去掉Lua的依赖的,但那样变化实在太大了,而且有不少事情放在Lua里做确实方便不少,就留着吧。
再说吧。
做了个梦,具体的已经忘掉了,只记得我一直在找她,却一直没找到,不知道她去哪里了,明明以为她就在那里,我强颜欢笑,我心如刀割。
可能我真的喜欢上她了吧,可是……我怎么会那么容易就喜欢上人呢……痛苦。
知道这样的结果,心里还是很难过,很阴暗的心理,唉。好好调整。
今天突然想起,给某个3个月后过生日的人准备份礼物?
其实这样的傻事以前就做过,还不止一次,后来每次回忆起来,都会觉得自己非常傻。可是即使一直觉得傻,后来还是会再去做,这才是最傻的,于是直到今天,我仍然傻着。
前天看到鱼本非鱼写的一个沙画软件,用来庆祝他女朋友生日快乐的。我想就是因为这件事,才又激起了我再傻一次的冲动。
记得小时候,大人们教育我们说,生日礼物要自己做的,才是感情最深的,最珍贵的。可是无论如果,在如今的现实社会中,我怎么都说服不了自己接受这个观点。但是,对于一个一无所有的可怜男人来说,虽然体内藏着一颗躁动的心,那爱出风头,喜欢标新立异,又希望玩点浪漫的心思在缺少金钱的支持下,是如此的无奈。
好吧,不找更多的借口和理由了,反正就是做为一名不合格程序宅,这只是一种惯用的表达方式而已。
Good luck!
在GTalk上聊天,说起同事集体活动,突然思绪飞回2005年了。我入部门的第一个周六便是项目组活动,去深圳东门的工人文化宫溜旱冰。我并不会溜,所以摔了半死,不过后来倒也勉强能滑一会儿了。
然后我想到了马姐姐,当年那个号称“光网络第一美女”的主管大人。我进测试部一直是一种说不清道不明的奇怪体验,因为我其实只想做开发的,记得到部门报到的那天,项目部的老大跟马姐姐交接了我们两个新人后,轻声跟马姐姐说我的培训计划要调整一下。这是我到现在都没明白是怎么回事的事。
在测试组呆了22个月,其实应该只有21.5个月,但印象却深刻得多,令我怀念得多。在测试组我的绩效一直不好,一直测不出产品问题,直到3个季度后通过代码审查才能凑够PBC指标。然后俨然一副(伪)高手的样子,哈哈。后来项目组迁移到成都,直接主管问我愿不愿意去成都,我不假思索地说不愿意。之后就直接把我释放到系统部去了,而听其他的同事说,他们都是至少被问过两次的,这也是让我觉得奇怪的事情。
还有件事也是不吐不快,这事一直是我们那拨人的谈资。测试部组织C语言考试,题目出得比较变态,要求75分合格。我们测试组的一帮人,咳咳,通过大家都知道的手段,有4个人考到80分以上,其中一个就是我。结果大条了,貌似其他组就没人合格的,就我们组就被整了,另外三个同事被叫去,结果当然是老实交代了。最意外的是我没被叫去,他们都说是看了我的答案。马姐姐作为我们的主管,当然事情就捅到她那里了,她就问我怎么回事,我一脸愤恨的说没办法,被逮住了是我们倒霉。现在想想当时的我真的挺欠揍的,呵呵,想来只要老实点认错,马姐姐的立场看怎么滴都是要保我们的。当然这事后来也是不了了之。
总之,从一个局外人的角度看,当年我在测试组的表现,可以说是成事不足败事有余,却莫名其妙的桀傲不训,作为我的主管应该很头痛吧。我转正后的第二个季度只完成了PBC一半的指标,于是自然而然被打了个D,我非常郁闷,思思玉玉和小妞都安慰我鼓励我,马姐姐和我的直接主管找我谈话,说是对我还有期望,不然就直接开了。我后来偶尔想起这个事了,就觉得有点诧异,为什么会给我个D然后又不开我呢?总不至于真是因为说这个招聘成本比较高,然后神马的吧,总觉得这说法不太靠谱。
马姐姐是个比较时尚的人,呃,这样说应该没什么大错吧。她喜欢运动,貌似打羽毛球很厉害,不过我没去看过她打球。她喜欢唱K,我们好几次活动都去唱了K,导致后来我们组的人很多都比较喜欢唱K。不过马姐姐有点色色的哦,喜欢跟组里几个唱歌好的帅正太对唱的,哈哈。哦,突然想起来,有一次活动,好像是他们下午泡温泉我没去,晚饭后又可以唱K打桌球神马的,我们在K厅里唱啤酒,马姐姐拿了我的那杯啤酒喝了一口呢,各种囧。
我们那么些年来一直在猜测马姐姐的婚姻状况,一直没得到确切的消息。直到我辞职的那年,呃,就是去年吧,才通过各种八卦得到比较准确的信息。那时我们已经都在不同部门了,偶尔还一起吃饭,马姐姐作为一个女人当然也喜欢八卦了,问起在坐的每个人的个人终生大事,最后终于有人忍不住问了一句“那你呢”,然后马姐姐就一然淡然地说“我结婚了啊”,再加一副“你们居然不知道,不知道应该是你们的错吧”的表情,但是至于是跟谁结的婚她就闭口不提了。后来跟王同学和她老公一起吃饭八卦,说起来马姐姐开的车跟某男开的是同一辆车,那时我们才比较坚定地相信这个消息应该是没错了。
最后再提一件我有点诧异的事。有一次在食堂吃饭,然后又说起男女关系什么的,说到我时马姐姐来了一句“YF(我的名字)眼光高”,我瀑布汗,她怎么这么看我,虽然可能也没错!
辞职的这一年多来,经常怀念在深圳的工作和生活,想念那些可爱的同事们。
上午大牛在twitter上DM我,说他升级了,6号时小吉给他生了个儿子。恭喜一下。
前些日子小思思发短信说生了个女儿的,而且还是比预产期晚了10天的,前天还用邮件给我发了张小侄女的照片。眼睛黑黑亮亮,脸圆圆肉肉,好可爱的。
再之前,大约半年前,孙同学和薛mm也发短信来说过生了女儿和儿子。
呃,我们这批同事中,大概最早的是宣宣的女儿了。
真是一帮幸福的人哇!
好多天前,木耳就说要来上虞搞社会实践,崧厦那边有个阳伞市场,嗯嗯,这点是可以理解的。前些天我在魔都,木耳11号傍晚就来了,而我是昨天下午才回来的。
本来木耳说的是要持续10天的样子,结果昨天突然说马上可以完成回去了,晕。今天刚好去了百官,我就问木耳在哪里,她说在沃尔玛。呃,我不认识路呀,问了下阿姨怎么走。然后我就跟木耳说,我去找她。嗯,还是比较近的,她跟几个同学在沃尔玛门口的快餐亭或坐或站。然后我就自告奋勇送他们几个去火车站,呃,果然走错路了,不过上虞这块确实小,而且他们的火车也还要一个小时才来,所以我是不慌不忙了。
另外还有个女生,木耳说她叫鲜,是个重庆mm,呃,以前在网上看到木耳提起过,还以为是个GG呢。
原来以为木耳会多呆些日子,我还想可以带他们到处转转呢。现在我又决定短期内不去魔都了,木耳还说我欠她一顿饭,不知道会是什么时候了,哈哈!
昨天下午木耳(@ainesmile)突然给我打电话,问我晚上有没有空一起出去玩,我当然有空啦。木耳的声音比我想象的要成熟一点,哈哈,其实再想想也是快大三的人了,这样的声音也正常。大概是像小妞,疯丫头那种腻腻,软软的声音听多,下意识的以为所有女的都应该那样了。不过后来发现木耳说话的语气还是有点点小女孩的那种感觉。
出门的时候刚好遇上下班人流高峰时段,地铁上好多人,前几个站一直是只上不下。到了人民广场站后,又绕来绕去,问了几个人,才找到来福士广场。木耳在KFC门口等我,我正要给她打招呼,她就一下认出我来了,让我觉得有点惊讶。找到坐在那里的猫猫(@maovivi),猫猫是个很开朗外向的人,总是逗木耳玩,我连话都插不上,只好在旁边坐着看她们玩。没多久后,可可(@zkaip)也来了,挺有速度的嘛!本来我以为可可是个小正太形象呢,囧!
四人出了KFC闲逛,找吃的地方,大家都对那块不熟,还打电话问了人,结果还是没结论,于是继续瞎逛,到了南京路步行街。之后经过小杨生煎,我之前只听人说过小杨生煎有机会一定要吃吃,于是心里暗喜。钱是可可出的,哇哈哈,蹭了一顿!不过最后那些汤浪费了,生煎倒是味道不错,就是大个了点,出乎我的意料,于是吃完生煎就没胃口继续喝汤了。
吃饱喝足继续逛街,猫猫好像是想买几个世博会的吉祥物海宝回去,不过最后都没挑到满意的。木耳一直说要在8点钟回去,又逛了一会儿就准备各自回家了。我们都是坐2号线,我跟木耳是一个方向,可可跟猫猫是一个方向。木耳比我先下,她在中山公园站转3号线,没几分钟她在推上说,坐错了,坐到4号线上去了,哈哈,真是木耳的风格呢!
看到小师妹在日志中说寻找同类好难、心头一阵酸楚,使得我也感觉很难受,还有心疼。
回头看一下自己有比较清晰记忆的过去的十几二十年,确实也一直在不知不觉地寻找同类,只不过小些时候追求很少,有一起玩的小伙伴就觉得很满足。稍微大点了,有了一些自己想要的东西时,烦恼就渐渐增加。
那是非常孤独的日子,却又是非常希望能找到依赖的日子,但是一却找寻不到。我也不知道是从什么时候起,开始对寻找同类不抱有信心,甚至于绝望。直到昨天看到小师妹的日志,我才发现,其实我不再试图寻找同类,是因为我已经自以为找到了。找到了,并不是说就能见到,或能接触交流。那是一种认可,成为我的同类的资格的认同。只要知道ta的存在,不管ta在世界的哪个角落,偶尔能知道ta又做了什么事,那已经足够了。其他的事,就只剩下自己努力了,那些一直以来自身需要的精神鼓舞和激励,都可以从ta的事迹中获取。所以,在这个事件中,我可以高声宣布,我不孤独!
希望小师妹不再不安,同类无处不在。
我不知道该给这篇文章取个什么题目,半个小时前,是先想好题目,然后决定要写这篇文章的,可是当我开始写的时候,觉得那个题目不合适,不能完全表达出我的心情、我的感受。
昨天从家里出发的时候,我看了一眼时间,那是清晨的8:14,当时只是为了计一下时,看我全程需要多久。最后停在上海的小区楼下时,时间是11点半左右,我没记清,我当时发出两条短信,分别给我当前我以为应该是对我来说最重要的两个女人。一个是我妈,还有一个……是她,因为她,我才决定来上海。
这是一个还没有开始,就已经曲折的故事。
我和她认识有5年半了,那这5年多来,一直只是在重要的节假日时互相发个祝福短信。直到今年元旦,她又发来祝福短信。然后很偶然地开始在网上聊天,真的很奇怪,为什么在那5年中,我们就没这么聊过。在网上,我们聊得很开心,至少我是非常开心。于是渐渐地,我沦陷了。我已经不能忍受没有她一起聊天的时光了。
我鼓起自己所有的勇气,我决定向她表白。那是愚人节后的第3天,那天她从上海回家去。本来说好是我去接她的,结果被她姑妈接走了。在那天晚上10点多的时候,我终于忍不住了,我一直认为表白应该是当面才显得有诚意,但是我已经没有办法继续等待,我在电话中跟她说,我喜欢她,请她做我的女朋友。无论是表白的场景,还是表白后的各种情况,都被我在脑海中预演过很多次。但果然现实是没有在我的预料中的,她说太突然了,都没有过渡的,感觉我像在开玩笑。我有点小郁闷,觉得委屈。我都已经沦陷在其中了,为什么仍会被说成像开玩笑。最后我实在没办法了,就说你就考虑下吧。
那是一个奇怪的情景,双鱼的优柔寡断从此可见一斑,于是她说就考虑下吧。挂掉电话,我觉得我应该再做些什么,躺在床上,最后想到一个很老土很容易想到的事情——写情书。恨当年,没多读些诗词古文,挖空心思总算花了一上午时间凑出几百字的小文,通过email发了出去,并用短信叫她去检查一下邮箱。她一直没理我。直到那晚上,才用短信说了下她在干吗。
之后的两天都是在浑浑噩噩中度过的。直到她要回上海的那天下午,我直接告诉她我去接她了。在车站,我们还是像往常一样的聊着,我仍然不敢在聊天的时候看她的眼睛。我像一个羞涩的小男生,我鄙视自己。送她上车后,她发短信给我,说要真实地相处一下,才有真实的感觉,嗯,我华丽丽地在真实的感觉前露出了原形。
因为要真实的相处,要真实的感觉,所以我决定,我要尽快到上海去,这样才能更多地和她在一起。我跟她约好,周六我去上海找房子,她陪我去找。那一周时间里,我觉得像是煎熬,双鱼的多疑充分发挥,我觉得她开始与我保持距离。
好不容易周六了,我乘长途汽车到了上海,然后坐地铁,直到淞鸿路跟她会面。我觉得我熟悉的那个她还在,她仍然对我很热情。我们在永和豆浆吃过中饭,开始去中介租房子。这是悲剧的开始。因为又要价格实惠,又要装修不差,这要的房子不好找,我们跑来跑去近一个下午,最后总算是搞定了。后来回忆中间的一些细节,我发现我经常会有些得意忘形。这是一个很不好的习惯,男人需要沉着并内敛,但我经常忘记,所以我不够成熟。具体一点的事说来,她总是为了房子中的各种设备、条件跟房东、中介讨价还价,而我却不时地打断她,说些不合时宜的话。照一个推友的说法,我的情商够低的。
后来晚上又让她陪着去逛了一些地方,直到晚上10来点的时候,她说膝弯的地方痛得不行了,说下午找房子的时候就已经开始痛了。我说我没感觉呀!她回到屋,我躺在酒店的床上给她发短信,我说如果明天还痛,我们就不走了,找个地方喝喝茶聊聊天。她却说,相信睡一觉会恢复的。
第二天10点钟,我从她小区等她出来,一起去买导航。我只是单纯想要买个导航,却没做过任何前期的调查工作。她问我有没有事先看过要什么牌子的,我说没有。然后两个人像无头苍蝇一样到处乱转。最后看了两家后,导航是买好了,时间也不早了,雨下得很大,我们就在一旁的真功夫吃了,然后她送我到长途汽车站。
回到家,我发现她对我似乎更加冷淡。每一天,我都试图给自己找些事情,填充自己的大脑,转移注意力。一旦停下来,又会想她为什么会这样。我回忆着我在上海时跟她一起的每一件事情,尝试从中找出一些蛛丝马迹。但是成效不大,我很无奈,我不知道我哪里做错了。父母得知我周六就要搬到上海,浓浓的不舍之情从言语、表情和行动上不停流露。我狠下心对自己说,我要勇敢,我不可能一辈子生活在父母的羽翼下。每天早上,我都是在焦虑和不安中醒来,为事业,也为爱情。她说觉得我浮夸,夸夸其谈,不踏实。我很难过,但我想知道我哪里做得不对,我问afei和王同学,结果吃惊的是afei说我对人不真诚。afei告诉我,跟人说话的时候,眼睛不要乱飘。我知道了,我跟她聊天的时候不敢看她的眼睛,以后跟她说话,我一定会注视着她的双眼。其实我经常反省自己,却发现自己仍然经常高估自己的能力,低估现实的难度。
昨天,就是我来上海的日子。来上海,我不迷茫,却充满了不安。我想我太理性,做一件事情总是会试图量化其成本和收益,从而判断是否值得。但是双鱼的感性,让我实际上做事往往只凭着一时冲动。我到达后发给她短信,却一直没收到回复。我是有点生气的,虽说是我在追求你,但你回条短信应付一下也是可以的吧。把东西都拿到屋里后,一件一件发出来,才体会到“儿行千里母担忧”的心情。我忍不住有点痛恨自己,想想我这二十几年,过得实在太失败了,既不能呆在父母身边敬孝,又没能力让父母在物质上过上比较富足的生活,甚至连传宗接代这种事都要父母操心着急,我真太没用了。
晚饭是一起吃的,还有她的室友。我在阿玛尼店门口见到她,一个陌生的她。我的心有点凉。吃饭的时候,我竭尽所能地表现得风趣幽默,结果是个杯具,一个上面刻满了“自以为是”的杯具。
今天她在网上问我,昨天为什么要讲那些恐怖的事情。我说我的出发点,是为了让你们平时多注意安全。她说,谢谢,我们会注意的。很平静,很客套。我的心很凉。她说她不能接受一个麻木的人。我理解,很理解。但我不愿放弃。我求她给我机会,让我慢慢改好,给我表现的机会。她说她是个被宠惯了的人,上次找房子和买东西,让她很无语。她还说我是被女孩子们照顾惯了,不懂照顾人。我很委屈,我打电话告诉她,这些我都会改,但得给我机会,还得在适当的时候提醒我,哪些地方做得不对做得不好。
是的,我真的从没这么委屈过,但所谓一物降一物吧。既然我决定投入了,就要认真地走下去,也许那条路有坎坷,但我仍要继续走下去。也许我会被摔得鼻青脸肿,甚至遍体鳞伤,但等以后回头来看,至少会少些遗憾。
故事已经开始,期待结局的圆满。
今天去庙里吃中饭,同一桌的有人告诉我,年底那桥下河边的地可以批出来了。我很激动,很紧张。
我要加倍努力啊,特立此据。
Category Technic
已经有好长一段时间了,在自己组装个台式机还是买个MBP之间难以抉择。昨天突然想,我就去徐家汇看看行情,我不买。果然还是没忍住,只是问了第一家,就决定买了。我对机器的需求非常简单,CPU要4核的,主频低一点没关系,内存要大,至少4G,最好8G,硬盘也要大,最好1T。其他的就比较随意了,能用就行。
只是没想到的是,现在组装机,还是比我想象的要贵一点。不过最后调整了各部分的预算,总算在3880块拿下来了。硬盘是500G的,现在就是贵了。内存倒是2*4G的,结果拿回来发现只能认出4G来,在网上找了一堆的解决方案,有硬件问题的,有软件设置问题的,最后我的情况发现是有一根是坏掉的。于是今天下午又跑了一趟徐家汇换了。那个上游卖家态度真他妈的想揍他,说什么他是专业换这个的,我懂么不懂云云。
昨天让我特别想要买个电脑,是因为这两天跑Eclipse把我伤到了。在那双核CPU,2G内存的Mac mini上卡得要死,笔记本上也很悲剧。唉,即使买来了,就认真写程序吧。
从Twitter上知道Readability免费注册啦,看来是纯粹靠收费用户流量太少了?马上注册了一下账号,这下可以从Reeder用Readability了,只是其实现在大部分RSS都是全文导出的,所以Readability在Reeder上的意义并不大,但是,作为与ReadItLater和Instapaper类似的服务,它也有存在的价值。Readability也开放了API,可供第三方开发者访问,这才是最吸引我的地方。原本Ninayan中是用Instapaper的很土的text view,不知道换用Readability的服务会不会好点,之前也用过一个国内的爱好者开发的PHP版的Readability服务,不过没多久就被墙了,真操蛋。
再加上embed.ly的服务,需要重新修改一下Ninayan中的相应的部分。
我总觉得,阅读将会是未来人们很重要,而且会是越来越重要的一项活动,方便的信息收集渠道,方便的阅读方式,为人们的阅读带来极大的便利。
10月12日,伟大的C语言之父,UNIX合作开发者,罕见的开发人员获取图灵奖得主,Dennis M. Ritchie去世了,享年70岁。但是从Twitter中文圈的反应来看,这位大神的去世远没有Steve Jobs去世激起的反响大,叹气。
呃,现在应该说是昨天下午,开会一直到6点半,team里的培训计划,让我负责MFC Message Mapping Mechanism,MSMQ,C# event Mechanism,好吧,其实我都不懂,又得硬着头皮上了。其实我倒是对这方面有点兴趣的,我就打算粗略地研究一下MFC、WTL、Qt、wxWidgets的消息映射/处理机制以及C#事件机制,然后进行比较如果可能,得把Gtk+也加上,只不过C#和Gtk+这两个我连使用经验都木有!
上午给实习生培训.NET Data Access和XML去了,原本写了个ppt,还以为就这么点内容讲不到两个小时,要误人子弟了,何况我自己本身就没接触过这方面的内容。好在准备还算比较充分,从书上抄了不少内容当讲稿,然后又抄了不少代码,讲一点就停下问下他们有没有问题,要是他们没问题,那就我问他们,哈哈。最后还真的讲了差不多2个小时。
自从上次笔记本拿去公司加入过域后,发现所有远程连接都不行了,包括http访问,远程桌面,smb共享文件夹,但ping ip是没有问题的,ping机器名是找不到主机的。昨天晚上一直搞到后半夜,各种组策略个性各种注册表修改仍然没有用。今天跟同事说了一下,同事说只要退出域就可以了。回来试了下,退出域,加入到workgroup,果然全都可以了,内牛满面啊!
鉴于笔记本的屏幕太小了,以后尽量都只从Mac远程连接过去访问吧。
昨天鬼使神差地想下几部爱情动作片看看,结果果然不幸中招了,乱78糟地起了一堆的进程,然后装上QQ医生,删那些可疑文件,最后不幸地不能进入系统了,一登录进桌面就立即自动注销了。于是只好恢复到出厂状态了,郁闷的是那块硬盘上的其他东西都备份不下来了。说起来,有各种备份措施可以使用的,但我仍然杯具了,是有原因了。
首先,我的笔记本自带的光驱不能工作了,这是一大杯具。进入Access IBM的备份和还原界面后,虽然有备份选项,还能找到硬盘上的所有数据,但即使在USB口上接了下刻录机,也找不到那个可写媒介。IBM的软件果然糟糕哇!
其次是我使用硬盘的方式有问题。一直都是整块硬盘的使用,不分区,然后有一块外接硬盘通过USB口使用。实践证明,外接USB硬盘已经有好几次貌似都因为USB的问题把整个分区甚至全部分区都弄得不能访问了。
最后要说的是,网络备份只是小孩子过家家的玩意儿,当然,我只是使用那些免费的服务,不但空间容量小,而且传输速度慢,以及到目前为止并没有证明其可靠性有良好的保证。
所以最后的结论是,等手头开始宽裕了,就装个高配置的台式机,最好能配个RAID,这样应该算是比较可靠的了。
见了这个表格好几次,这次终于忍不住了,本来我是不太乐意转帖文章在这里的,但这次稍微破个例,但愿不是个开头。我自己基本在level1和level2之间徘徊,需要加倍努力啊! 注意:每个层次的知识都是渐增的,位于层次n,也蕴涵了你需了解所有低于层次n的知识。 计算机科学 Computer Science 2n (Level 0) n2 (Level 1) n (Level 2) log(n) (Level 3) Comments 数据结构 不知道数组和链表的差异 能够解释和使用数组,链表,字典等,并且能够用于实际的编程任务。 了解基本数据结构时间和空间的折中,比如数组vs 链表,能够解释如何实现哈希表和处理冲突,了解优先队列及其实现。 高等的数据结构的知识,比如B-树、二项堆、斐波那契堆、AVL树、红黑树、伸展树、跳跃表以及前缀树等。 算法 不能够找出一个数组各数的平均值(这令人难以置信,但是我的确在应聘者中遇到过) 基本的排序,搜索和数据的遍历和检索算法。 树,图,简单的贪婪算法和分而治之算法,能够适度了解矩阵该层的含义。 能够辨识和编写动态规划方案,良好的图算法知识,良好的数值估算的知识,能够辨别NP问题等。...
Category Qt
不要使用Qt安装器中提供的CMake,而是自己另外安装一份,比如从CMake官网下载,或者macOS上可使用Homebrew在线安装。
Qt在Windows上支持众多编译器套件/版本,图省事可以直接从msys2的仓库通过pacman安装,有32位和64位,静态链接和动态链接总共4个包。还可以通过pacman安装Qt Creator,也有32位和64位共2个版本。经过简单试用下来发现,从msys2安装的Qt与从官网下载安装的MinGW版本Qt基本相同,但比MSVC版本要不好用些,我遇到几个问题不能解决:
今天手头上的Nexus 6通过OTA升级到了Android 7,之后发现几个用Qt写的App显示中文字符全变成方块了。这个问题在当时系统刚升级到6.0时也遇到过,解决办法是自己带一个中文字体,再在程序中指定使用这个中文字体。这是比较繁琐的解决方法,Qt官方也收到了问题报告,只不过修正后的版本还没有发布,但是问题报告下面有人提到了问题代码,所以要自己出个workaround也很容易,只要在自己的程序开头加这么一段代码就可以了:
最近想着赶紧弄个程序出来上架到Mac App Store去,因为我只会用Qt写Mac的GUI程序,所以要研究一下如何把Qt程序签名上架,结合网上找到的这篇、这篇,以及这篇文章,折腾了几天了,最终,仍然没搞定怎么签能上架Mac App Store的Qt程序,貌似只搞定了Developer ID类型的,即在Mac App Store以外发布的程序,这种签名唯一的用处貌似是别人拿去能直接运行而不会弹出个消息框说来自不受信任的开发者(其实我是猜的,没验证过。
仍然是日志查看程序,突然想要加个按正则表达式的查询,记得sqlite是支持REGEXP的,不过sqlite官方文档上说了,需要程序自己提供一个进行正则匹配的函数,然后调用sqlite3_create_function来实现。
这几天写了个查看日志的程序,日志是公司里产品项目用户log4cxx生成的,用于定位问题。以前看到过其他同事自己开发的这类程序,但都只限于他们自己使用,等他们离职了,就基本失传了,尽管他们是交接给其他同事了。
Qt for Mobile默认是用了一张纯黑的图片作为程序启动图片,所以一开始程序启动时会出现1到几秒的黑屏,机器越慢,这个时间越长,比较不美观,我们可以自己动手设置上适合的图片。
昨天突然又想在Qt for Mobile中用上Boost,于是先得把Boost编译到iOS/Android上,然后发现了一个叫CrystaX NDK的东西,它本身的可以作为官方Android NDK的替代,不但对标准库和编译器有了一些改进,还包含了预编译好的Boost库。
前些天想着给istkani在Android集成个push notification,用了腾讯的信鸽,结果在进程退出后老是会弹框说进程意外结束云云,于是就放下了。
这两天突然想把istkani在Android跑一下,本来是想集成个腾讯信鸽的推送功能,但是信鸽没集成好(程序老是挂掉),先去调了一下界面的问题。
先看一遍Apple的官方文档或者网上随便找个入门介绍文章,知道代码主要要做的是在AppDelegate里开头做点初始化工作,然后实现几个函数。Qt对各个平台底层都做了良好的抽象和封装,好在有人做过些相关的研究,可以自己写个AppDelegate替换掉原来的那个。那块代码抄过来后,要注意的是因为我们替换原有的AppDelegate已经过了didFinishLaunchingWithOptions的时机,所以我们在自己的AppDelegate里写一些初始化的代码在didFinishLaunchingWithOptions里是没用的,我的办法是在替换AppDelegate后再做那些初始化工作。但是另外带来些问题,原来写在didFinishLaunchingWithOptions里的一些代码是可以work的,写到其他地方时可能就直接crash了,比如以下这些代码:
QtQuickCompiler出来有一些日子了,自从istkani在iOS App Store上架后,就没怎么关心过Qt的进展,只是差不多每天例行扫一遍Qt的邮件列表而已。昨天心血来潮想试试QtQuickCompiler到底有多神,首先快速浏览了一下官方文档,发现使用还是很简单的,然后开始照文档的说明一步一步操作。
之前说过想用Intel C++编译Qt来着,于是从VeryCD上找到Windows、Mac和Linux的Intel C++安装镜象不辞辛苦地下载下来安装。结果让人很沮丧啊。
在Windows 7中,无论编译64位版本还是32位版本,都会编译失败,我怀疑是因为Intel C++用了Visual C++的头文件引起的问题,但是我直接用MSVC2010来编译64位的Qt,虽然也是编译失败,却跟Intel C++报的错误不同,好像C++11标准的问题,在Webkit部分中有类名为nullptr,这个名字在C++11中作为保留字了。也不知道那些用MSVC2010编译成功的是用了什么参数。至于使用MSVC2008的配置,我就没兴趣编译了,因为我不喜欢MSVC2008的SxS。
然后在Mac中编译,32位版本也是编译失败,64位版本编译倒是全部通过了,但貌似make install不完整,那些头文件就没有复制过去,还缺了些什么不知道,反正直接把Qt源代码目录中的include目录复制过去是不能用的。于是也放弃了。
后来么,在Windows上下载了32位和64位的TDM GCC,编译了两个晚上才编译出来,话说那个-nomake "demos examples docs"参数不起作用啊。试了试编译Ninayan 64位,可以运行。
这两天看到Nokia的Qt论坛上有个叫Qt4iOS的人,说他做的Qt for iOS插件就要可以正式发布了,好期待啊。又看到有人说,Necessitas虽然还在Alpha版本,但已经可用性很高了,我看了下,现在居然已经提供4.8.0版本的for Windows/Mac/Linux的SDK了。不过在Mac上安装好后想编译Ninayan才发现,源代码还需要做些修改,比如源代码中通过预定义宏只识别了Windows/Mac/X11/Symbian/Maemon,但是这个Android不知道是什么宏,不知道上哪去查点资料看看。
于是最近还在网上看到的消息,是说Windows Phone的下个版本会支持C++开发,如果这样的话,Qt也会很快就支持WP开发。啊,如果Qt真能用于Android、iOS和Windows Phone的开发,那就太牛逼了。说实话,如果这些port的质量可以的话,只要价格不是太离谱,我应该会买这license去的。
春节放假时有一天突然想到Qt是支持用Intel C++编译的,有icc的mkspec,而且Intel C++在Windows、Mac和Linux都有,还能生成32位和64位的可执行文件,于是就想试一下,如果确实可行,以后就不用GCC了,虽然GCC也很好。
比较囧的是,在Windows上,Intel C++除了最核心的编译器,其他的都是用Visual C++的,比如运行时,甚至包括nmake,于是很不幸的是nmake貌似不能通过命令行参数指定并行编译,只能单线程编译了,纠结。
自己编译Qt的话,Windows和Linux都要为32位和64位系统分别编译,Mac倒是只要编译一个就行了,但是有个小问题是上次在Mac OS X 10.6.7上编译Qt 4.8.0时64位版本到后面有个什么库没有,于是只能编译32位版本了,囧。
N9作为Nokia推出的唯一一部装载MeeGo系统的手机,主打宣传的是其滑动手势。
滑动手势在其他触摸屏设备上已经有所应用,各种移动操作系统也对其有一定的支持,但在N9上作为主推特性的滑动手势主要是基于Qt这个跨平台的开发框架实现的,因为从实现角度讲,N9装载的MeeGo系统的UI都是建立在Qt的基础之上的。
Qt自从被Nokia收购后,一直致力于在移动设备上的移植工作,尤其是对Symbian的支持越来越多。而MeeGo这个原本由Nokia和Intel合作开发的项目,同样做了很多跟Qt适配的工作。
Qt做了很多为方便实现触摸操作响应的工作,特别是后来推出的Qt Quick,彻底地让UI和业务逻辑分享。美工可以只使用非常简单的脱胎于JavaScript的声明式语言QML来构建UI,而程序员则可以专注于使用C++或JavaScript实现底层的业务逻辑。Nokia为QML提供了非常丰富的UI元素,还为Symbian系统特地实现了一组扩展的UI控件,这已经可以实现绝大多数的UI需求,各种UI元素又可以随意组合从而构建出更加复杂的应用。而且Qt还提供了多种QML与C++交互的机制,如果QML内建的UI元素不能满足实际需求,程序员可以用C++实现复杂的UI,而Qt本身又有基于CSS style sheet的UI方案和Graphics View的方案,这都让开发人员可以快速地制作出炫目的UI来。另外值得一提的是,基本上可见的QML UI元素,都为触摸操作甚至滑动手势提供了一定的支持,这从QML自带的Demo就可以看出来,不但需要的代码量非常少,而且做出的UI效果却非常时尚。
可以这么说,Qt推出Qt Quick这个方案,代表了应用程序开发的一个方向,快速制作精美UI的方向。基本上所有大的开发框架/解决方案都采用了类似的技术,比如微软的WPF,Mozilla的XUL,甚至Qt在开源界的长期竞争对手Gtk+也有类似的方案,即用简单的标记式、声明式的语言构建UI,减少美工们的学习负担和工作量,而使用其他功能强大、便于操控底层的语言实现业务逻辑。相比其他几个竞争对手,整体而言Qt的优势在于跨平台性好,配套的开发工具也一直在进步。但是它必然也有些缺点,比如一直以来Qt的运行效率不高,虽然Nokia收购后这在方面做了大量的努力;前不久Qt又回归了社区,Nokia成为了一个普通的贡献者,这也许会带来发展方向模糊,进度缓慢的问题,比如一直由开源社区在开发的Qt for Android的port,一年多了仍然没能正式发布。
总的说来,Qt是一个构建Windows、Linux、Mac OS X以及Symbian、MeeGo应用的低成本、高效率的解决方案。如果基于lighthouse机制的Android和iOS移植能尽快正式发布,那在普通消费型电子产品平台上,就真的如它的宣传语所说的Code Less, Create More, Deploy Everywhere了!
因为想要把CodingStudio移植到Mac,于是就想先编译下wxWidgets 2.9试试。结果在Windows下用VC9倒是正常编译通过了,用MinGW 4.4最后链接的时候报wxScintilla里一些符号找不到,真头痛。
后来就想试试Qt吧,找来QScintilla最新的稳定版本2.5.1,编译倒是基本上没问题,可是自带的那个example在一启动就崩溃。
在Mac下编译wxWidgets 2.9倒是正常通过了,而且确实是使用cocoa 64bit port,试了几个sample也能正常运行。
头痛。
好吧,Nokia真的把Qt卖掉了。不知道Nokia这样彻底放弃软件业务后,真的只做硬件了?它做得过天朝的山寨厂商么?想想其他的有点名气的有点野心的手机厂商,韩国的三星,大陆的魅族,还有台湾的众多厂商,哪个不是一开始做硬件,之后再想办法自己掌握一个操作系统(Android是它们的机会)?Nokia却反其道行之!好吧,算是看明白了,任何与微软合作的厂商都会被它搞垮,想想IBM的个人PC业务,想想Apple在经典Mac的时代,它们倒是瘦死的骆驼比马大,终于要么割肉要么涅槃继续着自己的辉煌,那再想想比较近的Borland,还有Novell,现在还有人记得它们么?Nokia,你以为自己是哪个?
Nokia是在Qt上投入了两三年后,等不及这只鸡下蛋了么?在HP的WebOS明确支持Qt(4.6.1)开发,RIM的PlayBook采用的QNX明确使用Qt构建其UI的年代,Nokia好大方地把Qt就这么丢掉了!问题是它丢却没丢干净,手里还握着LGPL许可!这算怎么回事,难道等着以后实在不行了却得见不得别人过得滋润,就开始咬人?
好吧,我觉得现在的情况可算是对Qt来说,最糟糕的情况了。Qt变得让人不想再用,不想再开发的东西。本来我一直想说,我用过的C++ GUI框架中,包括VCL、MFC、wxWidgets,Qt是外部接口设计上最好的一个。4.7版本加入的Qt Quick对于开发者来说,也真是一大福音。但是现在,一切都变得不确定,让人没有信心。好遗憾!
Ninayan的主要功能基本上都做出来了,剩下的主要是增加各种服务的支持,比如各种微博,各种SNS,以及Google Reader。其次便是界面和操作上的细节方面的调整,现在还是很粗糙的。
离上次W.I.P.已经有3周多了,这3周主要实现了文章浏览特性。文章浏览有3种模式,一种是仿feedly的可扩展的列表,一种是信reeder的分栏,还有一种是仿paper.li的报纸模式。但是,目前的效果还远远没达到预期。放几张图吧:
还增加了个视频观看视图,这是计划外的,但觉得有必要,也很粗糙:
直到这里才发现,在Mac OS X 10.6.6上一直以64位Cocoa编译的Qt,果然视频播放不了了,不记得在哪里看到过说明,QtWebKit在Mac上如果是64位的话是载入不了Flash播放插件的,因为Flash播放器稳定发布只有32位版本,于是在Mac上也自己编译了一把Qt,改成32位Cocoa框架的就可以了播放视频了,太纠结了,也难怪乔帮主要封杀Flash了。
今天觉得Ninayan大部分功能已经实现了,也差不多快可以发布beta版了,于是要打包,先解决Windows和Mac上的打包问题。 Windows上一直以来我都习惯用Inno Setup了,所以在如何制作安装包的问题上并不纠结,InnoIDE和ISTool都是很方便的工具,主要的问题在于解决Qt的插件的部署。Ninayan在Windows上也是用GCC(MinGW)编译的,相比VS2008,少了个SxS的问题,只要带两个dll一起发布就行了。Qt本身有一种简单但比较有用的插件机制,它的字符编码支持CJK,图形文件格式支持,数据库驱动等等都是由插件实现的。也就是说$(QTDIR)/plugins下的东西都要跟着发布,而且程序代码中需要自己在main()中,app对象创建后及时调用QCoreApplication::addLibraryPath()添加plugins的路径。另外由于用到了QtWebKit和QML,QDeclarativeEngine对象也需要指定一下qmlwebkitplugin插件的目录,把$(QTDIR)/imports/QtWebKit目录打包进去,然后在代码中调用QDeclarativeEngine::addImportPath()添加路径,这样整个目录就是发布的所有内容了。 在Mac OSX上比较流行用dmg,但这之前还要解决Qt的framework链接的问题。Qt在Mac OSX下官方发布的二进制包是framework形式的,这跟Windows下有点不同,呃,其实跟SxS有点类似。要用install_name_tool -change命令行修改自己的程序可执行文件链接的framework的位置,这个工作可以由Qt自带的一个叫macdeployqt的小工具完成,只要在命令行执行macdeployqt Ninayan.app就可以了。不过除此之外,还是由于qmlwebkitplugin的缘故,需要自己复制这个插件到程序的bundle中,我就放在跟最终的可执行文件相同的目录中,这个插件macdeployqt并不处理,除了要自己复制,还要自己用install_name_tool来修改链接的framework。这样操作后,是一个可以正常运行的,完整的应用程序bundle,整个bundle就有113MB,谁让Qt那么大呢!然后是把这个bundle打包成dmg。Mac OSX自带免费的工具,GUI和CUI的都有,GUI的叫Disk Utility,不过看了下感觉界面挺复杂的,还是用命令行的hdiutil爽,而且我前面是用命令行修改的符号链接,这里当然最好也是用命令行打包,这样一个shell脚本就能搞定编译后生成dmg的所有事情了。用hdiutil的话,这个命令行就可以打出一个dmg来: hdiutil create -srcfolder Ninayan.app -volname Ninayan -format UDZO -ov Ninayan.dmg 不过这个有点土,就是把Ninayan.app放成了dmg而已,其他什么都没有。我的要求其实也很简单,有自定义的背景图片,有Applications目录的链接,这样用户打开这个dmg就可以完成把Ninayan拖拽到Applications目录中的操作。在网上找了不少文章和视频,多是用其他的GUI工具,在stackoverflow上有个家伙用AppleScript写了段脚本,确实通用性和灵活性都比较好了。最后我选了条简易简陋没通用性的路子,但够用。首先需要明白的是,dmg被Finder打开后,就是当成一个普通的文件夹处理的,所以它的背景什么的设置,都是放在.DS_Store文件中的(Mac中以dot开头的文件都会自动隐藏),所以很dirty的做法是,先用这个命令行创建一个可读可写的dmg并挂载: hdiutil create -srcfolder Ninayan.app -volname Ninayan -format UDRW -size...
诺基亚与微软合作,以后放弃Symbian,在高端机型中使用Windows Phone7系统,而一直在大吹特吹的MeeGo将只作为一个实验性的作品,这消息发布后,网上就像炸了锅。
我个人表示很无语,感觉我期望的那个诺基亚已经远去了,那个Elop简直就是微软派去的卧底。关键一点是,以后也是使用微软的开发工具,最近两年那些开发出Qt、QtCreator、Qt SDK的人的工作,几乎等于打了水漂。不可否认微软的IDE很强大很好用,但它的框架(类库)我却是相当不喜欢,而且我现在觉得Qt实在是个有希望好好跨平台的方案,但这些大厂商硬要自己搞一套,实在烦人。Windows Phone开发用C#,Android开发用JAVA,iOS开发用ObjC,而Symbian/MeeGo开发用C++,这是让人非常纠结的事。而因为Qt的存在,让我曾经幻想,可以在WP、Android和iOS也使用C++/Qt进行开发,如今看来,毕竟是我贪心了,叹气。
现在网上都在说,以后就进入三足鼎立的时代了,要我选择的话,如果苹果的品质没有大的变化的话,我会首选iOS的,然后是Android,最后才会是WP。
昨天和前天晚上蛋疼地在Linux上编译Ninayan了。我用的是Mint9,也就是一个Ubuntu的修改版。在Linux上编译Qt程序有点麻烦的是需要自己编译一遍Qt,前天晚上就编译了一遍最新的qt-everywhere-opensource-src-4.7.1.tar.gz,过程比较顺利,再装上Qt Creator就可以编译出Ninayan了,简单试用了一下,很正常。而且令我比较惊讶的是,我学Hotot用了Droid Sans字体,最终的显示效果在我个人看来比Windows XP SP3和Mac OS 10.6.6上都要好,但XP SP3上加上Gdipp或MacType后,效果会有很大的提升。
昨天突然发现,Ninayan在Mint下不能访问https://api.twitter.com(不是被墙的缘故),测试了几次才确认是不能访问https的地址,于是想到前不久看过一篇博文说Qt 4.7是有这么个bug不能访问https的,因为原来Qt 4.6带了SSL证书,而Qt 4.7没带,于是照那篇文章的作者的说法,从Qt 4.6.2里找到qt-ca-bundle.crt文件,然后每次QNetworkRequest在被post或get前都设置一下Ssl证书。结果我的情况是连编译都不通过,于是可以确认是Qt在编译时没有编译进OpenSSL了。然后找到了这篇《Compile Qt 4.7 on Ubuntu 10.10》,先要安装一堆的库的开发包,再来编译Qt,最后再编译Ninayan,果然就正常了!于是我就不明白那篇博文讲述的到底是个神马问题了!
今天就比较烦躁地在做网址缩短功能了。本来打算内置goo.gl,bit.ly和is.gd三个短网址服务,结果很郁闷的是bit.ly总是返回INVALID_URI,但同样的URL我拿到Firefox下测试就能返回正确的数据,这不是歧视嘛,难道是在http header里还要设置神马东西?倒是goo.gl和is.gd都正常了!
内存泄漏的问题,调得我心力交瘁,都有点神经衰弱了,甚至有点绝望,唉。以前还真没有过这种强烈的负面情绪出现过。
每次UI刷新,从任务管理器里看Mem Usage都会增加2-3MB,这得有多严重的泄漏啊!可是我自己的代码中new出来的对象都经过跟踪是销毁掉了的。于是又把矛头指向Qt内部,或者是QML中了。
本来怀疑是QML中的实现可能有问题,于是把Qt从4.7.0升级到4.7.1,貌似泄漏得更严重了。所以现在都已经不敢怀疑是Qt有问题了,开始怀疑是没有遵循Qt的用法。有些Qt返回的东西,需要程序员来负责销毁,比如QNetworkAccessManager在调用get或post后返回的QNetworkReply对象,这是多么操蛋的设计啊,指不定就是每次在哪里它自己创建出一堆对象出来要我来销毁我却不知道呢!
从CodeProject上下载了个Visual Leaks Detector,从说明上看,说是在msvc的jit debugger里会自动打印信息到debugging output window里的,可我实际上试了之后,发现屁都没输出一句,难道它是for MFC-based project only的?有可能的,唉!
简直走投无路了。
现在不少服务都用OAuth认证了,在Qt下有QOAuth这个第三方库,它是个日本人为qTwitter这个Twitter客户端而编写的。要编译QOAuth,有几个步骤。
首先,编译QCA,这是个KDE下的项目,Qt下的加密算法库封装。
然后下载OpenSSL,需要头文件和导入库文件。编译qca-ossl,即连接QCA和OpenSSL的Qt库插件。
最后便可以编译QOAuth了,需要链接QCA和OpenSSL。
今天我试着用MinGW和MSVC2008编译QOAuth,除了编译qca-ossl时发现有个whirlpool算法分支编译不过外,其他的都编译出来了。接着我就想编译一下Qwit和qTwitter来测试一下QOAuth,结果编译倒是都能编译出来,不过最后运行有问题,在认证Twitter账号时,程序会死循环,不知道是OAuth认证的3个步骤中的哪步出错了,初步估计是第一步,因为连浏览器窗口都没弹出来。也不知道是几个库中的哪个库有问题,唉!
Qt Creator的插件机制比起CodeLite和Code::Blocks来要强大得多。每个插件至少有一个dll文件(以Windows平台为例),还有一个必须的.pluginspec文件。插件的基本信息在.pluginspec文件中描述,包括插件的名称、版本、版权、作者、基本信息、分类、网站等,最重要的一点是有依赖的插件信息。支持插件依赖可以获取得大的灵活性和可扩展能力,这点CodeLite和Code::Blocks都没做到,因为单靠一个动态链接库很难实现这种依赖关系的描述。
插件的实现同CodeLite和Code::Blocks类似,都放在dll中,但它的实现有点像是糅合了两者的作法,但又有所改进。Qt Creator应用程序本身的exe基本上只是实现了一个插件管理器,其他的IDE相关的业务逻辑全是由插件实现,甚至于主窗口也是放在一个叫Core的插件中实现。Qt Creator又定义了一组组的接口让插件实现,这点看来跟CodeLite比较像;但是它又基本上将接口的实现,至少是头文件全暴露了,插件在实现这些接口的时候可以直接调用它依赖的插件的服务,而不是通过接口调用,这点上看又有点像Code::Blocks的做法,我个人不是很喜欢这种暴露过多信息的做法,尤其是如果作为一个商业项目,应该尽量少地提供各种内部信息,当然Qt Creator本身作为一个开源项目,大概在这方面就比较随意了,如果全部用接口的形式交互的话,大概工作量会增多,跟实现一遍COM差不多了。
另外说一下,Qt提供了几个宏,用于定义插件类和使用插件,而且Qt框架本身的一部分特性也是通过这种插件机制实现的。只不过这种支持实在太过简陋,只能说了胜于无吧。
原本用Qt Creator生成工程文件.pro,然后通过qmake -spec macx-xcode xxx.pro可以生成Xcode可用的工程文件,但是说实话Xcode还是用得不习惯,至少我常常用的在class中声明一个函数后,用Visual Assist X可以在右键菜单中直接将其在cpp文件中生成函数框架,但Xcode中还要自己一个字一个字地敲进去,而且这个过程中输入类名都没有自动完成了。当然整个的编辑功能上,Xcode已经比Qt Creator强出太多了。
今天有人跟说我了下同样可以转换成VC的工程文件的,只是多了个参数,要这样用qmake -spec win32-msvc2008 -t vcapp xxx.pro,这样就可以生成.vcproj文件了,自己创建个空的解决方案就行了。注意在用qmake前,先在PATH中设置好Qt的bin目录路径,然后运行一下vsvars32.bat,这样qmake就能把所有东西都设置好了,用VS2008打开后是可以直接编译链接的。这样就可以在VS2008中编码调试了,赞!
突然想再整一下wxMac,之前曾经编译过,也编译出静态链接和动态链接的库了,记得也生成samples的可执行文件了,今天找了一下,那些samples的可执行文件找不到了,随便敲了下make,发现连头文件都没有找到,应该是wx-config没正确执行。然后好奇看了一下readme,赫然发现wxWidgets/Mac doesn't come with any guarantee whatsoever. It might crash your harddisk or destroy your monitor. 这个太夸张啦,不敢用啦,甚至开始觉得是不是以后别的用wxMac开发的程序也要先检测一下然后不用了呢!那个杯具的CodeLite和Code::Blocks都是用wxMac的呢!反正我是不想再用了。
下午尝试给CodingStudio加入命令行打开文件的功能,可是怎么整都是搞得程序启动就崩溃,郁闷了!
于是很有些后悔当初采用了wxWidgets,而不是Qt。但是想想以当时的情况,确实再来一次,很可能还是不会用Qt。当初对Qt很是不满意它对所有控件都是自绘,而不是native的,而且觉得Qt需要moc一下很无语。最关键的是当时参考了大量CodeLite和Code::Blocks的源代码,没办法啊,对于一个新接触的GUI framework,这是最直接有效的办法了!
哦,对了,今天的消息,国人得到Nobel Peace Prize了,具体情况,咳咳,不明真相的童鞋,需要当一回红杏。
Qt4.7.0发布有几天了,这个版本较4.6.x来说,最大的改动莫过于增加了Qt Quick。
Qt Quick是一套解决方案的统称,它包括一个称为declarative的framework,跟animation、state machine之类层次的东西,包括一个称为QML的声明式语言,还包括Qt Creator中辅助设计和编码的那部分。
开发人员可以通过名为QtDeclarative的C++模块,在自己的Qt程序中装入QML文件,并与之交互。QML语言通过一组丰富的QML元素,构建一棵对象树,以此来实现高度动态的可自定义的UI,它支持并实现了Qt的甚于QObject的类型系统,提供自动属性绑定,而且在语言层面实现了网络透明化。
之前一年多,我在wxWidgets程序中嵌入了Lua,并用wxLua在脚本中实现UI。相当于说,我在这方面自造了一个相当笨重且不好用的轮子。如今看来,Qt在脚本实现动态UI上的表现,就是我这几年来一直期望拥有的。不过QML并不能完全代替Qt原本的基于QWidget的UI方案,QML适用于创建大量简单的动态的UI,而QWidget则适用于创建复杂的静态UI。
从Qt4.7.0附带的几个declarative的demo看,UI效果挺炫的,在当今越来越注重外观,又越来越对开发效率有更高要求的大潮下,实在是个值得一用的方案。
我在Windows XP和Mac OS X 10.6上都试用了一下,感觉不错,至少demo中暂时没有发现什么严重问题。值得说一下的是,原来我在Mac OS X中安装的是Qt SDK,32位已经编译版本,发现有一部分demo运行并不正常,后来覆盖安装了64位已经编译的Qt libraries,发现那些原本不正常的demo全都正常了,真囧。不过就我看来,既然苹果官方都强烈建议开发64位程序,那就用64位的好了。
昨天在看QT的examples和demos的时候,猛然发现一组animation framework的示例,看了一下居然就是我一直在纠结在寻找的如何用QT做出那些酷炫界面的方法。话说其实之前也不时地翻一下QT的这些demo的,怎么就没发现呢!
看了一下程序的运行效果和代码,并配置着读了一篇animation framework的使用介绍,对如何使用QT做出那些动画效果有了一个简单的认识。今天跟@zhangh109讨论时了解到,苹果的系统使用Cocoa core animation functions来达到这种目的,而Android好像没有现成的,要开发人员自己实现。
到此为止,基本上解决了绝大部分的技术问题,剩下的主要是设计决策了。
昨天下午和晚上都在看代码,对QT的使用有了更多的了解,不过还缺少一本能跟上最近QT变化的比较系统的教材。QT在这几年变化比较大,而最近最流行的一本讲QT使用的书,是2006出的《C++.GUI.Programming.with.Qt4》,都整整过去4年了,QT都快出4.7了,这几年新加入QT的内容才是真正令人激动的。
一直有种想写个twitter客户端的冲动,不过一直没动手,因为手头正经事情还很多,还要留下不少时间去堕落。不过我想待现在手头这个东西完成后,就试着写写吧。昨天去折腾了一下QOAuth,结果它依赖QCA,而QCA又依赖OpenSSL,真是折磨人。
再花点时间研究一下用QT怎么做一些比较酷的界面效果,就可以动手啦!
Category SNS
这几天对Ninayan想了很多。
到目前为止,总的说来,尽管bug还很多,UI还不够精致,操作还不够方便,但功能上已经实现了原来预定的计划中的大部分,除了难度最大的按语义自动按用户喜好定义优先级。
最近轻博客突然吸引了好多眼球,大约两年前其实已经有Tumblr这个产品,只是它并没有大火特火起来。而就最近的几个月里,国内突然冒出好几个同类产品,点点,推他,据说新浪有个Qing。虽然像Twitter、新浪微博这种都有自己的方式展示多媒体信息,但用过轻博客后,明显感觉体验更进一层。于是我就想,其实从客户端层面出发,可以尽量抹平微博客和轻博客的差异,Ninayan就可以往这个方向发展,如果真这么做,无论UI还是底层,都需要做大量修改。
这些天我用新浪微博比较多,同时又不想落下Twitter,同时比较认真地维护两个账号,让我突然意识到,像我这样的人用微博,主要出于两个目的,一是分享自己的状态,二是获取自己关心的信息。而获取信息又可大体分为主动和被动两种,主动是指自己去主动阅读timeline,被动指被别人mention了。于是想到对于同时维护多于1个账号的情况下,提供一种合并显示所有账号的同类信息的功能会很有用,Mixero就有这种将多个账号的timeline显示到一块儿,mentions显示到一块儿等等这种选项,而Ninayan要做的则是可以跨服务合并显示,即比如把Twitter和新浪微博的timeline显示到一块儿。这样做会引发另一个问题是,过滤掉重复信息。这一方向得靠用户自己,仔细甄选该关注的人,比如有的人喜欢用同步工具,结果ta在多个服务中发布的消息几乎是一样的,那么只要在某个服务中关注ta一次就够了;另一方面可以在软件层面识别出相同信息进行过滤。另外要说的是,分享活动,最好是能随时随地方便地进行。这就是说,Ninayan目前光有Windows/Mac/Linux桌面版是不够的,还应该有iOS版和Android版,除了手机版,还要有平板版。还有,最好能自动截取到用户关心的活动,比如能自动获取当前系统中正在播放的歌曲的信息,浏览器正在浏览的网页的标题等等。
暂时就想到这样,好吧,可以做很久很久了。
一直准备把Ninayan移植到手机上去的。但是之前尝试把它移植到S60上不太顺利,simulator上跑得基本正常,一部署到手机上,就会自动退出,我估计是由于内存占用太多,或者同时并发的网络连接过多。写惯了桌面程序,确实对于这种资源受限环境的程序开发有点束手无策。于是就丢下暂时不管了。
这次打算尝试一下iOS开发。几个月前就买了本《iPhone SDK 3开发指南》,一直没怎么看,这最近两个星期又是看书又是看视频的,总算有点儿明白怎么个过程了。不过不同的屏幕大小,对于UI的需求也不一样,在iPhone这种屏幕受限的环境中,也只能尽量把有用的UI元素挤到一块了。我习惯的做法是先把界面画出来,然后给每个菜单项啊,按钮啊什么的加上功能……这是我10来年来养成的习惯,从一开始涉及GUI开发就自己形成的习惯。有了UI后,要移植Ninayan到iOS上,只需要找一个JSON解析库,一个OAuth库,其他的iPhone SDK就够了。
今天又折腾了下,可以直接点击列在工具栏中的超链接按钮,直接显示链接接的内容,分为图片,视频和文章三个类型。最后又揪出整个程序中最头疼的一个问题,Sqlite数据库的使用,总有冲突,叹气。不过在线显示内容的功能勉强能用了。
实在有点不乐意做Deardawn,心理障碍克服不了啊。
Ninayan今天被小言一说,才发现真的是添加不了账号了,原来是之前一次为了加快启动速度的修改,把其他功能破坏掉了,不但添加不上账号,还一开始不能发布消息,只有在显示过home timeline后才可以。
提取了几个model类,这样的实现比较优雅。
几个singleton在程序退出时都正确销毁了。
把AutoProxy的gfwlist信息配置保存到sqlite数据库里了,可以记录每条规则的enable与否,hit次数。在每次程序退出时刷新这些信息到sqlite数据库里。
给几个本地数据库建了几个索引,这样可以让查询速度加快一点点吧。
由于占用内存比较厉害,在Windows下就用::EmptyWorkingSet每分钟清空一次工作集,其他平台不知道有什么类似的方案。但实际上在Windows下如果窗口最小化时,内存会被一下子回收好多,不知道到底是怎么回事的。
本地数据库读写冲突的问题还没想到比较低成本的解决方案,叹气。
停下来想想,现在已经实现的功能也只是玩玩而已,最有用的应该还是Google Reader支持吧,可惜没找到确认无误的API文档。
blog被墙了就真不太想更新了。
Ninayan这段时间除了不时地发现些bug,然后修正外,主要是增加了对163、Sina、Sohu、QQ微博的支持。从开发者角度讲,163的API是最接近Twitter了,QQ的API设计最山寨,完全自己搞了一套,Sina和Sohu从技术角度讲跟QQ接近,接口设计仍然是模仿Twitter。
然后在google code上放了Linux版的可执行文件上去,今天才知道原来各发行版上普通的应用程序是可以做到二进制兼容的,也怪我以前看CodeLite、Code::Blocks它们都为每个发行版提供一个独立的安装包,就先入为主地以为每个发行版都要各自单独编译才行。今天突然想到Qt Creator就是同一个可执行文件在所有Linux发行版里可以运行,只是区分了32位和64位而已。我还傻乎乎地在12个系统里都编译了一把Qt,再分别编译出Ninayan,再分别打包,再分别上传,天呐!
首先一件很郁闷的事,貌似域名被墙了,直接用IP是可以打开本blog的,但是我暂时又不想去折腾这些了,先这么放着吧,问候下方校长18代祖宗及全体女性家属。
Ninayan最近动作倒是不大了,主要是先打了Mac,Win32和Linux的安装包给几个人试用了一下,结果反响很差,有点失落,难道真的定位有问题?
不过说起来,Ninayan现在也只是个雏形,真正的主要的理念需要的特性并没有实现,现在也只是把图片,视频和文章链接单独提取出来可以独立浏览而已,并没有做进一步的工作,比如要能打tag,可以检索,自动语义过滤,优先级排序等等。其次是RSS聚合也没做,Google Reader没实现,UI缺少专业的美工设计等等,总之可以做的工作还有很多很多。
另外,今天勉强让Ninayan在我的Nokia 5230上运行起来了,解决了不少问题,但最终还是由于报内存不足而自动退出。为了让Ninayan可以在5230上运行,遇到了不少问题。首先是开发环境的建立,我用的是Qt SDK 1.1 beta,这个SDK用的是Qt 4.7.2,但有bug,for S60v5的配置文件使用了for Symbian^3的配置,所以编译工程的时候会出错,要自己在工程的.pro里把opengl的配置去掉。其次是部署时,要安装Qt,还要单独安装sqlite,据说以前版本是合在一个安装包里的。最后是这两天一直在纠结的问题,运行后在TextInput获取输入焦点后,虚拟键盘没有显示出来,在Nokia的论坛和Stackoverflow上问,都没人回复,今天偶然想起qDou,试了下它在5230上至少是可以输入文字的,虽然之后会崩溃,于是发邮件问了一下作者,作者给了个网址,原来是我在TextInput控件一起放了个兄弟控件MouseArea,于是TextInput没能收到点击事件,于是虚拟键盘不会自动显示,只要自己强制调用它的openSoftwareInputPanel方法就可以了。
至于最后的自动退出,从现象结合网上的人们的讨论来看,似乎是因为同时请求的网络连接太多,以及内存占用过多引起的。叹气,桌面程序写惯了,散漫惯了,都不怎么注意内存的使用了,反而经常采取以空间换时间的策略,看来如果真要让Ninayan能在手机上正常跑起来的话,还得好好重新设计一下,把各种请求都放进队列里,不要一下并发几十个连接,其他的内存使用策略也得仔细看看,有点想看看侯捷翻译的那本讲内存受限系统的程序开发的书了。
Ninayan的主要功能基本上都做出来了,剩下的主要是增加各种服务的支持,比如各种微博,各种SNS,以及Google Reader。其次便是界面和操作上的细节方面的调整,现在还是很粗糙的。
离上次W.I.P.已经有3周多了,这3周主要实现了文章浏览特性。文章浏览有3种模式,一种是仿feedly的可扩展的列表,一种是信reeder的分栏,还有一种是仿paper.li的报纸模式。但是,目前的效果还远远没达到预期。放几张图吧:
还增加了个视频观看视图,这是计划外的,但觉得有必要,也很粗糙:
直到这里才发现,在Mac OS X 10.6.6上一直以64位Cocoa编译的Qt,果然视频播放不了了,不记得在哪里看到过说明,QtWebKit在Mac上如果是64位的话是载入不了Flash播放插件的,因为Flash播放器稳定发布只有32位版本,于是在Mac上也自己编译了一把Qt,改成32位Cocoa框架的就可以了播放视频了,太纠结了,也难怪乔帮主要封杀Flash了。
今天觉得Ninayan大部分功能已经实现了,也差不多快可以发布beta版了,于是要打包,先解决Windows和Mac上的打包问题。 Windows上一直以来我都习惯用Inno Setup了,所以在如何制作安装包的问题上并不纠结,InnoIDE和ISTool都是很方便的工具,主要的问题在于解决Qt的插件的部署。Ninayan在Windows上也是用GCC(MinGW)编译的,相比VS2008,少了个SxS的问题,只要带两个dll一起发布就行了。Qt本身有一种简单但比较有用的插件机制,它的字符编码支持CJK,图形文件格式支持,数据库驱动等等都是由插件实现的。也就是说$(QTDIR)/plugins下的东西都要跟着发布,而且程序代码中需要自己在main()中,app对象创建后及时调用QCoreApplication::addLibraryPath()添加plugins的路径。另外由于用到了QtWebKit和QML,QDeclarativeEngine对象也需要指定一下qmlwebkitplugin插件的目录,把$(QTDIR)/imports/QtWebKit目录打包进去,然后在代码中调用QDeclarativeEngine::addImportPath()添加路径,这样整个目录就是发布的所有内容了。 在Mac OSX上比较流行用dmg,但这之前还要解决Qt的framework链接的问题。Qt在Mac OSX下官方发布的二进制包是framework形式的,这跟Windows下有点不同,呃,其实跟SxS有点类似。要用install_name_tool -change命令行修改自己的程序可执行文件链接的framework的位置,这个工作可以由Qt自带的一个叫macdeployqt的小工具完成,只要在命令行执行macdeployqt Ninayan.app就可以了。不过除此之外,还是由于qmlwebkitplugin的缘故,需要自己复制这个插件到程序的bundle中,我就放在跟最终的可执行文件相同的目录中,这个插件macdeployqt并不处理,除了要自己复制,还要自己用install_name_tool来修改链接的framework。这样操作后,是一个可以正常运行的,完整的应用程序bundle,整个bundle就有113MB,谁让Qt那么大呢!然后是把这个bundle打包成dmg。Mac OSX自带免费的工具,GUI和CUI的都有,GUI的叫Disk Utility,不过看了下感觉界面挺复杂的,还是用命令行的hdiutil爽,而且我前面是用命令行修改的符号链接,这里当然最好也是用命令行打包,这样一个shell脚本就能搞定编译后生成dmg的所有事情了。用hdiutil的话,这个命令行就可以打出一个dmg来: hdiutil create -srcfolder Ninayan.app -volname Ninayan -format UDZO -ov Ninayan.dmg 不过这个有点土,就是把Ninayan.app放成了dmg而已,其他什么都没有。我的要求其实也很简单,有自定义的背景图片,有Applications目录的链接,这样用户打开这个dmg就可以完成把Ninayan拖拽到Applications目录中的操作。在网上找了不少文章和视频,多是用其他的GUI工具,在stackoverflow上有个家伙用AppleScript写了段脚本,确实通用性和灵活性都比较好了。最后我选了条简易简陋没通用性的路子,但够用。首先需要明白的是,dmg被Finder打开后,就是当成一个普通的文件夹处理的,所以它的背景什么的设置,都是放在.DS_Store文件中的(Mac中以dot开头的文件都会自动隐藏),所以很dirty的做法是,先用这个命令行创建一个可读可写的dmg并挂载: hdiutil create -srcfolder Ninayan.app -volname Ninayan -format UDRW -size...
已经不记得有几个大年三十的晚上是在电脑前写代码度过了,今年破天荒的因为客厅里电视在放春晚,打偶然走过去看几眼。
今天把超链接处理模块重构了,之前那个实现在Mac下崩溃得比较频繁,但在Windows和Linux下却不是很多。对于这个现象我有点疑惑,虽然说代码确实是写得有问题,但为什么只有在Mac才比较明显呢。好在Mac下崩溃了打印出来的栈回调信息比较详细,几乎能跟踪到最终引起崩溃的代码行。
原来的实现把所有中间数据结构以指针的形式保存在一个list里,然后在自认为结束的时候销毁对象。这样的做法本没有什么问题,关键是我在操作这个list时并没有考虑重入的情况。于是重构主要做了两个重大修改,一是在list中直接保存对象,而不是指针,这样更不容易写错;二是对list操作大部分情况下都加mutex锁住。顺便也修正了些其他的小问题,比如原来即使是基于embed.ly的服务识别url是图片还是视频也有问题,其实embed.ly是返回了这个类型的。
另外,今天还把主界面针对360*640分辨率修改了一下,因为Nokia的S60v5和Symbian^3现在几个机型都是用这个分辨率的。至此,图片浏览特性的实现暂时告一段落,接下来该实现文章阅读了。昨天大致研究了一下Readability,发现它在Firefox表现那么风骚,结果在QtWebkit下总是返回不能分析的错误。不知道是DOM树的实现还是JavaScript引擎的问题。难道真要我移植一个C++版本,这实在太费时费力,还不好维护了。
最后,上个最新界面截图。
终于勉强加上了一个功能比较凑合的图片浏览功能,还有很多地方需要改善。本来我的想法是UI上直接拿QML Demo PhotoViewer的代码来用的,可是昨天发现PhotoViewer中的代码会导致在Windows下程序不能切换输入法,于是只好自己写了。自己写就极大地简化了功能,才简化了代码,于是最后所有东西都放在一个QML文件中写完了,最终的效果,也就是几个视图场景切换时那个动画效果没有了。残念!
另外有个问题是图片下载的问题,现在的Twitter上比较流行的图床大多是被墙的,如果让QML的引擎自己通过代理下载图片,感觉不是一般的慢!所以我就觉得把这些图片事先下载到本地缓存起来似乎挺有必要的。
还有个比较重要的问题是全屏模式下浏览图片,默认是自动拉伸到整个显示区了,这样似乎比较影响显示性能,当然也是机器配置不是那么好的才会有这种卡的情况,在我的T43上会卡,拿到Mac mini上就流畅了。应该稍微改一下,看一下是不是在加载前就获取图片本身的尺寸,如果比显示区域大,才缩放,不大的话,就以图片本身的大小显示了,这样显示也更清晰点。
还有个浏览某张图片的大图就不截了,没啥好看的。
有些问题,总是那么奇怪。因为XP里的虚拟机在跑Debian编译Qt,于是在Mac下把QML的Demo PhotoView抠过来用,本来就很吃力,还顺带发现了一个因为先后顺序问题引起的崩溃bug,终于可以在Ninayan里看到PhotoView的样子了。可是到了晚上突然发现,在Windows下不能切换输入法了,一切换Ninayan就挂死!经过一部分一部分地屏蔽代码发现,引起这个问题的似乎是VirtualDataModel中Package的一些代码。好吧,决定索性不用抠别人的代码,用自己的方法写一遍相同的UI吧。
上一段提到,我又蛋疼地在Debian里编译Qt了,嗯,又花了一下午。之后就是编译Ninayan,呃,我现在最大的乐趣就在于在不同的系统里编译Ninayan并用它来上Twitter了,囧rz。想来也不会有多大问题,毕竟之前在Arch和Mint里都比较顺利的,唯一大的区别是在Arch和Mint里桌面都是用Gnome,而这次Debian里用的是KDE,很花哨的感觉。言归正传,Ninayan运行得很顺利,除了字体不太好看。在Twitter上报怨了一下后,@truthurt建议自带一个开源的字体,真是个不错的主意,在Mint里的那种就很好,我后来去网上找了文泉驿的微米黑,在Debian和Arch里效果都很好。其实昨天就想过字体的问题,不过当时想到的是直接将字体装入到系统中,然后在程序中直接通过字体family名使用。今天偶然想到,其实可以程序直接载入指定路径的字体文件来使用的!不过Windows下还是用微软雅黑吧,微米黑在XP下同一个字的不同笔画都有粗细差异,真糟糕。
今天照计划,实现了查看对话的功能,不过不完善,因为网络传输的原因,是一条消息一条消息从服务器获取后显示,如果显示到一半切断,又要显示另一组对话,就会把前一组对话后面没显示的那些消息作为后一组对话的消息。所以要考虑一下怎么加一个中断的机制,不过这个留到以后版本中完善吧,毕竟Ninayan一开始定位就不是一个完善的客户端。
然后又蛋疼地去装ArchLinux了。这个发行版安装比Ubuntu麻烦多了,它的iso镜像只装一个最基本的字符界面,然后带一个pacman包管理工具,GNOME之类的桌面需要自己再另外安装,所以最好有比较畅通的网络。
装完后,中文字体的显示惨不忍睹,google随便搜了一下,也挺折腾的,我懒得弄了。我就是想在上面试试编译Ninayan。没想到可以用pacman安装已经编译好的Qt 4.7.1,再装个Qt Creator,就可以编译Ninayan了。除了显示的字体不好外,其他的还算凑合吧。
明天开始做图片浏览和文章阅读功能吧。
昨天和前天晚上蛋疼地在Linux上编译Ninayan了。我用的是Mint9,也就是一个Ubuntu的修改版。在Linux上编译Qt程序有点麻烦的是需要自己编译一遍Qt,前天晚上就编译了一遍最新的qt-everywhere-opensource-src-4.7.1.tar.gz,过程比较顺利,再装上Qt Creator就可以编译出Ninayan了,简单试用了一下,很正常。而且令我比较惊讶的是,我学Hotot用了Droid Sans字体,最终的显示效果在我个人看来比Windows XP SP3和Mac OS 10.6.6上都要好,但XP SP3上加上Gdipp或MacType后,效果会有很大的提升。
昨天突然发现,Ninayan在Mint下不能访问https://api.twitter.com(不是被墙的缘故),测试了几次才确认是不能访问https的地址,于是想到前不久看过一篇博文说Qt 4.7是有这么个bug不能访问https的,因为原来Qt 4.6带了SSL证书,而Qt 4.7没带,于是照那篇文章的作者的说法,从Qt 4.6.2里找到qt-ca-bundle.crt文件,然后每次QNetworkRequest在被post或get前都设置一下Ssl证书。结果我的情况是连编译都不通过,于是可以确认是Qt在编译时没有编译进OpenSSL了。然后找到了这篇《Compile Qt 4.7 on Ubuntu 10.10》,先要安装一堆的库的开发包,再来编译Qt,最后再编译Ninayan,果然就正常了!于是我就不明白那篇博文讲述的到底是个神马问题了!
今天就比较烦躁地在做网址缩短功能了。本来打算内置goo.gl,bit.ly和is.gd三个短网址服务,结果很郁闷的是bit.ly总是返回INVALID_URI,但同样的URL我拿到Firefox下测试就能返回正确的数据,这不是歧视嘛,难道是在http header里还要设置神马东西?倒是goo.gl和is.gd都正常了!
话说前天偶然发现了MacType和Gdipp,觉得这种功能对Ninayan之类偏阅读的应用非常有帮助,于是我在极限论坛上给MacType的作者私下发了个email询问是否可以提供专门的API以便集成此功能。不过到现在也没收到回应,估计是不愿意了。
今天看了一下MacType的安装目录,发现有个MacLoader.exe,而Gdipp的安装目录下也有个loader文件,这时才明白过来,可以通过把可执行文件的完整路径作为命令行参数传递给这loader,那么该可执行文件会被启动运行,并被注入实现字体渲染增强效果。
经过简单的测试,Ninayan在我的XP SP3上使用微软雅黑字体,加上增强字体渲染效果,感觉确实更舒服了!而Gdipp是以GPLv3,最新的版本好像是用LGPL了,一起打包发布应该是木有问题的。我只要另外再写一个小小的启动程序,在安装包中把启动程序作为快捷方式添加到开始菜单和桌面等位置,可以自己调整是否使用增强字体渲染效果,使用什么样的渲染配置等等。
这样一来,似乎Windows上的效果都超过Mac上的了,一直没找到感觉特别好的Mac上的用于大段文字阅读的字体,微软雅黑只适合在Windows上用,而且至少要开了ClearType Tuner才行,有MacType或Gdipp最好。也许是因为我在Mac下用的是CRT的显示器的缘故,不止一个人对我说过那个视频信号转换后损失挺大的,也许用LCD的就要好些了!
今天心情不错,呼呼!
前面说到内存泄漏的问题。后来通过逐段屏蔽代码,终于找到了最大一处泄漏源。这个办法比较笨,但这次真的有用,主要还是因为程序结构简单,流程也不复杂才能用吧。
程序大体上分为三部分,UI层,数据层,网络通信层。用户在UI层上操作,1、UI层向数据层请求数据,2、数据层根据不同情况直接查询本地数据库或通过网络通信层获取数据,3、网络通信层自己有一个定时轮循的任务,每分钟从远程服务器获取数据,4、有了数据就发送给数据层,5、数据层将数据经过简单处理发送给UI层,6、然后显示,就是这么简单。
我开始主要怀疑UI显示调用的Qt/QML也许MM有问题,于是把最终UI显示的代码屏蔽掉。发现仍然泄漏的情况基本没有变化,说明跟UI显示的关系不大。后来发现Mem Usage的增长是有周期,大概是1分钟1次,那么可以确定是在4和5两步有问题。这时把第5步中代码全部屏蔽掉,果然Mem Usage就不增长了。然后逐步缩小范围,一点点放出代码,最后发现竟然是QSqlQuery查询本地数据库时,select出来的东西需要程序员自己clear掉!内牛满面啊,果然是Qt用得有问题!
今天偶然发现一个叫MacType的东东,可以在Windows下以进程注入的方式给指定进程增强字体渲染效果。跟微软官方的ClearType Tuner是一类东西,不过MacType的选项更丰富。于是我想到,我这个以阅读为主的工具,要是集成这么个美仑美奂的功能,该是多酷啊。在极限论坛翻了一遍帖子,貌似MacType是闭源的,另外有个新生的Gdipp项目,倒是在googlecode上开源了,不过听说它的配置复杂,而且目前不够稳定,尤其是32位系统上。好吧,反正这种功能对我有致命吸引力,一定要集成!
内存泄漏的问题,调得我心力交瘁,都有点神经衰弱了,甚至有点绝望,唉。以前还真没有过这种强烈的负面情绪出现过。
每次UI刷新,从任务管理器里看Mem Usage都会增加2-3MB,这得有多严重的泄漏啊!可是我自己的代码中new出来的对象都经过跟踪是销毁掉了的。于是又把矛头指向Qt内部,或者是QML中了。
本来怀疑是QML中的实现可能有问题,于是把Qt从4.7.0升级到4.7.1,貌似泄漏得更严重了。所以现在都已经不敢怀疑是Qt有问题了,开始怀疑是没有遵循Qt的用法。有些Qt返回的东西,需要程序员来负责销毁,比如QNetworkAccessManager在调用get或post后返回的QNetworkReply对象,这是多么操蛋的设计啊,指不定就是每次在哪里它自己创建出一堆对象出来要我来销毁我却不知道呢!
从CodeProject上下载了个Visual Leaks Detector,从说明上看,说是在msvc的jit debugger里会自动打印信息到debugging output window里的,可我实际上试了之后,发现屁都没输出一句,难道它是for MFC-based project only的?有可能的,唉!
简直走投无路了。
本来排除在计划外的事情,今天又去搞了,就是支持Twip4。前一天也折腾过一下,没弄好,这回问了一下Twip4的作者@yegle,他开始说是计算数字签名时用https://api.twitter.com/作为base string就行了。我试了下不行,后来他又说试试T模式吧,有几个客户端是经过实践T模式没问题的。于是一下子就明白过来了。 Twip4有T模式和O模式两种工作模式。T模式是完全的透明转发,Twip基本上不做任何处理,所以要请求oauth token和oauth token secret时原本是向https://api.twitter.com/oauth/access_token请求的,同时也是拿https://api.twitter.com/oauth/access_token作为base string计算数字签名的,在使用T模式的代理时,只要向http://www.myproxy.com/oauth/access_token请求就行了,仍然用https://api.twitter.com/oauth/access_token作为base string计算数字签名,这样就能无障碍获取oauth token和oauth token secret了。至于O模式,我看了下TweetDeck和Mixero的表现,发现它们也并不向O模式Twip请求oauth token和oauth token secret,或者请求了也没结果。所以我就推测其实O模式是没这功能的,O模式自己有consumer key和consumer secret,所以自己有一套oauth token和oauth token secret,但不是给客户端用的,即使客户端用自己有效的oauth token和oauth token secret发送给Twip请求,Twip也会把http header和url parameters里的东西处理一遍,用自己的那套oauth token和oauth token secret计算出来的东西替换掉。所以我想如果用O模式也要让用户可以无障碍认证的话,需要软件自己提供一个透明代理,软件先拿用户名和密码从那透明代理处获取oauth token和oauth token secret,然后在其他发布消息,收取消息时用O模式代理,就可以解决这个问题了。...
好吧,其实没做什么,本来的计划是先做图片浏览和文章阅读的,可是饭否上的内容实在太单薄了点,呃,这纯粹是借口,于是今天实现了对Twitter的支持。
昨天晚上弄到1点半才基本搞好怎么用xAuth认证获取oauth token和oauth token secret,今天就把twitter的timeline浏览,direct message浏览以及消息发布实现了。这内容比饭否丰富了许多,比如有了3列跟retweet有关的内容。twitter居然没有像饭否那样可以一次请求把foing和foer列表取下来,而只能先获取那些id,再由id去获取其他信息!于是这个功能就还没实现。还有比较影响使用的没实现的功能包括不能看conversation,不支持list,不能用快捷键操作。
不过有点值得欣慰的是,又修正了几处内存泄漏的问题。
今天就不上图了,因为基本上界面上没啥变化。
脑袋混沌了一天,终于基本上搞定超链接处理的功能了。
最开始是由于我使用的处理流程的关系,选择一个合适的数据结构让我头疼了好久,最后决定使用一个list,每个元素是一个结构体,每个结构体由两部分组织,一部分是URL列表,该列表会按短网址还原后的处理顺序存储URL,另一部分则是对该URL的描述,描述的字段包括当前是否已经完成全部的还原操作,最后一个URL能不能被embed.ly拆成两个新的URL列表,代表视频的html和html5等信息。
中间调试过程也是经历了重重磨难啊!其实也是自己代码写得有问题。一开始我是用一个map来存储url list和附着属性的,指针乱飘,调试得没有信心了,才改成上面描述的那个方案。还是有很多问题,经过层层排查,终于把所有的问题都找出来并解决掉了。甚至以为Qt的signal不能随便emit,会有对象生命周期相关的问题,最后也确认其实是在前面的代码写得有问题,哇哈哈!
明天就看一下怎么把数据库中的已有记录读取出来当历史记录来处理超链接。然后就可以做图片浏览的功能了!图片浏览功能完成后就做Readability的功能,之后再做twitter的支持,这就可以发布第一个版本了!
根据@zhangh109的建议,修改了一下界面,浏览文章有三种模式,在启动界面现在就只有一个入口Article View,在Article View中再添加切换浏览模式的入口。另外了加个图片浏览的视图,在启动界面中把原来About的入口替换掉了,About则移到原来的Quit按钮处。
URL处理部分今天还是没有搞定,不过思路清晰了很多,估计明天就可以完成总体的框架,到时候图片浏览部分应该就可以很快实现,而文章浏览部分需要把Readability的JavaScript代码移植过来,本来如果可以直接用它的那些JavaScript代码是最好的方案,可是之前我曾尝试过,不知道为什么内嵌的Webkit在装载完页面后,直接运行那个代码是没有作用的。所以干脆也不研究它了,直接移植成C++的,用Qt的接口操作Webkit的DOM树来解决吧。想来这移植工作需要花一些时间吧。
贴两张修改后的截图吧。
今天在处理超链接的问题,这是最重要的一环。
Ninayan提供给用户的信息分两大类:图片/视频和文章,微博消息只算是附属品。所以从微博消息中得到一个URL后,最终要能正确识别出它是一个图片/视频,还是一篇文章(当然,文章中也可以有图片和视频,但重点是它有文字),对于其他不可识别的类型,比如zip,则忽略。
我设计了如下的处理流程:
1、将URL与embed.ly可处理的类型用正则表达式匹配一下,如果可以匹配上,则用embed.ly处理,不能匹配上,则假设它是个短网址,将其还原成长网址。
2、embed.ly处理后,会返回缩略图和原图(如果是视频,则是一段HTML,可能还会有一段HTML5代码)的URL,假设这URL也是个短网址,也将其还原成长网址。
3、还原成长网址后,与原来的短网址比较,如果两者不相等,则假设该长网址仍然是个短网址,继续还原,如此循环迭代,直到还原失败或两者相等,最后还原的最终长网址与embed.ly可处理的类型用正则表达式匹配一下,如果可以匹配上,则用embed.ly处理。
4、如果第3步最终的长网址不能与embed.ly匹配上,则认为该网址是真正的最终应该由Ninayan处理的网址,可分为前面说的两类,图片/视频和文章。
至于怎么辨别出属于哪一类,我决定采用一个很粗糙的办法,如果前面经过embed.ly处理过的,那么肯定是图片/视频,或者URL最后是以诸如.jpg/.png/.gif等known的图片/视频文件扩展名结尾,那么也是图片/视频,其他的则都划入文章类型。而文章类型其实是个很粗糙的结果,网页是要经过像Readability那样的处理才是最终显示给用户的,而在Readability处理的过程中,可以过滤掉诸如.zip等不支持的文件类型的。
这个方案也只是考虑到了URL在网络交互上的处理过程。还有这处理结果怎么通知本地数据存储模块和UI显示模块,也是个问题。而这个问题涉及到何时通知,通知时采用什么数据结构,以及本地存储时采用什么数据结构。
添加了个图片本地缓存的功能,结果发现不是很好用。在Windows下实际使用时发现有时候装载本地文件仍然很慢,甚至不如直接从网络上加载的快。在Mac下发现压根就装载不上。初步估计是因为多处同时读写文件时有冲突,需要再仔细看看。
把删除消息,去fav后的响应也添加上了。
另外还有些细节方便的调整,比如所有显示图片的地方都添加了等待动画。
最后发现个奇怪的问题,在Mac下读取Friends列表有问题,json解析失败,这太诡异了。
今天听@shellexy说,用HTML5的话,配合JS/CSS这些东东,可以实现跨iOS/Android/WebOS/Symbian/MeeGo,呃,这也太强大了吧,而且据说Hotot移植到这些平台已经是在计划中了。得好好考察一番这种开发方案了。
昨天突然发现有内存泄漏,确实找到几次没有释放的,后来从任务管理器里看,貌似还有泄漏,但实在找不出有什么地方有问题了,最后今天把所有自己new和delete都放在一个类中统一调度跟踪,发现确实是都正确释放了的,只好先不管了。
今天搞定了显示friends和followers列表的功能,增加了显示所有自己发布的消息的功能。明天就搞一下显示之前的消息的功能。之后再修改一下消息显示的格式,比如图片预览,超链接处理等,然后就算是完成一个milestone了吧。
不多说,也是上两张图,还被@shellexy嘲笑了说~
经过一天的折腾,Ninayan已经能完成跟消息相关的绝大多数操作了,私信也搞定了。作为一个纯粹的微博客户端来说,也就剩下图片上传和用户Profile查看没做了。更多的诸如图片预览等功能属于比较有用的增值功能,不在这个范畴内。
汇报一下进度,Fanfou的API果然是最简单的,现在除了可以浏览时间线,回复线和收藏外,已经可以做些基本的操作了,比如发消息,当然包括回复,收藏和取消收藏,删除消息。而且也把消息都保存到本地了,每次切换页面时,显示消息的速度就相比以前会快一点,以前是每次都要从服务器上取下来才能显示。
接下来要解决的是,发布消息后刷新界面,以及消息中的超链接处理等细节问题。
今天折腾下来后,已经可以浏览饭否的最新的timeline,mentions和favorites了,当然,也仅仅只是能浏览而已,所有其他操作都还没做,不过至少证明这个架构是能正常工作的。上张截图吧:
其实是个小功能,真正实现起来还是有点花时间的,那就是移植AutoProxy的功能。在Ninayan中的过程大致如下:
1、从本地读取gfwlist.txt(假如存在的话),然后应用到代理管理器中;
2、从googlecode的svn上下载到最新的gfwlist.txt,然后应用到代理管理器中,如果第一步已经成功执行过了,那么这步的应用到代理管理器的操作会被略过;
3、将下载到的gfwlist.txt替换本地那个老的gfwlist.txt。
应用到代理管理器也不难,首先将gfwlist.txt内容全部读出,然后Base64解码,按行分隔,除掉空行和注释行,剩下有效的规则大约是2700多条。规则分为5类,分别是关键字匹配,主机域名包含匹配,正则表达式匹配,开始字符串匹配以及一种优先级最高的强行不代理规则的匹配。
现在的问题是,代理似乎是能正常工作了,但感觉有点性能问题。于是我就想是不是应该想点其他办法加速这个匹配过程,比较容易想到的是做个简单的缓存,比如已经被匹配过的,需要代理的URL就保存到缓存中,以后有新的代理验证请求来的时候,先在这个缓存中找是不是已经有过,如果有了,就直接返回。这是基于这样一个假设:用户浏览的网站比较集中。而且这个缓存不能大,粗略地想想,可以保持在几十或几百个URL的容量,然后每个URL要维护一个计数,如果缓存一满,就把计数最少的删掉。不过这要注意一个问题,如果时间一长,缓存中的每个记录的计数都很大,然后新的URL就再也进不了缓存了。这种情况很容易出现,比如用户突然从某天开始关注起一个以前都不关注的网站了。其实这个问题也有个笨的简单方案,就是为每个被规则匹配成功的URL都维护一个计数,然后定期选出计数最大的一批URL进缓存。不过这些只是我现在的构想,不知道是否可用,先放着吧,这个问题不是很急。
最后,传张代理配置界面的截图吧,这回是真实数据了。
兵马未动,粮草先行。第一次用Qt,第一次用QML,用QML Viewer做原型,可以强迫自己界面与逻辑分享,大赞啊!于是先把几个主要部分的界面用QML画出来,当然,所有显示的数据都是假的。现在还没想好显示和操作微博的界面应该弄成什么样,本来想模仿FaWave的,可是前些天Reeder把MobileRSS的界面抄袭抖出来后,弄得我不好意思抄别人的了,继续发呆神游天外。先放截图上来,其实用QML的主要原因除了比较容易做出漂亮的界面外,还因为操作上有各种动画效果,这里静态图片上就看不出来了。
另外还有个Paper视图,以paper.li的那种排版显示内容,其实就是一个网页浏览器,现在也没有可看的内容。
腾讯也开放微博API了,这对于一个一贯坚持封闭的公司来说,真是个很艰难的决定。但是,眼下的互联网环境中,开放已经成了大趋势,想想Facebook和Twitter这两种SNS的代表形式,由于API的开放,第三方的应用和客户端真是百花齐放,争奇斗艳,不开放就是死。腾讯在推出微博服务的时候,我猜他们一点都不担心自己的用户数,因为他们自以为有庞大的QQ用户基数支持,只要让QQ客户端支持微博,就能顺利将用户转移过去。事实是国内使用微博的用户,绝大多数不是使用网页端,就是使用手机客户端,同时可以想像得到,目前的QQ死忠用户鉴于他们的年龄,知识构成,社交习惯等因素,很难迅速接受并支持微博这种表达方式,对他们来说,QQ签名就足以支持他们对微博这种媒体形式的需求了,那样更方便,更直观。
开放API,并不是说将微博功能从网页端到其他桌面端或手机端实现一遍就完事了。Twitter在这方面无论是官方还是第三方都有不少的尝试,当然这也跟服务商对微博的定位有关系。比如Twitter之前说过他们做的不是社交服务,而是新闻服务,提供的是内容,所以Twitter官网的上次大改版就是往这个方向上发展的,它更注重内容的展现,希望用户可以方便快捷地获取到各种信息。而国内的诸多微博服务,无一不是停留在最原始的框架下,对于信息的回溯检索,或是扩散都没有任何明显的形式的支持。就像之前ifanr对和菜头的访谈中提到的那样,国内的微博在意识形态上仍然停留在精英制造内容,草根膜拜瞻仰的原始阶段。
这些天推友@lucifierya一直在推一些他对个人知识管理的想法和实践,他主要偏重从网络上获取的信息,包括RSS、Blog、Tweet等。其实这三部分独立的,都有各种实现得很好的方案,两种或三种结合的也有一些方案,但显然就很不被重视了。再回头说腾讯,腾讯有QQ阅读器,有QQ空间,也有微博,三者也有简单的关联,比如QQ阅读器中可以看到好友最新文章,但也仅此而已了。我对@lucifierya的一些想法深以为然,但也许因为他个人缺少对软件开发方面的知识和技能,他提供的解决方案就有点畸形。我在上Twitter的这一年来,一直在考虑自己实现一个Twitter客户端,一开始只是一个单纯的客户端,后来想法就逐渐有所延伸和扩展。单纯的客户端并不是我想要的,我的本意是需要一个获取信息,管理信息的工具。考察和试用了不少其他的服务,想法已经比较完整,但尚未明确和具体,大致如下:
1、连接各微博服务,当然首要是Twitter,提取微博中的网址超链接,作为一个信息源。
2、连接各书签分享服务,比如Delicious,ReadItLater,Instapaper等,作为第二个信息源。
3、订阅RSS以及Google Reader,作为第三个信息源。
4、方便地将超链接分享到微博和书签服务中去。
5、将网页主要内容提取显示。Readability、iReader等扩展的作用很明显,可以极大地提高用户体验,但将这功能放在浏览器中需要用户手工激活,有点繁琐,而在专业的内容阅读器中默认采用这种形式就方便了。
6、将所有内容条目以列表形式组织显示,如Feedly或Reeder那样,可以看到每个条目的开头的一部分信息以及内含图片的缩略图,用户就可以直接判断是否是自己感兴趣的内容。
7、将所有内容条目以报纸排版显示,如QQ阅读器或http://paper.li那样,这样除了有上一条的好处外,更多的是一种贴近传统习惯的用户体验,至少我个人是相当喜欢这种形式,只不过QQ阅读器一页显示的内容太少,以及不能自行添加RSS订阅,而http://paper.li时有乱码,更新周期太长,并且导致有时候一页内空白块太多,不够美观。
8、用户可以对内容添加评论,评论内容和相关链接可以保存到Google Docs上去,这样就可以移动应用了。
以上这些就是我总结出来的大的需求,其他小需求暂且不提。我会自己用Qt慢慢实现,以目前的能力来看,至少可以实现跨Windows/Mac/Linux/Symbian/MeeGo了,也许以后Qt移植到Android和iOS上后,也会支持Android和iOS吧,这是后话了。
昨晚突然发现twitter的hosts ip不能用了,在just-ping.com里找了一遍api.twitter.com的ip,挨个儿ping了一遍,没有一个能ping通的。真是太杯具了,如果用Mac OSX,倒是没什么影响,反正我都是连上SSH后进行全局代理的,Echofon for Mac本身不能设API和Proxy,全靠这样SSH上去用的。但在Windows下就很无奈了,我一般用TweetDeck或Seesmic Desktop2,这两个东西一个用的是Adobe AIR,另一个是用Microsoft Silverlight,也都不能设置Proxy,而且Windows貌似也没有可以将SSH设置成全局代理的功能,于是头疼了。办法是有的,可以用SocksCap之类的东西单独设置某个程序进行Proxy,唉!
我得加快动作了。
Saezuri是个UI设计得很精致的Twitter客户端,作者是个日本人,基于Adobe AIR开发。
Saezuri支持多账号,但添加账号的方式稍显繁琐,一方面需要Saezuri本身可以访问twitter.com,另一方面还需要浏览器可以访问twitter,以获取一个PIN号,将该PIN号填入Saezuri中才能使用该账号。而像Seesmic Desktop、Echofon for Mac、TweetDeck等都只要在客户端内填入用户名和密码就可以搞定。
Saezuri使用单列显示方式,跟Echofon类似,不过Saezuri在浏览用户profile和对话时,只是切换当前窗口内容,不像Echofon会在旁边弹出个小窗口。
比较不好的是,貌似Saezuri没有快捷键支持各种常见操作,全都通过快捷按钮完成。而且每次RT都需要用户选择是官方RT还是编辑后再发布,这点不太好,而且有个小问题是,如果用户设置了protected,就两种方式的RT都不可以了,而Echofon则只是屏蔽掉官方RT,在非官方RT时会弹出消息框提示该用户设置了tweet保护。个人感觉Echofon的实现更合适一点。
目前Saezuri还不支持Streaming API,可以设置每次新发推后自动刷新Timeline,在这点看来,这体验果然不如Echofon好,不过对于没用过实时更新的用户来说,其实并不太在意这个。
最后说一下,Saezuri是完全免费的,没有Echofon那样的广告,对Twitter功能的实现比较完整,如果它可以使用Streaming API,再加上那些操作快捷键,就比较完美了!
从TweetStats的每日统计可以看出,TweetDeck是除官方web外使用最多的客户端,对,没有之一。
与众多第三方客户端一样,TweetDeck也是基于Adobe AIR开发,不过说实话它并不像其他各种使用AIR开发的客户端那种拥有炫目的UI,甚至说,它在UI方面实在有点儿土。TweetDeck使用多列显示的UI,可以自定义在主界面顶部或底部出现输入框,而且会自动隐藏输入框,这点是比较赞的。而且TweetDeck不但支持Twitter服务,还支持MySpace等其他的SNS。而且TweetDeck可以为每个账号单独设置API,这点对于广大中国大陆用户来说非常有用。另外,最新的0.35.1版本已经支持Streaming API,可以在主界面底部的列按钮上弹出的tooltip可以看出当前是否使用了real time更新。TweetDeck在RT的时候可以让用户选择是使用官方retweet,还是编辑后再发布,这点设计感觉不太好,应该参考Echofon for Mac的做法,将这两个功能分开到不同的入口。TweetDeck也有自动缩短网址和恢复网址功能,以及图片上传功能。
TweetDeck最不好的一点是对中文的支持不好,在设置中选择使用国际化字体后,消息中的中文是可以正常显示的,不过像消息来源,以及查看用户profile的bio上的中文,全都显示不出来。
其次TweetDeck在主界面上安排了太多不常用元素,数一下总共有5行空间用于放置各种按钮,而这些按钮在大多数时候基本上是用不到的,这样的UI设计大大减小了正常的浏览空间。
再次,TweetDeck在添加列时,响应极其慢,点击需要新添加的列后,基本上没反应,要过不知道几分钟才会突然在主界面上显示出来,这很容易让用户误解,以为不能添加上。
最后,TweetDeck的各种操作缺少快捷键,这方面也要学习一下Echofon for Mac,它的快捷键就设计得比较方便。
总的说来,TweetDeck还是个不错的客户端,尤其是目前Streaming API似乎没有被墙,可以不设API直接使用。
在前些天的Nokia World2010中,Twitter的业务开发副总Kevin Thau明确表示,Twitter不是一个社交网络(SNS),而是新闻,是内容,是信息!大言不惭地说,这也是我最近刚刚领悟到的一点。
从半年前,就一直想着自己写一个Twitter客户端,但是不得不说,现在已经有非常多优秀的Twitter客户端了,从共享到免费都有,覆盖了各种平台,那如果我自己要写客户端的话,有什么特色值得用户们抛弃现有的那些客户端来转投这里呢。在这大半年的时间里,我根据自己对SNS的认识,以及自己需求,不断调整心目中的客户端的特性需求,到现在才在心中有一个相对比较固定的框架、模型。
为什么FlipBoard会受到如此热烈的追捧,这就说明对于很大一部分人来说,使用Facebook和Twitter主要并不是为了与人交互和玩游戏,而是为了获取信息,而FlipBoard这种经过整理,同时又有美观排版的方式,很能迎合那些主要为了从网络获取信息的用户的需求。
处于Twitter中文圈中,比较容易忽视的一点是,将Twitter当成一个公共聊天室。当然这也是很大一部分人使用Twitter的目的,传统的网络聊天室的没落,使得用户们不得不将这种需求搬到其他形式的网络服务中,可以看到在各种BBS、论坛、IM群等等都有这种版聊的现象,所以在Twitter中存在这种现象也是正常而且合理的。只不过,从服务提供商的角度讲,应该可以从服务器端,甚至客户端提供这样的信息过滤、隔离的功能,用户可以方便地在两种应用模式间来回切换,想版聊就版聊,想读新闻就读新闻。除了FlipBoard,http://paper.li/也提供了类似的服务,但它目前只能说,这种模式还不错,各种细节方面还很不够。
再扯远一点说,现在很多人应该喜欢使用Google Reader这个服务,但说实话,Google Reader这个界面仍然有很大的改进空间。之前网上一直有人在号召大家使用RSS全文输出,但全文输出后有一个很大的问题是,在Google Reader中如果是全部展开的阅读方式,花费很多时间在拖动滚动条过滤无兴趣的条目上,实际上对于订阅了大量内容的人来说,很多内容只要一眼看到标题,或者其中的某张插图,就没必要看正文了,那现在Google Reader这种阅读方式就显得很落后了。而有一家第三方的Google Reader同步服务在这方面做了不少努力和改进,那就是Feedly。Feedly自己也提供经过分类的新闻内容,但对Google Reader中文用户来说,更有价值的是它的同步Google Reader的功能,可以提取出条目的标题和插图以及正文摘要,并以一定的热度排版,并连接了几家最流行的SNS服务,可以及时分享自己的条目,自从用了Feedly后,我几乎就不用Google Reader的官方界面了(喂喂,你是他们的托儿啊)。
再说回Twitter客户端,目前现在的客户端,基本上都是简单地通过Twitter API将Twitter的Tweet功能从Web搬到桌面或手机端等,几乎没有做更多的需求挖掘。简单地看过几十个完成度较高的Twitter客户端,目前只看到Seesmic Look收集了几组全球知名媒体的账号,但也仅仅是收集,没有更多的特性拓展。现在Twitter推出了新版界面,可以说是诠释了Twitter自己的发展理念,引领了客户端发展的方向──它提供的是新闻,是内容,是信息!
最后可以得出,我想要的客户端,是融合了FlipBoard、http://paper.li/和Feedly几者特色的客户端。它一方面可以向用户提供类似传统书报媒体提供给用户的视觉感观享受,另一方面则是结合网络、计算机的优势,提供大容量、快捷的信息分享功能。所以它不应该只像FlipBoard、http://paper.li/和Feedly它们一样只有一两家内容提供商,它应该是彻底开放的,允许其他内容提供商以固定的接口接入并提供特有的信息。而且它应该有一定的信息自动分类和索引能力,过滤重复或无价值信息,减少用户浪费的时间。
Tweetie for Mac是个在Mac系统上比较流行的Twitter客户端。
首先,它是个原生的Mac应用程序,而且轻便小巧。但绝大多数的Twitter该有的功能,还是有的。不过要提最重要的一点是,它目前貌似不支持List,这是一大遗憾。很多Twitter用户是比较重视并依赖List功能来组织自己感兴趣的推友的,客户端不提供支持,则很容易让用户放弃这个客户端,转头寻找其他合适的产品。虽然有这个大缺憾,似乎用它的人还是挺多的,确实其他的功能还是做得很赞的,也支持几种常见图床和URL缩短服务。它支持多账号,但不能自定义API,也不能设置代理,仍是那句话,Mac系统补上了这个缺点。它也不能让用户自定义刷新间隔,而且目前仍然使用着OAuth API,不过想来随着将来Streaming API的使用,这个问题也将不复存在。
其次,它界面美观,清爽。使用类似Echofon的单列显示界面。界面切换时,有动画效果,虽然并没有实用价值,却仍能让人觉得炫目。就我觉得,这应该也算是Mac风格,或者说iOS风格的界面吧。
最后,它是个共享软件,也有免费版,据说是加入了广告,实际上我用了也没发现哪里有广告,所以尽管它的功能足够简单,但也大致够用,要是它能支持list,并使用Streaming API,我肯定毫不犹豫地放弃Echofon,转投Tweetie门下。
Seesmic是个盛产Twitter客户端的vendor,不但有PC桌面用的客户端,还有for iPhone和for Android的版本。光是PC桌面客户端,也有好几个不同的产品,有使用WPF开发的Seesmic Look,有基于AIR开发的Twhirl和Seesmic Desktop,还有使用Silverlight开发的Seesmic Desktop2。
Seesmic Desktop2最近出了新版本,原本它是只支持Windows系统的,在新版本中同时又支持Mac系统了。它与Seesmic Desktop一样,采用插件的架构,各种SNS服务都由一个插件实现,在安装的时候会自动联网下载几个常用的SNS服务的插件,包括Facebook和Twitter。Seesmic Desktop2与Echofon可算是SNS桌面客户端的两类典型代表,前者是走的整合路线,一个客户端内提供多种SNS服务的支持,一个客户端内可以完成所有事务,后者走的是精简路线,一个客户端只做好一种服务的支持,现在也不能说出哪种是更好的方式,各有优缺点吧。
Seesmic Desktop2的最新版也支持Twitter的Streaming API,不过经过我的试用发现,墙内用户需要在启动程序前先开启VPN,这样Seesmic Desktop2就会自动使用Streaming API,然后即使断开VPN也没有影响。如果一开始就没有翻墙,就会使用目前主流使用的OAuth API。Seesmic Desktop2与Echofon一样,程序本身既不提供自定义API功能,也不能设置代理服务器,也许它们从来不知道还存在我们这样的用户吧。Seesmic Desktop2的界面与TweetDeck类似,采用多列显示的方式,但总的说来,Seesmic Desktop2的界面更漂亮些,而且少一些没多少用处的界面元素,不过左侧有个侧边栏比较占用屏幕空间。Seesmic Desktop2提供很少的可配置项,不知道是不是作者认为默认的设置已经足够满足绝大多数用户的需求了。Seesmic Desktop2会在消息条目中直接显示几个常见图床上的图,这个功能还是比较赞的,很多客户端需虽然也本身提供图片预览功能,但需要用户点击链接后才会显示,就我个人感觉,这种不会明显影响用户读取消息的过程,应该程序可以帮助用户完成,当然如果能提供一个开关选项让用户自行选择就最好了。
Seesmic Desktop2也有一些小缺点,它的右键菜单弹出延迟很明显,有时候头像上方显示快捷按钮后不能自动恢复。最后是我一向比较反感的,非原生的应用程序,不但占用资源多,运行速度也慢。
最多不得不说,Seesmic Desktop2是很值得一用的客户端,多列显示的方式可以让用户一眼看到所有相关的消息,支持Streaming API又提升了用户体验,推荐使用。
想写这么个系列的文章,以介绍一下现有的各种Twitter客户端,已经有一段时间了,却一直没开始写,一方面是自己懒,另一方面则是真没有觉得有某个客户端的特性已经达到让我觉得不写不快的地步。不过自从用了Echofon for Mac后,我觉得很有想写一下的冲动。
Echofon有好几个版本,我刚开始上推的时候曾经用过几天它作为Firefox扩展的版本。由于寄生在Firefox上,所以貌似是可以通过Firefox的代理走的,又因为那时我是用Tor来翻墙的,速度那个慢啊,因此体验并不怎么好,而且为了单纯地上推不得不开一个庞大的Firefox(我装了二十几个扩展,很占内存),感觉并不是很好。之后有了其他的客户端,就再也没用过了,直到最近比较多地用Mac系统,试了几个for Mac的客户端后,发现了Echofon for Mac,一用就爱不释手了。
Mac桌面版的Echofon是个共享软件,如果不注册,则在Timeline页顶端会有一小块广告条,而且有时候在程序启动时会弹出对话框询问你是否注册,总的说来并不影响正常使用。Echofon在界面和操作上,都做得比较细致,而最吸引我的,主要是它已经直接Streaming API,可以实时更新Timeline和Replies等等。Streaming API目前还处于测试阶段,Twitter官方的消息目前只有Echofon和TweetDeck实现了,经过试用,感觉非常好。
除此之外,Echofon有丰富的菜单项,当然大部分常用操作也可以通过快捷键实现,另外还支持多个账号,不过它是单列单账号的显示方式,所以要自己手动切换当前活动账号。从界面上看,Echofon是个比较正统的Mac程序,如果想要原班移植到Windows上,可能反而不伦不类。
最后要说的是,Echofon自身不支持API,不支持代理,不过好在Mac系统可以比较方便地用全局代理,所以问题不大。
Category Ninayan
之前买了个二手的Kindle4,体验太好了,无论是E-ink屏,还是推送功能,都很舒服,唯一的不足是看扫描版PDF即使切了白边仍然字体过小,如果横屏来看又觉得操作不是很顺手,于是纠结了一阵后,看到有比较便宜的卖全新的DXG的,就趁刚发工资咬牙买了。
昨天早上在taobao拍的,今天下午收到货,然后迫不及待地开箱。没有WIFI就不能免费推送,这是一大遗憾。官方皮套看起来很厚实,装了几本扫描版PDF进去,仍然感觉小了点。官方系统默认不支持中文,书名中带中文的在目录中也不能正确显示,这是点小瑕疵。
忧郁啊,赚的钱远远不够花。这两天遇到瓶颈了,写程序写啥啥不会。想给Ninayan加上链接保存到Readability和发送到Kindle的功能,想想多简单的特性啊,居然遇到很大阻碍。
这两天又重新拾起Ninayan来,随着embed.ly的收费,Ninayan的主打的图片、视频浏览功能被废掉了,只好自己写代码来实现这部分了,但这工作量应该比较大,只能慢慢来了,有点想把这部分代码做成开源项目,叫SANSASORI。
之前也有断断续续地修改,支持Follow5,后来Follow5停运,然后支持StatusNet。这两天主要修改了一下UI,Twitter部分原本就支持使用Twip4的T模式和O模式,只不过没有设置UI,这次把账号设置的UI做了小部分高速,除了可以修改API地址,还为每种oauth服务都增加了用户自定义API Key的功能。这主要是在支持腾讯和新浪微博的过程中,一直遇到因为API Key不能正常使用的问题,如果用户可以自定义,应该能缓解一部分问题。
另外,还在Proxy部分增加了导入用户自定义的SSL证书的UI,这样就可以使用goagent做代理了。不过使用goagent的过程中偶尔发现会有所有网络连接都阻塞不返回,然后不能发起新的网络连接的问题,在网上找了一圈没找到怎么为QNetworkAccessManager的post和get方法设置timeout的方法,纠结。
把文章、图片和视频的浏览功能修复后就不打算再为Ninayan大动干戈了,不增加功能了,顶多就是有bug修一下。之后就开始做KarenMeu了。
基本上确认了,Ninayan不能使用goagent是SSL证书的问题。本来Ninayan用的是Qt4.6中带的证书,而goagent自己又带了证书,可能两个冲突了,修改一下Ninayan,让它不使用Qt 4.6的证书,就能使用goagent代理了,这就比较头痛了。问题是原来在Ninayan中使用Qt 4.6的证书是因为有的系统上的SSL证书不全,Ninayan会不能正常访问一些https地址,可是现在却又要去掉,囧。
今天老大做了个Design Patterns in XXX,这个XXX是他最近几个月来写的一个小工具,走马观花地讲了Template Method,Factory,Strategy和Facade,感觉吧这些模式是怎么回事还是懂的,跟复习了一遍差不多,不过我写代码时其实很少考虑要用什么模式,叹气。
昨天拍的集体照,今天看到了,我怎么胖成这样,上次跟bobo见面时被bobo说了句“你怎么胖成这样?”我还觉得是不是有点夸张,现在自己看到了,一比较,才发现真的好胖,尤其是脸都变形了,减肥刻不容缓啊。惆怅。
早上照例翻看了点东西,然后悲剧了。悲剧归悲剧,反而有点解脱的感觉。精神洁癖偶尔也有点好处,叹气。
这几天对Ninayan想了很多。
到目前为止,总的说来,尽管bug还很多,UI还不够精致,操作还不够方便,但功能上已经实现了原来预定的计划中的大部分,除了难度最大的按语义自动按用户喜好定义优先级。
最近轻博客突然吸引了好多眼球,大约两年前其实已经有Tumblr这个产品,只是它并没有大火特火起来。而就最近的几个月里,国内突然冒出好几个同类产品,点点,推他,据说新浪有个Qing。虽然像Twitter、新浪微博这种都有自己的方式展示多媒体信息,但用过轻博客后,明显感觉体验更进一层。于是我就想,其实从客户端层面出发,可以尽量抹平微博客和轻博客的差异,Ninayan就可以往这个方向发展,如果真这么做,无论UI还是底层,都需要做大量修改。
这些天我用新浪微博比较多,同时又不想落下Twitter,同时比较认真地维护两个账号,让我突然意识到,像我这样的人用微博,主要出于两个目的,一是分享自己的状态,二是获取自己关心的信息。而获取信息又可大体分为主动和被动两种,主动是指自己去主动阅读timeline,被动指被别人mention了。于是想到对于同时维护多于1个账号的情况下,提供一种合并显示所有账号的同类信息的功能会很有用,Mixero就有这种将多个账号的timeline显示到一块儿,mentions显示到一块儿等等这种选项,而Ninayan要做的则是可以跨服务合并显示,即比如把Twitter和新浪微博的timeline显示到一块儿。这样做会引发另一个问题是,过滤掉重复信息。这一方向得靠用户自己,仔细甄选该关注的人,比如有的人喜欢用同步工具,结果ta在多个服务中发布的消息几乎是一样的,那么只要在某个服务中关注ta一次就够了;另一方面可以在软件层面识别出相同信息进行过滤。另外要说的是,分享活动,最好是能随时随地方便地进行。这就是说,Ninayan目前光有Windows/Mac/Linux桌面版是不够的,还应该有iOS版和Android版,除了手机版,还要有平板版。还有,最好能自动截取到用户关心的活动,比如能自动获取当前系统中正在播放的歌曲的信息,浏览器正在浏览的网页的标题等等。
暂时就想到这样,好吧,可以做很久很久了。
终于大体上对iOS有一个模糊的轮廓了,做一个没有特别的技术点或者奇异的UI的app的话,基本上靠翻书和查手册应该能搞定了,就像几个月前开始用QML写Ninayan一样。
昨天被ObjC和Cocoa Touch给联合调戏了,我居然以为任何对象都可以随便release。实际上release了不该release的对象后,就会出现各种古怪的问题。
另外有件让我觉得比较蛋疼的事,苹果居然为了用ObjC实现一个singleton而提供了一段官方的样板代码,囧死了。
一直准备把Ninayan移植到手机上去的。但是之前尝试把它移植到S60上不太顺利,simulator上跑得基本正常,一部署到手机上,就会自动退出,我估计是由于内存占用太多,或者同时并发的网络连接过多。写惯了桌面程序,确实对于这种资源受限环境的程序开发有点束手无策。于是就丢下暂时不管了。
这次打算尝试一下iOS开发。几个月前就买了本《iPhone SDK 3开发指南》,一直没怎么看,这最近两个星期又是看书又是看视频的,总算有点儿明白怎么个过程了。不过不同的屏幕大小,对于UI的需求也不一样,在iPhone这种屏幕受限的环境中,也只能尽量把有用的UI元素挤到一块了。我习惯的做法是先把界面画出来,然后给每个菜单项啊,按钮啊什么的加上功能……这是我10来年来养成的习惯,从一开始涉及GUI开发就自己形成的习惯。有了UI后,要移植Ninayan到iOS上,只需要找一个JSON解析库,一个OAuth库,其他的iPhone SDK就够了。
今天又折腾了下,可以直接点击列在工具栏中的超链接按钮,直接显示链接接的内容,分为图片,视频和文章三个类型。最后又揪出整个程序中最头疼的一个问题,Sqlite数据库的使用,总有冲突,叹气。不过在线显示内容的功能勉强能用了。
Ninayan已经比较完善地支持Google Reader了,呃,我扫GR的积极性仍然没有一点提高,真是无趣啊!
现在比较大的问题是UI,我自己都不满意,没办法,前些天看一个人新上线的网站和软件,不由感叹,干我们这行的有个美工老婆真是太有优势了,江苏的阿达也是这样的搭配,叹气。
现在除了还要支持Facebook以及超链接的直接浏览和用户信息的直接查看,就没其他功能要加了。剩下的都是些优化工作了。
真是无趣啊!
这两天在给Ninayan添加Google Reader支持。Google Reader是Google众多服务中少数几个不开放官方API的服务之一,但仍然有众多第三方的客户端或官网增强辅助工具出现。好在有几个很好的人,把他们研究Google Reader的成果公布出来了,我主要参考这篇和这篇文档,再加上自己通过抓包工具观察官网的行为,现在基本已经得到实现一个Google Reader客户端所需要的所有资料。
不过现在有点头疼的是,要把Google Reader强塞到已经比较完整紧凑的架构中去,有不少需要调整的地方。比如新增一种账号类型,这种类型的账号就不同于以往的SNS账号,总之整个继承体系都被我修改过了。然后是界面交互的部分,也需要做不少的设计。
还有一点感受是,这个API不知道是不是Google本身的风格如此(我没用过Google其他服务公开的API,所以没有经验),还是说根本就没为第三方开发好好设计过,总感觉不太好用,虽然功能上都能实现,但不太方便。
实在有点不乐意做Deardawn,心理障碍克服不了啊。
Ninayan今天被小言一说,才发现真的是添加不了账号了,原来是之前一次为了加快启动速度的修改,把其他功能破坏掉了,不但添加不上账号,还一开始不能发布消息,只有在显示过home timeline后才可以。
提取了几个model类,这样的实现比较优雅。
几个singleton在程序退出时都正确销毁了。
把AutoProxy的gfwlist信息配置保存到sqlite数据库里了,可以记录每条规则的enable与否,hit次数。在每次程序退出时刷新这些信息到sqlite数据库里。
给几个本地数据库建了几个索引,这样可以让查询速度加快一点点吧。
由于占用内存比较厉害,在Windows下就用::EmptyWorkingSet每分钟清空一次工作集,其他平台不知道有什么类似的方案。但实际上在Windows下如果窗口最小化时,内存会被一下子回收好多,不知道到底是怎么回事的。
本地数据库读写冲突的问题还没想到比较低成本的解决方案,叹气。
停下来想想,现在已经实现的功能也只是玩玩而已,最有用的应该还是Google Reader支持吧,可惜没找到确认无误的API文档。
blog被墙了就真不太想更新了。
Ninayan这段时间除了不时地发现些bug,然后修正外,主要是增加了对163、Sina、Sohu、QQ微博的支持。从开发者角度讲,163的API是最接近Twitter了,QQ的API设计最山寨,完全自己搞了一套,Sina和Sohu从技术角度讲跟QQ接近,接口设计仍然是模仿Twitter。
然后在google code上放了Linux版的可执行文件上去,今天才知道原来各发行版上普通的应用程序是可以做到二进制兼容的,也怪我以前看CodeLite、Code::Blocks它们都为每个发行版提供一个独立的安装包,就先入为主地以为每个发行版都要各自单独编译才行。今天突然想到Qt Creator就是同一个可执行文件在所有Linux发行版里可以运行,只是区分了32位和64位而已。我还傻乎乎地在12个系统里都编译了一把Qt,再分别编译出Ninayan,再分别打包,再分别上传,天呐!
首先一件很郁闷的事,貌似域名被墙了,直接用IP是可以打开本blog的,但是我暂时又不想去折腾这些了,先这么放着吧,问候下方校长18代祖宗及全体女性家属。
Ninayan最近动作倒是不大了,主要是先打了Mac,Win32和Linux的安装包给几个人试用了一下,结果反响很差,有点失落,难道真的定位有问题?
不过说起来,Ninayan现在也只是个雏形,真正的主要的理念需要的特性并没有实现,现在也只是把图片,视频和文章链接单独提取出来可以独立浏览而已,并没有做进一步的工作,比如要能打tag,可以检索,自动语义过滤,优先级排序等等。其次是RSS聚合也没做,Google Reader没实现,UI缺少专业的美工设计等等,总之可以做的工作还有很多很多。
另外,今天勉强让Ninayan在我的Nokia 5230上运行起来了,解决了不少问题,但最终还是由于报内存不足而自动退出。为了让Ninayan可以在5230上运行,遇到了不少问题。首先是开发环境的建立,我用的是Qt SDK 1.1 beta,这个SDK用的是Qt 4.7.2,但有bug,for S60v5的配置文件使用了for Symbian^3的配置,所以编译工程的时候会出错,要自己在工程的.pro里把opengl的配置去掉。其次是部署时,要安装Qt,还要单独安装sqlite,据说以前版本是合在一个安装包里的。最后是这两天一直在纠结的问题,运行后在TextInput获取输入焦点后,虚拟键盘没有显示出来,在Nokia的论坛和Stackoverflow上问,都没人回复,今天偶然想起qDou,试了下它在5230上至少是可以输入文字的,虽然之后会崩溃,于是发邮件问了一下作者,作者给了个网址,原来是我在TextInput控件一起放了个兄弟控件MouseArea,于是TextInput没能收到点击事件,于是虚拟键盘不会自动显示,只要自己强制调用它的openSoftwareInputPanel方法就可以了。
至于最后的自动退出,从现象结合网上的人们的讨论来看,似乎是因为同时请求的网络连接太多,以及内存占用过多引起的。叹气,桌面程序写惯了,散漫惯了,都不怎么注意内存的使用了,反而经常采取以空间换时间的策略,看来如果真要让Ninayan能在手机上正常跑起来的话,还得好好重新设计一下,把各种请求都放进队列里,不要一下并发几十个连接,其他的内存使用策略也得仔细看看,有点想看看侯捷翻译的那本讲内存受限系统的程序开发的书了。
Ninayan的主要功能基本上都做出来了,剩下的主要是增加各种服务的支持,比如各种微博,各种SNS,以及Google Reader。其次便是界面和操作上的细节方面的调整,现在还是很粗糙的。
离上次W.I.P.已经有3周多了,这3周主要实现了文章浏览特性。文章浏览有3种模式,一种是仿feedly的可扩展的列表,一种是信reeder的分栏,还有一种是仿paper.li的报纸模式。但是,目前的效果还远远没达到预期。放几张图吧:
还增加了个视频观看视图,这是计划外的,但觉得有必要,也很粗糙:
直到这里才发现,在Mac OS X 10.6.6上一直以64位Cocoa编译的Qt,果然视频播放不了了,不记得在哪里看到过说明,QtWebKit在Mac上如果是64位的话是载入不了Flash播放插件的,因为Flash播放器稳定发布只有32位版本,于是在Mac上也自己编译了一把Qt,改成32位Cocoa框架的就可以了播放视频了,太纠结了,也难怪乔帮主要封杀Flash了。
今天觉得Ninayan大部分功能已经实现了,也差不多快可以发布beta版了,于是要打包,先解决Windows和Mac上的打包问题。 Windows上一直以来我都习惯用Inno Setup了,所以在如何制作安装包的问题上并不纠结,InnoIDE和ISTool都是很方便的工具,主要的问题在于解决Qt的插件的部署。Ninayan在Windows上也是用GCC(MinGW)编译的,相比VS2008,少了个SxS的问题,只要带两个dll一起发布就行了。Qt本身有一种简单但比较有用的插件机制,它的字符编码支持CJK,图形文件格式支持,数据库驱动等等都是由插件实现的。也就是说$(QTDIR)/plugins下的东西都要跟着发布,而且程序代码中需要自己在main()中,app对象创建后及时调用QCoreApplication::addLibraryPath()添加plugins的路径。另外由于用到了QtWebKit和QML,QDeclarativeEngine对象也需要指定一下qmlwebkitplugin插件的目录,把$(QTDIR)/imports/QtWebKit目录打包进去,然后在代码中调用QDeclarativeEngine::addImportPath()添加路径,这样整个目录就是发布的所有内容了。 在Mac OSX上比较流行用dmg,但这之前还要解决Qt的framework链接的问题。Qt在Mac OSX下官方发布的二进制包是framework形式的,这跟Windows下有点不同,呃,其实跟SxS有点类似。要用install_name_tool -change命令行修改自己的程序可执行文件链接的framework的位置,这个工作可以由Qt自带的一个叫macdeployqt的小工具完成,只要在命令行执行macdeployqt Ninayan.app就可以了。不过除此之外,还是由于qmlwebkitplugin的缘故,需要自己复制这个插件到程序的bundle中,我就放在跟最终的可执行文件相同的目录中,这个插件macdeployqt并不处理,除了要自己复制,还要自己用install_name_tool来修改链接的framework。这样操作后,是一个可以正常运行的,完整的应用程序bundle,整个bundle就有113MB,谁让Qt那么大呢!然后是把这个bundle打包成dmg。Mac OSX自带免费的工具,GUI和CUI的都有,GUI的叫Disk Utility,不过看了下感觉界面挺复杂的,还是用命令行的hdiutil爽,而且我前面是用命令行修改的符号链接,这里当然最好也是用命令行打包,这样一个shell脚本就能搞定编译后生成dmg的所有事情了。用hdiutil的话,这个命令行就可以打出一个dmg来: hdiutil create -srcfolder Ninayan.app -volname Ninayan -format UDZO -ov Ninayan.dmg 不过这个有点土,就是把Ninayan.app放成了dmg而已,其他什么都没有。我的要求其实也很简单,有自定义的背景图片,有Applications目录的链接,这样用户打开这个dmg就可以完成把Ninayan拖拽到Applications目录中的操作。在网上找了不少文章和视频,多是用其他的GUI工具,在stackoverflow上有个家伙用AppleScript写了段脚本,确实通用性和灵活性都比较好了。最后我选了条简易简陋没通用性的路子,但够用。首先需要明白的是,dmg被Finder打开后,就是当成一个普通的文件夹处理的,所以它的背景什么的设置,都是放在.DS_Store文件中的(Mac中以dot开头的文件都会自动隐藏),所以很dirty的做法是,先用这个命令行创建一个可读可写的dmg并挂载: hdiutil create -srcfolder Ninayan.app -volname Ninayan -format UDRW -size...
已经不记得有几个大年三十的晚上是在电脑前写代码度过了,今年破天荒的因为客厅里电视在放春晚,打偶然走过去看几眼。
今天把超链接处理模块重构了,之前那个实现在Mac下崩溃得比较频繁,但在Windows和Linux下却不是很多。对于这个现象我有点疑惑,虽然说代码确实是写得有问题,但为什么只有在Mac才比较明显呢。好在Mac下崩溃了打印出来的栈回调信息比较详细,几乎能跟踪到最终引起崩溃的代码行。
原来的实现把所有中间数据结构以指针的形式保存在一个list里,然后在自认为结束的时候销毁对象。这样的做法本没有什么问题,关键是我在操作这个list时并没有考虑重入的情况。于是重构主要做了两个重大修改,一是在list中直接保存对象,而不是指针,这样更不容易写错;二是对list操作大部分情况下都加mutex锁住。顺便也修正了些其他的小问题,比如原来即使是基于embed.ly的服务识别url是图片还是视频也有问题,其实embed.ly是返回了这个类型的。
另外,今天还把主界面针对360*640分辨率修改了一下,因为Nokia的S60v5和Symbian^3现在几个机型都是用这个分辨率的。至此,图片浏览特性的实现暂时告一段落,接下来该实现文章阅读了。昨天大致研究了一下Readability,发现它在Firefox表现那么风骚,结果在QtWebkit下总是返回不能分析的错误。不知道是DOM树的实现还是JavaScript引擎的问题。难道真要我移植一个C++版本,这实在太费时费力,还不好维护了。
最后,上个最新界面截图。
终于勉强加上了一个功能比较凑合的图片浏览功能,还有很多地方需要改善。本来我的想法是UI上直接拿QML Demo PhotoViewer的代码来用的,可是昨天发现PhotoViewer中的代码会导致在Windows下程序不能切换输入法,于是只好自己写了。自己写就极大地简化了功能,才简化了代码,于是最后所有东西都放在一个QML文件中写完了,最终的效果,也就是几个视图场景切换时那个动画效果没有了。残念!
另外有个问题是图片下载的问题,现在的Twitter上比较流行的图床大多是被墙的,如果让QML的引擎自己通过代理下载图片,感觉不是一般的慢!所以我就觉得把这些图片事先下载到本地缓存起来似乎挺有必要的。
还有个比较重要的问题是全屏模式下浏览图片,默认是自动拉伸到整个显示区了,这样似乎比较影响显示性能,当然也是机器配置不是那么好的才会有这种卡的情况,在我的T43上会卡,拿到Mac mini上就流畅了。应该稍微改一下,看一下是不是在加载前就获取图片本身的尺寸,如果比显示区域大,才缩放,不大的话,就以图片本身的大小显示了,这样显示也更清晰点。
还有个浏览某张图片的大图就不截了,没啥好看的。
有些问题,总是那么奇怪。因为XP里的虚拟机在跑Debian编译Qt,于是在Mac下把QML的Demo PhotoView抠过来用,本来就很吃力,还顺带发现了一个因为先后顺序问题引起的崩溃bug,终于可以在Ninayan里看到PhotoView的样子了。可是到了晚上突然发现,在Windows下不能切换输入法了,一切换Ninayan就挂死!经过一部分一部分地屏蔽代码发现,引起这个问题的似乎是VirtualDataModel中Package的一些代码。好吧,决定索性不用抠别人的代码,用自己的方法写一遍相同的UI吧。
上一段提到,我又蛋疼地在Debian里编译Qt了,嗯,又花了一下午。之后就是编译Ninayan,呃,我现在最大的乐趣就在于在不同的系统里编译Ninayan并用它来上Twitter了,囧rz。想来也不会有多大问题,毕竟之前在Arch和Mint里都比较顺利的,唯一大的区别是在Arch和Mint里桌面都是用Gnome,而这次Debian里用的是KDE,很花哨的感觉。言归正传,Ninayan运行得很顺利,除了字体不太好看。在Twitter上报怨了一下后,@truthurt建议自带一个开源的字体,真是个不错的主意,在Mint里的那种就很好,我后来去网上找了文泉驿的微米黑,在Debian和Arch里效果都很好。其实昨天就想过字体的问题,不过当时想到的是直接将字体装入到系统中,然后在程序中直接通过字体family名使用。今天偶然想到,其实可以程序直接载入指定路径的字体文件来使用的!不过Windows下还是用微软雅黑吧,微米黑在XP下同一个字的不同笔画都有粗细差异,真糟糕。
今天照计划,实现了查看对话的功能,不过不完善,因为网络传输的原因,是一条消息一条消息从服务器获取后显示,如果显示到一半切断,又要显示另一组对话,就会把前一组对话后面没显示的那些消息作为后一组对话的消息。所以要考虑一下怎么加一个中断的机制,不过这个留到以后版本中完善吧,毕竟Ninayan一开始定位就不是一个完善的客户端。
然后又蛋疼地去装ArchLinux了。这个发行版安装比Ubuntu麻烦多了,它的iso镜像只装一个最基本的字符界面,然后带一个pacman包管理工具,GNOME之类的桌面需要自己再另外安装,所以最好有比较畅通的网络。
装完后,中文字体的显示惨不忍睹,google随便搜了一下,也挺折腾的,我懒得弄了。我就是想在上面试试编译Ninayan。没想到可以用pacman安装已经编译好的Qt 4.7.1,再装个Qt Creator,就可以编译Ninayan了。除了显示的字体不好外,其他的还算凑合吧。
明天开始做图片浏览和文章阅读功能吧。
昨天和前天晚上蛋疼地在Linux上编译Ninayan了。我用的是Mint9,也就是一个Ubuntu的修改版。在Linux上编译Qt程序有点麻烦的是需要自己编译一遍Qt,前天晚上就编译了一遍最新的qt-everywhere-opensource-src-4.7.1.tar.gz,过程比较顺利,再装上Qt Creator就可以编译出Ninayan了,简单试用了一下,很正常。而且令我比较惊讶的是,我学Hotot用了Droid Sans字体,最终的显示效果在我个人看来比Windows XP SP3和Mac OS 10.6.6上都要好,但XP SP3上加上Gdipp或MacType后,效果会有很大的提升。
昨天突然发现,Ninayan在Mint下不能访问https://api.twitter.com(不是被墙的缘故),测试了几次才确认是不能访问https的地址,于是想到前不久看过一篇博文说Qt 4.7是有这么个bug不能访问https的,因为原来Qt 4.6带了SSL证书,而Qt 4.7没带,于是照那篇文章的作者的说法,从Qt 4.6.2里找到qt-ca-bundle.crt文件,然后每次QNetworkRequest在被post或get前都设置一下Ssl证书。结果我的情况是连编译都不通过,于是可以确认是Qt在编译时没有编译进OpenSSL了。然后找到了这篇《Compile Qt 4.7 on Ubuntu 10.10》,先要安装一堆的库的开发包,再来编译Qt,最后再编译Ninayan,果然就正常了!于是我就不明白那篇博文讲述的到底是个神马问题了!
今天就比较烦躁地在做网址缩短功能了。本来打算内置goo.gl,bit.ly和is.gd三个短网址服务,结果很郁闷的是bit.ly总是返回INVALID_URI,但同样的URL我拿到Firefox下测试就能返回正确的数据,这不是歧视嘛,难道是在http header里还要设置神马东西?倒是goo.gl和is.gd都正常了!
话说前天偶然发现了MacType和Gdipp,觉得这种功能对Ninayan之类偏阅读的应用非常有帮助,于是我在极限论坛上给MacType的作者私下发了个email询问是否可以提供专门的API以便集成此功能。不过到现在也没收到回应,估计是不愿意了。
今天看了一下MacType的安装目录,发现有个MacLoader.exe,而Gdipp的安装目录下也有个loader文件,这时才明白过来,可以通过把可执行文件的完整路径作为命令行参数传递给这loader,那么该可执行文件会被启动运行,并被注入实现字体渲染增强效果。
经过简单的测试,Ninayan在我的XP SP3上使用微软雅黑字体,加上增强字体渲染效果,感觉确实更舒服了!而Gdipp是以GPLv3,最新的版本好像是用LGPL了,一起打包发布应该是木有问题的。我只要另外再写一个小小的启动程序,在安装包中把启动程序作为快捷方式添加到开始菜单和桌面等位置,可以自己调整是否使用增强字体渲染效果,使用什么样的渲染配置等等。
这样一来,似乎Windows上的效果都超过Mac上的了,一直没找到感觉特别好的Mac上的用于大段文字阅读的字体,微软雅黑只适合在Windows上用,而且至少要开了ClearType Tuner才行,有MacType或Gdipp最好。也许是因为我在Mac下用的是CRT的显示器的缘故,不止一个人对我说过那个视频信号转换后损失挺大的,也许用LCD的就要好些了!
今天心情不错,呼呼!
前面说到内存泄漏的问题。后来通过逐段屏蔽代码,终于找到了最大一处泄漏源。这个办法比较笨,但这次真的有用,主要还是因为程序结构简单,流程也不复杂才能用吧。
程序大体上分为三部分,UI层,数据层,网络通信层。用户在UI层上操作,1、UI层向数据层请求数据,2、数据层根据不同情况直接查询本地数据库或通过网络通信层获取数据,3、网络通信层自己有一个定时轮循的任务,每分钟从远程服务器获取数据,4、有了数据就发送给数据层,5、数据层将数据经过简单处理发送给UI层,6、然后显示,就是这么简单。
我开始主要怀疑UI显示调用的Qt/QML也许MM有问题,于是把最终UI显示的代码屏蔽掉。发现仍然泄漏的情况基本没有变化,说明跟UI显示的关系不大。后来发现Mem Usage的增长是有周期,大概是1分钟1次,那么可以确定是在4和5两步有问题。这时把第5步中代码全部屏蔽掉,果然Mem Usage就不增长了。然后逐步缩小范围,一点点放出代码,最后发现竟然是QSqlQuery查询本地数据库时,select出来的东西需要程序员自己clear掉!内牛满面啊,果然是Qt用得有问题!
今天偶然发现一个叫MacType的东东,可以在Windows下以进程注入的方式给指定进程增强字体渲染效果。跟微软官方的ClearType Tuner是一类东西,不过MacType的选项更丰富。于是我想到,我这个以阅读为主的工具,要是集成这么个美仑美奂的功能,该是多酷啊。在极限论坛翻了一遍帖子,貌似MacType是闭源的,另外有个新生的Gdipp项目,倒是在googlecode上开源了,不过听说它的配置复杂,而且目前不够稳定,尤其是32位系统上。好吧,反正这种功能对我有致命吸引力,一定要集成!
内存泄漏的问题,调得我心力交瘁,都有点神经衰弱了,甚至有点绝望,唉。以前还真没有过这种强烈的负面情绪出现过。
每次UI刷新,从任务管理器里看Mem Usage都会增加2-3MB,这得有多严重的泄漏啊!可是我自己的代码中new出来的对象都经过跟踪是销毁掉了的。于是又把矛头指向Qt内部,或者是QML中了。
本来怀疑是QML中的实现可能有问题,于是把Qt从4.7.0升级到4.7.1,貌似泄漏得更严重了。所以现在都已经不敢怀疑是Qt有问题了,开始怀疑是没有遵循Qt的用法。有些Qt返回的东西,需要程序员来负责销毁,比如QNetworkAccessManager在调用get或post后返回的QNetworkReply对象,这是多么操蛋的设计啊,指不定就是每次在哪里它自己创建出一堆对象出来要我来销毁我却不知道呢!
从CodeProject上下载了个Visual Leaks Detector,从说明上看,说是在msvc的jit debugger里会自动打印信息到debugging output window里的,可我实际上试了之后,发现屁都没输出一句,难道它是for MFC-based project only的?有可能的,唉!
简直走投无路了。
本来排除在计划外的事情,今天又去搞了,就是支持Twip4。前一天也折腾过一下,没弄好,这回问了一下Twip4的作者@yegle,他开始说是计算数字签名时用https://api.twitter.com/作为base string就行了。我试了下不行,后来他又说试试T模式吧,有几个客户端是经过实践T模式没问题的。于是一下子就明白过来了。 Twip4有T模式和O模式两种工作模式。T模式是完全的透明转发,Twip基本上不做任何处理,所以要请求oauth token和oauth token secret时原本是向https://api.twitter.com/oauth/access_token请求的,同时也是拿https://api.twitter.com/oauth/access_token作为base string计算数字签名的,在使用T模式的代理时,只要向http://www.myproxy.com/oauth/access_token请求就行了,仍然用https://api.twitter.com/oauth/access_token作为base string计算数字签名,这样就能无障碍获取oauth token和oauth token secret了。至于O模式,我看了下TweetDeck和Mixero的表现,发现它们也并不向O模式Twip请求oauth token和oauth token secret,或者请求了也没结果。所以我就推测其实O模式是没这功能的,O模式自己有consumer key和consumer secret,所以自己有一套oauth token和oauth token secret,但不是给客户端用的,即使客户端用自己有效的oauth token和oauth token secret发送给Twip请求,Twip也会把http header和url parameters里的东西处理一遍,用自己的那套oauth token和oauth token secret计算出来的东西替换掉。所以我想如果用O模式也要让用户可以无障碍认证的话,需要软件自己提供一个透明代理,软件先拿用户名和密码从那透明代理处获取oauth token和oauth token secret,然后在其他发布消息,收取消息时用O模式代理,就可以解决这个问题了。...
好吧,其实没做什么,本来的计划是先做图片浏览和文章阅读的,可是饭否上的内容实在太单薄了点,呃,这纯粹是借口,于是今天实现了对Twitter的支持。
昨天晚上弄到1点半才基本搞好怎么用xAuth认证获取oauth token和oauth token secret,今天就把twitter的timeline浏览,direct message浏览以及消息发布实现了。这内容比饭否丰富了许多,比如有了3列跟retweet有关的内容。twitter居然没有像饭否那样可以一次请求把foing和foer列表取下来,而只能先获取那些id,再由id去获取其他信息!于是这个功能就还没实现。还有比较影响使用的没实现的功能包括不能看conversation,不支持list,不能用快捷键操作。
不过有点值得欣慰的是,又修正了几处内存泄漏的问题。
今天就不上图了,因为基本上界面上没啥变化。
脑袋混沌了一天,终于基本上搞定超链接处理的功能了。
最开始是由于我使用的处理流程的关系,选择一个合适的数据结构让我头疼了好久,最后决定使用一个list,每个元素是一个结构体,每个结构体由两部分组织,一部分是URL列表,该列表会按短网址还原后的处理顺序存储URL,另一部分则是对该URL的描述,描述的字段包括当前是否已经完成全部的还原操作,最后一个URL能不能被embed.ly拆成两个新的URL列表,代表视频的html和html5等信息。
中间调试过程也是经历了重重磨难啊!其实也是自己代码写得有问题。一开始我是用一个map来存储url list和附着属性的,指针乱飘,调试得没有信心了,才改成上面描述的那个方案。还是有很多问题,经过层层排查,终于把所有的问题都找出来并解决掉了。甚至以为Qt的signal不能随便emit,会有对象生命周期相关的问题,最后也确认其实是在前面的代码写得有问题,哇哈哈!
明天就看一下怎么把数据库中的已有记录读取出来当历史记录来处理超链接。然后就可以做图片浏览的功能了!图片浏览功能完成后就做Readability的功能,之后再做twitter的支持,这就可以发布第一个版本了!
根据@zhangh109的建议,修改了一下界面,浏览文章有三种模式,在启动界面现在就只有一个入口Article View,在Article View中再添加切换浏览模式的入口。另外了加个图片浏览的视图,在启动界面中把原来About的入口替换掉了,About则移到原来的Quit按钮处。
URL处理部分今天还是没有搞定,不过思路清晰了很多,估计明天就可以完成总体的框架,到时候图片浏览部分应该就可以很快实现,而文章浏览部分需要把Readability的JavaScript代码移植过来,本来如果可以直接用它的那些JavaScript代码是最好的方案,可是之前我曾尝试过,不知道为什么内嵌的Webkit在装载完页面后,直接运行那个代码是没有作用的。所以干脆也不研究它了,直接移植成C++的,用Qt的接口操作Webkit的DOM树来解决吧。想来这移植工作需要花一些时间吧。
贴两张修改后的截图吧。
今天在处理超链接的问题,这是最重要的一环。
Ninayan提供给用户的信息分两大类:图片/视频和文章,微博消息只算是附属品。所以从微博消息中得到一个URL后,最终要能正确识别出它是一个图片/视频,还是一篇文章(当然,文章中也可以有图片和视频,但重点是它有文字),对于其他不可识别的类型,比如zip,则忽略。
我设计了如下的处理流程:
1、将URL与embed.ly可处理的类型用正则表达式匹配一下,如果可以匹配上,则用embed.ly处理,不能匹配上,则假设它是个短网址,将其还原成长网址。
2、embed.ly处理后,会返回缩略图和原图(如果是视频,则是一段HTML,可能还会有一段HTML5代码)的URL,假设这URL也是个短网址,也将其还原成长网址。
3、还原成长网址后,与原来的短网址比较,如果两者不相等,则假设该长网址仍然是个短网址,继续还原,如此循环迭代,直到还原失败或两者相等,最后还原的最终长网址与embed.ly可处理的类型用正则表达式匹配一下,如果可以匹配上,则用embed.ly处理。
4、如果第3步最终的长网址不能与embed.ly匹配上,则认为该网址是真正的最终应该由Ninayan处理的网址,可分为前面说的两类,图片/视频和文章。
至于怎么辨别出属于哪一类,我决定采用一个很粗糙的办法,如果前面经过embed.ly处理过的,那么肯定是图片/视频,或者URL最后是以诸如.jpg/.png/.gif等known的图片/视频文件扩展名结尾,那么也是图片/视频,其他的则都划入文章类型。而文章类型其实是个很粗糙的结果,网页是要经过像Readability那样的处理才是最终显示给用户的,而在Readability处理的过程中,可以过滤掉诸如.zip等不支持的文件类型的。
这个方案也只是考虑到了URL在网络交互上的处理过程。还有这处理结果怎么通知本地数据存储模块和UI显示模块,也是个问题。而这个问题涉及到何时通知,通知时采用什么数据结构,以及本地存储时采用什么数据结构。
添加了个图片本地缓存的功能,结果发现不是很好用。在Windows下实际使用时发现有时候装载本地文件仍然很慢,甚至不如直接从网络上加载的快。在Mac下发现压根就装载不上。初步估计是因为多处同时读写文件时有冲突,需要再仔细看看。
把删除消息,去fav后的响应也添加上了。
另外还有些细节方便的调整,比如所有显示图片的地方都添加了等待动画。
最后发现个奇怪的问题,在Mac下读取Friends列表有问题,json解析失败,这太诡异了。
今天听@shellexy说,用HTML5的话,配合JS/CSS这些东东,可以实现跨iOS/Android/WebOS/Symbian/MeeGo,呃,这也太强大了吧,而且据说Hotot移植到这些平台已经是在计划中了。得好好考察一番这种开发方案了。
昨天突然发现有内存泄漏,确实找到几次没有释放的,后来从任务管理器里看,貌似还有泄漏,但实在找不出有什么地方有问题了,最后今天把所有自己new和delete都放在一个类中统一调度跟踪,发现确实是都正确释放了的,只好先不管了。
今天搞定了显示friends和followers列表的功能,增加了显示所有自己发布的消息的功能。明天就搞一下显示之前的消息的功能。之后再修改一下消息显示的格式,比如图片预览,超链接处理等,然后就算是完成一个milestone了吧。
不多说,也是上两张图,还被@shellexy嘲笑了说~
经过一天的折腾,Ninayan已经能完成跟消息相关的绝大多数操作了,私信也搞定了。作为一个纯粹的微博客户端来说,也就剩下图片上传和用户Profile查看没做了。更多的诸如图片预览等功能属于比较有用的增值功能,不在这个范畴内。
汇报一下进度,Fanfou的API果然是最简单的,现在除了可以浏览时间线,回复线和收藏外,已经可以做些基本的操作了,比如发消息,当然包括回复,收藏和取消收藏,删除消息。而且也把消息都保存到本地了,每次切换页面时,显示消息的速度就相比以前会快一点,以前是每次都要从服务器上取下来才能显示。
接下来要解决的是,发布消息后刷新界面,以及消息中的超链接处理等细节问题。
今天折腾下来后,已经可以浏览饭否的最新的timeline,mentions和favorites了,当然,也仅仅只是能浏览而已,所有其他操作都还没做,不过至少证明这个架构是能正常工作的。上张截图吧:
其实是个小功能,真正实现起来还是有点花时间的,那就是移植AutoProxy的功能。在Ninayan中的过程大致如下:
1、从本地读取gfwlist.txt(假如存在的话),然后应用到代理管理器中;
2、从googlecode的svn上下载到最新的gfwlist.txt,然后应用到代理管理器中,如果第一步已经成功执行过了,那么这步的应用到代理管理器的操作会被略过;
3、将下载到的gfwlist.txt替换本地那个老的gfwlist.txt。
应用到代理管理器也不难,首先将gfwlist.txt内容全部读出,然后Base64解码,按行分隔,除掉空行和注释行,剩下有效的规则大约是2700多条。规则分为5类,分别是关键字匹配,主机域名包含匹配,正则表达式匹配,开始字符串匹配以及一种优先级最高的强行不代理规则的匹配。
现在的问题是,代理似乎是能正常工作了,但感觉有点性能问题。于是我就想是不是应该想点其他办法加速这个匹配过程,比较容易想到的是做个简单的缓存,比如已经被匹配过的,需要代理的URL就保存到缓存中,以后有新的代理验证请求来的时候,先在这个缓存中找是不是已经有过,如果有了,就直接返回。这是基于这样一个假设:用户浏览的网站比较集中。而且这个缓存不能大,粗略地想想,可以保持在几十或几百个URL的容量,然后每个URL要维护一个计数,如果缓存一满,就把计数最少的删掉。不过这要注意一个问题,如果时间一长,缓存中的每个记录的计数都很大,然后新的URL就再也进不了缓存了。这种情况很容易出现,比如用户突然从某天开始关注起一个以前都不关注的网站了。其实这个问题也有个笨的简单方案,就是为每个被规则匹配成功的URL都维护一个计数,然后定期选出计数最大的一批URL进缓存。不过这些只是我现在的构想,不知道是否可用,先放着吧,这个问题不是很急。
最后,传张代理配置界面的截图吧,这回是真实数据了。
兵马未动,粮草先行。第一次用Qt,第一次用QML,用QML Viewer做原型,可以强迫自己界面与逻辑分享,大赞啊!于是先把几个主要部分的界面用QML画出来,当然,所有显示的数据都是假的。现在还没想好显示和操作微博的界面应该弄成什么样,本来想模仿FaWave的,可是前些天Reeder把MobileRSS的界面抄袭抖出来后,弄得我不好意思抄别人的了,继续发呆神游天外。先放截图上来,其实用QML的主要原因除了比较容易做出漂亮的界面外,还因为操作上有各种动画效果,这里静态图片上就看不出来了。
另外还有个Paper视图,以paper.li的那种排版显示内容,其实就是一个网页浏览器,现在也没有可看的内容。
腾讯也开放微博API了,这对于一个一贯坚持封闭的公司来说,真是个很艰难的决定。但是,眼下的互联网环境中,开放已经成了大趋势,想想Facebook和Twitter这两种SNS的代表形式,由于API的开放,第三方的应用和客户端真是百花齐放,争奇斗艳,不开放就是死。腾讯在推出微博服务的时候,我猜他们一点都不担心自己的用户数,因为他们自以为有庞大的QQ用户基数支持,只要让QQ客户端支持微博,就能顺利将用户转移过去。事实是国内使用微博的用户,绝大多数不是使用网页端,就是使用手机客户端,同时可以想像得到,目前的QQ死忠用户鉴于他们的年龄,知识构成,社交习惯等因素,很难迅速接受并支持微博这种表达方式,对他们来说,QQ签名就足以支持他们对微博这种媒体形式的需求了,那样更方便,更直观。
开放API,并不是说将微博功能从网页端到其他桌面端或手机端实现一遍就完事了。Twitter在这方面无论是官方还是第三方都有不少的尝试,当然这也跟服务商对微博的定位有关系。比如Twitter之前说过他们做的不是社交服务,而是新闻服务,提供的是内容,所以Twitter官网的上次大改版就是往这个方向上发展的,它更注重内容的展现,希望用户可以方便快捷地获取到各种信息。而国内的诸多微博服务,无一不是停留在最原始的框架下,对于信息的回溯检索,或是扩散都没有任何明显的形式的支持。就像之前ifanr对和菜头的访谈中提到的那样,国内的微博在意识形态上仍然停留在精英制造内容,草根膜拜瞻仰的原始阶段。
这些天推友@lucifierya一直在推一些他对个人知识管理的想法和实践,他主要偏重从网络上获取的信息,包括RSS、Blog、Tweet等。其实这三部分独立的,都有各种实现得很好的方案,两种或三种结合的也有一些方案,但显然就很不被重视了。再回头说腾讯,腾讯有QQ阅读器,有QQ空间,也有微博,三者也有简单的关联,比如QQ阅读器中可以看到好友最新文章,但也仅此而已了。我对@lucifierya的一些想法深以为然,但也许因为他个人缺少对软件开发方面的知识和技能,他提供的解决方案就有点畸形。我在上Twitter的这一年来,一直在考虑自己实现一个Twitter客户端,一开始只是一个单纯的客户端,后来想法就逐渐有所延伸和扩展。单纯的客户端并不是我想要的,我的本意是需要一个获取信息,管理信息的工具。考察和试用了不少其他的服务,想法已经比较完整,但尚未明确和具体,大致如下:
1、连接各微博服务,当然首要是Twitter,提取微博中的网址超链接,作为一个信息源。
2、连接各书签分享服务,比如Delicious,ReadItLater,Instapaper等,作为第二个信息源。
3、订阅RSS以及Google Reader,作为第三个信息源。
4、方便地将超链接分享到微博和书签服务中去。
5、将网页主要内容提取显示。Readability、iReader等扩展的作用很明显,可以极大地提高用户体验,但将这功能放在浏览器中需要用户手工激活,有点繁琐,而在专业的内容阅读器中默认采用这种形式就方便了。
6、将所有内容条目以列表形式组织显示,如Feedly或Reeder那样,可以看到每个条目的开头的一部分信息以及内含图片的缩略图,用户就可以直接判断是否是自己感兴趣的内容。
7、将所有内容条目以报纸排版显示,如QQ阅读器或http://paper.li那样,这样除了有上一条的好处外,更多的是一种贴近传统习惯的用户体验,至少我个人是相当喜欢这种形式,只不过QQ阅读器一页显示的内容太少,以及不能自行添加RSS订阅,而http://paper.li时有乱码,更新周期太长,并且导致有时候一页内空白块太多,不够美观。
8、用户可以对内容添加评论,评论内容和相关链接可以保存到Google Docs上去,这样就可以移动应用了。
以上这些就是我总结出来的大的需求,其他小需求暂且不提。我会自己用Qt慢慢实现,以目前的能力来看,至少可以实现跨Windows/Mac/Linux/Symbian/MeeGo了,也许以后Qt移植到Android和iOS上后,也会支持Android和iOS吧,这是后话了。
在前些天的Nokia World2010中,Twitter的业务开发副总Kevin Thau明确表示,Twitter不是一个社交网络(SNS),而是新闻,是内容,是信息!大言不惭地说,这也是我最近刚刚领悟到的一点。
从半年前,就一直想着自己写一个Twitter客户端,但是不得不说,现在已经有非常多优秀的Twitter客户端了,从共享到免费都有,覆盖了各种平台,那如果我自己要写客户端的话,有什么特色值得用户们抛弃现有的那些客户端来转投这里呢。在这大半年的时间里,我根据自己对SNS的认识,以及自己需求,不断调整心目中的客户端的特性需求,到现在才在心中有一个相对比较固定的框架、模型。
为什么FlipBoard会受到如此热烈的追捧,这就说明对于很大一部分人来说,使用Facebook和Twitter主要并不是为了与人交互和玩游戏,而是为了获取信息,而FlipBoard这种经过整理,同时又有美观排版的方式,很能迎合那些主要为了从网络获取信息的用户的需求。
处于Twitter中文圈中,比较容易忽视的一点是,将Twitter当成一个公共聊天室。当然这也是很大一部分人使用Twitter的目的,传统的网络聊天室的没落,使得用户们不得不将这种需求搬到其他形式的网络服务中,可以看到在各种BBS、论坛、IM群等等都有这种版聊的现象,所以在Twitter中存在这种现象也是正常而且合理的。只不过,从服务提供商的角度讲,应该可以从服务器端,甚至客户端提供这样的信息过滤、隔离的功能,用户可以方便地在两种应用模式间来回切换,想版聊就版聊,想读新闻就读新闻。除了FlipBoard,http://paper.li/也提供了类似的服务,但它目前只能说,这种模式还不错,各种细节方面还很不够。
再扯远一点说,现在很多人应该喜欢使用Google Reader这个服务,但说实话,Google Reader这个界面仍然有很大的改进空间。之前网上一直有人在号召大家使用RSS全文输出,但全文输出后有一个很大的问题是,在Google Reader中如果是全部展开的阅读方式,花费很多时间在拖动滚动条过滤无兴趣的条目上,实际上对于订阅了大量内容的人来说,很多内容只要一眼看到标题,或者其中的某张插图,就没必要看正文了,那现在Google Reader这种阅读方式就显得很落后了。而有一家第三方的Google Reader同步服务在这方面做了不少努力和改进,那就是Feedly。Feedly自己也提供经过分类的新闻内容,但对Google Reader中文用户来说,更有价值的是它的同步Google Reader的功能,可以提取出条目的标题和插图以及正文摘要,并以一定的热度排版,并连接了几家最流行的SNS服务,可以及时分享自己的条目,自从用了Feedly后,我几乎就不用Google Reader的官方界面了(喂喂,你是他们的托儿啊)。
再说回Twitter客户端,目前现在的客户端,基本上都是简单地通过Twitter API将Twitter的Tweet功能从Web搬到桌面或手机端等,几乎没有做更多的需求挖掘。简单地看过几十个完成度较高的Twitter客户端,目前只看到Seesmic Look收集了几组全球知名媒体的账号,但也仅仅是收集,没有更多的特性拓展。现在Twitter推出了新版界面,可以说是诠释了Twitter自己的发展理念,引领了客户端发展的方向──它提供的是新闻,是内容,是信息!
最后可以得出,我想要的客户端,是融合了FlipBoard、http://paper.li/和Feedly几者特色的客户端。它一方面可以向用户提供类似传统书报媒体提供给用户的视觉感观享受,另一方面则是结合网络、计算机的优势,提供大容量、快捷的信息分享功能。所以它不应该只像FlipBoard、http://paper.li/和Feedly它们一样只有一两家内容提供商,它应该是彻底开放的,允许其他内容提供商以固定的接口接入并提供特有的信息。而且它应该有一定的信息自动分类和索引能力,过滤重复或无价值信息,减少用户浪费的时间。
Category GUI Framework
今天开始整理代码,突然又觉得现在嵌入Lua的方法实在太丑陋了。
为了连接C++和Lua,我用了Luabind、SWIG和wxLua。而主要问题在于这三者在映射C++的自定义类型时对同一个C++类型做出了不同的映射,所以不能互相兼容使用。
最早决定是引入wxLua的,因为一开始是确定用wxWidgets框架,并嵌入Lua做扩展,于是必然的Lua会要操作wxWidgets的类型,同时Lua扩展也会需要有一些界面需要画。但实际上,当时没搞清楚使用wxLua到底能不能满足这些需要。而经过真正使用后,才知道wxLua中的类型并不能直接用于让嵌入的Lua解释器来映射到宿主程序中的wxWidgets的类型。于是现在的状况是,wxLua和宿主程序的wxWidgets是互不相干地使用着。wxLua仍然用于画些对话框,做些文件IO之类的操作。宿主程序的wxWidgets组件却是由Luabind和SWIG来实现粘合的。
使用SWIG,是由于要在Lua中操作wxScintilla类型,而Scintilla有几千个常量,然后自己又定义了一堆方法,于是用SWIG感觉是顺理成章的。
而使用Luabind,只是觉得它的call方法很方便,基本可以做到无视函数参数个数和参数类型从C++调用Lua函数。只是马上发现,通过Luabind来调用Lua函数时,把C++对象传递过去时,即使时实际上的同一个C++对象,在Lua中表示的类型却是Luabind中的一份,跟SWIG中注册的类型全无关系,跟wxLua中的也全无关系,比如说一个wxString,三个工具/库,有三种表达方式,互不兼容。
于是我就觉得很丑陋了。突然就有种冲动,自己实现那么一套东西,应该是集合了SWIG和Luabind、wxLua的特点,却又能互相通用。也就是说,有工具可以自动扫描C++声明,生成胶水代码,又有库,可以自由绑定C++类型,同时又提供对wxWidgets,甚至Qt和Gtk+的绑定。其实说起来这并不是非常困难的事,只要修改一下SWIG生成代码的方式,以Luabind的方式生成胶水代码就可以,而wxLua则也以Luabind进行绑定,这样应该就是我想要的那套东西了吧。
Category KarenMeu
前天傍晚下班回来的路上被追尾了。因为车速比较快,前面的一辆的士突然停下载客,我就急刹车,差点点就要撞上前面的,我都感觉到我的车好像因为刹车踩得太猛而什么东西突然断裂了一样,但是后面另一辆的士就没刹住,撞上我了。看了一下,我只是后面有几条划痕,那的士是右大灯完全废了,都往里陷入了。我也懒得跟他计较,只想着快点回去。
最近几天因为原来做面试的两个同事都到美国培训去了,于是把面试的活都仍给我了。开始还觉得有点新鲜感,两三次后就有点厌倦了,电话面试了好些人,不少还是硕士,不过貌似大多对软件开发并不是很熟练。
接到几个Watson bug,不过实在没经验啊。
KarenMeu迟迟不开工,主要是有两大块还没一个清晰的思路。界面部分想模仿Qt Creator,看了一点源代码,没头绪。另外就是想有一个极度灵活的插件架构,插件主要分两类,一类是界面插件,一类是业务插件,业务插件产生数据,提供给界面显示和操作。同一个业务插件可以让用户自由地选择不同的界面插件进行显示。具体细节想不好该如何实现。
最近过得很开心。
Category Kindle
昨晚公司,本来都有点不太想去,因为往年的经历开一次年会失一次望,不如回家陪妹子。跟妹子聊起这个事,妹子倒劝我还是去参加吧,抽奖奖品我确实很想要一台带背光的Kindle,家里已有的Kindle4和DXG都没背光,晚上吊顶的灯光不适合看。于是还是去参加了,还当了一回苦力拉了几箱东西,包括所有抽奖奖品去酒店。
之前买了个二手的Kindle4,体验太好了,无论是E-ink屏,还是推送功能,都很舒服,唯一的不足是看扫描版PDF即使切了白边仍然字体过小,如果横屏来看又觉得操作不是很顺手,于是纠结了一阵后,看到有比较便宜的卖全新的DXG的,就趁刚发工资咬牙买了。
昨天早上在taobao拍的,今天下午收到货,然后迫不及待地开箱。没有WIFI就不能免费推送,这是一大遗憾。官方皮套看起来很厚实,装了几本扫描版PDF进去,仍然感觉小了点。官方系统默认不支持中文,书名中带中文的在目录中也不能正确显示,这是点小瑕疵。
忧郁啊,赚的钱远远不够花。这两天遇到瓶颈了,写程序写啥啥不会。想给Ninayan加上链接保存到Readability和发送到Kindle的功能,想想多简单的特性啊,居然遇到很大阻碍。
又好久没写blog了。上上周从推友处入了个二手的Kindle4,这是个很划算的事。350元顺丰到付,成色很新,还有个山寨的皮套。拿到手后,我就爱不释手了。
首先,Kindle4很小很轻,只有6寸,而且没有键盘,一只手就可以竖握整个机器,拿起来很方便,随身携带比带书轻便多了。
其次,E-ink屏真的很赞,真的只有自己实际把玩过,才会体会到它的好。之前很多次都冲动想买个Kindle,都被自己以“我不是个爱看书的人”为理由扼杀了这冲动。这次之前是橙子拿她刚到手的Kindle4来让我玩了一下下,于是就冲动了,刚好推上求二手也便宜,就入了。E-ink的屏幕观感上很接近纸版印刷,让人看起来相比电脑,手机,平板等等觉得更类似书本,另外个好处是,我早上上班路上会拿出来看点东西,如果露天有大太阳的情况下,用Nexus S手机看小说时得把屏幕调到最亮才能看清,E-ink则不在乎这个问题,但同样的,晚上回来如果天黑光线不足,E-ink就不行了,据说可以通过配备小照明灯解决。
再次,Kindle4有很方便的推送功能,只要把指定格式的电子书作为附件发送到Amazon给分配的邮箱里,Kindle在连上WIFI后就会后台自动把书下载来。这样一来,可以实现很不错的功能。比如定时推送RSS等内容,虽然网上已经有一些免费或付费的推送Google Reader或RSS的服务,但我还是打算自己写一个。有几个原因,一是这些服务免费的一般都有比较大限制,比如Google Reader推送时间只能一天一次,顶多一天两次,推送RSS则往往对订阅数有限制。二是我想增加多一些推送的类型,比如小说更新,漫画更新,还有从SNS消息中提取的链接内容。三是推送过来的字体、排版以及插入广告之类,终归不是很舒服。因此要写这样一个程序,打算设计成一个C/S架构的应用,客户端和服务器都具有内容下载生成的功能,但服务器端可以实现定时推送的功能,客户端可以把定时推送的请求发送给服务器端。
最后想说下遗憾的事,6寸屏对于看扫描版16开或22开大小的PDF还是不够理想,我在考虑是不是再入个DXG。
Category Coding
因为程序使用了多进程的架构,有时候需要在子进程被启动后非常早的阶段就进行调试,比较常见的极端情况是要调试子进程的main()函数,MSVS上有插件可以在同一个调试环境同时挂载父进程和子进程进行调试,WinDBG在启动被调试程序时自带选项支持同时调试父子进程,但就我使用下来的体验发现,这时调试器的性能会变得非常差,非常影响心情和调试效果。也有比较low的办法,就是在子进程的main()函数开头加一个MessageBox,使其启动后用户有机会使用调试器attach子进程进行调试,但要改代码终归麻烦了点,而且不是所有程序都适合加MessageBox。
前些时间脑子发热在淘宝上买了个DeskMini X300,但是出于预算方面的原因,选了个最低档的CPU——AMD 3000G,到手后发现跑Windows10非常慢,有点后悔没有多加千把块钱配个好点的CPU。
过去一周仍然花了些时间更新微信公众号爬虫,又踩到些坑,记录一下。
一直想要抓取微信公众号文章,目前终于可以一半手动一半自动地抓取指定公众号的所有文章了。
最近这段时间写了个债权匹配管理系统,然后交给同学公司的人去用了,结果各种小问题都暴露出来了。比如因为服务器上默认时区设置的不同,导致从数据库里取出来的时间字符串格式有些微变化,而客户端在解析这字符串时的逻辑写得太死了,于是挂了。比如double类型与字符串类型互转,在数值比较小的时候没问题,数值较大时就用科学记数法表示了,于是转不下去了。
之前写过一篇文章谈到为Android app设置splash screen,以避免Qt写的app启动时有一段时间黑屏。今天收到一位朋友的email询问,在splash screen之前仍然会有一个黑屏,怎么去除。
昨天又折腾了大半天iOS Push Notification的证书,之前也折腾过一次,真是麻烦,网上的文章大多步骤相似却不能只靠文章中的步骤得到能用的证书。这里暂且记一下。
自从Rust版本号跳到1.0,即使离正式发布还有很长一段时间,我就开始打算要学一下Rust,主要还是因为想跟Go比较一下,用Go也一年了,已经能做些比较实用的小项目了,我想看看Rust有哪些方面更优秀,或者说比Go更合适来做某些方面的开发。
这几天在赶饭店的项目,我做服务器部分,前端外包给一个同事做,但这个同事这几天大概比较忙,投入很少,今天他来找我,实现了一点点。
今天一个人闲来无事跑去图书馆续证,结果发现证上说的2年有效期虚惊一场,不知何时起已经改成永久有效了。于是又去中文外借室逛了一圈,还真找到几本感兴趣的书。其中一本是老毛子写的《深入实践Boost》,里面有一段讲到了Boost.coroutine,看了一遍不是很明白其中的用意,于是我又想起Lua中的coroutine来了。Lua在几年前学过用过,写过几万行的代码,但最精髓的部分(coroutine,table高级用法等)却被我略过了。于是这次在网上逛搜了一通相关的中文文章,终于有了一点点理解。
Rust总用来跟C++,尤其是Go来对比。我也差不多学了并用了近一年的Go,基本上可以用来独自做些并不复杂的程序,最近特别想去学一下Rust,想看看到底和Go各有什么优缺点。
之前很长一段时间都是用ConEmu来实现Tab化的PuTTY,后来由于发现PuTTY的屏幕刷新不如SecureCRT的快,最近用了一段时间的SecureCRT,不过又发现SecureCRT有两个很让我受不了的问题:
其实我大概10年前就知道ACE了,并且把国内翻译引入的3本以ACE为蓝本的讲C++网络编程的书都收齐了,之所以说是收齐,是因为自己买了两本《C++网络编程》,而由译者马维达送了一本ACE开发指南。但是三本书入手后并没有认真读过,后来工作上也跟C++网络开发基本不相关,于是一直了解不多。直到现在这份工作,虽说终于转向网络开发了,但实际上要么因为老代码已经把底层封装好了,要么就直接用了Boost.Asio而不求甚解。
Yiili论坛程序是从wetalk改过来的,所以是用了beego这个Web Framework的。前两天Beego从1.2.0升级到1.3.0,有一个用到的接口被删了,用另一个新增的接口替代,于是Yiili就编译不过了。其实据说这个被删掉的接口已经有3,4个版本标记为deprecated了,只是我才接触beego差不多1个月,所以肯定不会知道这回事的,于是即使自己照猫画虎地尝试修改,即使能编译通过了,运行也仍然不正常。Beego的官方论坛上也有人在喊这个问题,一直到第二天,Beego的作者astaxie大概实在受不了人的呱噪,直接把wetalk的不兼容代码给改了。这次事件给我的感觉非常不好,还跑到Go的中文邮件列表去问遇到这种第三方库接口变化引起不兼容的问题该怎么解决。结果有人说,官方的做法是把第三方库在自己的代码库里copy一份,唔,这是我最不喜欢的做法,像svn external,git submodule不都是为了避免这种做法吗!但是go get不支持版本,所以是没办法做到的。还有人提出个我觉得还能接受的办法,在GOPATH里加3个路径,第一个专门放go get取下来的第三方库,里面的东西随时可以删掉,第二个专门放被自己修改过或认为是stable的第三方库,可以保证自己的项目能编译通过的,第三个专门放自己的项目代码。
今天早上csdn的人打电话来催了,让我快点提交应用,我说我已经写了一半了。其实不然,我只能说只搭了个框架,所有核心的内容都没开始动手呢。这次又是被block住了,又是因为不能为这个业务设计一个合适的数据结构而进行不下去了。总的说来简单的数据结构在学校时学过一点,然后就一直啃老到现在,但一直缺少能根据具体业务逻辑而举一反三地设计合理的数据结构的能力。真是忧伤啊!
Category Startup
已经过去大半个月了,十一前婷婷发来一堆图片,十几个zip包总共大概有10来GB,整个十一我就全用来上架到店铺去了。上半年妹子开了个淘宝店,从http://shop109252741.taobao.com/或http://shop.yii.li/访问,长长半年也就卖掉两件衣服,哈哈。婷婷上个月说有一批秋装,可以拿来上架,于是妹子跑去西安游山玩水了,我就苦逼地在家上货。那个MacBookAir也着实不好用,主要是屏幕太小,软件缺少,以及淘宝后台网页不好用。但是事实证明,节后我回到上海用台式机上的Windows,也好用不了多少,阿里做的软件真烂啊,淘宝助理经常崩溃,经常不能上传,经常刷不出图片空间。
昨天找SSL代购买了个支持泛域名的SSL证书,现在Yiili就支持https了,我在nginx上加了个重定向,把所有http的请求都指向https了。
花了好几天时间,终于给Yiili的程序加上了Memcached和Redis的支持。前面也说过,我只是用它们来实现缓存的功能,把一些本来需要查数据库得到的数据缓存起来,比如帖子列表、话题列表、分类列表等,目前看来,效果确实是有一点的,但因为测试环境的帖子太少,还不能看出来以后帖子多起来的时候效果有多少。另外就是Memcached和Redis在效率上的区别也基本看不出来,估计也得是比较大数据量和查询操作才能比较明显得体现出来。
Yiili和MiaoCoffee是基于同一个codebase,目前的区别主要在描述性文字等周边部分。现在Yiili和MiaoCoffee都算正式上线了,之后的工作重心就在运营上了。MiaoCoffee的运营我肯定基本上是不管的,那个其实不算我自己的项目,我的主要精力将放在Yiili上,Yiili上我才有绝对的控制力和话语权。总的说来,我也只是因为有Yiili才会顺便花点时间给MiaoCoffee做些技术支持工作。我在人脉方面几乎没有任何基础,所以很难直接拉些人来活跃气氛。于是我想着前期只能自己生产些内容来吸引流量了,而内容生产是件不容易的事,对我来说有两条路可以走,一是找那些还算有交情并且交情还不错的又在某方面的知识掌握得比较多的朋友,请他们偶尔抽空写点两三百字的超短篇,再配张图就算是图文并茂了,二是从国外找内容自己翻译。前者产量极不稳定,后者产量要稳定得多但要占用大量时间。除了通过生产内容吸引流量外,另外我想到的一个也许效果并不怎样的办法是同步SNS,比如微博,微信等等。等项目起步后,就可以开始考虑推出移动app了,这样既能显示专业和认真,又能降低使用门槛和提高用户体验。大体思路就是学v2ex那样通过技术手段来弥补一些资源上的不足。
忘了从何时起,就不太乐意写blog了,一直在长草。前两天从知乎网友Jim处扒来一个非常简洁明快的Jekyll theme,于是打算写点文字除除草。
Category network
以前也尝试过在DNS上做手脚拦截广告,但因为误杀太多以及漏网之鱼太多,觉得还不如不折腾呢。
鉴于移动免费送了1年200M的一条宽带,没多犹豫决定还是要用起来。经过一番折腾,基本搞好了,目前的情况大概是这样的:
去年12月在家里用了TP-Link全家桶,实现了AC+AP的WIFI全覆盖,用的是TL-R470GP-AC这款最便宜的4口千兆PoE带AC的路由器一体机,功能上基本够用。
不知道是不是住的房子户型奇葩,或者是承重墙太厚,这些年一直被WIFI信号很难覆盖到大部分面积而困扰。自搬进自己家后,一直心心念念的AC+AP终于可以试一下了。
2022年5月更新:gnb早已开源并更名为OpenGNB,所有源代码可在GitHub下载,且可自行编译。
之前用tinc构建了虚拟专网,实现了在不同局域网内的机器通过tinc互相访问,但是遇到一个问题,我想从公司里访问到家里其他没有装tinc的机器,或者从家里其他没有装tinc的机器访问到公司里装了tinc的机器。经过一番简单的设置便可以达到想要的效果。
之前写过一篇文章讲如何在家里无缝访问公司网络,用的是frp的方案,但正如使用ngork一样,frp也会莫名其妙地突然不工作,而且几乎没有什么错误信息可供调查。后来知道了有zerotier这个东西,相对来说还是比较稳定的,速度也凑合,免费额度可以在一个网络中添加最多100个设备,但是流量通过别人的服务器总归有点不爽,直到最近知道了tinc这个东西,可用于创建点对点的虚拟专网。
有时候在家里时想访问公司网络,干点活(真是个好员工),主要就是开开内网的网页,连连内网的IM(Cisco Jabber)。本来这个事情只要有一个VPN就可以搞定了,但是!但是我没有权限申请VPN,于是只好另辟蹊径了。
某天早上起来,发现屋里手机、电脑都上不了网了,照惯例先后重启了一下路由器和WIFI中继,都不管用,感觉问题有点严重了。
在路由器上部署了全局翻墙后,出于简化部署的考虑,我把接在路由器后的一个Raspberry Pi作为VPN server,部署了OpenVPN,然后再在路由器上设置端口映射,可以从外网连回Raspberry Pi。这个方案有几个好处:
之前在香蕉派上通过he.net的tunnel得到IPv6后,遗留下一个问题,二级路由器Netgear R6300v2刷了梅林固件后,不能分配内网IPv6地址,网上看也有人提出了相同的问题,后来在其他人的指点下,找到解决这个问题的几个办法。
自从苹果要求iOS app能支持IPv6以来,我就一直想在自己屋里搞一个IPv4/IPv6双栈的环境,不为实用,只是为了满足那点强迫症,直到现在才有点进展。
屋里的网络突然变得很慢,连打开百度首页、电信首页都非常吃力,转圈很久仍然有不少图片不能加载出来,重启了光猫和所有路由器,仍然没有改善,最后是通过打电话给电信客服,让客服在他们那边重启了一下什么设备或是线路才搞定。
前几天预约的升级,今天下午电信维修人员上门来,带了个新的光猫,我说我有个老的单口光猫够用了,能不能保留,维护人员说可以,但新猫还是留下了,说是万一以后用得着。
之前就发现了,Linode是默认带一个IPv6地址的,最近公司里的项目要做一点跟IPv6相关的工作,我就想多了解点IPv6相关的东西,于是想到把我的web站点支持IPv6。
最近又被结结实实体验了一把国内的恶劣的网络环境。两件事情,一件还是说之前那位同事要搞个社区,域名备案的问题,用了阿里云的主机,然后说已经准备齐全了各种材料去备案,已经快递到了河南省内某处,过了大概快3个星期了,前几天他跟我说收到那边的消息,说还需要大概20个工作日才可能会给他进一步的是否备案通过的消息。我表示只能呵呵了,这么搞真的有意义么有意义么有意义么?
Category Go
用C++写程序时,有些事情发现用Go做很容易,用C++则比较折腾,所以就想用Go实现,然后通过cgo链接到C++程序中。但是cgo在Windows上只能使用gcc实现,有时我又有必须使用MSVC的理由。
没心情给avege做新功能,就断断续续做些重构工作,用gocyclo看出来很多函数的圈复杂度都很高,常规的做法,除了把一个大函数拆成几个小函数外,还要对代码逻辑进行调整,比较可观的做法是把if-else,switch-case和select-case替换掉。
之前也折腾过,但是没完美解决,最近在爬些数据,然后想保存成统一的编码,于是自然而然地有编码转换的问题,在网上找最多的解决方案是通过CGO调用iconv实现,这个方案在mac或Linux之类的系统上很好解决,因为基本上都会有iconv的链接库,即使没有,一条命令就装上了,但在Windows上就麻烦些,首先Windows上用CGO就要稍微麻烦点,需要首先装一个gcc编译器,比如MinGW或其衍生品。我的系统上有个msys2,上面也有iconv的链接库,直接从网上go get一个iconv的go封装package就会通过CGO试图寻找那些归档文件,但它会说找不到mingwex和mingw32的归档文件,这个问题可以通过在CGO_LDFLAGS环境变量中设置链接器搜索路径解决。
今天要把一段文本从gb2313转换为UTF-8,网上有一些第三方库,比如使用iconv之类来转换,其实有比较官方的方法:
周末两天都用于参加第一届Gopher China技术大会了,这是我第一次参加这类活动。大会在浦东软件园了的浦软大厦2楼举行,很糟糕的一点是那大会堂里联通信号都没有,我那Nexus6估计一直在尝试连接网络,一整天都烫手,电池只能撑6个小时。
昨天花了一天时间,把github上几个Go程序通过travis实现交叉编译,再把编译生成的二进制可执行文件push回github上的prebuilt branch,这样每次有新的commit后,都会自动生成各个支持平台的最新的二进制可执行文件,相当方便。
虽然使用Go语言写东西已经有一段时间了,但仍然不是很熟练,一些常见的用法仍然要不停地翻官方文档和搜以前写过的代码。前些天用Go的zlib包对数据进行压缩再传输,发现小数据量,比如4MB以下,总是压出结果只有2字节,这是明显有问题,实际上大点的数据量,比如5MB或更多,虽然压出的结果不是2字节了,但现在想来也是有问题的。看了很多网上的代码,发现跟我的几乎没区别。最后偶然才发现,原来是得到一个io.Writer写完后就马上关闭,再去看压缩后的结果,那时就是正确的,而我之前一直是在关闭前就去取结果了。
之前注册了搜狐云景PaaS,被送了100元的券,不过当时看了一下发现不支付Go程序,于是就没玩下去了。前几天连续收到几封邮件,说钱要花完了,也没放在心上,觉得反正玩不了,就随它去吧。今天在v2ex上看到有人说可以免费送3个月的使用配额,于是又上后台看了一下,发现它居然使用限制那么少,可以自己在配置文件中指定要运行的程序路径,这样就可以部署Go程序了,立马把之前在京东云上部署的ifconfig在搜狐云景上也部署了一个,感觉还不错。
昨天在写微信公众号文章的爬虫,中间需要解析一段GBK编码的XML,结果发现Go语言自带的encoding/xml包默认是不支持除UTF-8以外其他编码的。在网上随便搜了搜,能看到代码的方法不是过时的就是不能work的,最后还是看到比较官方的一个包可以解决这个问题,代码如下:
学Go语言已经有一段时间了,其实之前就一直在改Yiili就是用Go语言写的,但毕竟只是在别人已经比较完整的程序上修修补补而已。从周日开始总共花了近3天时间,把公司那个项目的消息转发服务器用Go语言实现了。主要还是不够熟练,很多基本的东西仍然要不停地翻说明文档和在网上查解决方案,所以比较慢,相信熟练起来后这个时间可以大大缩短。这个服务器只是个RESTful API服务器,功能也非常简单,包含了操作数据库和memcached,代码量总共才几百行,真爽快,如果用C++实现肯定不止这么点。
Category idea
Category os
之前在PVE上装了几个BSD系统后,也没怎么用,就时不时更新一下,各个BSD有各自的更新方式,这里简单记一下。
昨天想在装在T43上的FreeBSD上编译些软件,结果不是缺这个库就是那个so版本号不对,应该都是上次试图将9.2升级到10.0失败后rollback造成的。我就觉得现在这系统虽然能运行,但连个程序都编译不了,那跟废了有什么区别啊,果断再次试图升级。
Category iOS
2011年买的iPad2服役3年多了,一直用得不错,我当初买其实就图个新鲜感,新鲜劲一过就没什么兴趣了。妹子来了后,就几乎成了她的专属看片工具了。毕竟是款比较老的机型了,在iOS出8后,我就没再升级了,一直停留在7,因为7我都感觉比以前慢了不少,我怕8会使得机器更慢。
Category Cloud
突然发现Azure中国缺不少我想要的功能,这也是因为前些天看了下AWS才意识到的。
Category device
旧台式机是在2011年底去徐家汇组装的,当时紧缩预算,仍然花了近4000块钱,这五年多来用着噪音又大,又要经受每天1~3次自动重启,AMD的CPU和ATI的显卡都是我不喜欢的配置,但是便宜啊!
今天无聊地把老本子拿出来,因为之前发现它的显卡似乎已经有问题了,开机几分钟GUI就会卡死没有反应,所以只装了Archlinux,还没装X。顺手就敲了个sudo pacman -Syu让它跑着,跑着跑着,然后发现它不知道什么时候已经不亮了,屏幕黑了,插着电源线的指示灯也不亮了,按开关按钮也没反应,这回它应该是真的彻底挂了,10年了。
Category embed
今天,我屋里的树莓派uptime已经达到365天了,整整一年,截图留念一下。
今天还在树莓派上试了一下之前买的华为E8372这块4G无线路由器。树莓派上运行的系统是Raspbian,直接把E8372插到USB上是没什么反应的,用lsusb是能看到有东西:
从妹子家里拿回来的树莓派1B不知道出了什么问题,开机只能跑个一两天,之后就连不上网了,从路由器看它也掉线了,只能断电重启才能再次连上。连续遇到两次,我也没耐心继续耗下去了,打算重装系统,原本用着Raspbian,1B的机能实在差了点,于是想着装Archlinux这种比较轻量级的试试,另外一个想用Archlinux的原因是它的官方仓库里一般会有比较新的GccGo安装包,avege用Go开发,试试GccGo编译是否会有更好的性能表现。
之前想着要换软路由,不但把拨号的极路由1S换掉,还要把翻墙网关树莓派也换掉。但看了一下我的树莓派,还真承担了很多任务呢!
想做这个东西想了有好些日子了,一方面是懒,执行能力太差,另一方面是在纠结要不要自己写一个程序,昨天经过一天的折腾,终于搞定了,最后我终于没有自己写程序。
树莓派2代出来已经不短时间了,手头有一个1代B,用来挂pt,做dns缓存,http和socks代理,以及其他少量文件共享之类的服务,一直觉得机能不足,局域网传输最快才4,5MB/s,但也因为一直勉强够用,我又没有什么刚需,于是一直在犹豫,一直没入手。
Category gochess
昨天举世瞩目的AlphaGo vs 李世乭,第一局,AlphaGo居然赢了,心情不太好,当真担心人类在自己作死的路上又进了一步。
Category Router
前些天脑袋一热,就在淘宝花了400大洋入了一个GL.iNet MT1300,主要是换了工作后单位里只是普通电信宽带,上Google搜索是我刚需,尝试了在Windows上用tun2socks和在Virtualbox里装Linux做旁路由后,最后还是决定需要一个额外的小设备专门做这种事情。
前面一直在说要把极路由和树莓派换掉,其实这个念头有很久很久了,最早是一年多前就想攒个小主机或家庭服务器,由于NUC、Gen8的价格远远超出我的预算,所以后来就考虑像占美之类的小主机,还是觉得贵,再后来考虑过二手的Atom主板来组,在淘宝翻了几天,觉得水很深,想来想去还是ARM板比较合适,偶然发现Banana Pi R1这块ARM板,CPU和内存其实跟最新版的树莓派从数据上看差不多,但关键是它有千兆网口,而且是5个口,1个WAN和4个LAN口!然后偶然发现了Banana Pi的官方Telegram群,询问了一些我关心的问题后,觉得R1是很适应我的需求,于是上淘宝买一块,昨天收到,包括一块板子,一块散热片,一块TF卡,一个输出5V3A DC的电源。贪便宜在另一家拍了一个外壳,快一周了也没发货,郁闷。
一直以来对刷路由器固件很抗拒,觉得麻烦,收益小,可玩性低,风险大,就跟刷Android手机一样。但是实在受不了Netgear R6300v2那渣渣的官方固件了,功能弱也就算了,信号太弱就不能忍了,相隔不到10米的房间就关上门,屋里一票电脑手机就要罢工!
Category blog
得益于Cloudflare CDN的强力支持,偶然发现本站已经支持HTTP3/QUIC了,初步使用体验下来,比传统的HTTP1.1和HTTP2协议要快不少,值得大力宣传和使用。
虽然现在写blog的频率大不如前,但折腾blog仍然是件很有趣的事,以及新学到些Cloudflare玩法。
突然心血来潮,花了点时间写了个Jekyll的插件,用于生成PlantUML的各种图。用法大体是这样的:
今天发现自己的blog实在太慢了,偶然的机会知道了AppDynamics这个服务,注册了个账号可以免费试用15天,然后就给blog加上试了下,发现blog慢得让人发疯,我前些天把家里的线路优化,海外IP全部走IPLC,今天看来blog打开仍然很慢,更别提其他家里网络没我好的人了,我觉得没法忍,必须改。
去年把blog托管到了coding pages上,以为可以为大陆提供更好的访问速度,但实际上效果似乎并没有想像的那么好,coding pages貌似是为了规避大陆网页要求备案,把大陆访问IP引导到了香港的主机上,网络一旦出了国,速度就会降很多,另一点是免费的coding pages要求在页面上添加他们的声明信息,虽然就算他们不要求,我也会在页脚处添加各种感谢声明,但强行要求就让我心里总有点疙瘩。
自从重新开始写blog,都是托管在github pages上,然后通过cloudflare中转以及https证书。这一套方案总的说来工作得挺好的,但是,万事就怕但是,在大陆cloudflare的服务并不是特别稳定。后来发现Coding.net也提供Pages服务了,还集成了Let’s Encrypt的证书服务,于是就迁过去了。
Category cmake
鉴于最近买了个梯子,不大稳定,速度也没以前的快,直接打开在线的开发文档就感觉不大舒服了,想在本地弄个快的。今天编译试用了一下Zeal,感觉不错,比当时刚出来的时候好多了,不会随便动两下就遇到奇怪的bug,界面也不那么丑了。
用CMake的好处一是屏蔽了多种常见编译器的编译选项和命令行参数差异,二是可以选择目标构建工具。我前段时间要写一个SDK,希望SDK能在主流操作系统(Windows,Linux,macOS)上跑,能用常见的编译器套件(MSVC,GCC,Clang,Intel C编译器等等)编译,这正好是CMake的用武之地。
Category Network