Windows Phone 7上面的通信方式和限制

最近在看WP7通信相关的内容,做个小结。

首先说说什么可以用(from Networking in Silverlight for Windows Phone):

  • WCF,也就是Windows Communication Foundation,微软力推的(把WSE拍死在沙滩上的)新一代框架,面向服务但是用起来对OOP程序员友好(不过细节上说起来就不行了,例如不能直接支持重载之类),消息基于SOAP Message。扩展性很好。后面会专门提到WP7上的WCF。
  • 大名鼎鼎的WebClientHttpWebRequest。这两个类是MS在System.Net中对于Socket的封装。
  • 上面两类通信的基本验证(Basic authentication)功能,以及设定user-agent的能力。
  • Push Notification。也是微软力推的一个服务,和Azure合体的话能做出不错的东东,例如现在Marketplace里那个”Send to WP7″程序。

你可能会问了,Socket呢?蓝牙呢?Wifi控制呢?Socket的话,微软的意思就是让你安心用WebClient去做HTTP请求吧,至于什么监听端口啊拆包啊之类就不要想了。虽然有人(搜Jeremish Morrill)Hack出了直接访问Socket的方法,但用本地代码也只能得到接口,上层封装——包括各种System.Net内的框架类(IPEndPoint之类)——都写出来工作量不会小,弄不好写完时候API已经开放(虽然去年这个时候MS就说“未来会开放”)。

而蓝牙……至少在开放的API中没有看到任何消息。现在连文件对传都不行,所以估计一时半会没法实现。最后,有关Wifi:对于一般的程序而言,网络访问是系统全局控制的,程序没有办法选择是利用蜂窝网络还是Wifi作为访问方式。不过可以得到当前的网络类型:

NetworkInterface.NetworkInterfaceType

CodeProject上有人封装了一个网络相关的类用于检测网络类型以及判断手机各种连接状态(包括Zune连接),很好用,文章和代码见Zune Detection and Network Awareness

另外,还要注意,Silverlight在WP7上和其他版本的Silverlight也有不同,例如NTLM认证、UDP多播和Silverlight的Tookit网络功能都无法使用,更多信息可以参考Differences Between Silverlight and Silverlight for Windows Phone

好了,现在来说最后一个话题,WP7上的WCF。之前在桌面平台以及Silverlight里面用过WCF的同学们要失望了:WP7上的WCF纯粹就是一充满了太监类的太监框架。先来看看我这几天在学习过程中遇到的各种不支持:

  • 不支持basicHttpBinding以外的各种内置Binding方式,同时也就是说:
  • 不支持Duplex方式访问,无法进行有session的访问以及服务器端的回调,同时也就是说:
  • 不支持PerCall之外的另两种服务实例的维护方式(PerSession, Singleton),你每一次访问服务都会创建/销毁一次Service实例(靠……)
  • 不支持自定义Binding
  • 不支持代码自定义创建Channel和Client,只能使用SLsvcutil.exe创建或者用IDE的Add Web Reference
  • 不支持basicHttpBinding的大部分属性(……),我这边试了一下,代码中只能修改MaxBufferSize和MaxReceivedMessageSize,剩下的必须在.config里面配置。

好了,这么看来,WCF在WP7上的可玩性真的不高,我能想到的就是远程控制之类的单向消息程序,顺带一提”PC Remote for WP7″和“LazyAdmin”就是基于WCF的。今天决定好好学学WCF,推荐这个教程《我的WCF之旅》和《WCF后续之旅》,作者是WCF和分布式开发的大牛,写过《WCF技术剖析》,是难得的在布教微软技术以及本身技术能力方面都强大的MS MVP。

发现这篇Blog多数都是在说“不支持”,没有办法,现状如此。但就算如此也有很多牛逼的程序被做出来,例如GoVoice和FreeTalk这两个Google Voice的客户端,还有前两天出来的那个Youtube客户端。

在Windows Phone 7上获取原始摄像头数据

此篇文章只是拾人牙慧而已,顺带总结过程避免浪费脑细胞。过程比较曲折,也希望遇到的各种问题和错误解决过程能给后来的同学们省时间。

周末拿到HD7后一直在摆弄,发现了一个可以使用对焦摄像头的第三方程序,还有大名鼎鼎的ZXing Barcode的WP7移植版。当时觉得奇怪,因为按照之前看过的教程来看,微软开放出来的摄像头接口只有一个PhotoTask,作用是切换到内置摄像头程序,等用户拍照完毕后返回照片数据,无法直接在程序中打开摄像头查看图像。于是祭出神器Reflector查看,它用到了Microsoft.Phone.Media.Extended.PhotoCamera和VideoCamera类。然后通过ZXing的代码验证,确实如此。

打开VS2010 Express创建工程,却发现根本没有这类——连Microsoft.Phone.Media.Extended这个程序集都没有。顺藤摸瓜找到了Den Delimarsky写的两篇文章Not your regular photo and video camera on Windows Phone 7和How VideoCamera/PhotoCamera content is saved on Windows Phone 7,前一篇介绍了如何使用PhotoCamera和VideoCamera进行摄像头图像实时显示,后一篇则是介绍怎么取到拍照后的数据,写得很棒,通俗易懂。文章中提到:

通过反射调用摄像头比较慢而且增加多余的代码。所以我转而使用GAC程序集“GAC_Microsoft.Phone.Media.Extended_v7_0_0_0_cneutral_1.dll”,由于是托管代码,所以就不用加上WMInteropManifest.xml文件(或者<Capability Name=”ID_CAP_INTEROPSERVICES”/>)了。

并且提供了GAC Dump(可以看作未开放API程序集的集合)下载。不过没有详细教程,于是搜了一下实现GAC Dump的牛人Thomas Hounsell的Blog,找到了方法 Avoiding Reflection: Adding the InteropServices library to the WP7 SDK。总结起来很简单:

首先下载Hounsell那篇文章里面的7z文件。

捡自己需要的放到C:\Program Files\Reference Assemblies\Microsoft\Framework\Silverlight\v4.0\Profile\WindowsPhone,记得改名,把前后下划线前的内容都去掉。比如对于原生摄像头,我们需要Microsoft.Phone.Media.Extended.dll。

打开RedistList文件夹里面的FrameworkList.xml文件,记得用管理员权限。新增一个File标签(复制之前的就行),程序集名改成你刚刚加入的那个dll的,去掉publicKeyToken属性。保存。

于是我欣然照做(后来尝试发现,对于InteropServices需要这么做,但Media.Extended似乎不用,dll扔过去就可以了),结果……

搞屁啊……连设计器都打不开了!只好再搜,找到个帖子[Q] Usage of Microsoft.Phone.Media.Extended,问题类似,都是“强名称验证失败”,不过帖子中还能打开设计器而运行时出现COMException:

解决方法很简单,利用Window SDK的工具sn.exe执行下面的命令跳过验证,看到后面的信息即可(也要用管理员权限,或者从VS命令行执行):

sn.exe -Vr [dll path]

Verification entry added for assembly ‘Microsoft.Phone.Media.Extended,24EEC0D8C86CDA1E’

有关强名称和sn.exe的信息可以参看具有强名称的程序集强名称工具 (Sn.exe)。简单说来强名称就是带有唯一公钥信息的程序集,好处是可以验证程序集的可靠性以及dll名字可以随便改。但坏处就是现在遇到的问题了:每台机器的.net环境都需要强名称程序集验证后才能使用。

其实这个地方还是衰了一下,因为我发现Windows Phone Developer Tools中的Visual C# Express并没有传说中的sn.exe(靠……),于是又跑到微软网站上下了个Visual C++ Express 2010,这才彻底搞定。如果你直接装了Pro版那就没这个困扰了。

最后再说一下有关PhotoCamera的使用。首先建议详读Den Delimarsky那两篇文章,基本覆盖了所有使用和可能碰到的问题。除了里面提到的API外,还有个比较有用的是GetCurrentFrame()。这个函数接受一个WritableBitmap参数,尺寸一定要是640 x 480,不然会有异常抛出来。另外拿到的WritableBitmap最好不要尝试通过ImageBrush画出来,不然会慢死(模拟器上大概200ms处理一帧,真机也就500ms)。下面截图就是模拟器的效果,大的白色区域(加那个黑方块)是原生的View Finder,左上角的是通过GetCurrentFrame()后重新画的。

最近

最近一篇blog是1月写的去年阅读总结。这俩月并非抽不出时间写点东西,问题在于拿不出东西可写。于是觉得写写最近做的事、玩的游戏、看的书,凑数成一篇blog吧。

微软和Nokia合作,成了Mikia(黑桐干也:谁叫我?),于是之前Qt辛辛苦苦整出来的那一套QtQuick又成了后妈生的。QtQuick和QML虽然是被逼出来的一种界面、引擎代码分离解决方案,但实际上可玩性相当高。QML的语法容易学(至少比XAML更容易懂),对于美工、UX或者原型设计师来说好用,再会点JS,可以替代Flash作为界面原型和UI演示的制作工具(如果再有个Blend那样的工具就更好了)。比如这个例子,模拟WP7主屏,都是利用QML自带动画和标签实现的效果。

春节期间补了一下神作《空之境界》。之前一直没看是因为误解了标题中的“空”为“天空”的空,于是脑补了最不喜欢看的宇宙大战、机器人肉搏之类的场景……年三十儿那天偶然点进去了《空镜》的Wikipedia页面,发现那个空不读sora而是kara,也就是“色即是空”的那个“空”,于是一下子就哲♂学了。动画已经补课完毕,开始看小说版。

一般来说,死程序员在完成本职工作外都会对更底层的东西感兴趣,比如做C#的通常都会学学CLR;写脚本的会自己拆拆Python、Ruby的源代码;做C/C++的都会搞搞汇编、编译器之类的;做汇编的学机器码;玩机器码的……用针扎出来win98?于是我下定决心开始重新学习8086和80×86汇编了。教材用的是王爽著《汇编语言》。推荐个神器emu8086。

STG尝试中——体会就是,数学功底太差和想象力不足(比如我)不适合做弹幕类STG!