﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-Jiang's C++ Space-随笔分类-Windows Embedded Programming</title><link>http://www.cppblog.com/guogangj/category/13734.html</link><description>创作，也是一种学习的过程。</description><language>zh-cn</language><lastBuildDate>Thu, 08 Sep 2011 13:09:17 GMT</lastBuildDate><pubDate>Thu, 08 Sep 2011 13:09:17 GMT</pubDate><ttl>60</ttl><item><title>安装VS2010后VS2008无法调试Windows Mobile程序的问题</title><link>http://www.cppblog.com/guogangj/archive/2011/09/08/155351.html</link><dc:creator>Jiang Guogang</dc:creator><author>Jiang Guogang</author><pubDate>Thu, 08 Sep 2011 06:07:00 GMT</pubDate><guid>http://www.cppblog.com/guogangj/archive/2011/09/08/155351.html</guid><wfw:comment>http://www.cppblog.com/guogangj/comments/155351.html</wfw:comment><comments>http://www.cppblog.com/guogangj/archive/2011/09/08/155351.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guogangj/comments/commentRss/155351.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guogangj/services/trackbacks/155351.html</trackback:ping><description><![CDATA[大概大约半年多前遇到过一次，当时Windows Phone 7的SDK发布，好奇，也就下载了一个安装了，感觉在公司的破机器（E2200的CPU）上跑得很慢，更郁闷的是由于显卡不支持DX9，Windows Phone 7模拟器的运行效果惨不忍睹，而这些其实都没什么，因为装了这个，导致我的VS2008无法调试Windows Mobile的程序了，现象如图：<br /><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/f5_error.png" width="415" height="249" /><br />按F5，Deploy成功之后就立即弹出这个消息款，只有一个&#8220;确定&#8221;按钮，没有任何别的提示。折腾了半天依旧如此，网上查资料，可能是由于还做Windows Mobile开发的人太少，没几个人遇到这个问题，相似的都是说ASP.net在VS2010下无法启动调试，需要修改Web.config配置等。<br /><br />不幸中的万幸是我卸载掉VS2010之后，一切都正常了，所以之后也一直没安装VS2010。<br /><br />而最近项目需求又要用到VS2010，我清理了半天已经&#8220;见红&#8221;的系统盘之后开始安装VS2010 Ultimate版本，之前装的是Express版，安装中还不断祈祷不要出现以前那种问题。结果，还是出现了，难道我只能卸载掉VS2010么？毕竟调试Windows Mobile程序是必须的。心不甘，毕竟装一次卸一次花费时间不少。<br /><br />用google搜索了半天后，终于，功夫不负有心人，在Microsoft的官方网站上找到了解决方案：<br /><a href="http://social.msdn.microsoft.com/Forums/en/windowsphone7series/thread/7afdadc0-7e16-4018-85a8-a13fe9c4b8cb">http://social.msdn.microsoft.com/Forums/en/windowsphone7series/thread/7afdadc0-7e16-4018-85a8-a13fe9c4b8cb</a><br />浏览完整个帖子之后，知道大概缘由是这样：<br /><br />由于VS2010改变了某些环境变量，导致VS2008找不到调试器，在我的机器上，VS2008的智能设备调试器存放处是：<br />C:\Program Files\Microsoft Visual Studio 9.0\SmartDevices\Debugger\target\wce400\armv4i\edm2.exe<br />将这个文件复制到VS2010的相应目录下就OK了：<br />D:\Program Files\Microsoft Visual Studio 10.0\SmartDevices\Debugger\target\wce400\armv4i\edm2.exe<br />也许你已经发现，由于系统盘捉襟见肘的剩余空间，我把VS2010安装到D盘了，但在系统盘依旧要占用不少空间的。希望老板很快给我换好机器&#8230;&#8230;<br /><img src ="http://www.cppblog.com/guogangj/aggbug/155351.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guogangj/" target="_blank">Jiang Guogang</a> 2011-09-08 14:07 <a href="http://www.cppblog.com/guogangj/archive/2011/09/08/155351.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>帮Windows Mobile实现gmtime，localtime，mktime和strftime</title><link>http://www.cppblog.com/guogangj/archive/2011/06/30/149827.html</link><dc:creator>Jiang Guogang</dc:creator><author>Jiang Guogang</author><pubDate>Thu, 30 Jun 2011 08:45:00 GMT</pubDate><guid>http://www.cppblog.com/guogangj/archive/2011/06/30/149827.html</guid><wfw:comment>http://www.cppblog.com/guogangj/comments/149827.html</wfw:comment><comments>http://www.cppblog.com/guogangj/archive/2011/06/30/149827.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/guogangj/comments/commentRss/149827.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guogangj/services/trackbacks/149827.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 偶尔发现Windows Mobile连一些标准的C语言库函数都没有实现，而这些函数的在头文件中的声明却是有的，实在有些不方便，上网一搜索，才知道原来Windows CE也没实现，而Windows Mobile这方面照搬了Windows CE的，如果真要用这些函数，只能自己来写了，我写了这几个：gmtime，localtime，mktime，strftime，其中用到了Variant Time这个类...&nbsp;&nbsp;<a href='http://www.cppblog.com/guogangj/archive/2011/06/30/149827.html'>阅读全文</a><img src ="http://www.cppblog.com/guogangj/aggbug/149827.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guogangj/" target="_blank">Jiang Guogang</a> 2011-06-30 16:45 <a href="http://www.cppblog.com/guogangj/archive/2011/06/30/149827.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows Mobile上网设置详细图解</title><link>http://www.cppblog.com/guogangj/archive/2011/05/31/147787.html</link><dc:creator>Jiang Guogang</dc:creator><author>Jiang Guogang</author><pubDate>Tue, 31 May 2011 13:48:00 GMT</pubDate><guid>http://www.cppblog.com/guogangj/archive/2011/05/31/147787.html</guid><wfw:comment>http://www.cppblog.com/guogangj/comments/147787.html</wfw:comment><comments>http://www.cppblog.com/guogangj/archive/2011/05/31/147787.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guogangj/comments/commentRss/147787.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guogangj/services/trackbacks/147787.html</trackback:ping><description><![CDATA[我玩Windows Mobile好几年了，但对其网络设置一直很迷惑，微软这方面做得实在不是很人性化，误导了我不少，所以打算整理一下，争取能找出一种比较&#8220;万能&#8221;的设置方法，我研究的对象是Windows Mobile 6.0及其以上版本的系统，版本太低的就略过吧。<br />开始 -&gt; 设置 -&gt; 连接 -&gt; 连接<br />打开连接设置对话框，在我的手机上是这样显示的：<br /><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/wm_net_setup_01.png" width="241" height="322" /><br />&lt;图1&gt;<br />各台机器上可能不一样，这没关系，我们现在点&#8220;高级&#8221;标签，如图：<br /><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/wm_net_setup_02.png" width="241" height="320" /><br />&lt;图2&gt;<br />再点&#8220;选择网络&#8221;按钮，如图：<br /><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/wm_net_setup_03.png" width="241" height="321" /><br />&lt;图3&gt;<br />点击下拉框，发觉除了&#8220;单位设置&#8221;和&#8220;Internet设置&#8221;两个网络设置之外，还有一个名为&#8220;MMS&#8221;的设置，为了减少迷惑，我们现在只要保留&#8220;单位设置&#8221;和&#8220;Internet 设置&#8221;，把其它的设置删除。在下拉框中选中&#8220;MMS&#8221;，如图：<br /><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/wm_net_setup_04.png" width="242" height="322" /><br />&lt;图4&gt;<br />点&#8220;编辑&#8221;按钮，如图：<br /><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/wm_net_setup_05.png" width="242" height="320" /><br />&lt;图5&gt;<br />选择&#8220;常规&#8221;标签，如图：<br /><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/wm_net_setup_06.png" width="241" height="321" /><br />&lt;图6&gt;<br />点&#8220;删除设置&#8221;按钮。<br />全部删除不必要的网络设置之后，（特别说明：事实上，&#8220;单位设置&#8221;和&#8220;Internet 设置&#8221;两个网络设置虽然不能被删除，但它们的名称却是可以改的，这里假设这两个网络设置的名字还是默认的名字，没有被修改）在&#8220;选择网络&#8221;对话框中，按照图3去设置，上面选择&#8220;Internet 设置&#8221;，下面选择&#8220;单位设置&#8221;，&#8220;单位设置&#8221;是个不太好理解的名称，在英文版的Windows Mobile中，它的名字是&#8220;My Work Network&#8221;，直译过来应该是&#8220;我的工作网络&#8221;，而&#8220;Internet 设置&#8221;在英文版中的名称为&#8220;My ISP&#8221;，直译过来应该是&#8220;我的Internet服务提供者&#8221;，总的来说，意思都不是很明确，这也是让人迷惑的原因之一。<br />特别要说明一下的就是，&#8220;Internet 设置&#8221;和&#8220;单位设置&#8221;这两个网络设置是删除不掉的。<br />我们现在简单地这么理解：<br />&#8220;Internet 设置&#8221;是直连模式，而&#8220;单位设置&#8221;是代理模式。<br />现在，我们点&#8220;在程序自动连接到Internet时&#8221;下面的&#8220;编辑&#8221;按钮，如图：<br /><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/wm_net_setup_07.png" width="240" height="321" /><br />&lt;图7&gt;<br />如果已经有连接项了，那么先把连接项删除，方法是按住连接项，然后在呼出的上下文菜单中选择&#8220;删除&#8221;，如图：<br /><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/wm_net_setup_08.png" width="241" height="322" /><br />&lt;图8&gt;<br />在图7的界面中点&#8220;新建&#8221;按钮，然后如图设置：<br /><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/wm_net_setup_09.png" width="241" height="320" /><br />&lt;图9&gt;<br />其中的名称可以起别的名字，不一定是&#8220;移动Internet&#8221;，这个并不影响最终的结果，好了之后点&#8220;下一步&#8221;，再如图设置：<br /><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/wm_net_setup_10.png" width="242" height="321" /><br />&lt;图10&gt;<br />特别说明：我使用的网络是移动的，所以这里填cmnet，如果我没记错的话，联通的这里应该填写&#8220;uninet&#8221;，联通3G网络的话应该填写&#8220;3gnet&#8221;，电信的则填写&#8220;ctnet&#8221;。<br />好了之后再&#8220;下一步&#8221;，这步留空，什么都不用填，直接点完成，如图：<br /><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/wm_net_setup_11.png" width="240" height="320" /><br />&lt;图11&gt;<br />这个时候，我们就能看到我们刚添加的连接项了，如图：<br /><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/wm_net_setup_12.png" width="242" height="321" /><br />&lt;图12&gt;<br />点&#8220;ok&#8221;，回到上一界面，现在点&#8220;在程序自动连接到专用网络时&#8221;下面的&#8220;编辑&#8221;按钮，出现了类似图7的界面，删除掉不必要的连接项后，我们点&#8220;新建&#8221;，如图设置：<br /><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/wm_net_setup_13.png" width="242" height="322" /><br />&lt;图13&gt;<br />完成后点下一步，再如图设置：<br /><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/wm_net_setup_14.png" width="242" height="321" /><br />&lt;图14&gt;<br />这里我输入的是cmwap，因为我用的是移动的网络，联通的应该是uniwap，联通3G的应该是3gwap，电信的应该是ctwap，大家根据实际情况输入。然后下一步，这步不需要填写什么内容，留空即可。再点&#8220;完成&#8221;，如图：<br /><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/wm_net_setup_15.png" width="242" height="322" /><br />&lt;图15&gt;<br />&#8220;单位设置&#8221;和前面的&#8220;Internet 设置&#8221;不同的是多了&#8220;VPN&#8221;和&#8220;代理服务器设置&#8221;的标签，从上图可以看出来，所以我前面也提到了：&#8220;Internet 设置&#8221;是直连模式，而&#8220;单位设置&#8221;是代理模式。我们接下来设置代理服务器，点&#8220;代理服务器设置&#8221;标签，如图设置：<br /><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/wm_net_setup_16.png" width="241" height="321" /><br />&lt;图16&gt;<br />再点击&#8220;高级&#8221;按钮，如图设置：<br /><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/wm_net_setup_17.png" width="241" height="321" /><br />&lt;图17&gt;<br />ok，ok，ok&#8230;&#8230;<br />这样应该就完成了。<br />如果还是不行，那估计就是手机的电话模块有问题，我就遇到过这种情况，电话能打，短信能收能发，但网络无论如何都用不了，重新刷机有可能解决这个问题；另外还有可能就是电话欠费而停机了，即便你充了值，网络服务也未必马上能开通，关闭并重新打开电话或者重启手机可能解决这个问题。<img src ="http://www.cppblog.com/guogangj/aggbug/147787.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guogangj/" target="_blank">Jiang Guogang</a> 2011-05-31 21:48 <a href="http://www.cppblog.com/guogangj/archive/2011/05/31/147787.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>奇怪的Windows Mobile输入面板刷新问题</title><link>http://www.cppblog.com/guogangj/archive/2011/04/12/144018.html</link><dc:creator>Jiang Guogang</dc:creator><author>Jiang Guogang</author><pubDate>Tue, 12 Apr 2011 03:25:00 GMT</pubDate><guid>http://www.cppblog.com/guogangj/archive/2011/04/12/144018.html</guid><wfw:comment>http://www.cppblog.com/guogangj/comments/144018.html</wfw:comment><comments>http://www.cppblog.com/guogangj/archive/2011/04/12/144018.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guogangj/comments/commentRss/144018.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guogangj/services/trackbacks/144018.html</trackback:ping><description><![CDATA[<p>这是最近弄的一个程序，其实以前在使用别的程序的时候貌似也出现过类似的问题，那就是：有些时候点击菜单栏上的输入法按钮，输入法面板却无法正常隐藏。而经过进一步研究后发现，其实并不是没有隐藏，而是没有刷新，而且不能通过常规的手段来刷新，比如调用InvalidateRect，或者&#8220;遮挡/重新调出&#8221;等常规手段。如图：<br><br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/wm_input_panel_problem_1.png" width=460 height=768><br><br>仔细看菜单栏上的&#8220;S&#8221;按钮，这是搜狗输入法的按钮，现在它应该处于关闭状态，而输入法面板却还在显示，并且，点上去无效，效果是&#8220;点击穿透&#8221;，下面这张图是输入法面板正常的情况：<br><br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/wm_input_panel_problem_2.png" width=460 height=768><br><br>这是菜单栏上的输入法按钮处于激活状态。<br><br>当出现问题的时候，你让企图通过&#8220;遮挡/重新调出&#8221;的手段让这块区域重绘，那会导致类似下面的情况，下面这张图就是我呼出开始菜单，然后又关闭开始菜单之后，得到的结果。<br><br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/wm_input_panel_problem_3.png" width=460 height=768><br><br>事实上，我的应用程序窗口确实是填满了整个客户区的，至于为什么不能正常刷新，真是令人费解。但经过大量折腾，我看起来是解决了这个问题，那就是把我窗口处理函数中的代码拿掉一点：<br></p>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">case</span><span style="COLOR: #000000">&nbsp;WM_ACTIVATE:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SHHandleWMActivate(hWnd,&nbsp;wParam,&nbsp;lParam,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">s_sai,&nbsp;FALSE);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">break</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;WM_SETTINGCHANGE:<br></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SHHandleWMSettingChange(hWnd,&nbsp;wParam,&nbsp;lParam,&nbsp;&amp;s_sai);<br></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;</span></div>
<br>下面注释掉的代码就是我拿掉的代码，似乎这个问题就不再出现了，但为什么这样我还是不懂。而Windows Mobile开发中遇到的这种问题真是数不胜数&#8230;&#8230;
<img src ="http://www.cppblog.com/guogangj/aggbug/144018.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guogangj/" target="_blank">Jiang Guogang</a> 2011-04-12 11:25 <a href="http://www.cppblog.com/guogangj/archive/2011/04/12/144018.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows Mobile的安全模型简介</title><link>http://www.cppblog.com/guogangj/archive/2011/04/02/143292.html</link><dc:creator>Jiang Guogang</dc:creator><author>Jiang Guogang</author><pubDate>Sat, 02 Apr 2011 09:26:00 GMT</pubDate><guid>http://www.cppblog.com/guogangj/archive/2011/04/02/143292.html</guid><wfw:comment>http://www.cppblog.com/guogangj/comments/143292.html</wfw:comment><comments>http://www.cppblog.com/guogangj/archive/2011/04/02/143292.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guogangj/comments/commentRss/143292.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guogangj/services/trackbacks/143292.html</trackback:ping><description><![CDATA[PocketPC可用第一套安全模型（T1），而SmartPhone则可用第一套和第二套安全模型（T2）。安全模型并不能确保Windows Mobile一定不受到恶意程序的影响。<br><br><strong>安全模型的几个方面<br><br>1，应用程序执行<br></strong>针对可执行程序，控制运行在机器中的程序以及这些程序能干什么。<br><br><strong>2，设备配置<br></strong>针对设备管理设置，控制谁能够访问设备的配置以及相关访问级别。<br><br><strong>3，远程访问接口（RAPI）<br></strong>通过ActiveSync来控制桌面Windows的程序能在设备上干啥。<br><br><span style="FONT-SIZE: 24pt"><strong>T1<br></strong></span>T1区分&#8220;已签名&#8221;（signed）和&#8220;未签名&#8221;（unsigned）的应用程序。已签名的程序拥有特权，拥有特权就可以访问设备上的所有资源，包括各种系统API，受保护的注册表键值等。如需了解更多，请在MSDN上查找&#8220;Privileged APIs&#8221;。<br><br>对于未签名的应用程序，则使用以下策略来决定这个程序是否可以在设备上运行：<br><br>&#8220;Unsigned Application策略&#8221;(SECPOLICY_UNSIGNEDAPPS)被用来检测一个未签名应用程序是否可以在设备上运行。<br><br>如果允许运行未签名应用程序(SECPOLICY_UNSIGNEDAPPS=1)，那么就检查&#8220;Unsigned Prompt策略&#8221;(SECPOLICY_UNSIGNEDPROMPT)，如果&#8220;Unsigned Prompt策略&#8221;是1，那么就不提示用户，直接让应用程序以特权模式运行，如果&#8220;Unsigned Prompt策略&#8221;是0，那么就要提示用户，是否让这个程序运行，如果用户选&#8220;是&#8221;，这个程序就以特权模式运行了。<br><br><span style="FONT-SIZE: 24pt"><strong>T2<br></strong></span>T2(SECPOLICY_PRIVELEGEDAPPS=0)模型提供了更好的伸缩性。在T1模型，应用程序只有两种可能，一是运行，二是不运行，而在T2模型中，一个应用程序的运行还有&#8220;普通模式&#8221;和&#8220;特权模式&#8221;之分。已签名应用程序以特权模式运行的时候， 可以访问设备的一切资源；已签名应用程序以普通模式运行的时候，不可以访问受保护的系统API和注册表。<br><br>T2模型根据应用程序的签名来决定它是&#8220;特权模式&#8221;运行还是&#8220;普通模式&#8221;运行。如果应用程序是用特权证书签名的，那么就用&#8220;特权模式&#8221;运行，如果应用程序是用普通证书签名的，那就用&#8220;普通模式&#8221;运行。<br><br>T1和T2相互间不能自由切换，如果要换，那就得重新弄。（弄个新的ROM）
<img src ="http://www.cppblog.com/guogangj/aggbug/143292.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guogangj/" target="_blank">Jiang Guogang</a> 2011-04-02 17:26 <a href="http://www.cppblog.com/guogangj/archive/2011/04/02/143292.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>浅析Windows Mobile内存机制</title><link>http://www.cppblog.com/guogangj/archive/2011/03/24/142653.html</link><dc:creator>Jiang Guogang</dc:creator><author>Jiang Guogang</author><pubDate>Thu, 24 Mar 2011 08:39:00 GMT</pubDate><guid>http://www.cppblog.com/guogangj/archive/2011/03/24/142653.html</guid><wfw:comment>http://www.cppblog.com/guogangj/comments/142653.html</wfw:comment><comments>http://www.cppblog.com/guogangj/archive/2011/03/24/142653.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/guogangj/comments/commentRss/142653.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guogangj/services/trackbacks/142653.html</trackback:ping><description><![CDATA[Windows Mobile的ROM，RAM可能会比较令人迷惑，这是因为：操作系统所说的ROM，RAM并不是硬件上的ROM芯片和RAM芯片。概念不同，所以必须理解清楚这个不同之后才能继续。<br><br>首先说硬件上的ROM，RAM，我们购买手机的时候，在手机参数里通常喜欢这么说明（以我的HTC HD2为例）：<br><br>ROM：1024M<br>RAM：576M<br><br>这是什么意思呢？这指的是手机上面的两颗芯片的数据容量，ROM这颗芯片其实并非真的Read-only，它的特点只是断电后上面数据不会丢失，而RAM这颗芯片则跟我们PC上的内存条芯片一样，断电后数据丢失。<br><br>接下来是操作系统所说的ROM和RAM，Windows Mobile的刷机其实就是将ROM文件的内容写入到那颗ROM芯片去。而操作系统第一次启动的时候将完成一些后续的相关初始化。Windows Mobile所认为的ROM，指的是ROM芯片中被写入的那些只读的部分，这部分的内容是不能改变的，（刷机才能改）那么剩下的能被程序和操作系统改变的，就是RAM了，所以RAM也不等同于硬件上的RAM芯片，它还包括了ROM芯片中可以读写的那一部分。<br><br>那么，下面所提到的ROM和RAM都是操作系统概念上的ROM和RAM，而不是硬件上ROM芯片和RAM芯片。<br><br>任何Windows Mobile设备，ROM保存了整个操作系统，包括操作系统自带的那些应用程序，也都在ROM里边。如果ROM里边的模块（在资源管理器中看到的可执行文件，通常是EXE和DLL，在这里称之为模块）没有被压缩，那么操作系统就它&#8220;当地执行&#8221;（Excute In Place，也就是缩写词XIP）；反之，如果ROM里边的模块是压缩过的，那操作系统就只能先把模块解压缩到RAM中，然后再在RAM中执行它。至于哪些模块可以XIP，那是OEM相关的。<br><br>使用XIP有很大好处，最重要的是节省了宝贵的RAM，也节省了模块家载入RAM中所需要消耗的时间。<br><br>那我们平常安装的软件，保存的配置，是存放在哪里呢？——存放在&#8220;对象存储&#8221;（Object Store）或者卡上，存放在&#8220;对象存储&#8221;或者卡上的可执行模块，是无法XIP的，只能先加载入RAM，然后再在RAM中执行。<br><br>上面提到了&#8220;对象存储&#8221;，下面进一步讲解：<br><br>Windows Mobile的RAM（再次提醒一下，指的不是硬件上的RAM芯片）分为两个部分：<br><br>其一就是&#8220;对象存储&#8221;，&#8220;对象存储&#8221;里的内容在断电后继续保留，不会丢失；另一个就是&#8220;程序内存&#8221;，程序内存的内容会在断电后丢失。<br><br>&#8220;对象存储&#8221;存放的内容包括各种文件，数据库，数据库记录，注册表等；而&#8220;程序内存&#8221;则存放应用程序运行时候的堆（heap）和栈（stack）。<br><br>当Windows Mobile启动的时候，它创建了单独的4G虚拟地址空间，这4G的空间中划分了33个格子，每个格子32M，所有的进程共享这个地址空间，当一个进程启动的时候，操作系统就为它选一个格子来映射。这是跟桌面的Windows很不一样的机制，据说Windows CE 6.0已经改进了这种内存机制，但最新版本的Windows Mobile 6.5其实还是基于Windows CE 5.x内核的。微软这么设计估计是因为想节省便携式设备本来就很宝贵的资源，但这样做的缺点显而易见，一是只能最多跑32个进程（第1个格子总是用来映射前端进程的地址空间），二是每个进程默认只能有32M的虚拟空间（虽然你还可以通过内存映射文件机制或调用VirtualAlloc函数来分配超过32M的虚拟内存）。<br><br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/windows_mobile_memory_structure.png" width=308 height=355>&nbsp;<br><br>我们在Windows Mobile的系统设置里面看到的&#8220;主内存&#8221;，指的就是RAM。而ROM呢？ROM不光是只读，我认为它还是不可读，几乎不可见的，常规的程序是看不到ROM的，即便你能够在资源管理器里找到那些属于ROM的&#8220;文件&#8221;，但你还是无法读取它或者将它&#8220;复制&#8221;出来。<br><br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/windows_mobile_memory_controlpanel.png" width=461 height=768><br><br>如上图，主内存分两类，一是&#8220;存储&#8221;，一是&#8220;程序&#8221;，其实也就是前面提到的&#8220;对象存储&#8221;和&#8220;程序内存&#8221;了。也许你发觉&#8220;程序&#8221;的总内存只有460.02M，而不是硬件上标称的576M，要解释这个可相当不容易，具体参考我前面转载的一篇文章：<br><br><a href="http://www.cppblog.com/guogangj/archive/2010/12/19/136927.html">http://www.cppblog.com/guogangj/archive/2010/12/19/136927.html</a><br>
<img src ="http://www.cppblog.com/guogangj/aggbug/142653.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guogangj/" target="_blank">Jiang Guogang</a> 2011-03-24 16:39 <a href="http://www.cppblog.com/guogangj/archive/2011/03/24/142653.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows Mobile中文拼音序</title><link>http://www.cppblog.com/guogangj/archive/2011/02/12/139943.html</link><dc:creator>Jiang Guogang</dc:creator><author>Jiang Guogang</author><pubDate>Sat, 12 Feb 2011 09:05:00 GMT</pubDate><guid>http://www.cppblog.com/guogangj/archive/2011/02/12/139943.html</guid><wfw:comment>http://www.cppblog.com/guogangj/comments/139943.html</wfw:comment><comments>http://www.cppblog.com/guogangj/archive/2011/02/12/139943.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/guogangj/comments/commentRss/139943.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guogangj/services/trackbacks/139943.html</trackback:ping><description><![CDATA[为了实现中文拼音序，就必须能够用拼音来比较汉字大小，默认情况下，Windows Mobile下的字符都是UNICODE，UNICODE明显并不是拼音序，所以不能直接用_tcscmp之类的函数，我记得Windows环境下可用strcoll实现，但当我在Windows Mobile环境下尝试使用strcoll时，却发现strcoll并没有被实现，郁闷。查了很多资料之后，发觉GBK码是拼音序的，OK，就用这个权宜之计吧：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;&nbsp;MAX_WCHAR_LENGTH&nbsp;&nbsp;&nbsp;64</span><span style="COLOR: #000000"><br></span><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;&nbsp;MAX_CHAR_BUFF_LEN&nbsp;&nbsp;(MAX_WCHAR_LENGTH*2)</span><span style="COLOR: #000000"><br><br>INT&nbsp;StrCmpPinyin(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;WCHAR</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;str1,&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;WCHAR</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;str2)<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;WCHAR&nbsp;szWStr1[MAX_WCHAR_LENGTH];<br>&nbsp;&nbsp;&nbsp;&nbsp;WCHAR&nbsp;szWStr2[MAX_WCHAR_LENGTH];<br>&nbsp;&nbsp;&nbsp;&nbsp;CHAR&nbsp;szStr1[MAX_CHAR_BUFF_LEN];<br>&nbsp;&nbsp;&nbsp;&nbsp;CHAR&nbsp;szStr2[MAX_CHAR_BUFF_LEN];<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;StringCchCopyW(szWStr1,&nbsp;MAX_WCHAR_LENGTH,&nbsp;str1);<br>&nbsp;&nbsp;&nbsp;&nbsp;StringCchCopyW(szWStr2,&nbsp;MAX_WCHAR_LENGTH,&nbsp;str2);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;WideCharToMultiByte(CP_ACP,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;szWStr1,&nbsp;</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">,&nbsp;szStr1,&nbsp;MAX_CHAR_BUFF_LEN,&nbsp;NULL,&nbsp;NULL);<br>&nbsp;&nbsp;&nbsp;&nbsp;WideCharToMultiByte(CP_ACP,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;szWStr2,&nbsp;</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">,&nbsp;szStr2,&nbsp;MAX_CHAR_BUFF_LEN,&nbsp;NULL,&nbsp;NULL);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;_stricmp(szStr1,&nbsp;szStr2);<br>}</span></div>
测试了一下，效率还行&#8230;&#8230;
<img src ="http://www.cppblog.com/guogangj/aggbug/139943.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guogangj/" target="_blank">Jiang Guogang</a> 2011-02-12 17:05 <a href="http://www.cppblog.com/guogangj/archive/2011/02/12/139943.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]谁用了我的内存--PPC RAM的缺失本质</title><link>http://www.cppblog.com/guogangj/archive/2010/12/19/136927.html</link><dc:creator>Jiang Guogang</dc:creator><author>Jiang Guogang</author><pubDate>Sun, 19 Dec 2010 04:27:00 GMT</pubDate><guid>http://www.cppblog.com/guogangj/archive/2010/12/19/136927.html</guid><wfw:comment>http://www.cppblog.com/guogangj/comments/136927.html</wfw:comment><comments>http://www.cppblog.com/guogangj/archive/2010/12/19/136927.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guogangj/comments/commentRss/136927.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guogangj/services/trackbacks/136927.html</trackback:ping><description><![CDATA[<p><span style="COLOR: #0000ff">博主：关于Windows Mobile的ROM和RAM的相关问题，我也确实够头大的，虽然自己经过了一些研究有了一些结论，但还是未能完全解释为什么会这样，今天偶尔找到一篇文章，总算比较全面的描述了这些相关的细节问题，虽然对于一个软件开发者来说，不明白这些也关系不大，但有一个比较全面的了解很明显能够帮助我们理清思路。<br></span><br>转自：<a href="http://club.tech.sina.com.cn/mobile/thread-61369-1-1.html">http://club.tech.sina.com.cn/mobile/thread-61369-1-1.html</a><br><br>网上看帖，发现常有网友尤其新手在问：我的机器标称有128 MB 的RAM，为什么打开系统设置里的内存选项却显示总的程序内存（RAM）只有11x MB或10x MB。机器RAM说是64 MB, 可是为什么总的内存显示只有5x 甚至4x MB？<br><br>回答则是五花八门，莫衷一是：内置软件，后台程序，开机服务和程序，系统缓存或缓冲池，常驻内存的核心占用，系统占用，甚而解释为刷系统就占用的（部分ROM占用）.&#8230;&#8230;<br><br>个别回答更为武断：谁的PPC使用中的内存加上剩余内存会等于机器所标称的内存的？－－所以实在没有深究的必要。<br><br>话虽如此，毕竟这个差值对不同的机器往往不同，个别甚至相差还很大，因而很多用户仍免不了有些心中惴惴。<br><br>那么究竟哪种解释更为准确呢？本文的目的就是解开一部分用户心中的这个疑惑。<br><br><strong style="FONT-SIZE: 24pt">【谁用了我的内存？】<br></strong>为什么WM5/6系统显示的总程序内存（RAM）会比标称内存总量少几兆，十几兆，甚至几十兆字节的容量呢？</p>
<p>产生这种疑问的根源在于WM5/6系统设置实际并没有显示出实际总的RAM容量，它所显示的只是WM操作系统在载入时及载入后应用程序和进程所可控制/支配的内存总量，它包括&#8220;已使用&#8221;（In use）和&#8220;闲置&#8221;(Free)两部分。其中&#8220;已使用&#8221;部分除操作系统占用外，还包括了硬件驱动，个人信息管理，电话拨号等在系统启动时自动加载的，用户实际没有控制权的程序。这些程序，一部分来自微软，一部分来自设备制造商，还有一部分来自移动通讯服务商（PPC Phone）。</p>
<p>除设置中所显示的总容量外，其余部分的内存被固定用作了其它方面的用途而并未被系统设置里的内存状况显示所计算在内。这是用户所不能控制的并且更为隐蔽的另一部分被占内存。</p>
<p>这部分隐蔽的被占内存主要被用在了五个方面。</p>
<p><strong>1. 缓存池（Page Pool）</strong></p>
<p>系统运行程序，程序代码和代码所产生的数据都会消耗内存。对于NOR型flash ROM的设备，代码可以从ROM里直接被CPU调用执行。这种执行方式叫作&#8220;立即执行&#8221;或&#8220;就地执行&#8221; (XIP: execute in place)。对于NAND型flash ROM的设备，程序代码必须首先被调入内存，然后再从内存里被CPU逐条执行。如果没有缓存池，代码会首先被全部调入普通的内存里。缓存池实际上就是起到了限制执行代码时占用过多内存的作用，也就是说，超出了缓存池容量的其余代码不会被预先调入内存，而只有需要时再行调入。</p>
<p>WM5系统的NAND型ROM设备的缓存池大小一般是4.5 MB。</p>
<p><strong>2. 射频协议栈（Radio Stack）</strong></p>
<p>在PPC手机中，有相当部分的代码是用于和发射基站间的通讯。在某些设备里，这一无线通讯模块有自己的RAM和ROM。而在其它设备里，无线通讯模块的代码是被存储在系统的ROM里的。这样，它或者是就地执行，或者是调入内存执行。如果是后者，那么这部分被占内存会直接从总的内存中划掉而不被计入系统设置里所显示的总的内存容量的。</p>
<p>这一模块（射频协议栈）占用约 4 MB内存。</p>
<p><strong>3. 直接存取内存区（DMA Buffers）</strong></p>
<p>一些硬件可以不经CPU的处理和控制而自行写内存，这叫作直接性内存读写(DMA: Direct Memory Access）。这块内存区在系统加载前已被事先分出（而不受CPU支配）。这种方式的优点在于能够极高效和通常更低能耗地进行数据的传送。在早期的 PPC里，这主要用在音频采集上，通常占用内存很小。现在，它被用于视频采集，从而也占用了大得多的内存。</p>
<p>机器的生产商会根据机器在应用方面的定位来调整这部分内存的大小。譬如如果主要用途是预设为拍照，则会需要较小的DMA内存，而如果考虑用于摄像，则需要占用大得多的内存，而如果是视频会议的话，所需内存会更大。</p>
<p>直接存取内存区的容量从300 KB 到 6 MB 不等。对于把视频采集作为主要应用方向之一的机器，可能会在4 MB左右。</p>
<p><strong>4. 核心区（XIP Kernel）</strong></p>
<p>操作系统最核心的部分需要就地执行（XIP）的模式。对于NAND型ROM的设备，在系统加载时，需要把这部分代码首先载入内存，并从这部分代码开始执行后面的任务。由于系统正在运行时还无法分辨正被执行的这部分核心代码是从ROM还是RAM执行的，所以它会假设是从ROM里执行的从而把这部分内存排除在外。</p>
<p>核心区占用约 1.5 到 2 MB 大小。</p>
<p><strong>5. 帧缓冲区（the Frame Buffer)</strong></p>
<p>这部分内存专门用作存储当前屏幕上显示的一切信息。大多数设备，每个像素占用两个字节（16-bit 65535种色彩）。所以一般320x240的QVGA屏需要150 KB，而640x480的VGA屏需要600 KB。有时为了显示性能方面的原因，机器 会设置两个帧缓冲区，这样就会占用1.2 MB的内存容量。</p>
<p>最后来做一下加法：Page Pool (+Radio Stack)+DMA Buffer+XIP Kernel+Frame Buffer</p>
<p>4.5 (+4) + 0.3 | 6　+ 1.5 | 2 + 0.15 | 1.2 = 6.45 | 13.7 (10.45 | 17.7)</p>
<p>所以基于NAND型ROM 的PPC里所占用的未显示内存范围在6.45-13.7 MB，PPC Phone会多占用约4 MB。而基于NOR型flash ROM的机器可能会减少约4.5 MB (PPC) 的内存占用。其它方面，有摄像头尤其更强调动态视频摄录效果的设备占用容量会更大，VGA显示的机器也会高一些。</p>
<p>举例：手头的HP iPAQ 21x (PPC，640x480 VGA，无摄像头，WM6，NAND flash ROM): 128 MB(总)-121.40(显示)＝6.6 MB，与上面的估算结果相当符合。对于现在市场上一般配置的PPC手机（基本都是基于NAND型flash ROM的设备），这部分未显示内存大约会占用13-15 MB的空间。</p>
<p>另外，需要说明的个例是HTC Touch DiaMond。该款机器号称有192 MB DDR SDRAM，但实际上其中的64 MB是内置于CPU中的显存（供3D图形显示用，有说亦用于无线模块的），所以对整个系统而言，可资利用的有效内存仍只有128 MB（内存利用上在图形显示方面或许会节省一些---未知）。因此与其它128 MB RAM的类似配置的设备相比，钻石机的用户并没有发现在可用RAM上有什么优势。HTC Touch HD的标称RAM容量也存在同样的数字游戏。</p>
<p>最后强调的一点是，在对内存的利用和分配上，机器生产商总可能会针对不同型号机器的某些组件作一定调整，也总会在预载应用软件与速度及用户可利用的内存资源上作出取舍。所以即使对于具有相同操作系统和同样标称内存但不同款型的机器，机器启动后的用户可用内存也可能会相差很大。</p>
<p><span style="FONT-SIZE: 24pt"><strong>【关于Flash ROM的基本常识】</strong></span></p>
<p>在性能上，RAM的读写速度非常快（读、写速度基本相当），由于需要频繁刷新，也非常耗电（所以对掌上设备而言，RAM并非完全是多多益善，过多闲置无用的RAM会耗掉大量不必要的电力）；而ROM的读写速度相比RAM慢很多，尤其是写入速度更慢，但耗电较少（由于不需要高频刷新来维持记忆）。<br><br>所以应用上，ROM主要是用以存储程序和数据，而RAM主要用以运行程序。<br><br>Flash ROM 按照实现的整个电路逻辑结构及相应存储单元擦写操作的不同分为NAND和NOR两种类型。NOR型提供完整的寻址与资料总线，并允许随机存取内存上的任何区域，因而其特点是读取数据快，但需要较长的时间进行擦写。NAND型没有随机存取外部寻址总线，必须以区块性的方式进行读取。与NOR型相比，它具有具有较快的擦写时间,但数据读取的速度较慢。NAND型ROM的每个储存单元的面积也更小，这使得NAND Flash相较于NOR Flash具有较高的储存密度与较低的单位存储成本。同时它的可重复擦写次数也高出NOR Flash一个量级。所以现在所有的存储卡都是NAND型的flash ROM。<br><br>NOR型ROM更类似传统的ROM，支持CPU进行字节级别的读取。而NAND型ROM则类似于硬盘，适合作为大量数据存储介质。所以对于NOR型 ROM，CPU可以进行就地执行（XIP）而省去了把代码先读入RAM的步骤，载入和运行代码的速度更快，并可减少所需的RAM空间。<br><br>在实际系统中，XIP只能用于底层的（操作系统）代码。对于后续安装的被列入文件系统的程序，是必须载入RAM才能够被CPU执行的。<br><br>对于NOR flash ROM和XIP的关系再补充一点的是，并非NOR型flash ROM都会选择XIP方式。因为对于一块flash ROM芯片不能同时进行读/写操作，所以如果代码和数据都装在一个ROM上，既要XIP，又要同时进行数据写入的话，实现上相当麻烦（因为写入时无法从 ROM读入代码，所以对中断的处理会很复杂）。所以解决方法或者是不用XIP，或者是将XIP代码和数据区分离在两个ROM上，或者采用比较复杂的技术来实现（IPSM）。<br><br><span style="FONT-SIZE: 24pt"><strong>【关于设备里ROM的占用情况】<br></strong></span>应有的朋友的要求，这里补充说明一下关于ROM的占用情况。对于ROM占用，由于没有黑幕（除引导记录和文件分配表外），所以情形相对简单一些。 <br><br>与RAM的情况有些类似，在系统设置里，ROM，即存储内存（Storage)的总容量与设备的标定ROM相比有一个几十兆的大缺口。举例而言，HP iPAQ 210系列，WM6.0, 标定256 MB ROM, 系统设置显示总存储内存为162.30 MB, 有近96 MB的差值。但发现并解释这个差值则简单明了得多。这部分系统设置没有显示的空间是从软件意义上来说的真正的ROM（只读）部分，文件系统没有读写的权力，是系统的操作系统和备份文件以及预装在ROM部分的程序（包括来自微软，设备制造商以及移动服务商，对于自制的系统还包括ROM包里的其它程序和数据），主要装在\windows目录下。用资源管理器查看属性会发现有ROM属性，对文件无法修改，也无法复制－－操作系统是禁止对ROM文件的操作的。所以操作系统在显示时把这部分干脆拿了出来，因为这是文件系统无法使用的部分。修改这部分文件的途径只有通过刷ROM来重写。硬启时设备也是通过这部分文件来恢复系统到初始状态。<br><br>硬启后会发现存储内存的已使用部分并不是0，这是根据ROM文件恢复的，文件系统内可以读写的部分操作系统的文件。现在我们做加法。把所有设备上的存储空间（除存储卡外）加起来。以手头的iPAQ为例，用Resco Explorer，把所有目录和文件全选（包括"iPAQ File Store&#8220;，这实际是从系统的flash ROM分出的一个存储卡结构，在硬启时不会被刷新），去掉SD Card和CF Card（如果有的话）以及RAM Disk （RAM模拟的）为111.15 MB。系统设置里的空闲存储空间为134.83 MB。总的ROM容量就是：111.15+134.83 = 245.98 MB。<br><br>这个数字接近256 MB了，但仍有约10 MB的差距。<br><br>这里可以想到的有两种解释。<br><br>第一，是由文件系统的结构，尤其是大量小文件造成的。<br><br>一般写入一个1个字节甚至0字节的文件，虽然查看发现全部文件的总字节数没有增加，但实际上这个文件已经占用了一个区，比如512个字节的空间，所以系统的可用空间实际已经减少了512个字节。对于大文件来讲，这个比例会很低，但对小文件，这个浪费的空间比例很高，尤其是很多小文件时，浪费的总的空间就相当可观了。这个现象在硬盘上尤其突出，因为它的每个最小的文件单位-簇的空间相对更大，所以比如1个字节的文件，会占用4KB或更大(fat, fat32)的有效空间。<br><br>但WM系统的ROM（只读）文件使用的不是一般的文件体系，而是压缩的形式，即文件大小是多少，就会实际占用多少（关于这一点，见下一部分的说明）。这样就只能由第二点来解释。<br><br>第二，ROM的总空间的确小于标定容量。<br><br>这里涉及到存储介质容量的单位问题。在计算机应用方面，1KB=1024字节，而不是1000, 1MB=2^20, 1GB=2^30。但是存储介质（硬盘，存储卡等）的生产厂家在宣传产品时，偷换了单位，即标定容量的1MB=1,000,000 字节，而不是2^20=1,048,576 字节，1GB=1,000,000,000字节，而不是2^30=1,073,741,824字节，从而变相降低了成本。所以买回来的号称80G的硬盘，计算机上显示的可用空间只有70多GB。存储卡也是如此。（少5% (M为单位)到 7%（G为单位））<br><br>所以对于和存储卡在物理上一致的系统内置ROM，出现同样的数字游戏也并不新奇。<br><br>另外就是flash ROM的实际容量对于比如每个卡可能都不同，有一个波动范围，flash ROM在生产时也会留有一定的冗余空间以备出现坏区时备用。<br><br>所以考虑第二点原因，245.98 X 1.024^2= 257.93 MB，这与标定的256 MB的ROM总容量是基本吻合的。<br><br>注：关于这部分的讨论可能有错漏，需参考更多资料核实。</p>
<p><span style="FONT-SIZE: 24pt"><strong>【 关于WM系统&#8220;\Windows&#8221;目录下的两类文件 】<br></strong></span>搞清这一点，其一是为上一部分关于ROM空间的分析作补充说明，其二是为了阐明为什么通常无法对\Windows系统里的ROM属性的文件进行常规的文件操作，为什么对有些系统文件（非ROM属性）却可以。<br><br>实际上WM系统对内置ROM的使用，的确是分成了两部分区别对待的。其一是文件（Files）部分，其二是模块(Modules)部分。<br><br>文件部分与磁盘、存储卡等用来存放文件的存储空间的性质和文件结构是一类的，原则上用户具有完全的读写权力。操作系统里所有图片及多媒体文件都被存放在这一部分。这也是为什么我们可以随意更换桌面图片－－尽管桌面图片文件也是属于操作系统自带的文件之一。一些程序也是以通常的（可执行）文件形式存放在这部分的，所以也会发现对某些&#8220;\Windows&#8220;的可执行文件我们也可以随意处置。（<span style="COLOR: #ff0000">博主：假如我删除了这类文件，在硬重置的时候它们会被恢复么？如果会，那如何解释？</span>）<br><br>对于第二部分的文件，则用常规的方法来进行操作一般都是无能为力的。查看属性就会发现这类文件都标有一个&#8220;ROM&#8221;属性，而且无法更改。实际上，这部分程序文件在被刷入flash ROM前，是经过了特别处理的。大多数文件的文件头已被截去，文件代码和数据在ROM里的存放地址也是完全固定的。所以从存放的形式来说，这些程序是可以直接被运行而不必先被调入RAM的。即便不需要XIP，这种存储形式也提高了代码载入、执行的效率。另外，这些文件本身变小了，而且不同文件能够以更紧凑的形式存放在这个部分，从而节省了ROM空间。<br><br>存放的形式也决定了即使可以把ROM属性的程序文件拷贝出来（有工具可以做到），也无法立即使用它们－－必须再利用工具重新生成一个正常文件（加上文件头），同时还要考虑到有些程序可能针对特定的设备进行过代码的优化与压缩－－这决定了这不是一件直截了当，总能成功的活儿。 所以通常制作的新ROM总是非常依赖于特定机型的。</p>
<img src ="http://www.cppblog.com/guogangj/aggbug/136927.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guogangj/" target="_blank">Jiang Guogang</a> 2010-12-19 12:27 <a href="http://www.cppblog.com/guogangj/archive/2010/12/19/136927.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>WM_SIZE在WM_CREATE之前？</title><link>http://www.cppblog.com/guogangj/archive/2010/10/21/130733.html</link><dc:creator>Jiang Guogang</dc:creator><author>Jiang Guogang</author><pubDate>Thu, 21 Oct 2010 05:01:00 GMT</pubDate><guid>http://www.cppblog.com/guogangj/archive/2010/10/21/130733.html</guid><wfw:comment>http://www.cppblog.com/guogangj/comments/130733.html</wfw:comment><comments>http://www.cppblog.com/guogangj/archive/2010/10/21/130733.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guogangj/comments/commentRss/130733.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guogangj/services/trackbacks/130733.html</trackback:ping><description><![CDATA[我一直认为创建一个窗口的时候，窗口处理过程处理WM_CREATE是在处理WM_SIZE之前的，所以很多初始化的东西都放在WM_CREATE处来做，但最近弄一个程序发现到了WM_SIZE处出错，原因是空指针，而这个指针应该是在WM_CREATE的时候被赋值的，奇怪了，难道WM_SIZE会在WM_CREATE之前？于是设两个断点，不看不知道，一看还真的如此，如下图：<br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/size_before_create_1.png" width=684 height=291><br>程序每次总是先触到WM_SIZE的这个断点，难道我理解一直有误？于是我创建了一个hello world程序，调试了半天，又发觉没有这个问题，WM_CREATE总是在WM_SIZE之前，我尝试在别处重现问题，无果&#8230;&#8230;现在，你再仔细看一下上图，你发现问题了么？<br><br>我想经过我这么提示，你应该知道了：原因就是WM_CREATE这个断点前一行的SetWindowLong这个调用，这个调用会引起一个WM_SIZE事件，所以这就制造了WM_SIZE在WM_CREATE之前这个假象。处理这个问题很简单，把SetWindowLong这行拿掉，然后把WS_NONAVDONEBUTTON这个属性交给CreateWindow，如下图：<br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/size_before_create_2.png" width=835 height=140><br>这样就好了，我想顺便提个问题，我在设计一个程序的时候，也碰到了&#8220;布局&#8221;和&#8220;加载&#8221;的先后问题，因为布局可能需要重新调整加载的资源，而加载资源又需要参考布局的尺寸，由于功能上的原因，我必须把两者分开，所以存在我前面说的这个先鸡先蛋的难题。最后我是这么弄的，做一个&#8220;资源是否已经加载&#8221;的标志，然后总是先&#8220;布局&#8221;，布局的时候检查这个标志，如果没有资源的加载，那就只更改尺寸参数而不调整资源，这样看起来就没什么问题了，从逻辑上来说我的设计确实是WM_SIZE优先于WM_CREATE&#8230;&#8230;<br><br>欢迎对这些方面的设计问题留言讨论。
<img src ="http://www.cppblog.com/guogangj/aggbug/130733.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guogangj/" target="_blank">Jiang Guogang</a> 2010-10-21 13:01 <a href="http://www.cppblog.com/guogangj/archive/2010/10/21/130733.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>让窗口“最大化”显示</title><link>http://www.cppblog.com/guogangj/archive/2010/08/20/124098.html</link><dc:creator>Jiang Guogang</dc:creator><author>Jiang Guogang</author><pubDate>Fri, 20 Aug 2010 07:24:00 GMT</pubDate><guid>http://www.cppblog.com/guogangj/archive/2010/08/20/124098.html</guid><wfw:comment>http://www.cppblog.com/guogangj/comments/124098.html</wfw:comment><comments>http://www.cppblog.com/guogangj/archive/2010/08/20/124098.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guogangj/comments/commentRss/124098.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guogangj/services/trackbacks/124098.html</trackback:ping><description><![CDATA[<p>闲话不说了，这是一种可能有问题的做法：</p>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;cap&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;GetSystemMetrics(SM_CYCAPTION);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;wid&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;GetSystemMetrics(SM_CXSCREEN);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;hei&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;GetSystemMetrics(SM_CYSCREEN);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;hWnd&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;CreateWindow(szWindowClass,&nbsp;szTitle,&nbsp;WS_NONAVDONEBUTTON</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">WS_VISIBLE</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">WS_POPUP,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;cap,&nbsp;wid,&nbsp;hei</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">cap,&nbsp;NULL,&nbsp;NULL,&nbsp;hInstance,&nbsp;NULL);</span></div>
这才是比较地道的做法：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;RECT&nbsp;rectWorkArea;<br>&nbsp;&nbsp;&nbsp;&nbsp;SystemParametersInfo(SPI_GETWORKAREA,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;(PVOID)</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">rectWorkArea,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;hWnd&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;CreateWindow(szWindowClass,&nbsp;TEXT(</span><span style="COLOR: #000000">""</span><span style="COLOR: #000000">),&nbsp;WS_NONAVDONEBUTTON</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">WS_VISIBLE</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">WS_POPUP,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rectWorkArea.left,&nbsp;rectWorkArea.top,&nbsp;rectWorkArea.right</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">rectWorkArea.left,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rectWorkArea.bottom</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">rectWorkArea.top,&nbsp;NULL,&nbsp;NULL,&nbsp;hInstance,&nbsp;NULL);</span></div>
两种创建出来的窗口的高度可能相差几个像素，前一种方法可能导致窗口在创建完之后，有一次莫名其妙的WM_SIZE消息产生，有些东西啊，懂就是懂，不懂就是不懂&#8230;&#8230;想也想不出来。
<img src ="http://www.cppblog.com/guogangj/aggbug/124098.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guogangj/" target="_blank">Jiang Guogang</a> 2010-08-20 15:24 <a href="http://www.cppblog.com/guogangj/archive/2010/08/20/124098.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows Mobile锁屏软件的初级实现</title><link>http://www.cppblog.com/guogangj/archive/2010/08/09/122733.html</link><dc:creator>Jiang Guogang</dc:creator><author>Jiang Guogang</author><pubDate>Mon, 09 Aug 2010 02:13:00 GMT</pubDate><guid>http://www.cppblog.com/guogangj/archive/2010/08/09/122733.html</guid><wfw:comment>http://www.cppblog.com/guogangj/comments/122733.html</wfw:comment><comments>http://www.cppblog.com/guogangj/archive/2010/08/09/122733.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/guogangj/comments/commentRss/122733.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guogangj/services/trackbacks/122733.html</trackback:ping><description><![CDATA[锁屏并不是一个很难的功能，初步想了一下觉得这样，其实未必&#8230;&#8230;本文是我琢磨了好几天下来的成果，而且只是&#8220;初级&#8221;的，对Windows Mobile不够熟，没人辅导，真是累啊。<br><br>先给读者些感性认识，这是我手机上Windows Mobile 6.1默认的锁屏程序：<br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/lockscreen1_1.png" width=320 height=320><br>虽然说是锁屏，其实是连键盘一块儿锁了，真正的英文名称是叫&#8220;Lock Device&#8221;的，锁设备。锁了之后，你碰一碰键盘上其它按键，大致就这样显示：<br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/lockscreen1_2.png" width=320 height=320><br>表示你要继续使用设备的话，得先&#8220;解锁&#8221;。<br>从按键盘按键设备还有反应这点上看，所谓锁屏其实并没有真正屏蔽掉所有按键，只是对这些按键进行了一些别的处理而已。<br><br>但无疑这个锁屏太土了，很多人不喜欢，所以才有了别的锁屏软件，比如下面这个叫S2U2，这是个免费软件，好评率还蛮高的，这是它默认的锁屏界面，其实界面还是可以定制的，可以弄得很漂亮：<br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/lockscreen1_3.png" width=320 height=320><br>这个软件的&#8220;锁屏&#8221;方式跟系统默认的就有所不同了，它貌似屏蔽了所有的键盘按键，只能通过滑动屏幕上的那个滑块来解锁。<br>现在接下来找个Windows Mobile 6.5的手机看看。<br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/lockscreen1_4.png" width=240 height=320><br>更好看一些，我稍微研究了一下6.5的锁屏，其实也并非屏蔽所有按键，你可以这么试验一下：隐藏所有窗口，在&#8220;今日&#8221;下锁屏，然后按一下绿色的电话键，然后解锁。你就会发觉屏幕显示的不是&#8220;今日&#8221;，而是拨号面板，说明电话键还是起作用了，但我尝试下来挂机键却没起作用。<br>如果上面这些问题你都不认为是什么问题，那么处理来电消息的问题呢？有没想过。默认情况下，电话一来，系统会弹出消息框，键盘自动解锁，但这很容易引起误操作，所以我看见HTC的锁屏就很好地处理了这个问题，它需要用户在屏幕上划一下，才解锁，虽然有的用户会嫌麻烦，但我想总比误接听好吧？<br><br>现在你认识到了吧，&#8220;锁&#8221;，不是简单的锁而已。<br><br>前面是不是说得有点多了，所以本文显得有些头重脚轻，因为我目前实现的只有&#8220;初级&#8221;，所以内容还不是很多。<br><br>首先是锁键盘，锁屏时候屏蔽所有按键，这个可以用钩子，关于Windows Mobile上的钩子，网上文章有不少，但你看完后发觉都是抄来抄去的，烦都烦死，原作我找了一下，很可能（不是100%）是来自这里：<a href="http://www.codeproject.com/KB/windows/wincekbhook.aspx">http://www.codeproject.com/KB/windows/wincekbhook.aspx</a>，而且，目前只能设置WH_KEYBOARD_LL类型的钩子，WH_KEYBOARD_LL被define为20，这个跟Windows系统还不一样，不过也不能怪Microsoft，因为hook在Windows Mobile中本来就是undefined的，不推荐使用。而且我在使用钩子的过程中遇到了问题，就是钩子对我的手机Samsung i780完全无效，（而模拟器还有另外两台多普达的机器是没问题的）当然了，安装钩子的时候我查看过返回值，都是正常的，只是hook不到任何键盘消息，我的手机上出现了这种情况，这也意味着别的手机也可能出现。<br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/lockscreen1_5.png" width=286 height=374><br>折腾了许久之后，（我还尝试了另外好几种方法，但都不理想）我终于找到了解决方案，那就是从GAPI中分离出来的一个API，AllKeys，在本地的MSDN中是找不到这个函数的，但通过在线的MSDN很快就能找到这个函数的说明，用起来十分十分简单，完全能达到我的功能要求，而且对我的Samsung i780是有效的！<br><br>键盘解决了，然后是来电处理，来电时候我目前的处理跟系统默认的一样，一来电，就立即自动解锁键盘，并且显示电话拨号面板，电话结束后再自动锁上，这样做虽然不是很好，但至少可以接受。那就要处理来电和挂断消息了，一开始打算用TAPI，网上很多人也都这么说的，但TAPI非常复杂，功能很强大，而我需要的仅仅是得到通知这么一个功能，有点牛刀杀鸡的感觉，而TAPI还有个问题，就是貌似它具有&#8220;独占性&#8221;，我的程序一旦占据了电话，别的程序要用电话就可能有问题了，这个我没深入研究。<br><br>最后我采用的方法是注册系统通知消息，RegistryNotifyWindow，现在把关键代码贴出来：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #0000ff">#define</span><span style="COLOR: #000000">&nbsp;WM_USER_TELEPHONE_STATE&nbsp;&nbsp;(WM_USER+1086)</span><span style="COLOR: #000000"><br><br></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">WM_CREATE<br></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Register&nbsp;the&nbsp;notification&nbsp;for&nbsp;monitoring&nbsp;the&nbsp;telephone&nbsp;state.</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">RegistryNotifyWindow(SN_PHONEINCOMINGCALL_ROOT,&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">defined&nbsp;in&nbsp;snapi.h</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;SN_PHONEINCOMINGCALL_PATH,&nbsp;SN_PHONEINCOMINGCALL_VALUE,&nbsp;hWnd,&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">handle&nbsp;to&nbsp;our&nbsp;window&nbsp;to&nbsp;receive&nbsp;msg</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;WM_USER_TELEPHONE_STATE,&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">app&nbsp;defined&nbsp;message&nbsp;to&nbsp;send</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;NULL,&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">app&nbsp;defined&nbsp;value</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;NULL,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">g_hregNotifyPhone);<br><br></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"><img src="http://www.cppblog.com/Images/dot.gif"><img src="http://www.cppblog.com/Images/dot.gif"><br></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Phone&nbsp;state&nbsp;changed!</span><span style="COLOR: #008000"><br></span><span style="COLOR: #0000ff">case</span><span style="COLOR: #000000">&nbsp;WM_USER_TELEPHONE_STATE:<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;((wParam</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">SN_PHONEINCOMINGCALL_BITMASK)</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">SN_PHONEINCOMINGCALL_BITMASK<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">||</span><span style="COLOR: #000000">&nbsp;(wParam</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">SN_PHONECALLTALKING_BITMASK)</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">SN_PHONECALLTALKING_BITMASK)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AllKeys(FALSE);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ShowWindow(hWnd,&nbsp;SW_HIDE);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;{</span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AllKeys(TRUE);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ShowWindow(hWnd,&nbsp;SW_SHOW);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SHFullScreen(hWnd,&nbsp;SHFS_HIDETASKBAR</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">SHFS_HIDESIPBUTTON);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SetForegroundWindow(hWnd);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">break</span><span style="COLOR: #000000">;</span></div>
<br>代码看起来简单，我却研究了许久&#8230;&#8230;这样实现的功能就是来电时候锁屏窗口隐藏，解锁键盘，让系统默认程序接管，电话结束时候重新show出窗口，继续锁屏。其余细节代码就不贴了，虽然细节还有很多，但大致就这些，要真正弄出跟HTC那样的锁屏，还有很多要研究的。下次有机会我再写吧，当然前提是我已经研究出来之后。<br>
<img src ="http://www.cppblog.com/guogangj/aggbug/122733.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guogangj/" target="_blank">Jiang Guogang</a> 2010-08-09 10:13 <a href="http://www.cppblog.com/guogangj/archive/2010/08/09/122733.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows Mobile程序全屏与非全屏</title><link>http://www.cppblog.com/guogangj/archive/2010/08/03/122035.html</link><dc:creator>Jiang Guogang</dc:creator><author>Jiang Guogang</author><pubDate>Tue, 03 Aug 2010 02:09:00 GMT</pubDate><guid>http://www.cppblog.com/guogangj/archive/2010/08/03/122035.html</guid><wfw:comment>http://www.cppblog.com/guogangj/comments/122035.html</wfw:comment><comments>http://www.cppblog.com/guogangj/archive/2010/08/03/122035.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/guogangj/comments/commentRss/122035.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guogangj/services/trackbacks/122035.html</trackback:ping><description><![CDATA[Windows Mobile如何让应用程序全屏显示，网上问这个问题的人很多，你也能轻松找到答案，但很多人反映效果不完美，如切换程序后又没了全屏效果，这次我花了些时间整理出我的实现，当然我也不保证我的就很完美，但至少在我用了这么久之后发觉自己这种方法还是蛮可靠的。<br><br>所谓全屏，也就是让应用程序窗口占满整个屏幕，任务栏不显示，菜单栏不显示，另外顺便在这里普及下知识，什么叫任务栏（Task Bar），什么叫菜单栏（Menu Bar），什么是开始图标（Start Icon），什么是软输入法按钮（SIP Button）。直接看图：<br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/fullscreen_1.png" width=350 height=500><br>通过上图，我想大家也都了解怎么回事了，真是长篇大论不如一张小图。任务栏你可以理解为Windows Mobile的一部分，跟Windows的任务栏一样，是一直存在的，开始图标就处于任务栏的左边，跟Windows不一样的是Windows Mobile的任务栏一般处于屏幕顶端；而菜单栏则跟Windows的菜单也有点像，它属于应用程序的一部分，当应用程序不创建它的时候，它就是不存在的，当然了，它和Windows的菜单一样，并不包含在窗口客户区内。<br><br>知道这个之后，那我们的工作就比较明确了：第一，不要创建菜单栏；第二：隐藏掉任务栏或者把任务栏放在我们的窗口的下面。当然了，还要把窗口调整为屏幕大小。就这么多了。相应的API为SHFullScreen，看一下MSDN，貌似很简单，OK，直接在WM_CREATE中加入SHFullScreen(SHFS_HIDETASKBAR)如何？<br><br>结果没有反应，再仔细看看MSDN的说明，对于SHFS_HIDETASKBAR参数有以下描述：It is the responsibility of the application to make sure it is sized FULL SCREEN before using this flag. Otherwise, it will appear as though the function did nothing。注意&#8220;before&#8221;这个词，看来我们要在掉SHFullScreen之前将窗口位置及大小调整为全屏。代码：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #000000">RECT&nbsp;rectFullScreen;&nbsp;<br>SetRect(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">rectFullScreen,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">, GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN));<br>SetWindowPos(hWnd,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;rectFullScreen.left,&nbsp;rectFullScreen.top, rectFullScreen.right</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">rectFullScreen.left, rectFullScreen.bottom</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">rectFullScreen.top,SWP_NOZORDER);<br>SHFullScreen(hWnd,&nbsp;SHFS_HIDETASKBAR);</span></div>
这样就能够全屏了，但还不够，为什么？也许你注意到软输入法按钮并没有被隐藏掉，你再试试看再打开一个程序，然后回到你的全屏程序去，这时候你发觉全屏变成了非全屏了，如图：<br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/fullscreen_2.png" width=350 height=500><br>所以我们还得做些事情，我直接给出代码：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #0000ff">case</span><span style="COLOR: #000000">&nbsp;WM_ACTIVATE:<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Try&nbsp;to&nbsp;hide&nbsp;the&nbsp;boring&nbsp;SIP&nbsp;button.</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;dwHideOption&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;SHFS_HIDESIPBUTTON;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(g_bFullScreenState)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dwHideOption&nbsp;</span><span style="COLOR: #000000">|=</span><span style="COLOR: #000000">&nbsp;(SHFS_HIDETASKBAR);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(wParam</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">WA_ACTIVE&nbsp;</span><span style="COLOR: #000000">||</span><span style="COLOR: #000000">&nbsp;wParam</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">WA_CLICKACTIVE)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SHFullScreen(hWnd,&nbsp;dwHideOption);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Notify&nbsp;shell&nbsp;of&nbsp;our&nbsp;activate&nbsp;message</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;SHHandleWMActivate(hWnd,&nbsp;wParam,&nbsp;lParam,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">s_sai,&nbsp;FALSE);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">break</span><span style="COLOR: #000000">;</span></div>
其中的&#8220;g_bFullScreenState&#8221;是程序记录是否全屏状态的一个布尔型变量，然后你再试试，我不确切在你机器上是否OK，但在我这里尝试了6.0和6.5的机器，都是没问题的，你把程序切来切去都是可以保证看到它全屏的，而且全屏与非全屏间还可以自由切换。这是我写的demo的截图：<br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/fullscreen_3.png" width=350 height=500>
<img src ="http://www.cppblog.com/guogangj/aggbug/122035.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guogangj/" target="_blank">Jiang Guogang</a> 2010-08-03 10:09 <a href="http://www.cppblog.com/guogangj/archive/2010/08/03/122035.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>记一下，老是忘：如何生成map文件</title><link>http://www.cppblog.com/guogangj/archive/2010/07/27/121390.html</link><dc:creator>Jiang Guogang</dc:creator><author>Jiang Guogang</author><pubDate>Tue, 27 Jul 2010 04:48:00 GMT</pubDate><guid>http://www.cppblog.com/guogangj/archive/2010/07/27/121390.html</guid><wfw:comment>http://www.cppblog.com/guogangj/comments/121390.html</wfw:comment><comments>http://www.cppblog.com/guogangj/archive/2010/07/27/121390.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guogangj/comments/commentRss/121390.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guogangj/services/trackbacks/121390.html</trackback:ping><description><![CDATA[本文只有一图，让自己别再忘了。<br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/the_map_file.png" width=749 height=580>
<img src ="http://www.cppblog.com/guogangj/aggbug/121390.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guogangj/" target="_blank">Jiang Guogang</a> 2010-07-27 12:48 <a href="http://www.cppblog.com/guogangj/archive/2010/07/27/121390.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>按挂机键，程序窗口不隐藏</title><link>http://www.cppblog.com/guogangj/archive/2010/07/14/120332.html</link><dc:creator>Jiang Guogang</dc:creator><author>Jiang Guogang</author><pubDate>Wed, 14 Jul 2010 07:09:00 GMT</pubDate><guid>http://www.cppblog.com/guogangj/archive/2010/07/14/120332.html</guid><wfw:comment>http://www.cppblog.com/guogangj/comments/120332.html</wfw:comment><comments>http://www.cppblog.com/guogangj/archive/2010/07/14/120332.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guogangj/comments/commentRss/120332.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guogangj/services/trackbacks/120332.html</trackback:ping><description><![CDATA[<span style="FONT-FAMILY: 宋体">用过Windows Mobile的人都知道，一般情况下，按下挂机键（就是挂电话那个按键，通常是红色的），就相当于Windows XP中点了那个&#8220;显示桌面&#8221;的图标，所有窗口都最小化，桌面显示出来了，Windows Mobile中的&#8220;今日&#8221;（Today）就相当于Windows的桌面，按挂机键，&#8220;今日&#8221;就显示出来了，别的窗口都隐藏（最小化）。<br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/spb_home_0.png" width=303 height=99><br>这个效果我是想模仿一个叫Spb Home的桌面美化程序，用过Spb Home的都很清楚这是怎样一个效果。<br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/spb_home_1.png" width=243 height=323><br>那我现在有这么个需求，我希望我的程序不被挂机键隐藏，也就是说希望我的程序取代&#8220;今日&#8221;，在别的窗口都被隐藏或关闭的时候，我的程序窗口依旧显示。下面是我的思路轨迹：<br><br>做Windows编程出身的我首先想到WM_SHOWWINDOW消息，我程序的主窗口被最小化的时候应该能够收到这个消息，我只要对这个消息进行相关处理即可，但令我感到意外的是Windows Mobile似乎没有这个消息，到网上search，没有答案，纳闷&#8230;&#8230;<br><br>没有WM_SHOWWINDOW，终归有别的吧？于是我用Windows CE Remote Spy观察一个窗口在按下挂机键时候接收到的消息，分析了多种情况后，我发现有一个消息确实是按下挂机键时候能接收到的，但这个消息没有在MSDN中被提及，我只知道它的值为0xC005。<br><br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/spb_home_4.png" width=626 height=76><br><br>响应这个消息，每次收到的时候调用一下SetForegroundWindow()，这么一来，果然奏效了！但问题来了，每次按挂机键的时候，屏幕总要闪一下，为什么？原因就是我的窗口收到0xC005消息的时候，它已经被隐藏了，我重新把它show出来当然要闪一下，这个效果并不理想。<br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/spb_home_5.png" width=546 height=141><br>继续想办法，那能不能通过钩子来重定义挂机键的动作呢？后来想想不妥，因为我并不是要屏蔽或者修改挂机键的功能，我只是不想让我的窗口被它隐藏而已，况且钩子是undocumented的东西，恐怕不太好。<br><br>再思考，如果挂机键的功能就是被默认地定义为隐藏所有窗口，那我如何阻止它呢？这是不太可能的吧？所以我想来想去还是想到Spb Home了，看看Spb Home的窗口究竟有什么不同，结果还真的有了新发现，问题也因此得解。大家看：<br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/spb_home_3.png" width=653 height=522><br>看窗口风格这个值，0x90010000，跟我的程序最大的不同是：首bit是1！第一个bit是什么意思呢？是WS_POPUP，于是我有样学样，在我的窗口上加上WS_POPUP属性，就OK了！WS_POPUP窗口不会自动最大化显示，我们要指定它的显示位置和大小，这是跟overlapped window的不同，关于popup，overlapped这些东西，我有另一篇比较完整的文章来阐述的，地址是：</span><a href="http://blog.csdn.net/guogangj/archive/2008/12/06/3460267.aspx"><span style="FONT-FAMILY: 宋体">http://blog.csdn.net/guogangj/archive/2008/12/06/3460267.aspx</span></a><br><br><span style="FONT-FAMILY: 宋体">问题终于解决了，没想到处理起来这么简单，但知道这么弄，却让我研究了好久。<br></span>
<img src ="http://www.cppblog.com/guogangj/aggbug/120332.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guogangj/" target="_blank">Jiang Guogang</a> 2010-07-14 15:09 <a href="http://www.cppblog.com/guogangj/archive/2010/07/14/120332.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>core error unable to track?</title><link>http://www.cppblog.com/guogangj/archive/2010/07/14/120322.html</link><dc:creator>Jiang Guogang</dc:creator><author>Jiang Guogang</author><pubDate>Wed, 14 Jul 2010 05:51:00 GMT</pubDate><guid>http://www.cppblog.com/guogangj/archive/2010/07/14/120322.html</guid><wfw:comment>http://www.cppblog.com/guogangj/comments/120322.html</wfw:comment><comments>http://www.cppblog.com/guogangj/archive/2010/07/14/120322.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/guogangj/comments/commentRss/120322.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guogangj/services/trackbacks/120322.html</trackback:ping><description><![CDATA[程序运行时出错，如果是以下两种情况之一，我通常都能解决：<br>一，能够定位出错的大概位置。<br>二，错误能够被重现。<br>但，如果出错几率极低，不知道怎么重现，那我就没辙了。前段时间我的程序就遇到这么个问题：<br><br>RaiseException: Thread=85e6b8fc Proc=803dbc00 'SetupDemo.exe'<br>AKY=00000401 PC=03fad178(coredll.dll+0x00063178) RA=80009e54(NK.EXE+0x00008e54) BVA=00000000 FSR=00000000<br><br>从出错提示上看，是(coredll.dll+0x00063178)这个位置的问题，但coredll.dll根本没有代码，也不知道我的程序是从什么地方进入到这个出错的地方的，更糟糕的是——我没法重现这个错误，它出现概率很低，我完全不知道什么时候它会蹦出来。<br><br>今天运气比较好，我居然找到出错地方了，根本不是什么coredll.dll的代码有问题，说了你都觉得好笑，这是一个典型的除零错误，只不过出现概率很低。后来我另写了一个程序，故意执行了一个除零错误，结果也是出现类似的错误提示：<br><br>RaiseException: Thread=96d18a40 Proc=80096b80 'ZeroDivisor.exe'<br>AKY=00000401 PC=03fb09f8(coredll.dll+0x000629f8) RA=88037538(NK.EXE+0x00007538) BVA=00000000 FSR=00000000<br><br>我就纳闷着为什么调试器不会停在出错的地方，以便我发现这个错误呢？<br><br>经验经验，有时候我觉得我们开发者像艺术家，有时候我却觉得像侦探&#8230;&#8230;
<img src ="http://www.cppblog.com/guogangj/aggbug/120322.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guogangj/" target="_blank">Jiang Guogang</a> 2010-07-14 13:51 <a href="http://www.cppblog.com/guogangj/archive/2010/07/14/120322.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows Mobile模拟器上网设置</title><link>http://www.cppblog.com/guogangj/archive/2010/07/12/120127.html</link><dc:creator>Jiang Guogang</dc:creator><author>Jiang Guogang</author><pubDate>Mon, 12 Jul 2010 08:33:00 GMT</pubDate><guid>http://www.cppblog.com/guogangj/archive/2010/07/12/120127.html</guid><wfw:comment>http://www.cppblog.com/guogangj/comments/120127.html</wfw:comment><comments>http://www.cppblog.com/guogangj/archive/2010/07/12/120127.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guogangj/comments/commentRss/120127.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guogangj/services/trackbacks/120127.html</trackback:ping><description><![CDATA[<p style="FONT-FAMILY: 宋体">有时候我们需要用Windows Mobile模拟器测试一些网络应用，需要用模拟器上网。一开始我是准备在模拟器的configuration中设置的，如图：<br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/wm_simulator_online_5.png" width=528 height=407><br>但后来发觉比较复杂，又遇到了别的问题，一直没搞好，很是郁闷，我想用VMWare架设的虚拟机都能直接桥接到主机，那Windows Mobile模拟器应该也有这个功能吧，经过一番折腾，终于搞定了，方法如下：<br><br>启动&#8220;Windows Mobile 设备中心&#8221;（Windows Mobile Device Center），以前都叫ActiveSync的，后来到了Windows Vista就把名称换成这个了（这个我不是很确定），所以现在我们新的系统，Windows Vista和Windows 7装的就是这个玩意儿了。如果你的机器上没有的话就到Microsoft的网站下一个，搜索一下很快能找到的，但我不太相信你的机器上没装，因为Visual Studio 2008调试Windows Mobile的时候需要这个玩意儿。启动之：<br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/wm_simulator_online_2.png" width=404 height=496><br>设备中心启动后如下图那样设置，特别注意一下，允许连接到以下任一端口选择&#8220;DMA&#8221;，否则下面可能行不通：<br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/wm_simulator_online_3.png" width=834 height=602><br>然后启动Device Emulator Manager。（这里讲点题外话，Emulator是仿真器的意思，而我们常说的模拟器对应的英文单词是Simulator，两者其实是有点差别的，感兴趣的话去搜索引擎查查）<br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/wm_simulator_online_4.png" width=406 height=496><br>选择你要使用的模拟器，Connect。我这里选择的是WM6 Pro VGA。<br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/wm_simulator_online_6.png" width=503 height=442><br>连接好之后，在同样的地方选择Cradle，意思是把它安装到底座。<br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/wm_simulator_online_7.png" width=503 height=442><br>这时候Windows Mobile设备中心的主界面出现，选择&#8220;不设置设备就进行连接&#8221;。<br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/wm_simulator_online_9.png" width=718 height=483><br>这个时候回头看模拟器，其界面下方出现了个小图标，表示和电脑连接起来了。<br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/wm_simulator_online_10.png" width=480 height=640><br>这个时候就可以上网了。</p>
<img src ="http://www.cppblog.com/guogangj/aggbug/120127.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guogangj/" target="_blank">Jiang Guogang</a> 2010-07-12 16:33 <a href="http://www.cppblog.com/guogangj/archive/2010/07/12/120127.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows Mobile的高效贴图</title><link>http://www.cppblog.com/guogangj/archive/2010/06/20/118316.html</link><dc:creator>Jiang Guogang</dc:creator><author>Jiang Guogang</author><pubDate>Sun, 20 Jun 2010 12:04:00 GMT</pubDate><guid>http://www.cppblog.com/guogangj/archive/2010/06/20/118316.html</guid><wfw:comment>http://www.cppblog.com/guogangj/comments/118316.html</wfw:comment><comments>http://www.cppblog.com/guogangj/archive/2010/06/20/118316.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.cppblog.com/guogangj/comments/commentRss/118316.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guogangj/services/trackbacks/118316.html</trackback:ping><description><![CDATA[<span style="FONT-FAMILY: 宋体; FONT-SIZE: 12pt">位图这个概念对于计算机图形学来说是个至关重要的概念，我们在屏幕上看到的任何东西，对计算机来说，其实都是位图，简单地说，无论你是想显示文字，还是线条，抑或bmp，png，jpg和gif等图像文件，最终都是要直接或间接转变为计算机显示设备所认识的位图，才能显示在屏幕上。<br><br>我最近接手了一个项目，是Windows Mobile平台的，主要做UI美化，贴图是其中的一大块，我遇到的最大的问题就是贴图的效率问题，如何将一张内存里的图片高效绘制出来，实现平滑流畅的UI动画效果。我尝试了许多办法，甚至DirectDraw，但我发觉在硬件不支持的情况下，DirectDraw除了让代码变得更复杂之外，没有任何优点。好，接下去我们来分析一下如何尽量发挥GDI的威力。<br><br>跟贴图相关的函数有几个：<br><strong style="COLOR: #0000ff">BitBlt</strong>：最基本的块传输函数。<br><strong style="COLOR: #0000ff">StretchBlt</strong>：比同BitBlt，它支持图像的拉伸和压缩，当不需要拉伸和压缩时候，它的效果和BitBlt并无二致。<br><strong style="COLOR: #0000ff">TransparentBlt</strong>：比同StretchBlt，它多了个&#8220;抠色&#8221;（Color Keying）功能，能把某种颜色或者某个范围的颜色抠去而不作块传输处理，以此来绘制不规则图像。<br><strong style="COLOR: #0000ff">AlphaBlend</strong>：比同StretchBlt，它支持Alpha混合，即&#8220;半透明&#8221;效果，效果比简单的&#8220;抠色&#8221;更好。<br><br>这几个函数是一个比一个强，但也意味着效率一个比一个低，总体上看差不多是这样的，运算量越大，当然就越慢，但测试下来发觉这其实并不绝对，后面会提到。<br><br>了解了这几个函数之后，我们开始加载一张图片来观察效果，我准备的是一张320*320的png图片，利用Windows Mobile 6.0提供的IImage接口来加载它，并把它转变为位图，获得HBITMAP。加载png的代码可以通过搜索引擎搜索&#8220;IImage用法&#8221;等关键词来获取，此处略过。<br><br>加载好图片后，创建一个和设备显示设备兼容的DC（Device Context），选入上面加载的位图，用BitBlt绘制，代码如下（为简洁起见，只贴出关键代码，并且不考虑资源释放）：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #000000">HDC&nbsp;hWndDC&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;GetDC(hWnd);<br>HDC&nbsp;hMemDC&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;CreateCompatibleDC(hWndDC);<br>SelectObject(hMemDC,&nbsp;hBitmap);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">hBitmap是前面加载的图片</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">BitBlt(hWndDC,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;iWidth,&nbsp;iHeight,&nbsp;hMemDC,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;SRCCOPY);</span></div>
<br>我们通过添加一些debug代码来观察BitBlt的执行时间，在我的模拟器上大约是50 - 60ms，我发觉这个速度并不快，按道理说，BitBlt应该可以在极短的时间之内完成的（1 - 2ms），也只有这样才能实现&#8220;流畅&#8221;的UI动画效果，否则图一旦多起来，岂不是更慢。<br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/wm_paint_paint_time.PNG" width=623 height=629><br><br>我尝试修改BitBlt的最后一个参数，我发觉换成NOTSRCCOPY，速度更慢，变成了70多ms，说明运算量更大了，这不是简单的内存拷贝；而当我把最后一个参数换成BLACKNESS或者WHITENESS的时候，速度则很快，1ms-2ms即可完成，很显然，对BitBlt来说，把目标全部置为黑色或者白色，运算量远少于像素传送。在实验的时候把BitBlt替换为另外的几个函数，效果和预期的相差不大，如果图像需要拉伸，则执行得更慢一些，但如果图像不是拉伸，而是压缩，即缩小显示，执行速度居然比较快，有些意外，这是因为压缩后图像变小，需要传输的像素变少的缘故。<br><br>我考虑如何提高绘图效率，经过很多次尝试，终于有所突破，我最后发现：如果先把位图存放在一个和DC兼容的位图中，再用这个位图对目标设备进行像素传输，速度十分理想。代码：<br>
<div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #000000">HDC&nbsp;hWndDC&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;GetDC(hWnd);<br>HDC&nbsp;hMemDC&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;CreateCompatibleDC(hWndDC);<br>HDC&nbsp;hMemDCToLoad&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;CreateCompatibleDC(hWndDC);<br>HBITMAP&nbsp;hMemBmp&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;CreateCompatibleBitmap(hWndDC,&nbsp;iWidth,&nbsp;iHeight);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;The&nbsp;compatible&nbsp;bitmap</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">HGDIOBJ&nbsp;hOldBmp&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;SelectObject(hMemDC,&nbsp;hMemBmp);<br>SelectObject(hMemDCToLoad,&nbsp;hBitmap);<br>BitBlt(hMemDC,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;iWidth,&nbsp;iHeight,&nbsp;hMemDCToLoad,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;SRCCOPY);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">Do&nbsp;this&nbsp;in&nbsp;initialization</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">BitBlt(hWndDC,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;iWidth,&nbsp;iHeight,&nbsp;hMemDC,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;SRCCOPY);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">This&nbsp;BitBlt's&nbsp;speed&nbsp;is&nbsp;very&nbsp;fast</span></div>
<br>第一次调用BitBlt，可以看作是初始化，我们计算第二个BitBlt的耗时，只有1 - 2ms，非常不错，经过分析，我认为原因应该是这样（不一定全对，如有不妥请读者指出）：<br><br>只有在位图格式完全一致的情况下，BitBlt才能执行真正的内存拷贝，否则是要经过转换的，转换是需要消耗CPU时间的，所以慢。<br><br>那如何知道位图的格式呢？用GetObject可以看出来：<br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/guogangj/wm_paint_bmp_format.PNG" width=551 height=302><br>如上图所示，bmp是从png文件加载进来的位图的信息，而bmp2是用CreateCompatibleBitmap创建的位图的信息，从这我们能看到，前者是24bit位图，即一个像素用3个字节表示，而后者是16bit位图，一个像素用两个字节来表示，这个BitBlt执行过程中，就需要转换了，因此耗时。而实际上位图的差别可能比这个还要复杂些，如果再讨论设备无关位图，那就说不完了&#8230;&#8230;<br><br>总而言之，为了提高效率，我们要想方设法把加载进来的位图转变为设备兼容位图，绘制的时候直接BitBlt这些设备兼容位图，来实现位图的高效绘制。<br><br>前面讨论的主要是BitBlt，那对于别的几个Blt函数呢？我都尝试过了，除了AlphaBlend之外，兼容位图到设备的Blt速度上都有显著的提高，而AlphaBlend则无法正常工作，因为兼容位图不带Alpha通道，而AlphaBlend貌似需要32bit的ARGB格式的位图方可正常工作，这个问题我思考了好久都无解，如果哪位读者对提高AlphaBlend的工作效率有心得，不妨跟我联系下，我正急需这方面的技术资料。<br><br>因此，我给出这样的结论，阶段性结论：从文件（或资源）加载位图后，把位图转为设备兼容位图，这样使得BitBlt在执行SRCCOPY的时候直接使用内存拷贝，速度很快，即便需要拉伸压缩或者抠色等运算，使用兼容位图的速度也是相当不错的，而使用AlphaBlend的时候，如果需要较高的效率，就应从设计上避免绘制大幅位图，改用小幅位图，在不必要对每一帧都执行Alpha混合的时候，就避免执行，以免影响画面的流畅性。<br></span>
<img src ="http://www.cppblog.com/guogangj/aggbug/118316.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guogangj/" target="_blank">Jiang Guogang</a> 2010-06-20 20:04 <a href="http://www.cppblog.com/guogangj/archive/2010/06/20/118316.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>屏幕分辨率</title><link>http://www.cppblog.com/guogangj/archive/2010/06/03/117096.html</link><dc:creator>Jiang Guogang</dc:creator><author>Jiang Guogang</author><pubDate>Thu, 03 Jun 2010 05:16:00 GMT</pubDate><guid>http://www.cppblog.com/guogangj/archive/2010/06/03/117096.html</guid><wfw:comment>http://www.cppblog.com/guogangj/comments/117096.html</wfw:comment><comments>http://www.cppblog.com/guogangj/archive/2010/06/03/117096.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/guogangj/comments/commentRss/117096.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guogangj/services/trackbacks/117096.html</trackback:ping><description><![CDATA[<span style="FONT-FAMILY: 宋体">近日翻看典著《Windows程序设计》，作者提起到&#8220;分辨率&#8221;（Resolution）一词时候，指出这个词其实是有两种含义的，一种就是我们广为熟悉的纵横像素数目表示法，另一种就是DPI，DPI在打印机和扫描仪领域更常用。<br><br>先说纵横像素数目表示法，我想我们都不会陌生，640*480，这是VGA的分辨率，800*600，这是15寸CRT常用分辨率，1024*768，这是17寸CRT常用分辨率，1280*1024，这是17寸和19寸LCD额定分辨率，而目前主流的24寸16:10的LCD的额定分辨率则是1920*1200。<br><br>对于DPI，我们可能相对陌生一点，其实DPI就是像素每英寸，为什么是英寸而不是厘米？这是因为发明计算机的老美使用的长度计量单位是英制的，据我所知好像就米国和英国继续用英制了吧，别的都换成公制了，其实也不难换，1英寸等于2.54厘米。横向分辨率为96DPI的显示器，在横向的2.54厘米里，就有96个像素，可以这么说，假如你有一张100*100像素的小图片，在96DPI的显示器上（为了方便起见，假设纵横DPI都一样）应该显示为2.65*2.65厘米，在128DPI的显示器上，应该显示为1.98*1.98厘米，图片看起来在高DPI显示器上显示得更小了。那么17寸和19寸的LCD显示器都是1280*1024的，17寸LCD的DPI是否高于19寸LCD的呢？理论上应该说是的，但我们的操作系统往往不管这些，都默认是96DPI，因为就算DPI有差距，通常也差别不大，就算差别大，用户难接受，还可以改变系统的显示分辨率来达到较好的显示效果呢，而除此之外，Windows还提供了调整字体DPI的选项来让字体显示大小适应用户习惯。<br><br>情况到了便携设备上就发生了些变化，因为便携设备的纵横像素数目分辨率不能调整，而且DPI可能差距很大。我的手机是Samsung SGH-i780的，方屏，分辨率为320*320，有次同事看了我的手机，说：&#8220;字怎么这么小的？&#8221;，他用的是240*320的，我就对比了一下我们的手机，屏幕宽度基本一致，高度我的就比他的短了一截，你想啊，垂直像素总数大家都是320点，而我的短了一截，所以看起来显示的文字就比较小了。还有更夸张一些的，现在新出的手机有480*800分辨率的，称作WVGA，横向480点，但实际物理尺寸跟我的320点的屏幕差不多，那上门的字恐怕就更小了，可能小到看不清了。而事实上呢？<br><br>事实上并没有这样，因为手机软件的作者已经考虑到这种事情了，所以在绘制文字的时候，会把文字弄大一点，这样文字的物理尺寸还是差不多的，而看起来却更加&#8220;细腻&#8221;。<br><br>横向DPI和纵向DPI可以这样获取：<br><br>GetDeviceCaps(hdc, LOGPIXELSX);<br>GetDeviceCaps(hdc, LOGPIXELSY);<br><br>对Windows Mobile来说，应该是这样的：<br>
<table style="WIDTH: 221px; BORDER-COLLAPSE: collapse; HEIGHT: 162px" border=1 cellSpacing=0 cellPadding=3>
    <tbody>
        <tr>
            <td>屏幕分辨率</td>
            <td>DPI</td>
        </tr>
        <tr>
            <td>240x320</td>
            <td>96</td>
        </tr>
        <tr>
            <td>480x640</td>
            <td>192</td>
        </tr>
        <tr>
            <td>240x240</td>
            <td>96</td>
        </tr>
        <tr>
            <td>480x480</td>
            <td>192</td>
        </tr>
        <tr>
            <td>480x800</td>
            <td>192</td>
        </tr>
        <tr>
            <td>320x320</td>
            <td>128</td>
        </tr>
    </tbody>
</table>
<br>你也许要问，为什么能够保证是这样？厂家能不能偷偷把屏幕做大一些，或者小一些？我想大概这是一种规范吧。生产Windows Mobile硬件的厂商也就那么几个，应该蛮好保证的。<br><br>那从我们开发者的角度来说，如何开发适用于各种DPI的程序呢？按照Microsoft的说法，可以这样：<br>You can continue to work in pixels but remove assumptions about the DPI by: <br>&#8226;Using the SCALEX and SCALEY macros to scale 96-DPI pixel coordinates, or using the metrics returned by GetSystemMetrics.<br>&#8226;Expressing sizes or positions relative to other controls.<br>&#8226;Expressing sizes or positions relative to a font.<br><br>更具体内容参考：<br></span><a href="http://msdn.microsoft.com/en-us/library/bb416656.aspx"><span style="FONT-FAMILY: 宋体">http://msdn.microsoft.com/en-us/library/bb416656.aspx</span></a><br>
<img src ="http://www.cppblog.com/guogangj/aggbug/117096.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guogangj/" target="_blank">Jiang Guogang</a> 2010-06-03 13:16 <a href="http://www.cppblog.com/guogangj/archive/2010/06/03/117096.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows CE, Pocket PC, Smart Phone, Windows Mobile和Windows Phone到底有何分别？</title><link>http://www.cppblog.com/guogangj/archive/2010/05/06/114558.html</link><dc:creator>Jiang Guogang</dc:creator><author>Jiang Guogang</author><pubDate>Thu, 06 May 2010 01:21:00 GMT</pubDate><guid>http://www.cppblog.com/guogangj/archive/2010/05/06/114558.html</guid><wfw:comment>http://www.cppblog.com/guogangj/comments/114558.html</wfw:comment><comments>http://www.cppblog.com/guogangj/archive/2010/05/06/114558.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/guogangj/comments/commentRss/114558.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/guogangj/services/trackbacks/114558.html</trackback:ping><description><![CDATA[尽管微软在桌面操作系统领域呼风唤雨，但在嵌入式领域却连连受挫，因为它得面对许多强大的竞争对手，Symbian，Linux，iPhone，还有迅猛崛起的Android，一个个都很强大。而微软本身的产品线则显得有些混乱，我以前常常被一些名词搞得很糊涂，即便现在，我想还是有很多人搞不懂本文标题这些名词的区别。<br><br>那如何简单地来说一下呢？<br><br>Let's make is simple：微软的嵌入式OS都是基于Windows CE的。<br><br>用&#8220;基于&#8221;这个词比较准确，可以这么说，Windows CE是微软的操作系统，而其它那些名词则是不同时候的不同产品线，现在主流产品是Windows Mobile；Pocket PC和Smart Phone是过去时；而Windows Phone（准确说是Windows Phone 7）则是将来时。<br><br>不同的产品线就意味着不同的删减和增加，界面可能差别很大，API甚至有不同，所以彼此间也不尽兼容。<br>
<img src ="http://www.cppblog.com/guogangj/aggbug/114558.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/guogangj/" target="_blank">Jiang Guogang</a> 2010-05-06 09:21 <a href="http://www.cppblog.com/guogangj/archive/2010/05/06/114558.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>