Mobile部分技术总结

 

  • ActiveSync 的原理

使用 USB 驱动把 PC 与设备之间的链接模拟成一个网络,在 PC 上可以看到一个虚拟的网络适配器(网卡),手机设备上运行着 ActiveSync 的设备端程序,可以看作服务器,PC 上运行客户端程序,两者可以通过虚拟网卡进行 TCP/IP 通讯。

 

  • SP 与 PPC 编程的区别

1. PPC 有触摸屏,需要考虑鼠标消息的处理,SP 没有。

2. PPC 需要考虑同时支持横屏和竖屏,除非是正方形的屏幕。 

3. SP 有键盘,需要考虑键盘消息的处理,比如加速键、热键、后退键等,PPC 一般没有,但也可以有。 

4. 电源管理不同,SP 可以完全关闭,PPC 没有设计关闭系统的功能。 

5. Shell 不同,一些 Shell API 在两者之上的支持不同。 

6. 界面风格不同,SP 有传统的九宫格和翻页式的列表菜单,PPC 则更像桌面,使用带滚动条的列表菜单,PPC 还有弹出式菜单,SP 因为没有触摸屏,所以没有弹出式菜单。 

7. SP 大量应用 COM,比如“设置”里的控制面板项,PPC 的控制面板项则使用普通的 DLL。 

8. SP 有大量配置信息是保存在 XML 文件里的,PPC 更多是使用数据库和注册表。

 

d 将参数以十进制的形式输出 

o 将参数以无正负号八进制的形式输出 

x 将参数以无正负号的十六进制的形式输出 

u 将参数以无正负号的十进制的形式输出

  

 SHCloseApps()

  必须是这样的程序才会被关闭:

 

1. 有窗体,并没有隐藏

2. 包含 WS_OVERLAPPED(不能包含 WS_POPUP)

3. 所有程序响应 WM_HIBERNATE 后依然内存不足

4. 不是 SAN 不关闭程序,比如 WMP 就是不会关闭的,怎么整都不会关 WMP。

 

  • UTF8 和 Unicode 编码的互相转换

在英文字符占大多数的情况下,使用 UTF8 可以节省存储空间,一般 XML 文件都是 UTF8 编码的。以前做 GSM6702 时,发现 Smartphone 里的 XML 文件是没有 BOM UTF8 编码格式,如果只有英文,则和 ANSI 编码没有差别。

 

LdapUnicodeToUTF8 LdapUTF8ToUnicode 这两个 API 就是用来做转换的。编码格式其实很简单,不多说了,这里提出来只是想建议大家,如果自己的模块里遇到需要把数据保存成文件的话,刚好大部分字符都是英文时,记得使用 UTF8 编码。当然,在 PC 上也是建议这样做的,只是移动设备存储空间比较小,更应该这样做。

  • 更新待机界面

PostMessageW( GetDesktopWindow(), WM_SETTINGCHANGE, 242, 0L ); 可以更新待机界面,包括重载主题、墙纸、待机插件等。如果要写待机插件的 Release 安装包,可以使用 SetupDll 调用这一语句,来确保安装后马上生效,不用再进入“开始-设置-今日-项目”里设置。

 

我是这样研究出这个语句的:“开始-设置-今日-项目”这个控制面板页是有这个功能的,我猜测它是发送某个消息给桌面窗口,就用 Remote Spy 截取桌面窗口的消息,发现了这个消息,测试后确定。

  • 注册我们的应用程序

比较一下微软的快捷方式文件和我们自己的就会发现,有一个明显的不同之处:微软大部分应用程序的快捷方式并不是直接写路径名的,而是一个以 : 开头的化名(半角的冒号),为什么微软要这样绕弯子?用化名很明显还要先解析,比直接用路径名慢。

答案还是和 WM 特殊的内存管理有关,系统最多只能跑 32 个进程,我们来想像一下这样的苛刻条件:系统里已经跑了 32 个进程,其中必定有 Shell32.exe,“开始-程序”这个界面是 shell32.exe 的窗口,假设其中最不常用的进程是 Windows Media,“最不常用”说明有新进程要跑时,被关掉的就会是这个“最不常用”的进程。那么,用户在“开始-程序”里选择运行 Windows Media 时会发生什么?Windows Media 会先被关闭,然后又新建了 Windows Media 的进程。

所以,我们常常写的“兼容程序”靠运行时检测系统里有没有同样类名的窗体来判断前例的方法是不健壮的!因为即使这样检测,程序依然有一段时间是存在两个实例的,有两个进程,就说明可能在新进程跑起来时,由于 32 个进程的限制,而导致前例被关闭,这样就变成一个程序先关掉再运行一次,浪费时间,浪费系统资源。

那为什么用化名就不会这样?还是以 Windows Media 为例,Windows Media 的化名是 :WMPLAYER,打开注册表 [HKEY_LOCAL_MACHINE/Software/Microsoft/Shell/Rai/:WMPLAYER] 会发现这个键下面有一个名为 0 的字符串值,其数据是 WMP for Mobile Devices,这刚好是 Windows Media 主窗体的类名,还有一个名为 1 的字符串值,数据是其程序名。当某个进程用 ShellExecuteEx 运行 :WMPLAYER 或者指向 :WMPLAYER 的文件时,ShellExecuteEx 会先查找系统里有没有类名为 WMP for Mobile Devices 的窗体,如果找到就激活,不会再新建 Windows Media 的进程,这个过程,是在调用者进程里完成的,没有新建被调用者进程。

建议大家都注册一下自己的模块,以后快捷方式里统一都用化名,例如:AmoiTest.exe 的注册信息为:

[HKEY_LOCAL_MACHINE/Software/Microsoft/Shell/Rai/:AMOITEST]

"0"="AmoiTestClassName"

"1"="AmoiTest.exe"

 另外还有 2 3 DWORD 值,我还没完全研究清楚(SAN Based App 用的),不过只要有 1 2 就可以完成这个机制了。

  • DPI Aware Text and Fonts

电脑显示器也有 DPI 的概念,但一般不被关心,而移动设备屏幕的 DPI 相对就很重要,微软文档里有一篇 DPI Aware Text and Fonts,建议大家看看,代码可以参考 SDK Sample 里的 BasicApp。

设置 - 系统 - 屏幕 - 文字大小,这个控制面板页可以设置系统部分应用的文字大小,为了支持从这个页改变字体大小,应用程序需要遵守一定的规范。

遵守 DPI Aware Fonts 规范的程序,例如:微软联系人(列表界面)、信息(列表界面)、待机插件等,规范请参考 DPI Aware Text and Fonts 文中的 Getting the User Font Size 节,下面简单提一下:

1. 调用 SHGetUIMetrics 取得字体高度

2. LONG dwFontSize = 12;

3. SHGetUIMetrics(SHUIM_FONTSIZE_PIXEL, &dwFontSize, sizeof(dwFontSize), NULL);

lf.lfHeight = -dwFontSize;

4. 如果是普通窗体应用程序,则要处理字体大小改变的通知消息,这个消息是 String Message,要先注册:

 

UINT g_uMsgMetricChange = RegisterWindowMessage(SH_UIMETRIC_CHANGE);

 

然后再 WndProc 里加入对这个消息的处理,重建字体,刷新界面,具体参考 BasicApp。

5. 如果是待机插件则不用处理 SH_UIMETRIC_CHANGE 消息,因为待机插件管理器会处理这个消息,把所有插件销毁,再重建,字体也就重建了。

 

• Handle WM_HIBERNATE

  We get this message when the device is running low on memory. All applications should free any memory and resources that they can.

 

  我看了很多我们自开发的应用,还没看到一个有处理这个消息的。请参考 SDK 带的 Sample 里的 BasicApp

1. 如果程序没必要跑了,直接销毁窗体,退出进程,这样的程序,例如:大字体、关机、照相机(最小化时)。 

2. 如果程序不在前台,可以销毁软键行(MenuBar,这也是一种窗体,耗的资源挺大的),但记得要设计成窗体激活时还可以重建:

// 销毁

CommandBar_Destroy(g_hWndMenuBar);

g_hWndMenuBar = NULL;

 

// 重建

if( !g_hWndMenuBar )

{

  g_hWndMenuBar = SHCreateMenuBar ...

} 

3. 释放所有没必要的 GDI 资源,BasicApp 就是例子。

相关资料:

 

低内存环境

  当系统运行在一个低RAM环境中,应用程序将调整并最小化它们的内存使用。Windows CE运行在一个几乎永久的低内存环境中。Pocket PC被特意设计为运行低内存环境。在Pocket PC中的应用程序没有关闭按钮,当系统需要更多内存时,外壳(shell)自动关闭这些程序。正因为如此,Windows CE有许多方法来管理运行在低内存系统中的程序。

WM_HIBERNATE 消息

  Windows CE 第一个最明显的变化时是增加了 WM_HIBERNATE 消息。Windows CE 的 shell 发送消息给最顶层的有WS_OVERLAPPED 式样(那就是说,既没有 WS_POPUP 也没有 WS_CHILD 式样)和 WS_VISIBLE 式样的窗口。这些限制将允许大多数程序至少有一个窗口可以接受 WM_HIBERNATE 消息。有一个例外就是,当应用程序不能真正结束程序而只是简单隐藏所有窗口。这种方式允许应用程序可以快速启动,因为它下次只是显示窗口。但是这就意味着,当用户想关闭它们的时候仍然占据着 RAM。这对程序设计来说是正确的,但是不应用在 Windows CE 中,这种方式会造成程序被隐藏时总处在冬眠(hibernate)模式,因为它们永远接收不到 WM_HIBERNATE 消息。

  Shell 发送 WM_HIBERNATE 消息给最顶层的窗口在 Z 轴相反的位置(reverse Z-order)直到内存被释放,使可用内存超过系统预先的限制。当应用程序接收到一个WM_HIBERNATE消息,它会尽可能减少内存占有程度。这包括释放被缓冲(cached)的数据;释放 GDI 对象,例如字体,位图和画刷;并销毁任何窗口控件。从本质上来说,应用程序将会减少内存到维持它内部状态的最小值。

  如果发送 WM_HIBERNATE 消息给后台的应用程序不能释放足够的内存以便使系统离开内存被限制的状态。WM_HIBERNATE 消息将会发送给前台程序。如果你正在冬眠的程序开始销毁窗口的控件,你必须确保它不是前台的程序,控件消失不会给用户带来兴奋的感觉而是困惑。

内存限度

  Windows CE 监视系统自由的 RAM,并对越来越少的 RAM 作出响应。当很少内存可用时,Windows CE 首先发送 WM_HIBERNATE 消息,接下来会限制可能的内存分配。下面的两个表显示了 Explorer shell Pocket PC 引发的低内存事件的自由内存级别。Windows CE 定义了是个内存状态:normallimitedlow critical。系统的内存状态依赖于整个系统有多少内存可用。这些限制都比 4-KB 页要高,因为系统具有内存最小分配限制,就像 7-1 7-2 的表。

表 7-1 Explorer Shell 的内存限度

事件自由内存

1024-Page Size 自由内存

4096-Page Size 注解

Limited-memory state 128 KB 160 KB 发送 WM_HIBERNATE 消息给in reverse Z-order的应用程序。释放栈空间并回收利用。

Low-memory state 64 KB 96 KB 限制虚拟内存分配为16 KB。 显示Low-memory对话框。

Critical-memory state 16 KB 48 KB 限制虚拟内存分配为8KB。

表7-2 Pocket PC的内存限度

事件自由内存

1024-Page Size 自由内存

4096-Page Size 注解

Hibernate threshold 200 KB 224 KB 发送 WM_HIBERNATE 消息给in reverse Z-order的应用程序。

Limited-memory state 128 KB 160 KB 开始关闭在 reverse Z-order上的应用程序。释放栈空间并回收利用。

Low-memory state 64 KB 96 KB 限制虚拟内存分配为16 KB。

Critical-memory state 16 KB 48 KB 限制虚拟内存分配为8 KB。

 

  这些内存状态的影响是共享剩余的财富。首先,WM_HIBERNATE 消息被发送给应用程序,并请求减少它们的内存占有率,当应用程序被发送了一个 WM_HIBERNATE 消息后,系统将检测内存级别,确认是否可用内存在限度之上,如果可用内存不足,WM_HIBERNATE 消息将被发送给下一个程序。这会持续到所有程序被发送了 WM_HIBERNATE 消息。

  Exlporer shell Pocket PC 的低内存策略在这点上有区别。如果 Explorer shell 运行时,系统会显示 OOMout of memory)对话框,并请用户确认是否关闭一个应用程序或把对象存储区的RAM重新划分给程序内存。如果用户选择了其中之一,仍然没有足够的内存,out of memory 对话框将会再次出现,这个过程会重复,直到H/PC有足够的在限度之上的内存。

  Pocket PC 来说,操作稍微有些不同。Pocket PC shell 自动开始关闭最近最少使用的应用程序,而不询问用户。如果关闭除了前台程序和 shell 之外的所有程序,仍然没有足够内存,系统将会使用其他的技术来从栈开始清理自由的页,并限制虚拟内存分配。

  如果在任何一个系统上,应用程序被请求关闭却没有关闭,系统在 8 秒钟后将会清理该应用程序。这就是一个应用程序不要分配大量的栈空间的原因。如果应用程序被关闭而导致低内存环境,很可能是栈空间不能分配,应用程序将被挂起。如果发生在系统请求应用程序关闭以后,可能是清除内存以后没有适当的恢复状态。

  low critical-memory 状态,应用程序被限制了内存分配的大小。在这些情况下,甚至还有可以满足要求的内存剩余情况下,请求分配大过允许限度的虚拟内存将会被拒绝。记住,并不止是虚拟内存分配被限制,堆分配和栈分配也被禁止,要满足分配请求,那么分配时需要虚拟内存在可允许的限制之上。

  我这里要指出,发送 WM_HIBERNATE 消息和自动关闭应用程序是由系统的 shell 执行的。在一个 OEM 自己可以编写 shell 的嵌入式系统中,实现 WM_HIBERNATE 消息和其他内存管理技术是 OEM 厂商的责任。幸运的是,Microsoft Windows CE PlatForm Builder 提供了 Exlporer shell 实现 WM_HIBERNATE 消息的源码。

  这里不言而喻,应用程序要检查任何内存分配调用的返回代码,但是因为这里还没说,所以我还是要说。检查内存分配调用的返回代码。在 Windows CE 中比在桌面版本的 Windows 中可能有更多的机会导致内存分配失败。应用程序必须很好地实现拒绝内存分配。

  Windows CE 不支持完全的 Win32 内存管理 API,但是很清楚这里有对 WindowsCE 设备受限制内存的足够支持。

o 尽量用 ShellExecuteEx 代替 CreateProcess

理由:

1. WM 目前最多只能运行 32 个进程,如果已经达到 32 个进程了,用 CreateProcess 去调用外部程序,必定失败,而 ShellExecuteEx 则会先检查当前系统的进程数,如果已经满了,就先关掉一些窗体,等待进程退出后再新建进程。 

2. CreateProcess 只能用来运行可执行文件,而 ShellExecuteEx 支持所有注册类型的文件,并且可以解析运行 RAI Based 程序。

(*) RAI Based 程序是指有在注册表里注册自己的程序,例如 :MSPIE。

 

心得:如果有 Shell API 和 Core API 可以完成同样的任务,应该选择用 Shell API,因为 Shell API 更高层,会考虑更多高层的异常处理。

 

ChangeDisplaySettingsEx

 

切换屏幕旋转模式通过调用 ChangeDisplaySettingsEx 来实现,如:

DEVMODE devmode = {0};

devmode.dmSize = sizeof(DEVMODE);

devmode.dmDisplayOrientation = DMDO_90; //水平模式

devmode.dmFields = DM_DISPLAYORIENTATION;

ChangeDisplaySettingsEx(NULL, &devmode, NULL, 0, NULL);

 

取得当前模式的代码如下:

DEVMODE devmode = {0};

devmode.dmSize = sizeof(DEVMODE);

devmode.dmFields = DM_DISPLAYORIENTATION;

ChangeDisplaySettingsEx(NULL, &devmode, 0, CDS_TEST, NULL);

通过 devmode.dmDisplayOrientation 的值可以判断当前模式。

 

值得注意的是,这样切换模式并不是永久的,当设备重新起动后,就会还原为初始状态。

如果你需要在保留切换的屏幕模式,可以通过设置注册表中

 

HKEY_LOCAL_MACHINE/System/GDI/Rotation 下的两个键值实现

Angle - DWORD (0, 90, 180, 270)

LandscapeMode - DWORD (0,1)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值