WM有约II(九):再谈部署
WM有约II(九):再谈部署
Written by Allen Lee
当多语言应用程序遇到CabWiz……
创建安装包的方法非常简单,如果你对此没有了解,我建议你先去阅读《WM有约(五):部署应用程序》。安装包创建好后,拿到模拟器里安装,安装好后,你可以在"开始"菜单的"程序"里找到应用程序的图标:
图 1
因为我们在简体中文系统上运行应用程序,而简体中文又是应用程序支持的语言,所以应用程序会使用简体中文作为当前语言:
图 2
由于简体中文系统也支持英文,当我们在选项窗体里把当前语言改为英文时,应用程序应该能够正确显示英文界面,然而,事实并非如此!
图 3
问题究竟出在哪里?是当前语言设置出错吗?我修改代码,通过MessageBox显示当前语言,发现已被正确设为英文。当我通过Visual Studio部署到模拟器时,一切正常,而当我通过安装包部署到模拟器时,英文界面就变成上面这样了,这意味着资源文件本身应该是没问题的,但安装包里的资源文件可能出错或者损坏了。我不知道有没有第三方的安装包创建工具,如果没有的话怎么办?难道无法为多语言应用程序创建安装包?
在Windows Mobile 6 SDK文档里找到这么一段话:
Files that are packaged into a .cab file to be installed on a device are stored by file name, without regard to their installation directory. For this reason, if multiple files within a .cab are given the same name but different install directories, only one of the files will be installed in all locations. To work around this behavior, be sure to use unique names for all files within a single .cab file.
这么看来,CabWiz在创建安装包的时候,误把简体中文和英文资源文件看作一样的了,因为它们的名字是一样的。怎么解决这个问题?Jose A. Garcia Guirado给出了解决方案:
你可以按照他的方法手动修改INF文件和运行CabWiz,也可以使用他的工具自动化这个过程。创建好正确的安装包后,拿到模拟器里测试,这次就正常了:
图 4
值得提醒的是,如果你修改了应用程序,想重新创建安装包,你可以在命令行里运行CabWiz,并向它传递修正的INF文件,或者使用Jose在上面那篇文章里提到的方法,不要重新编译安装包项目,因为这样会覆盖修正的INF文件,并产生有问题的安装包。
让部署更简便
对于资深WM玩家来说,程序员的任务已经结束了,然而,如果你让普通WM用户把CAB文件拿到手机里安装,他们要么用问题轰炸你,要么把应用程序打进冷宫,显然,这些都不是你想要的结果,怎么办?
一个办法是为应用程序创建一个MSI安装程序,协助用户把应用程序安装到手机里,怎么创建呢?Christopher Tacke写了一篇文章,详述整个创建过程:
然而,这个过程非常繁琐,虽然客户乐了,可也不能苦了程序员,再说,这个办法会把包含Custom Action的DLL安装到桌面电脑里,显得有点多余,说白了,它其实就是调用CeAppMgr.exe,并把描述应用程序的INI文件作为参数传给它,这样的话,为什么不直接创建一个简单的应用程序来执行这个任务呢?
于是,我用Expression Blend创建了一个Cab Installer:
图 5
Cab Installer在启动时会判断ActiveSync是否已经安装,如果没有安装,它会禁用Install按钮:
代码 1
而CeAppManager则通过查找注册表来确定CeAppMgr.exe是否已经安装:
代码 2
当用户单击Install按钮时,Cab Installer会调用CeAppManager.Install方法来安装应用程序,为了避免用户多次单击Install按钮,Cab Installer在调用CeAppManager.Install方法后会禁用Install按钮:
代码 3
而CeAppManager.Install方法则负责启动CeAppMgr.exe,并把INI文件的完整路径传给它:
代码 4
编译Cab Installer项目,把CabInstaller.exe、Trombone.cab和Trombone.ini三个文件放在同一个文件夹里,然后运行CabInstaller.exe。当用户单击Install按钮时,Cab Installer将会启动CeAppMgr.exe来完成后续工作:
图 6
目前,Cab Installer和应用程序紧密耦合,不过,要让它服务其它应用程序也是很容易的,我们也可以把它改成通用安装程序,通过配置文件来指定应用程序的图标和名称、安装程序上显示的文字以及Cab文件等。说到这里,你可能会问:"能否通过它来部署.NET Compact Framework?"我试了一下,答案是可以的,但我不知道如何获知目标设备是否已经安装了所需版本的.NET Compact Framework,这可能会导致重复安装,如果有办法获取这个信息,那么Cab Installer就有一般化的价值了。
尼古丁解决方案
既然安装了应用程序,不妨运行一下,看看上次的本地化是否足够彻底。噢,有点不妥:
图 7
这个日期和时间格式是英文的,查看DateTimePicker的属性窗口,发现这个格式是当初硬编码进去的,怎么处理?一个办法是通过CultureInfo.DateTimeFormatInfo获取格式信息,并设置DateTimePicker.CustomFormat属性:
代码 5
修改一下主窗体的构造函数,然后重新部署应用程序,再来看看运行效果:
图 8
图 9
简体中文的格式没问题了,却轮到英文的格式出问题了!为什么会这样?原来,DateTimePicker只是使用我们提供的格式,而格式里面指代的"上午符号"和"下午符号"则从设备的区域设置里获取,假如我们在设备的区域设置里把它们分别设为"OK"和"KO",那么我们的应用程序也会跟着改:
图 10
.NET Compact Framework的区域设置是基于每个设备而不是每个线程的,而我们的应用程序却允许不同于设备的区域设置,于是出现了假设性冲突,怎么处理?既然我们的假设和.NET Compact Framework的有冲突,那就惟有放弃使用它提供的日期和时间格式,我们可以把这个格式放在对应的资源文件里,然后在当前语言更改时把它读到DateTimePicker.CustomFormat属性。
这个办法虽然解决了我们的问题,却引入了另一个问题,就是从今以后我们要自己管理日期和时间的格式了,这不禁让我想起温伯格在《你的灯亮着吗?》里的一句话:
每种解决方案都会带来新的问题。
从本质上来说,我们没有解决问题,而是对它应用"变换"和"转移"这两种操作,正如温伯格在《你的灯亮着吗?》里说的:
有时候,我们使问题变得不那么棘手,其实只是把问题放在"别人家的后院儿里"。
温伯格把这种技巧叫做"转嫁问题",事实上,我们每天都和"转嫁问题"打交道,当客户把项目交给你时,他其实是在使用"转嫁问题",只不过他需要为此付你报酬,从这点来看,"转嫁问题"实质上是"价值交换",正因为这些层出不穷的问题,人类社会才得以延续下去。
"转嫁问题"有一个有趣的推论,QQ空间的抢车位是这个推论的其中一个完美的体现。这个游戏是免费的,除了你的时间之外,它"似乎"无需其它支出,纵观到目前为止的众多更新,你不难发现它在努力创建一个更好的"竞争视图",你可以很方便地看到自己在整个圈子里处于一个什么竞争状态,利用人的攀比心态是腾讯成功的秘诀之一,当大家都沉浸在这个游戏里时,它推出了"管家服务",如果你没空停车,但又不希望排名落后于他人,那么你可以通过支付一定的费用雇佣管家来帮你停车,免除你的烦恼,这是一个非常水到渠成的解决方案,然而,当你沉浸在这个游戏里时,你怎么也想不到,你花钱雇用管家来解决的烦恼正是这个游戏导致的!噢,这不禁让我想起Allen Carr在《这书能让你戒烟》里的一句话:
吸烟者点燃香烟的目的是缓解尼古丁戒断症状,而这症状正是由吸烟导致的。
我把这种做法称为"尼古丁解决方案":
你现在为人们解决的问题,正是你当初为他们种下的问题。
为了打破人们的心理防线,"尼古丁解决方案"通常会和"免费策略"结合使用,虽然人们通常不会认为免费的东西是什么好东西,但免费这个特性很容易让人们产生"不高兴可以扔掉"的想法,这种派生出来的"零成本自由"恰恰就是让人们上当的诱饵。噢,感觉我们像在探讨魔鬼的手段,内心似乎多少有些抗拒,哈哈,这其实是因为社会文化让我们有了先入为主的观念,正如李子勋在《幸福从心开始》里说的:
物质存在的本身没有对错的,但人类社会的有序存在需要秩序,所以对错就被发明出来。
我本人并不吸烟,我看《这书能让你戒烟》是想了解"戒瘾原理"和"成瘾机制",前者可以用来打破旧有规则,后者则可以用来建立新的规则,当然,我主要想知道"戒瘾原理"是否适用于其它成瘾行为。
最后……
如果你足够细心,或许你会发现,在这个系列文章里,我从未使用Trombone来称呼这个应用程序,这是故意的,因为我想把这宝贵的第一次留给此刻,之所以取名Trombone是为了纪念我和一个人的关系,而这个人是玩长号的。
和那些WM高手相比,我只是一个接触WM开发还不到半年的初学者,在这个过程里,我学到很多东西,也得到很多乐趣,我希望这些文字能对其他WM初学者有所帮助,当然,如果WM高手也能有所得益就更好了。
嗯,我知道你想说什么,源代码是吧,我已经把它放在Codeplex上了,单击下面连接就能找到了:
那么,下一季玩点啥呢?嘘,萨斯顿三原则第一条:
魔术表演之前绝对不透漏接下来的表演内容。