All Stories

让SMTP支持中文

  项目里要有发送邮件的功能,想法非常简单,公司有个SMTP服务器,通过它直接就可以发送到notes中了。网上SMTP的源代码也是一堆一堆的,找了一个CodeProject上的,加上base64编解码也只有4个文件,接口非常简单,于是稍微改了一下,base64本来我就有,就只需要加入2个文件就可以了,附件也能正常发送,很是满意。不过上周五的时候突然发现,主题和内容中的所有中文都变成乱码了,有点气馁,随便又找了几个其他的代码,也是一样。  今天闲起无事,就想改一下。只知道在哪里看到过说要用base64,就能解决这个问题。尝试着先把主题编码了,发现收到后就是编码后的字符串了,这也是预料之中的。上公司的论坛发了个帖,没人回复。后来自己忍不住了,用Outlook Express写了个邮件,主题和内容都是中文,然后打开Wireshark,抓包,比较了一下CodeProject上那个代码发送的,看出区别了,原来也就是加上个charset="gb2312",再base64,就搞定啦!

嵌入Python真辛苦啊

  两年前,就嵌入过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真辛苦啊!

杨柳坑快乐游

  部门组织去杨梅坑游玩,之前只看别人去玩过,自己却没去过,所以在出游前,一直有点儿兴奋。  早上等车等错了地方,有点囧,有点恼。坐了一个多小时车,终于到了目的地。每人都去挑了自行车,好久不骑了,有点感怀。租好了车,却一直不出发,等几个自驾车过来的人,有点不耐烦。估计等了有十几二十分钟吧。  一路逆风,而且风很大,路上看到不少前面的人被风吹掉的旅游帽。大概骑了半个小时,到了目的地,一个别墅,再过去就是悬崖了,悬崖不高,下面是海!在这么偏僻的地方看到悬崖,不禁想起很多肥皂剧里的那些跳崖的剧情,有点无语,当时的人们想像力还真是不够丰富啊。  悬崖上也风很大,拍了几张合影,也没什么玩的,就回去了。回去是理所当然的顺风,大概15分钟就当了,然后就是吃中饭。中饭比较合我口胃,是海鲜,但称不上大餐。价格不便宜,但也算不上贵。海鲜也是最常见的虾、蟹、鱼、花甲、扇贝,其他的就没什么值得说了,不过我还是吃了3碗饭,哈哈。  吃过中饭,就去桔钓沙。上一次去桔钓沙应该是2006年9月9日吧,记得当时小丫头不在深圳,说得她很遗憾的样子,小丫头应该很喜欢去海边玩吧。这次时节不适合下水了,风也很大,于是我只是躺在席子上用手机上网看小说,就这么过了一下午,直到4点半,打道回府。

n多bug

  今天终于发版本发出去了,但是,用别人的话说,几乎不可用。  这个版本确实进行了大幅修改,不但增加了新功能,还进行了重构,对原来使用的那一套机制50%被翻修过了。  那些出现的问题,都落在没有经过单元测试的模块,但是那些模块都是我不知道如何进行方便有效的单元测试的。  其中主要的还在于两个模块,一个是界面交互,确实不好测,另一个是数据库操作。当时的接口设计可能过于复杂了,导致后来想做单元测试时,很是畏惧。实际上,数据库操作部分,也是可以进行单元测试的,而且我想着要把本地数据库从Access换成SQLite,更是应该趁这个机会补充单元测试用例了。

马不停蹄

  今天写代码可用马不停蹄来形容,一天下来,不停地敲键盘,不停地commit,不停地收到CruiseControl的构建报告。一直到下班,回顾一下,觉得好像也没做很多事情,可能是太零碎了,写日志的时候,看了看SVN里的commit记录,确实可以写好多条。  明天就要发版本了,不知道有哪些地方落下没考虑到的!  倒是在用hhc.exe编译doxygen生成的文档时,老是崩溃,搞得我有点郁闷。本来嘛,一个工程有一个chm文档就够了,现在好了,只能用zip把众多html文件打包,要看的时候还得解压,而且解压速度不快!

在家烫火锅

  约了几个同事(F、S、W)来家里烫火锅,早上还是跟平时上班时一样准时自动醒来,已经麻木地不知道郁闷,在床上赖了一会儿,起来开电脑,看了一下更新的小说,然后无所事事,整那些代码,一直到9点多,出去剪头发。剪头发这件事已经酝酿了很久了,但一直没有兑现,今天终于狠了狠心,看了一下记录,上一次剪头发是3个多月前,汗!  剪完头发,离约定的时候还早,便又回到家中玩电脑,一直到W给我打电话,匆匆赶出去,一起去超市买菜,买了不少,我也没有估计我们食量的能力,所以就尽量多买点。  吃了两顿,挺好玩的!

bug,死循环

  昨天就发现了,程序结束时,会退不出,看样子是死循环。今天单步跟了一下,发现特别恶搞的原因,在一个while后直接一个分号,单步时还没看清楚,只是奇怪怎么一直在这一行跳,还以为VC调试器出问题了呢,汗!  中午时,突然想起来,这几天一直被之前的思路占据着,还是沿用老的那一套,结果搞得我午觉都没睡安逸,心里惦记着一件事情,真不爽啊,差点还以为之前写的都要推倒重来,下午调了调,发现还是可以保留一部分代码的。CppUnit用得还是安逸的,昨天从网上找来了CppUnitLite、CppUnitLite2、GoogleTest、UnitTest++几个测试框架,打算稍微看一下,最后选择其中一种来用。先看了CppUnitLite,没有文档,有一个简单的demo,对我来说,上手太不容易了。我估摸着,最终还是会继续使用CppUnit的。  又有人提到加强编辑器的联想功能了!VAX确实可算是所有代码编辑器自动提示功能的典范,我们一直在说,我们做不到像VAX这种程度,是因为Ruby动态语言的特征,不能通过静态分析得到某个对象的类型。我有时在想,假如我们用的是C++,我们能做到像VAX那种程度吗?针对这个问题,我回了一封邮件给老大,分析了VAX的自动提示功能分成三部分来做,我们有什么对应的策略。这三部分分别是,分析源代码,得到各种变量、对象的类型进行提示;编辑代码片段,设置快捷键进行提示;加入拼写检查,可在一定程度拼写错误的情况下,进行提示。第一点,需要一个完善的语法分析器,目前我们没有;第二点,技术要求不高,原来我也想过要做,结果被其他事缠着,就搁浅了;第三点,从来没有研究过,没有技术积累,根本不知从何下手。邮件发出去,估计老大也是眼睁睁地看着没有办法,所以什么回应都没有。

搞定弹出Windows域账户对话框

  今天上午下决心问了一下同事,又用proxy登出外网,搜了几下,终于搞定通过弹出Windows域账户对话框来输入新的用户名。代码在codeproject上有完整的,效果很好。弄得我心情很愉快,自我感觉良好,极大的改善了易用性啊!  完成了这个后,却没有做多少其他事情。其实我也没有多少懈怠,只是偶尔停下来休息一下,但进展确实很缓慢。我现在丝毫不怀疑单元测试的作用和必要性,尽管它似乎花我了不少时间,但我总觉得是值得的,无论是对我心情的调节,还是对代码质量的保障,都有很大作用。  后来主要集中精力在做组织结构管理模块。该模块将数据保存在远程数据库中和本地配置文件中,而两个地方保存的数据的格式差别比较大,读出来的还需要再互相转换一下。这不但需要多写不少代码,而且可以预见到的是,也会占用不少执行时间。我都开始怀疑当时把两边的格式差异弄得这么大,是否很不明智。结果到下班,还是没有完全搞定格式转换部分,只好明天继续了。另外想起来,应该提供一种途径,可以执行一些特权操作,比如明确从某配置文件加载数据,明确将数据写入数据库等等。总的说来,机制部分基本做得差不多了,后面实现用户交互部分应该没有多少工作量了吧!

又被培训了一下ruby

  今天又培训了一把ruby,再次让我感受了一遍ruby的强大,真是一个无所不包的魔幻型语言啊!  开始,老大先演示了一个分布式ruby包的应用,几行代码,就能实现一个服务器端组件,再几行代码,又实现了一个客户端,调用了服务器端的对象,其简便程度太让人吃惊了。这种应用很能吸引人,特别是可以做一些加密功能。但我想我还是不放心就这么去用它的,我很担心它的性能。反正WEBrick开的Gem server有内存泄漏问题,就一直让我对ruby做实际应用持有怀疑心理。在我看来,也许脚本语言的真的主要战场在字符串处理上,写个小程序也许可以应付,开发成本比起C++来确实低得多,但做稍微有点规模的应用,就还是让C++来吧。  而Lua这种,在我看来真的还是用来做为C++应用的扩展机制,描述一下插件逻辑,我想不出还有哪里能更适合它的,和还有哪个脚本语言比它更适合来做这个的了。  Ruby让我最不爽的是,对嵌入支持不好,《Programming Ruby》一书就提到,ruby不是设计成用来嵌入的。不过我在想,以我目前的需求,即使要嵌入,一个进程用一个解释器应该能满足需要了。看公司那个项目里,为了让嵌入的ruby解释器多做点事,就创建了一个又一个新的工程来嵌入,也是一种解决办法啊,哈哈。