GMobileSync出现事件重复的bug
Outlook中新建一个Appointment,同步到Google Calendar,然后马上再同步一次,Outlook中就会出现两个同样的事件,但第三次同步就不会出现更多的重复了。
调试之后找到了原因:
新建的Appointment同步到Google
Calendar时使用的queryUri是”http://www.google.com/calendar/feeds/default/private/full”,
同步完返回的EventEntry的absoluteUri的形式为
http://www.google.com/calendar/feeds/default/private/full/9ess8r22fljetplumv3rkmfitk
然后程序把Appointment的id和EventEntry的absoluteUri存入GMobileSync.xml用于下次同步时使用。
在下一次的同步中,先从gCal中获取所有的Event,这个被新加到gCal的事件的absoluteUri将变成如下的形式:
http://www.google.com/calendar/feeds/owenib%40gmail.com/private/full/9ess8r22fljetplumv3rkmfitk
这样,在上次同步的列表中将找不到这个absoluteUri对应的Appointment
ID。于是程序误认为这是一个新Event,于是就在本地新建一个Appointment,然后把Appointment
ID和这个absoluteUri保存到GMobileSync.xml中。所以,第三次同步就不会再有重复。
不知道为何今天才发现这个错误,我之前的使用过程中不可能没出现过这样的操作,但是没遇到过这样的现象。难道Google Data
API调整了插入Event时的返回值?
解决办法比较简单,因为absoluteUri的改变不过是把default换成了你的email账号。你可以把absoluteUri存入GMobileSync.xml之前先手动把default转换一下。
不过我换了另外一个更简单的方式,只保存absoluteUri的最后一部分:9ess8r22fljetplumv3rkmfitk。
当然,理论上会有重复的可能。比如我的gCal中添加了别人的Calendar,那么下载下来的event可能和我Calendar里面的event有同样的后缀。
不过,概率太太太小了。
GMobileSync还有很多可以改进的地方,比如指定下载的Calendar以及指定默认把事件添加到哪个Calendar。
有空再加上这个功能。
GMobileSync开发环境搭建
前期的准备工作。
首先,搭建Windows Mobile开发平台,很简单,依次装下面这些软件就可以了。
- Microsoft Outlook 2 003。(Microsoft ActiveSync依赖它)
- Microsoft ActiveSync 4.5。(用于同步手机和模拟器)
- Visual Studio .Net 2005。(安装C#的时候要选上smart device)
- Windows Mobile 5.0 Pocket PC SDK。(GMobileSync采用WM5.0的SDK)
- .NET library for the Google Data API。
打开GMobileSync工程,在项目的References中,引用了
Google.GData.AccessControl
Google.GData.Calendar
Google.GData.Client
Google.GData.Extensions
如果引用无效,则重新在菜单Project -> Add References里面添加一下引用,对应的DLL文件在C:\Program Files\Google\Google Data API SDK\Redist\Mobile\WindowsMobile目录下。
第二步,如何调试。选择菜单Debug -> Start Debugging 之后会出现deploy对话框。如果你有手机并已经连线,你可以选择Windows Mobile 5.0 PocketPC Device ,或者你也可以选择Windows Mobile 5.0 PocketPC Emulator。
如果选择了Emulator,部署完成之后需要执行下面的步骤来建立网络连接:
- 在Tools菜单中打开Device Emulator Manager。
- 我们刚刚部署完成,可以看到Windows Mobile 5.0 PocketPC Emulator前面显示了一个绿色的箭头,表示模拟器正在运行。
- 在Windows Mobile 5.0 PocketPC Emulator上点击右键,选择Cradle。
- ActiveSync应该会自动和Emulator建立连接。如果没有,就在ActiveSync的菜单里面选择File -> Connection Settings。在打开的对话框中选中 Allow connections to one of the following,在它的下拉菜单中选择DMA。然后点击对话框右上角的Connect按钮,完成连接。
- OK,此时在模拟器上已经运行GMobileSync,可以测试它的功能了。
简单的看了一下 GMobileSync源代码。
- 程序的主要逻辑集中在frmMain.cs和GMobileSync.cs中。
- 程序的配置信息存放在/Application Data/GMobileSync/GMobileSync.xml中,包括用户名,密码,时区,上次同步过的事件等等。
- GMobileSync.IsReallyConnected() 会尝试下载”http://rareedge.com/gmobilesync/connected.txt”,如果下载成功则表示WAP连接已经建立。感觉这种方法会影响速度,毕竟要访问国外的网站然后把文件下载下来。如果WM SDK中带有测试Internet连接的API,这里就可以得到改进吧。
- Google Calendar中的每个Event会有一个唯一的URL地址,Mobile Outlook里面的每个Appointment有一个唯一的ID。GMobileSync.xml里面会保存上次同步过的事件,形式就是<Appointment ID, Event URL>的pair。
- 为了日历的双向同步,需要能检查 Appointment或者Event是否改变。程序会为Appointment和Event计算md5,并且保存为Appointment的属性,GmsGoogleChecksum是Event的md5,GmsLocalChecksum是Appointment的md5。
GMobileSync的同步流程:
GMobileSync的同步流程:
- 从Google Calendar中下载同步日期间的所有Event。
- 对于每个Event
- 出现在上次同步的列表(列表信息记录在GMobileSync.xml中)中
- 找到本地对于的Appointment,计算远程Event的md5 checksum,与本地Appointment的“GmsGoogleChecksum”属性比较
- checksum不相同,则用远程的Event信息更新本地的Appointment。
这说明如果自上次同步之后,本地和远程都对事件修改过,那么以远程修改为准,本地修改将被丢弃。 - Checksum相同,do nothing
- checksum不相同,则用远程的Event信息更新本地的Appointment。
- 找不到本地对应的Appointment,则Appointment自上次同步后在本地被删除,删除Event。
此时,远程修改将被丢弃。
- 找到本地对于的Appointment,计算远程Event的md5 checksum,与本地Appointment的“GmsGoogleChecksum”属性比较
- 不在上次同步的列表中,则根据Event信息新建Appointment。
- 出现在上次同步的列表(列表信息记录在GMobileSync.xml中)中
- 从Mobile Outlook中取得同步日期间的所有Appointment。
- 对于每个Appointment
- 存在“GmsLocalChecksum”属性
- 计算当前Appointment的md5 checksum,与记录的checksum比较,可以知道Appointment是否在本地被修改。
- 根据“GmsSelfUri”属性找到Appointment对应的Event的URL,然后测试Event是否存在。
- Event不存在,则删除本地Appointment。本地修改将被丢弃。
- Event存在,且Checksum不同,则更新远程的Event。
- Event存在,且Checksum相同,do nothing。
- 不存在“GmsLocalChecksum”属性,新Appointment,添加到Google Calendar。
- 存在“GmsLocalChecksum”属性
五句话
zz from 快乐时间不工作
第一句话:优秀是一种习惯
这句话是古希腊哲学家亚里士多德说的。如果说优秀是一种习惯,那么懒惰也是一种习惯。人出生的时候,除了脾气会因为天性而有所不同,其他的东西基本都是后天形成的,是家庭影响和教育的结果。所以,我们的一言一行都是日积月累养成的习惯。我们有的人形成了很好的习惯,有的人形成了很坏的习惯。所以我们从现在起就要把优秀变成一种习惯,使我们的优秀行为习以为常,变成我们的第二天性。让我们习惯性地去创造、思考,习惯性地去认真做事情,习惯性地对别人友好,习惯性地欣赏大自然。
第二句话:生命是一种过程
事情的结果尽管重要,但是做事情的过程更加重要,因为结果好了我们会更加快乐,但过程使我们的生命充实。生命本身其实是没有任何意义,只是你自己赋予你的生命一种你希望实现的意义,因此享受生命的过程就是一种意义所在。
第三句话:两点之间最短的距离并不一定是直线
在人与人的关系以及做事情的过程中,我们很难直截了当就把事情做好。我们有时需要等待,有时需要合作,有时需要技巧。你一定知道两点之间直线距离最短,如果你在走路,从A到B,明明可以直接过去,但所有人都不走,你最好别走,因为有陷阱。
第四句话:只有知道如何停止的人才知道如何加快速度
我在滑雪的时候,最大的体会就是停不下来。刚开始学滑雪时没有请教练,结果从山顶滑到山下,实际上是滚到山下,摔了很多个跟斗。最后我反复练习怎么在雪地上、斜坡上停下来。练了一个星期,终于学会了在任何坡上停止、滑行、再停止。这个时候我就发现自己会滑雪了。因为我知道只要我想停,一转身就能停下来。只要你能停下来,你就不会撞上树、撞上石头、撞上人,你就不会被撞死。因此,只有知道如何停止的人,才知道如何高速前进。
用汽车来比喻,宝马可以上200公里,奇瑞却只能上120公里,为什么?发动机估计不相上下,差距在刹车系统,上了200公里刹不了车!
第五句话:放弃是一种智慧,缺陷是一种恩惠
当你拥有六个苹果的时候,千万不要把它们都吃掉,因为你把六个苹果全都吃掉,你也只吃到了六个苹果,只吃到了一种味道,那就是苹果的味道。如果你把六个苹果中的五个拿出来给别人吃,尽管表面上你丢了五个苹果,但实际上你却得到了其他五个人的友情和好感。以后你还能得到更多,当别人有了别的水果的时候,也一定会和你分享,你会从这个人手里得到一个橘子,那个人手里得到一个梨,最后你可能就得到了六种不同的水果,六种不同的味道。人一定要学会用你拥有的东西去换取对你来说更加重要和丰富的东西。所以说,放弃是一种智慧。
做人最大的乐趣在于通过奋斗去获得我们想要的东西,所以有缺点意味着我们可以进一步完美,有匮乏之处意味着我们可以进一步努力。当一个人什么都不缺的时候,他的生存空间就被剥夺掉了。如果我们每天早上醒过来,感到自己今天缺点儿什么,感到自己还需要更加完美,感到自己还有追求,那是一件多么值得高兴的事情啊!
Powered by Zoundry Raven
什么都想做,什么都没有做
GMobileSync有时候会出一些问题,为了弄清原因,这几天把它的源代码看了一下。官网最新的Release是2007年12月23日的1.3.6。不过在版本库里面,还有更新,我直接checkout最新的源代码看的。最新的版本里面比1.3.6有不少改动,比如可以同步Google Calendar里面的多个日历,可以为事件添加参与人,事件名称后面还加上了创建者的名称。不过这些功能我都用不上,我在源代码里面把这些功能屏蔽了。把这个版本放到手机上之后,目前还没出问题。
看完源代码,激发了我写个类似软件的兴趣我想以GMobileSync为基础,自己从头写一个类型的软件,同时加入同步联系人的功能。这两天倒弄了一下Google Contact API,也学了一点Window Mobile开发环境的东西,但是距离做出实际有用的东西还差很远。要做一个好软件不容易,我现在连软件名字也没有想,实验室还有很多工作要做,我能坚持下去写出一个真正可用的手机软件吗?
我什么都想做,结果什么都没有做。
年会之升级赛
中心年会在九华山庄召开,第一天晚上进行扑克牌比赛.
最初有八对选手报名,但是老板临时加入,又拉进几个人,所以第一轮用了非常规的方法:4个组,每组5个人.比赛方式是2vs3,打三副牌,每个人记各自的分数取小组前两名进入下一轮。每一局庄家的盟友是开打时自己叫牌指定的,比如叫第二个黑桃A,就说明第二个出黑桃A的人就是庄家的盟友。这种方式有时候会出现尴尬的1vs4的情况。师姐就出现过一次,叫第一张黑桃A,然后自己出犯错第一个把黑桃A出了,就成她1vs4了。
第一轮四个分组,我所在的组都是学生,水平都一般,高手都集中到其他组了。我们这组人都觉得其他组的规则太复杂,就干脆再拉进来一个人3v3,至于要出线的两个人就最后抽签。徐薇就和我们急,说我们太没技术含量了,呵呵。
经过一个半小时的’苦战’,我们组秉承和谐游戏的宗旨,也不抽签了,自由申请出线,于是我和涂强进入第二轮。第二轮名单确定后,其他组出线的都是高手,我和涂强就想组一队,免得拖别人后腿。结果老板发话了,随机抽签。我和涂强这对送分童子就被拆散了。不过我运气很好,抽签和姜金荣师兄组队,他可是实力派选手啊,不过我心里一点都不高兴,反而担心自己拖他后腿。半决赛对阵老赵和程强。从2开始打,一个小时后打成7比7,然后经过1轮加赛,我和姜师兄艰难晋级决赛。
另一个赛场,涂强和金钟也战胜对手和我们会师决赛。很意外,我和涂强居然要战斗到最后一刻。决赛一共三局,第一局姜金荣做庄,没有悬念。第二局我的庄,牌不错,不过我失误被罚了20分,底牌埋了分又没保住底。被对手抓了70分,虚惊一场。第三局对手必须抓到200分才能赢,或者160分打加赛。不过姜师兄牌又不错,我们就有惊无险的赢得了决赛。
奖品是200块的购物卡,哈哈,运气真好。不过涂强可惜了,只有冠军有奖,亚军没有。
Powered by Zoundry Raven
七上八下
每天的心情就是七上八下。
昨天下午,百度又让我去面试,让我心里又燃起了一丝希望。听师兄说,还是系统部,上次系统部面试,是10月11号。都两个月了!
然后,昨晚,EMC终于有动静了。很多人收到拒信,也有人说收到offer。可是我啥也没有。我也只好再安慰自己,no news is good news. 晚上睡觉还在想,说不定明天就给offer了。今天上午,继续不停地刷水木,北邮,上交的BBS。有人说offer已经发完了,没拒信没offer的人就是在waiting list。我不愿相信,然而没多久,突然弹出邮件提醒,EMC的邮件,我心一颤,但是打开扫了一眼,没看到”Thank you”的字眼,再仔细看了一遍,既不是offer,也不是拒信。应该就是waiting list了。hdd,盈mm也都收到了这封信。再刷BBS,看到不少人在讨论,看来有不少人收到了这封信。
额,心情反复无常,这样的日子,何时是个头。什么都不想做,明天上午就要做年终总结,可我到现在,一个字都没写。
Powered by Zoundry Raven
苦闷
罗罗拿到完美时空的offer,凯歌拿到腾讯的offer。
只要努力坚持,都会有好结果的。
而我,继续苦闷的等着奇迹的发生。EMC今年招人肯定不多,另外,虽然我自己感觉面试很好,但是我很害怕那句话,面试者的感觉和面试官的感觉往往是相反的。
我一直认为自己实力比一般同学要好,现在觉得自己错了。实力是一个综合的素质。虽然在专业知识、编程能力上确实比一般同学要强一点,但是在其他的一些方面,我就要差很多。
太懒。很多公司都没投,有些是自己觉得希望不大,有些则是纯粹的懒于去投。一件事情如果没有很大的把握,我就不会去做。我这种性格,要想成事,太难了,需要大把大把的运气。道理再简单不过,机会总是自己去争取的,而且机会只会留给有准备的人。要是真的天上掉馅饼,我还不一定接得住。
没毅力。找工作确实是个艰难的过程。每天的心情跌宕起伏,我根本没法静下心来准备什么。面完微软,我就坚持不下去了。打游戏,逛BBS,完全不想看书了。
表达能力不行。
远程控制实验室机器
实验室有强大的防火墙,而且管理很严格。封了很多端口,比如浩方,QQ游戏,电驴。
一直都想着在寝室的时候如何去远程控制实验室的机器。一般的远程控制软件都是要在被控制的机器上装一个server,监听外部的连接请求。然后我从另外一个机器上运行client,连接到这个server,进行远程控制。但是因为防火墙的存在,从外面主动去连接实验室的机器,是不可能连接上的。
其实我一般也就想远程控制实验室的机器下点电影什么的。不需要实现真正的远程控制。我可以把要下载的文件链接或者bt种子放在一个公共的ftp上面,然后实验室的机器上跑一个程序,每隔几分钟就去ftp上查一下,自动把bt种子下载下来,然后自动开始bt下载。
这样做起来很简单,但是功能太弱,不好做复杂的下载任务。另外还有一个问题。我想使用DriveHQ提供的免费文件服务做ftp中转,这种网站会不会限制你每天的连接次数?如果我频繁的去连接,有可能被封帐号。
于是为了更强大的控制,我要尝试另外的方式–QQ的远程控制。实验室机器上运行一个qq,然后主动的向别人发起远程控制的请求,可以穿透防火墙,实现远程控制。我要解决的问题即使如何让实验室的机器主动发起请求。
以前用过PAMIE来做自动填表。它就是自动在网页上找控件,然后做填表或者点击的动作。当时还看到过自动处理windows窗口事件的demo。是不是也可以类似的自动操作QQ聊天窗口呢?
搜到一个例子,思路就是找窗口和控件的句柄,然后向句柄发送消息。我也要这么办,而且用可爱的Python来实现。不过我需要先安装pywin32,它提供了win32api的python支持。另外,有一个很有用的辅助工具Spy++。用FindWindow和FindWindowEx查找句柄时,它可以辅助编程。另外它可以监听窗口的消息以确定人手动进行正常操作时产生了哪些事件。
如果你在和一个昵称为”owen”的人聊天,那么聊天窗口的标题就是”owen”,下面的代码可以找到这个聊天窗口,然后最小化窗口。
import win32gui,win32con dlg=win32gui.FindWindow(None,"owen") win32gui.ShowWindow(dlg,win32con.SW_MINIMIZE)
当然,我要做的事情可不是简单的最小化窗口,我需要找到窗口中的控件,然后做点击操作。可以用FindWindowEx来查找窗口内部的控件。很遗憾,经过我多次尝试,我用FindWindowEx只能找到一个子句柄,而这个子句柄没有自己的子句柄。这和我设想的不太一样。我原先认为我可以找到远程控制的button,然后发送鼠标点击的事件。但是我现在找不到button的句柄,就没法做下去了。我水平太低,QQ应该是故意设计成这样来增加设计外挂的难度的,不然我都能轻松的写一个外挂出来,QQ的安全性何在?
此路不通!怎么办?
我不是真的要设计外挂,所有可以用笨一点,不通用但是实用的办法:模拟鼠标点击。
思路:把聊天对话框移动到屏幕的左上角,然后在固定的位置模拟鼠标依次点击:”应用”,”远程协助”。然后等待对方确认连接之后再点击”确认”和”申请控制”。代码如下:
#在屏幕的(x,y)位置点击鼠标左键
def click_at_pos(x,y):
win32api.SetCursorPos((x,y))
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN,0,0,0,0)
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP,0,0,0,0)
def startRemoteControl():
# 找到聊天对话框
dlg = win32gui.FindWindow(None,'owen')
# 还原对话框(之前可能是最小化的状态)
win32gui.ShowWindow(dlg,win32con.SW_RESTORE)
# 对话框移动到屏幕的左上角
win32gui.MoveWindow(dlg,0,0,0,0,1)
# 激活对话框,提升到所有窗口的前面
win32gui.SetForegroundWindow(dlg)
# 点击 应用,下面的两个坐标都是试出来的。
# 因为窗口移动到左上角后,这些按钮的位置就固定了。
click_at_pos(320,60)
# 点击 远程协助
click_at_pos(320,100)
# 等待对方同意远程协助
time.sleep(15)
# 点击 确认
click_at_pos(400,450)
# 等待连接建立
time.sleep(15)
# 点击 申请控制
click_at_pos(400,450)
经过测试,上述代码可以成功的建立远程控制。
现在的问题就是什么适合发起远程协助的请求?
监听QQ的聊天内容?有点难度。聊天?恩,我曾经用Python写过MSN机器人呐,给MSN机器人发消息,然后机器人去调用上面的代码,发起远程协助。爽!
只需要简单的改动机器人代码中,收到消息后的回调函数。另外,我根据不同的消息内容来做不同的操作。原来的startRemoteControl中,发起远程协助的请求之后要等待对方确认,默认等待15秒。如果对方在收到请求后15秒内没有响应,上面的代码还是会继续执行,就达不到建立远程连接的效果了。如果把默认等待的事件调长,又可能会让接受请求方等待的时间变长。所以,把startRemoteControl分为3步,根据msn机器人收到的消息内容决定做哪一步操作,就可以解决这个问题。
def handle(m,email,msg):
if email=='msn@live.com' :
if msg=='1':
# 点击 远程协助
dlg = win32gui.FindWindow(None,'owen')
win32gui.ShowWindow(dlg,win32con.SW_RESTORE)
win32gui.MoveWindow(dlg,0,0,0,0,1)
win32gui.SetForegroundWindow(dlg)
click_at_pos(320,60)
click_at_pos(320,100)
elif msg=='2':
# 点击 确认
click_at_pos(400,450)
elif msg=='3':
# 点击 申请控制
click_at_pos(400,450)