﻿<?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++博客-Aiscanf-文章分类-Wince</title><link>http://www.cppblog.com/Aiscanf/category/10754.html</link><description /><language>zh-cn</language><lastBuildDate>Tue, 02 Jun 2009 01:58:26 GMT</lastBuildDate><pubDate>Tue, 02 Jun 2009 01:58:26 GMT</pubDate><ttl>60</ttl><item><title>wince1：最简单的窗口程序</title><link>http://www.cppblog.com/Aiscanf/articles/86465.html</link><dc:creator>Aiscanf</dc:creator><author>Aiscanf</author><pubDate>Mon, 01 Jun 2009 13:11:00 GMT</pubDate><guid>http://www.cppblog.com/Aiscanf/articles/86465.html</guid><wfw:comment>http://www.cppblog.com/Aiscanf/comments/86465.html</wfw:comment><comments>http://www.cppblog.com/Aiscanf/articles/86465.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Aiscanf/comments/commentRss/86465.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Aiscanf/services/trackbacks/86465.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 一共有三个代码：打包下载：http://files.cppblog.com/Aiscanf/wince1.rar#include&nbsp;&lt;windows.h&gt;#include&nbsp;&lt;CommCtrl.h&gt;#define&nbsp;dim(x)&nbsp;(sizeof(x)/sizeof(x[0]))typedef&nbsp;struct&nbsp;&nbsp...&nbsp;&nbsp;<a href='http://www.cppblog.com/Aiscanf/articles/86465.html'>阅读全文</a><img src ="http://www.cppblog.com/Aiscanf/aggbug/86465.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Aiscanf/" target="_blank">Aiscanf</a> 2009-06-01 21:11 <a href="http://www.cppblog.com/Aiscanf/articles/86465.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>wince杂</title><link>http://www.cppblog.com/Aiscanf/articles/86464.html</link><dc:creator>Aiscanf</dc:creator><author>Aiscanf</author><pubDate>Mon, 01 Jun 2009 13:09:00 GMT</pubDate><guid>http://www.cppblog.com/Aiscanf/articles/86464.html</guid><wfw:comment>http://www.cppblog.com/Aiscanf/comments/86464.html</wfw:comment><comments>http://www.cppblog.com/Aiscanf/articles/86464.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Aiscanf/comments/commentRss/86464.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Aiscanf/services/trackbacks/86464.html</trackback:ping><description><![CDATA[对文本输出的两个常用函数：<br><strong>BOOL</strong> <strong>ExtTextOut(</strong><br>&nbsp; <strong>HDC</strong> <em><a class=synParam onclick=showTip(this) href=""><u><font color=#0000ff>hdc</font></u></a></em><strong>, </strong><br>&nbsp; <strong>int</strong> <em><a class=synParam onclick=showTip(this) href=""><u><font color=#0000ff>X</font></u></a></em><strong>, </strong><br>&nbsp; <strong>int</strong> <em><a class=synParam onclick=showTip(this) href=""><u><font color=#0000ff>Y</font></u></a></em><strong>, </strong><br>&nbsp; <strong>UINT</strong> <em><a class=synParam onclick=showTip(this) href=""><u><font color=#0000ff>fuOptions</font></u></a></em><strong>, </strong><br>&nbsp; <strong>const</strong> <strong>RECT* </strong><em><a class=synParam onclick=showTip(this) href=""><u><font color=#0000ff>lprc</font></u></a></em><strong>, </strong><br>&nbsp; <strong>LPCTSTR</strong> <em><a class=synParam onclick=showTip(this) href=""><u><font color=#0000ff>lpString</font></u></a></em><strong>, </strong><br>&nbsp; <strong>UINT</strong> <em><a class=synParam onclick=showTip(this) href=""><u><font color=#0000ff>cbCount</font></u></a></em><strong>, </strong><br>&nbsp; <strong>const</strong> <strong>int* </strong><em><a class=synParam onclick=showTip(this) href=""><u><font color=#0000ff>lpDx</font></u></a></em><br><strong>);</strong> <br><br><strong>int</strong> <strong>DrawText(</strong><br>&nbsp; <strong>HDC</strong> <em><a class=synParam onclick=showTip(this) href="">hDC</a></em><strong>, </strong><br>&nbsp; <strong>LPCTSTR</strong> <em><a class=synParam onclick=showTip(this) href="">lpString</a></em><strong>, </strong><br>&nbsp; <strong>int</strong> <em><a class=synParam onclick=showTip(this) href="">nCount</a></em><strong>, </strong><br>&nbsp; <strong>LPRECT</strong> <em><a class=synParam onclick=showTip(this) href="">lpRect</a></em><strong>, </strong><br>&nbsp; <strong>UNIT</strong> <em><a class=synParam onclick=showTip(this) href="">uFormat</a></em><br><strong>);</strong>
<img src ="http://www.cppblog.com/Aiscanf/aggbug/86464.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Aiscanf/" target="_blank">Aiscanf</a> 2009-06-01 21:09 <a href="http://www.cppblog.com/Aiscanf/articles/86464.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>wince内存管理</title><link>http://www.cppblog.com/Aiscanf/articles/86460.html</link><dc:creator>Aiscanf</dc:creator><author>Aiscanf</author><pubDate>Mon, 01 Jun 2009 12:35:00 GMT</pubDate><guid>http://www.cppblog.com/Aiscanf/articles/86460.html</guid><wfw:comment>http://www.cppblog.com/Aiscanf/comments/86460.html</wfw:comment><comments>http://www.cppblog.com/Aiscanf/articles/86460.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Aiscanf/comments/commentRss/86460.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Aiscanf/services/trackbacks/86460.html</trackback:ping><description><![CDATA[<a href="http://www.cppblog.com/milkyway/archive/2007/03/27/20738.html">http://www.cppblog.com/milkyway/archive/2007/03/27/20738.html</a><br><br>
<h2><a id=viewpost1_TitleUrl href="http://www.cppblog.com/milkyway/archive/2007/03/27/20738.html"><u><font color=#800080>VirtualAlloc和VirtualCopy的蕴含知识点</font></u></a> </h2>
1.VirtualAlloc用来在进程的虚拟地址空间中保留（reserve)或者提交(commit)页。在保留时以64KB为粒度，即保留空间以64K为单位。而提交虚拟地址时，则以页(典型大小为4KB)为单位。<br><br>2.VirtualCopy用来绑定一块物理内存到当前进程虚拟地址空间。参数里的lpvSrc既可以是内核段的虚拟地址也可以是物理地址(用page_physical来标记)。同时要注意lpvSrc的右移与否。<br><br>3.使用VirtualAlloc要包含Winbase.h;使用VirtualCopy时要包含plfuncs.h.两者都要链接coredll.lib. <br><br>4.在CE5.0之前,使用VirtualAlloc获得的虚拟地址空间分为两种情形:<br>(1)大小在2MB以下时,位于调用进程的虚拟空间中;<br>(2)大小大于2MB时,位于用户态的共享地址空间内(0x42000000-0x7E000000 ) <br><br>关于VirtualCopy函数中lpvSrc参数的设定，我有一个问题一直想不明白。 <br>问题是，lpvSrc何时需要右移8位？ <br><br>我有下面理解，希望指教。 <br>1. 如果copy的物理地址在512M范围内，那么由于静态映射的存在，lpvSrc可以为静态映射的虚拟地址，也可以为物理地址。采用后者需要指定page_physical，同时lpvSrc右移8位。 <br>2. 如果copy的物理地址在512M范围外，那么由于微软的如下规定&#8220; <br>VirtualCopy also supports the PAGE_PHYSICAL flag. You must set this flag when you are mapping physical memory that resides beyond 512 MB, that is, physical memory with an address above 0x1FFFFFFF.&#8221; <br>lpvSrc只能为物理地址，同时需要右移。 <br><br>--------<br>可以简单认为，只要设置了PAGE_PHYSICAL 为真，那么就需要把lpvSrc右移8位<br><br>
<h2><a id=viewpost1_TitleUrl href="http://www.cppblog.com/milkyway/archive/2007/03/27/20737.html"><u><font color=#800080>wince下的地址映射知识点滴</font></u></a> </h2>
1.如果是在bootloader中打开MMU之前，程序访问设备寄存器，可以直接操作物理地址，无需虚实映射。<br><br>2.wince启动后，硬件上ARM和X86体系的处理器启动了MMU，操作系统只能访问到虚拟地址，不能直接操作物理内存了。但是如果是X86的CPU，由于它的外设I/O端口和存储器空间分开编址，可以直接嵌入汇编或者使用宏read_port_xxx,write_port_xxx来读写设备寄存器的物理地址。<br><br>3.wince软件结构里对应MMU的是一个名为OEMAddressTable的数据结构（<font size=4>源文件oeminit.asm中）</font>，其中建立了物理地址和虚拟地址的<font color=#ff0000>静态</font>映射关系，也可以在其中改动系统所能识别物理内存的大小,以支持大内存。<br><br>4.我们也可以在wince启动后调用CreateStaticMapping和NKCreateStaticMapping来实现OEMAddressTable中的这种物理地址和虚拟地址的<font color=#ff0000>静态</font>映射关系。<br><br>5.建立了静态映射关系的虚拟地址只能由内核模式下的程序来操作，例如 ISR。除非你在定制系统时，选择了full kernal mode，使所有程序都运行在完全内核模式下，这将导致系统不稳定。<br><br>6.如果要在驱动程序中访问设备寄存器，必须建立<font style="BACKGROUND-COLOR: #ffffff" color=#ff0000>动态</font>虚拟地址映射，可以调用MmmapIoSpace函数来实现，或者通过VirtualAlloc和VirtualCopy函数来实现。其实MmmapIoSpace内部就调用了后者。<br><br>7.在驱动中访问虚拟地址时，必须是非缓存段（位于0xA0000000&nbsp;到 0xBFFFFFFF ）。<br><br>8.使用VirtualCopy函数映射物理内存时，其lpvSrc参数必须右移8位，且相应的fdwProtect参数必须带page_physical。<br><br>9.如果是ARM体系的处理器，访问挂在系统总线上的设备寄存器前，必须先把总线地址转化成<font color=#ff0000>CPU</font>的地址，通过HalTranslateBusAddress实现两种物理地址的变换，然后再调用MmmapIoSpace函数作虚实地址的转换。<br>&nbsp; wince5.0下可以使用CreateBusAccessHandle(总线注册表路径）+BusTransBusAddrToVirtual来实现总线物理地址到系统虚拟地址的直接变换。
<p class=postfoot>posted on 2007</p>
Windows CE引入了虚拟内存机制管理多达4G的虚拟内存,最大支持512MB的物理内存.不同的CPU内存管理方法不同。对于MIPS和SHX系列CPU来说，地址映射是由CPU完成的,CE内核可以直接访问512MB的物理内存。对于x86系列和ARM系列的CPU来说，在内核启动过程中它会将现有物理内存地址全部映射到0x8000 0000以上的虚拟地址空间中供内核以后使用,这个虚实映射机制软件上通过OEMAddressTable实现,硬件上要求具备MMU.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;参考microsun的文章:&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"WINCE的内存（包括SDRAM及FLASH）的配置包含两个方面：源代码(包括C和汇编)中的定义,及系统配置文件CONFIG.BIB中的定义。源代码中需要定义内存的物理及虚拟地址，大小，并初始化名为OEMAddressTable的结构数组，以告知系统物理地址与虚拟地址的对应关系，系统根据其设置生成MMU页表。而CONFIG.BIB中一般会将内存定义成不同的段，各段用作不同的用途。"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我的理解是在*.h文件中声明各虚拟地址,比如用到的寄存器结构体.在虚实地址映射文件(如ARM下的map.a)的OEMAddressTable中建立虚实地址的静态映射关系,包括RAM,FLASH各部分存储空间. (OS启动后所能够识别的物理内存). 接着在config.bib的MEMORY段(参考HELP里的Memory Section)把RAM映射后的虚拟地址进行分段,比如NK的大小,各种外设缓冲区的保留等.(注意这里是虚拟地址的划分,必须建立在映射基础上)&nbsp; 这种静态的虚拟地址只能够由内核层访问,如果在APP中访问,还必须建立动态映射. <br>//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////<br>
<p><span>对外设进行</span> <span>I/O</span> <span>操作实际上也就是读写外设的寄存器,而我们通常使用的X86或者ARM处理器在硬件上决定了wince系统启动后,无法直接访问物理地址,因此需要做一些工作来实现I/O操作.</span> </p>
<p><span>首先要理解</span> <span>windows CE</span> <span>下的地址映射机制。</span> <span>wince有两种地址：物理地址和虚拟地址．不同架构的</span> <span>CPU</span> <span>硬件上的区别导致地址映射也不同。ＭＩＰＳ和ＳＨ</span> <span>x</span> <span>处理器，不采用ＭＭＵ，直接在ＣＰＵ和内核里定义</span> <span>1G</span> <span>的物理地址；而Ｘ８６和ＡＲＭ带有</span> <span>MMU</span> <span>单元，在</span> <span>OEMAddressTable</span> <span>中定义物理地址到虚拟地址间的映射关系或者是ＯＳ启动后调用</span> <span>CreateStaticMapping</span> <span>和</span> <span>NKCreateStaticMapping</span> <span>来实现从虚拟地址到物理地址的静态映射．经过静态映射的地址，可以由操作系统内核用于</span> <span>ISR</span> <span>访问设备。如果我们要在应用程序中访问外设，必须在物理地址和虚拟地址间建立动态映射关系，我们可以使用</span> <span>VirtualAlloc</span> <span>和</span> <span>VirtualCopy</span> <span>（或者直接调用</span> <span>MmmapIoSpace</span> <span>函数）来实现。</span> </p>
<p><span>其次，如果是操作通过总线挂接的</span> <span>I/O</span> <span>或者存储器，必须先把总线地址转化成</span> <span>CPU</span> <span>上的系统地址，再做物理地址到虚拟地址的映射。这里需要查</span> <span>CPU</span> <span>的</span> <span>Datasheet</span> <span>，找出所要操作的I/O地址.先调用</span> <span>HALTranslateBusAddress( )<font face=宋体>把总线地址转化成</font><span>CPU</span><span>上的系统地址,</span></span> <span>再调用</span> <span>MmmapIoSpace</span> <span>函数实现虚实映射；也可以使用</span> <span>TransBusAddrToVirtual</span> <span>（）直接把总线上的地址转化成系统的虚拟地址。</span> </p>
<p><span>第三，在一般的应用程序中访问</span> <span>I/O</span> <span>是访问它的缓存段虚拟地址，而驱动中必须访问无缓存段虚拟地址。简单来说无缓存段虚拟地址</span> <span>=</span> <span>缓存段虚拟地址</span> <span>+0x20000000</span> <span>。</span>&nbsp;<br><font size=3><span>&nbsp;&nbsp;&nbsp; 总结起来，如果是</span> <span>wince</span> <span>内核(如HAL)访问外部</span> <span>I/O</span> <span>，只需要在</span> <span>OEMAddressTable</span> <span>中定义物理地址到虚拟地址间的映射关系就可以了；<br>如果是应用程序或者驱动要访问</span> <span>I/O</span> <span>，<br>要做的工作包括：</span> <br><span>1</span> <span>。在</span> <span>CPU</span> <span>物理地址和虚拟地址间做一个动态映射，</span><br>&nbsp;<span><span>2</span> </span><span>。对虚拟地址进行操作。</span> <br><br>C#如何调用VirtualAlloc()和VirtualCopy()函数？<br>在程序前面加上: #include&lt;window.h&gt; <br>这样声明: <br>public static class API <br>{ <br><br>[DllImport( "Kernel32.dll", CharSet = CharSet.Ansi, EntryPoint = "VirtualAlloc" )] <br>public static extern IntPtr VirtualAlloc( <br>IntPtr lpAddress, <br>uint dwSize, <br>uint flAllocationType, <br>uint flProtect ); <br><br><br>[DllImport( "Coredll.dll", CharSet = CharSet.Ansi, EntryPoint = "VirtualCopy" )] <br>public static extern bool VirtualCopy( <br>IntPtr lpvDest, <br>IntPtr lpvSrc, <br>uint cbSize, <br>uint fdwProtect ); <br>} <br><br><br></p>
<p><span>在<span>X86</span>和<span>ARM</span>架构的<span>CPU</span>中<span>,wince</span>访问系统内存的方法随程序所属模式层次的不同而有所区别<span>.<br>&nbsp; 1.</span>在系统内核模式下<span>(kernel mode),在</span><span>OAL层</span>访问<span>,</span>只需要在<span>OEMAddressTable </span>中做静态的虚实地址映射就可以了<span>.</span>例如<span>X86</span>架构的映射表格式如下<span>:<br>&nbsp;&nbsp;&nbsp;; OEMAddressTable defines the mapping between Physical and Virtual Address&nbsp; // </span>定义<span>4GB</span>的虚拟地址和<span>512MB</span>存储的映射关系<span><br>&nbsp;&nbsp; ;&nbsp;&nbsp; o MUST be in a READONLY Section<br>&nbsp;&nbsp; ;&nbsp;&nbsp; o First Entry MUST be RAM, mapping from 0x80000000 -&gt; 0x00000000<br>&nbsp;&nbsp; ;&nbsp;&nbsp; o each entry is of the format ( VA, PA, cbSize )<br>&nbsp;&nbsp; ;&nbsp;&nbsp; o cbSize must be multiple of <st1:chmetcnv tcsc="0" numbertype="1" negative="False" hasspace="False" sourcevalue="4" unitname="m" w:st="on">4M</st1:chmetcnv><br>&nbsp;&nbsp; ;&nbsp;&nbsp; o last entry must be (0, 0, 0)<br>&nbsp;&nbsp; ;&nbsp;&nbsp; o must have at least one non-zero entry<br>&nbsp;&nbsp; ; RAM 0x80000000 -&gt; 0x00000000, size <st1:chmetcnv tcsc="0" numbertype="1" negative="False" hasspace="False" sourcevalue="64" unitname="m" w:st="on">64M</st1:chmetcnv>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //</span>把物理地址为<span>0x00000000</span>映射到虚拟地址为<span> 0x80000000&nbsp;</span>处<span><br>&nbsp;&nbsp; dd&nbsp; 80000000h,&nbsp;&nbsp;&nbsp; 0,&nbsp;&nbsp; 04000000h<br>&nbsp;&nbsp; ; FLASH and other memory, if any<br>&nbsp;&nbsp; ; dd&nbsp; FlashVA,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FlashPA,&nbsp;&nbsp;&nbsp; FlashSize<br>&nbsp;&nbsp; ; Last entry, all zeros<br>&nbsp;&nbsp; dd&nbsp; 0&nbsp;&nbsp; 0&nbsp;&nbsp; 0<br>2.</span>在驱动或应用程序<span>(user mode)</span>中访问<span>RAM,</span>既可以通过<span>OEMAddressTable+VirtualCopy</span>方式<span>,</span>也可以直接用<span>MmMapIoSpace</span>函数建立物理地址到当前进程虚拟地址的映射关系<span>.<br></span>经过<span>OEMAddressTable,</span>实现的只是<span>CPU</span>物理地址到<span>OS</span>内核层虚拟地址的一次映射<span>,</span>如果需要在普通的应用程序中访问内存<span>,</span>还要再用<span>VirtuaAlloc+VirtualCopy</span>做一个内核到当前进程的二次映射<span>(</span>有一种情况例外，就是你的<span>OS</span>被配置成<span>Full Kernel Mode</span>，这时任何应用程序都可以访问<span>OS</span>内核地址<span>).<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>简单说明几个关键函数<span>:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;VirtualAlloc</span>用于在当前进程的虚拟地址空间中保留或者提交空间，在保留时以<span>64KB</span>为单位，提交时以<span>4KB</span>为单位。其函数原型为</span> </p>
<p><span>&nbsp;LPVOID VirtualAlloc(</span> </p>
<p><span>&nbsp;LPVOID <span><span><u><font color=#0000ff>lpAddress</font></u></span></span>, &nbsp;//</span> <span>分配虚拟地址的起始指针</span> </p>
<p><span>&nbsp;DWORD <span><span><u><font color=#0000ff>dwSize</font></u></span></span>, <span>&nbsp;&nbsp;&nbsp;&nbsp;</span>//</span> <span>大小，以字节为单位 </span></p>
<p><span>&nbsp;DWORD <span><span><u><font color=#0000ff>flAllocationType</font></u></span></span>, //</span> <span>类型，设为<span>MEM_RESERVE</span></span> </p>
<p><span>&nbsp;DWORD <span><span><u><font color=#0000ff>flProtect</font></u></span></span><span>&nbsp;&nbsp;&nbsp;</span>&nbsp;//&nbsp;</span><span>存取保护，设为<span>PAGE_NOACCESS</span></span> </p>
<p><span>); </span></p>
<p><span>&nbsp;VirtualCopy</span> <span>用来绑定物理地址到静态映射虚拟地址：</span> </p>
<p><span>&nbsp;BOOL VirtualCopy( </span></p>
<p><span>&nbsp;LPVOID <span><span><u><font color=#0000ff>lpvDest</font></u></span></span>, <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>// </span><span>虚拟目的地址指针，接受<span>VirtualAlloc</span>的返回值</span> </p>
<p><span>&nbsp;LPVOID <span><span><u><font color=#0000ff>lpvSrc</font></u></span></span>, <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>// </span><span>源物理地址指针</span> </p>
<p><span>&nbsp;DWORD <span><span><u><font color=#0000ff>cbSize</font></u></span></span>, <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>// </span><span>大小必须与虚拟地址相同</span> </p>
<p><span>&nbsp;DWORD <span><span><u><font color=#0000ff>fdwProtect</font></u></span></span><span>&nbsp;&nbsp;</span>// </span><span>存取保护类型</span> </p>
<p><span>);</span> </p>
<p><span>这里需要注意的是</span> <span><span><span><span><u><font color=#0000ff>fdwProtect</font> </u></span></span></span></span><span>参数。如果是驱动程序访问，需要设置为</span> <span>PAGE_NOCACHE</span> <span>，以访问无缓存段虚拟地址。如果映射的物理地址范围在</span> <span>0x1FFFFFFF</span> <span>之上，必须使用</span> <span>PAGE_PHYSICAL</span> <span>，此时必须把</span> <span><span><span><span><u><font color=#0000ff>lpvSrc</font> </u></span></span></span></span><span>右移八位，实现地址对齐。（这是由内核中</span> <span>VirtualCopy</span> <span>的实现决定的，在那个函数中会判断如果是</span> <span>PAGE_PHYSICAL</span> <span>就将</span> <span>PHYSADDR</span> <span>左移</span> <span>8</span> <span>位移回来，源代码位于</span> <span>private/winceos/coreos/nk/kernel</span> <span>目录下的</span> <span>virtmem.c中的<font size=2>DoVirtualCopy</font></span> <span>）</span> </p>
<p><span>&nbsp;<a name=wce50lrfmmmapiospace></a>&nbsp;&nbsp;&nbsp; MmMapIoSpace </span><span>用来把物理地址直接映射到与进程无关的虚拟地址上。函数原型为</span> </p>
<p><span>&nbsp;PVOID MmMapIoSpace( </span></p>
<p><span>&nbsp;PHYSICAL_ADDRESS <span><span><u><font color=#0000ff>PhysicalAddress</font></u></span></span>, </span></p>
<p><span>&nbsp;ULONG <span><span><u><font color=#0000ff>NumberOfBytes</font></u></span></span>, </span></p>
<p><span>&nbsp;BOOLEAN <span><span><u><font color=#0000ff>CacheEnable</font></u></span></span></span> </p>
<p><span>);<br></span></p>
<p><span>&nbsp; </span><span>一个使用</span> <span>VirtualAlloc+Copy</span> <span>的例子：把物理地址为</span> <span>0x10000000</span> <span>的单元映射到虚拟地址空间中。</span> </p>
<p><span>#include &lt;windows.h&gt;</span> </p>
<p>&nbsp;</p>
<p><span>#define PHYSADDR&nbsp;((PVOID)0x10000000)</span> </p>
<p><span>// PHYSADDR is the physical address of the peripheral</span> </p>
<p><span>// registers</span> </p>
<p>&nbsp;</p>
<p><span>#define SIZE&nbsp;(4800*4)</span> </p>
<p>&nbsp;</p>
<p><span>LPVOID lpv;</span> </p>
<p><span>BOOL bRet;</span> </p>
<p>&nbsp;</p>
<p><span>lpv = VirtualAlloc(0, SIZE, MEM_RESERVE, PAGE_NOACCESS);</span> </p>
<p><span>// For a user mode driver, always leave the first</span> </p>
<p><span>// parameter 0 and use only the flags MEM_RESERVE</span> </p>
<p><span>// and PAGE_NOACCESS Check the return value: lpv == 0</span> </p>
<p><span>// is an error</span> </p>
<p>&nbsp;</p>
<p><span>printf(TEXT("VirtualAlloc reservation @%8.8lx\r\n"), lpv);</span> </p>
<p><span>bRet = VirtualCopy(lpv, PHYSADDR&gt;&gt;8, SIZE, PAGE_READWRITE | PAGE_NOCACHE | PAGE_PHYSICAL);</span> </p>
<p><span>// The lpv parameter is the virtual address returned</span> </p>
<p><span>// by VirtualAlloc().</span> </p>
<p><span>// Always use PAGE_NOCACHE */</span> </p>
<p>&nbsp;</p>
<p><span>// Check the return value: bRet ==0 is an error */</span> </p>
<p><span>printf(TEXT("VirtualCopy returned: %d\r\n"), bRet);</span> </p>
<p>&nbsp;</p>
<p><span>// At this point lpv is a virtual address which maps</span> </p>
<p><span>// the I/O registers</span> </p>
<p><span>// at PHYSADDR for SIZE bytes */</span> </p>
</font>
<img src ="http://www.cppblog.com/Aiscanf/aggbug/86460.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Aiscanf/" target="_blank">Aiscanf</a> 2009-06-01 20:35 <a href="http://www.cppblog.com/Aiscanf/articles/86460.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>wince的一些对sdk封装成c runtime库的实现</title><link>http://www.cppblog.com/Aiscanf/articles/86456.html</link><dc:creator>Aiscanf</dc:creator><author>Aiscanf</author><pubDate>Mon, 01 Jun 2009 11:41:00 GMT</pubDate><guid>http://www.cppblog.com/Aiscanf/articles/86456.html</guid><wfw:comment>http://www.cppblog.com/Aiscanf/comments/86456.html</wfw:comment><comments>http://www.cppblog.com/Aiscanf/articles/86456.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Aiscanf/comments/commentRss/86456.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Aiscanf/services/trackbacks/86456.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: /**//*&nbsp;&nbsp;Copyright&nbsp;(c)&nbsp;1990-2003&nbsp;Info-ZIP.&nbsp;&nbsp;All&nbsp;rights&nbsp;reserved.&nbsp;&nbsp;See&nbsp;the&nbsp;accompanying&nbsp;file&nbsp;LICENSE,&nbsp;version&nbsp;2000-Ap...&nbsp;&nbsp;<a href='http://www.cppblog.com/Aiscanf/articles/86456.html'>阅读全文</a><img src ="http://www.cppblog.com/Aiscanf/aggbug/86456.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Aiscanf/" target="_blank">Aiscanf</a> 2009-06-01 19:41 <a href="http://www.cppblog.com/Aiscanf/articles/86456.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>FILE*和handle之间的转换</title><link>http://www.cppblog.com/Aiscanf/articles/86455.html</link><dc:creator>Aiscanf</dc:creator><author>Aiscanf</author><pubDate>Mon, 01 Jun 2009 11:37:00 GMT</pubDate><guid>http://www.cppblog.com/Aiscanf/articles/86455.html</guid><wfw:comment>http://www.cppblog.com/Aiscanf/comments/86455.html</wfw:comment><comments>http://www.cppblog.com/Aiscanf/articles/86455.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Aiscanf/comments/commentRss/86455.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Aiscanf/services/trackbacks/86455.html</trackback:ping><description><![CDATA[<div class=postTitle>&nbsp;</div>
<br>windows下发时经常会碰到诸如c运行库函数与win32 Api对文件资源的公用的问题<br><br>很简单的方法: <br>&nbsp;&nbsp;&nbsp; FILE *f = fopen (...);<br>&nbsp; &nbsp; HANDLE h = (HANDLE)_get_osfhandle (_fileno (f));<br>&nbsp;&nbsp;&nbsp; WriteFile( h,....);<br>&nbsp;&nbsp;&nbsp; f = fdopen ( (int)h,"w");<br>&nbsp;&nbsp;&nbsp; fwrite(f,...)<br>
<img src ="http://www.cppblog.com/Aiscanf/aggbug/86455.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Aiscanf/" target="_blank">Aiscanf</a> 2009-06-01 19:37 <a href="http://www.cppblog.com/Aiscanf/articles/86455.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>学习wince的十个忠告</title><link>http://www.cppblog.com/Aiscanf/articles/86453.html</link><dc:creator>Aiscanf</dc:creator><author>Aiscanf</author><pubDate>Mon, 01 Jun 2009 11:28:00 GMT</pubDate><guid>http://www.cppblog.com/Aiscanf/articles/86453.html</guid><wfw:comment>http://www.cppblog.com/Aiscanf/comments/86453.html</wfw:comment><comments>http://www.cppblog.com/Aiscanf/articles/86453.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Aiscanf/comments/commentRss/86453.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Aiscanf/services/trackbacks/86453.html</trackback:ping><description><![CDATA[<p>-- 作者： zshan<br>-- 发布时间： 2007/11/20 11:53am
<p>将已有的应用程序移植到Microsoft Windows CE中。一般说来，这个计划不是太难。我们起步于Microsoft Win32代码，当然Windows CE是基于Win32应用程序接口（API）的。有利的是，我们的应用程序（即Raima 数据管理器）有方便的使用接口，并包含一个大约由150个子函数组成的库，这些函数都是由C语言写成，可以用来创建、管理和访问数据库。
<p>　　按建立应用程序的方式来说，我们原以为将它移植到Windows CE中是一项相对简单的C语言编程练习。然而，我们不久便遇到好些困难。从粗心大意的错误开始，比如在基于Windows NT 的Windows CE仿真器上使用Microsoft Windows NT库，接着又违背Windows CE的编程戒律，如"千万不要给Unicode（国际标准组织10646标准）字符分配奇数内存地址"。
<p>　　大约有百分之九十的问题或多或少地与Unicode有关。尽管Unicode编程不难，但是，当给单字节字符编写代码时，很容易出错（我有过许多次错误）。
<p>　　下面这些忠告是根据我们在Windows CE上编写Raima 数据管理器的经验总结出来的，但我相信，在做任何其它Windows CE程序之前，它们都值得借鉴。毕竟大多数Windows开发者，当他们创建第一个Windows CE应用程序时，真正运用的是已掌握的Win32知识。
<p>　　1. 不要在仿真器上使用Windows NT库
<p>　　这里所讨论的第一个错误实在太愚蠢了，但我还是陷了进去，也许你也会。当用Microsoft VC++（5.0版）创建一个Windows CE程序时，你会发现，包含路径（include）、 库路径（library）、及可执行程序路径被自动调整以匹配反应目标环境的选择。因此，比如说为Windows CE模拟器建立应用程序时，你会发现，include路径没有指向Win32的包含文件（在VC目录下），而是指向Windows CE包含文件（在WCE目录下）。千万别去修改。
<p>　　由于Windows CE在Windows NT下运行，所以仿真器上运行的程序能够调用任一Windows NT动态链接库(DLL)中的函数，即使这个DLL不是模拟器的成员也一样。显然，这不是很好的事，因为相同的函数也许在手持PC(H/PC)或Windows CE设备上不可用，而你的软件最终要能在这些设备上运行。
<p>　　第一次将非Unicode应用程序装入Windows CE仿真器时，你会发现，许多正在使用的函数它都不支持，例如美国国家标准协会(ANSI)定义的字符函数strcpy()。这也许引诱你去链接Windows NT 运行时间库，以便能解决所有问题。
<p>　　如果你是刚开始用Windows CE编程，可能你能用的包含文件和库文件是明显的。答案就是，你不要采用那些在写普通Win32或非Windows CE程序时使用的包含文件和库文件。
<p>2. 不要混淆TCHARs和bytes
<p>　　如果你正在Windows CE上写非Unicode应用程序，你或许要将所有的字符串从单个字符(chars)转换为宽字符(widechars)（例如，C变量类型whcar_t）。几乎所有Windows CE支持的Win32和运行时间库函数都要求宽字符变量。Windows 95不支持Unicode，然而，为了使程序代码具有可移植性，你要尽可能采用tchar.h中定义的TCHAR类型，不要直接使用wchar_t。
<p>　　TCHAR是定义为wchar_t还是char，取决于预处理器的符号UNICODE是否定义。同样，所有有关字符串处理函数的宏，如_tcsncpy宏，它是定义为Unicode函数wcsncpy还是定义为ANSI函数strncpy，取决于UNICODE是否定义。
<p>　　在现存的Windows应用程序中，有些代码也许暗示字符长为单字节。这在给字符串分配内存时经常用到，例如：
<p>int myfunc(char *p)<br>{<br>char *pszFileName;
<p>pszFileName = malloc(MAXFILELEN);<br>if(pszFileName)<br>strncpy(pszFileName, p, MAXFILELEN);<br>/*etc*/
<p>　　在这段代码中，分配的内存块应该写作(MAXFILELEN * sizeof(char))，但是大多数程序员喜欢将它简化为MAXFILELEN，因为对于所有的平台来说sizeof(char)的值等于1。然而，当你用TCHARS代替多个字符时，很容易忘记这种固有的概念，于是将代码编写成下面的形式：
<p>int myfunc(TCHAR *p)<br>{<br>TCHAR *pszFileName;
<p>PszFileName = (TCHAR*)malloc(MAXFILELEN);<br>If (pszFileName)<br>tcsncpy(pszFileName, p, MAXFILELEN);<br>/*etc*/
<p>　　这是不行的。它马上会导致出错。这里的错误在于malloc函数中指定变量大小为bytes，然而_tcsncpy函数中使用的第三个变量却指定为TCHARs而不是bytes。当UNICODE被定义时，一个TCHAR等于两个字节数(bytes)。
<p>　　上述代码段应该改写为：
<p>int myfunc(TCHAR *p)<br>{<br>TCHAR *pszFileName;
<p>PszFileName = (TCHAR*)malloc(MAXFILELEN * sizeof(TCHAR));<br>if(pszFileName)<br>tcsncpy(pszFileName, p, MAXFILELEN);<br>/*etc*/
<p>　　3. 不要将Unicode 字符串放入奇数内存地址
<p>　　在Intel系列处理器上，你可以在一奇数内存地址储存任何变量或数组，不会导致任何致命的错误影响。但在H/PC上，这一点不一定能行 ? 你必须对大于一个字节的数据类型小心谨慎，包括定义为无符号短型（unsigned short） 的wchar_t。当你设法访问它们的时候，将它们置于奇地址会导致溢出。
<p>　　编辑器经常在这些问题上提醒你。你无法管理堆栈变量地址，并且编辑器会检查确定这些地址与变量类型是否相匹配。同样，运行时间库必须保证从堆中分配的内存总是满足一个word边界 ，所以你一般不必担心那两点。但是，如果应用程序含有用memcpy()函数拷贝内存区域的代码，或者使用了某种类型的指针算术以确定内存地址，问题也许就出现了。考虑下面的例子：
<p>int send_name (TCHAR * pszName)<br>{<br>char *p, *q;<br>int nLen=(_tcslen(pszName) + 1) * sizeof(TCHAR);
<p>p=maloc(HEADER_SIZE + nLen);<br>if(p)<br>{<br>q = p + HEADER_SIZE;<br>_tcscpy((TCHAR*)q, pszName);<br>}<br>/* etc */
<p>　　这段代码是从堆中分配内存并复制一个字符串，在字符串的开头留一个HEADER_SIZE的大小。假设UNICODE定义了，那么该字符串就是一个widechar字符串。如果HEADER_SIZE是一个偶数，这段代码就会正常工作，但如果HEADER_SIZE为奇数，这段代码就会出错，因为q指向的地址也将为奇数。
<p>　　注意，当你在Intel系列处理器中的Windows CE仿真器上测试这段代码时，这个问题是不会发生的。
<p>　　在这个例子中，只要确保HEADER_SIZE为偶数，你就可以避免问题的发生。然而，在某些情况下你也许不能这么做。例如，如果程序是从一台式PC输入数据，你也许不得不采用事先定义过的二进制格式，尽管它对H/PC不适合。在这种情况下，你必须采用函数，这些函数用字符指针控制字符串而不是TCHAR指针。如果你知道字符串的长度，就可以用memcpy()复制字符串。因此，采用逐个字节分析Unicode字符串的函数也许足以确定字符串在widechars中的长度。
<p>　　4. 在ANSI和Unicode字符串之间进行翻译
<p>　　如果你的Windows CE应用程序接口于台式PC，也许你必须操作PC机中的ANSI字符串数据（例如，char字符串）。即使你在程序中只用到Unicode字符串，这都是事实。
<p>　　你不能在Windows CE上处理一个ANSI字符串，因为没有操纵它们的库函数。最好的解决办法是将ANSI字符串转换成Unicode字符串用到H/PC上，然后再将Unicode字符串转换回ANSI字符串用到PC上。为了完成这些转换，可采用MultiByteToWideChar()和WideCharToMultiByte () Win32 API 函数。
<p>5. 对于Windows CE 1.0的字符串转换，劈开（hack）
<p>　　在Windows CE 1.0 版本中，这些Win32API函数还没有完成。所以如果你想既要支持CE 1.0又能支持CE 2.0，就必须采用其它函数。将ANSI字符串转换成Unicode字符串可以用wsprintf()，其中第一个参数采用一widechar字符串，并且认识"%S"(大写)，意思是一个字符串。由于没有wsscanf() 和 wsprintfA()，你必须想别的办法将Unicode字符串转换回ANSI字符串。由于Windows CE 1.0不在国家语言支持(NLS)中，你也许得求助于hack，如下所示：
<p>/*<br>Definition / prototypes of conversion functions<br>Multi-Byte (ANSI) to WideChar (Unicode)
<p>atow() converts from ANSI to widechar<br>wtoa() converts from widechar to ANSI<br>*/<br>#if ( _WIN32_WCE &gt;= 101)
<p>#define atow(strA, strW, lenW) \<br>MultiByteToWidechar (CP_ACP, 0, strA, -1, strW, lenW)
<p>#define wtoa(strW, strA, lenA) \<br>WideCharToMutiByte (CP_ACP, 0, strW, -1, strA, lenA, NULL, NULL)
<p>#else /* _WIN32_WCE &gt;= 101)*/
<p>/*<br>MultiByteToWideChar () and WideCharToMultiByte() not supported o-n Windows CE 1.0<br>*/<br>int atow(char *strA, wchar_t *strW, int lenW);<br>int wtoa(wchar_t *strW, char *strA, int lenA);
<p>endif /* _WIN32_WCE &gt;= 101*/
<p>#if (_WIN32_WCE &lt;101)
<p>int atow(char *strA, wchar_t *strW, int lenW)<br>{<br>int len;<br>char *pA;<br>wchar_t *pW;
<p>/*<br>Start with len=1, not len=0, as string length returned<br>must include null terminator, as in MultiByteToWideChar()<br>*/<br>for(pA=strA, pW=strW, len=1; lenW; pA++, pW++, lenW--, len++)<br>{<br>*pW = (lenW = =1) ? 0 : (wchar_t)( *pA);<br>if( ! (*pW))<br>break;<br>}<br>return len;<br>}
<p>int wtoa(wxhar_t *strW, char *strA, int lenA)<br>{<br>int len;<br>char *pA;<br>wchar_t *pW;<br>/*<br>Start with len=1,not len=0, as string length returned<br>Must include null terminator, as in WideCharToMultiByte()<br>*/<br>for(pA=strA, pW=strW, len=1; lenA; pa++, pW++, lenA--, len++)<br>{<br>pA = (len==1)? 0 : (char)(pW);<br>if(!(*pA))<br>break;<br>}<br>return len;<br>}
<p>#endif /*_WIN32_WCE&lt;101*/
<p>　　这种适合于Windows CE 1.0的实现办法比使用wsprintf()函数要容易，因为使用wsprintf()函数更难以限制目标指针所指向的字符串的长度。
<p>　　6. 选择正确的字符串比较函数
<p>　　如果你要分类Unicode标准字符串，你会有以下几个函数可供选择：
<p>wcscmp(), wcsncmp(), wcsicmp(), 和wcsnicmp()
<p>wcscoll(), wcsncoll(), wcsicoll(),和wcsnicoll()
<p>CompareString()
<p>　　第一类函数可用来对字符串进行比较，不参考当地（Locale）或外文字符。如果你永远不想支持外文，或者你仅仅想测试一下两个字符串的内容是否相同，这类函数非常好用。
<p>　　第二类函数使用现有的当地设置(current locale settings)（系统设置，除非你在字符串比较函数之前调用了wsetlocale()函数）来比较两个字符串。这些函数也能正确分类外文字符。如果当地的字符"C"（"C" locale）被选定，这些函数与第一类函数就具有了相同的功能。
<p>　　第三类函数是Win32函数CompareString()。这个函数类似于第二类函数，但是它允许你指定当地设置（the locale）作为一个参数，而不是使用现有的当地设置(current locale settings)。CompareString()函数允许你选择性地指定两个字符串的长度。你可以将第二个参数设置为NORM_IGNORECASE，从而使函数比较字符串时不比较大小写。
<p>　　通常，即使不将第二个参数设置为NORM_IGNORECASE，CompareString()函数也不用来区分大小写。我们经常用wcsncoll()函数来区分大小写，除非使用当地的字符"C"（"C" locale）。所以，在我们的代码中，不使用CompareString()函数来区分大小写，而用wcsncoll()函数来区分大小写
<p>　　7. 不要使用相对路径
<p>　　与Windows NT不一样，Windows CE没有当前目录这个概念，因此，任何路径只是相对于根目录而言的。如果你的软件给文件或目录使用相对路径，那么你很可能把它们移到别的地方了。例如，路径".\abc"在Windows CE中被当作"\abc"看待。
<p>　　8．移走了对calloc()和 time()函数的调用
<p>　　C运行库中的calloc()函数不能使用，但是malloc()函数可以代替calloc()函数。并且不要忘记，calloc()函数初始化时分配的内存为零，而malloc()函数不一样。同样，time()函数也不能使用，但你可以使用Win32函数GetSystemTime()函数代替time()函数。
<p>　　经过以上的警告后，你会高兴地学习最后令你惊讶的两点忠告。
<p>　　9. 不需要改变Win32 输入/输出（I/O）文件的调用
<p>　　Win32的输入输出函数，Windows CE也支持。允许你象访问Win32文件系统那样访问对象。CreateFile()函数在Windows CE中不能辩认标志FILE_FLAG_RANDOM_ACCESS，但是这个标志仅用作可选的磁盘访问，并且不影响函数调用的功能。
<p>　　10. 不要担心字节的状态
<p>　　当我们把应用程序写入Windows CE时，有了一个美好的发现，那就是Windows CE的数字数据类型的字节状态与Intel结构的字节状态一样，在所有的处理器上，Windows CE均支持。
<p>　　几乎象所有的数据库引擎一样，Raima数据库管理器在数据库文件中以二进制形式保存数字数据。这就意味一个记录无论何时写入数据库或从数据库读出，均被当作一系列的字节来处理，不管它域的内容。只要数据库文件不要传给别的任何系统，数字数据的字节状态问题就解决了。如果数据库文件被一个来自原始系统且带有不同字节状态的处理器访问，数字数据将被误解。
<p>　　无论何时，当你在拥有不同处理器的机器上传输文件时，就会出现这个问题。在这个问题上，值得高兴的是所有类型的处理器都使用相同的字节状态。
<p>　　在使用Windows CE时，这10点忠告应该引起你足够的重视，避免学习时走弯路。</p>
<img src ="http://www.cppblog.com/Aiscanf/aggbug/86453.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Aiscanf/" target="_blank">Aiscanf</a> 2009-06-01 19:28 <a href="http://www.cppblog.com/Aiscanf/articles/86453.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>wince中消息处理</title><link>http://www.cppblog.com/Aiscanf/articles/86452.html</link><dc:creator>Aiscanf</dc:creator><author>Aiscanf</author><pubDate>Mon, 01 Jun 2009 11:22:00 GMT</pubDate><guid>http://www.cppblog.com/Aiscanf/articles/86452.html</guid><wfw:comment>http://www.cppblog.com/Aiscanf/comments/86452.html</wfw:comment><comments>http://www.cppblog.com/Aiscanf/articles/86452.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Aiscanf/comments/commentRss/86452.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Aiscanf/services/trackbacks/86452.html</trackback:ping><description><![CDATA[<p>WINDOWS CE的消息处理机制(一）
<p><br>学习过windows编程的人，都明白windows的消息处理机制，在Windows CE中继承了这种机制。
<p>为了能够获得消息，需要调用GetMessage函数<br>通常一个工程在消息循环中调用GetMessage函数
<p>下面的代码，显示了如何在消息循环中调用GetMessage函数
<p>while (GetMessage(&amp;msg, NULL, 0, 0)) <br>{
<p>TranslateMessage(&amp;msg);
<p>DispatchMessage(&amp;msg);
<p>}
<p>当一个线程调用GetMessage函数时，Windows CE检测消息队列，Windows CE按照以下的步骤处理消息：
<p>（1）Windows CE检测消息队列，这些消息是通过SendMessage函数产生的。当系统从消息队列提取消息后，它通过GetMessage函数将消息发送到适当地窗体过程，这样就可以保证消息的发送和接收保持同步。必须通过调用GetMessage函数才能保证消息被处理。
<p>（2）如果没有通过SendMessage得到的消息，Windows CE检测由PostMessge发送的消息队列。
<p>（3）如果没有通过PostMessage得到的消息，Windows CE检测用户用户输入消息。<br>在处理用户输入消息时，系统保证在处理下一个消息以前已经处理结束前一个输入的消息。
<p>（4）如果没有用户输入消息，Windows CE检测WM_QUIT消息，该消息是由PostQuitMessage函数发送的。
<p>（5）如果没有WM_QUIT消息，Windows CE检测WM_PAINT消息。
<p>（6）如果没有WM_PAINT消息，Windows CE检测WM_TIMER消息
<p>当GetMessage接收到任何消息，它返回消息的内容，该线程必须调用DispatchMessage函数来把消息发送到正确的窗体处理过程。如果这个消息是WM_QUIT消息，GetMessage函数的返回值为0，触发线程结束消息循环。
<p>系统处理的消息是通过GetMessage函数在消息循环中的调用，又通过在消息循环中调用DispatchMessage函数来处理分派消息。
<p>在通过DispatchMessage函数分发通过GetMessage得到的函数以前，用户可能需要处理这些消息，最常用的函数就是TranslateMessage, TranslateAccelerator, 和IsDialogMessage这三个函数。其中的一些函数可以自己分发消息，这样就必再次调用DispatchMessage来分发消息。
<p><br>WINDOWS CE的消息处理机制(二）
<p>
<p>用户通常使用TranslateMessage函数。该函数可以决定哪些字符对应相应的键盘消息。该函数同时也可以将字符发送到消息队列中，让下一次消息循环继续处理。
<p>截取键盘消息产生菜单命令，用户可以调用TranslateAccelerator 函数，要对无模式对话框进行适当的操作需调用IsDialogMessage函数。
<p>下面的例子向用户显示一个消息循环的例子，它使用到了DispatchMessage函数, TranslateMessage函数, TranslateAccelerator函数,和IsDialogMessage函数以及GetMessage函数。
<p>while (GetMessage(&amp;msg, NULL, 0, 0)) <br>{
<p>if (!TranslateAccelerator(msg.hwnd, hAccelTable, &amp;msg))
<p>{
<p>if (hwndDLGCurrent != NULL || !IsDialogMessage(hwndDLGCurrent,
<p>&amp;msg))
<p>{
<p>TranslateMessage(&amp;msg);
<p>DispatchMessage(&amp;msg);
<p>}<br>}<br>}
<p>用户可以通过GetMessage函数取得消息队列中的事件，并且从消息队列中去除该消息，用户也可以用PeekMessage函数从一个消息队列中获得消息，但却不必从消息队列中去除它。
<p>通过该函数可以把有关消息的信息填充到MSG结构中。使用PeekMessage函数时要小心，因为它并不会阻止消息的等待，这样一个程序就会不管消息队列中是否有消息而不停地运行，这样CPU就不会处于low-power 模式，从而导致电池用电量过大。
<p>当处理消息的时候，Windows CE不仅支持系统定义的消息同时也支持用户自定义的消息。系统消息定义从0到0x3ff，用户可以使用0x400到0x7fff定义自己的消息。Windows CE把0x400定义为WM_USER。如果用户想定义自己的一个消息。可以在WM_USER上加上一个值。下面的过程讲述了如何进行自定义消息。
<p>#define WM_MYNEWMESSAGE (WM_USER + 999)
<p>有两种系统定义的消息，一种是窗体消息，使用于所有的窗体，还要一种是特殊目的的消息，应用于一定的窗体类。通常的窗体消息覆盖的范围非常大，包括输入设备和一些键盘的消息，同时也包括一些如窗体建立和管理的消息。 一定的消息包含有特定的前缀，比如说，一个通常的WINDOWS消息通常以WM开头，属于按钮的消息通常以BM开头。
<p>用户可以定义自己的消息，如果定义消息，一定要保证窗体过程争取地接收和解释消息，因为操作系统不会自动地处理用户定义的消息。
<p>偶尔，用户也需要通过消息和别的进程中的休息保持通信。这种情况下，用户必须通过调用RegisterWindowMessage 函数来注册一个消息句柄。这样就可以保证消息号在整个系统中是唯一的，从而避免了不同的进程使用相同的消息号，造成冲突。
<p>Windows CE不支持钩子函数，因为钩子函数需要的额外进程会不利于WINDOWS CE的执行。
<p>在一个程序中处理消息序列时，请注意WM_HIBERNATE 消息。WINDOWS CE在系统资源不足时，通过WM_HIBERNATE 消息来通知应用工程。当一个工程接受到这个消息，它就会尽可能地释放资源。系统每隔五秒钟检测一次系统内存状态。
<p>每一个WINDOWS CE的应用工程由于要适当地使用内存，所以都要能接收WM_HIBERNATE 消息。
<p>如果一个应用工程的窗口不可见，该工程不能接收WM_HIBERNATE 消息。之所以收不到该消息，是因为WM_HIBERNATE 消息仅仅被发送到一个在任务栏上有相应菜单的工程。一个隐藏的窗体即使是占用内存很多，也不会接收到该消息。 </p>
<img src ="http://www.cppblog.com/Aiscanf/aggbug/86452.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Aiscanf/" target="_blank">Aiscanf</a> 2009-06-01 19:22 <a href="http://www.cppblog.com/Aiscanf/articles/86452.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>为什么部署到基于 Windows Mobile 的 Pocket PC 设备或模拟器会因共享冲突错误而失败</title><link>http://www.cppblog.com/Aiscanf/articles/86439.html</link><dc:creator>Aiscanf</dc:creator><author>Aiscanf</author><pubDate>Mon, 01 Jun 2009 10:15:00 GMT</pubDate><guid>http://www.cppblog.com/Aiscanf/articles/86439.html</guid><wfw:comment>http://www.cppblog.com/Aiscanf/comments/86439.html</wfw:comment><comments>http://www.cppblog.com/Aiscanf/articles/86439.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Aiscanf/comments/commentRss/86439.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Aiscanf/services/trackbacks/86439.html</trackback:ping><description><![CDATA[<p>自己遇到了<br>网上找到的解决方案<br><a href="http://hi.baidu.com/yeflower/blog/item/17f9fefa6f81bed6b58f31ac.html">http://hi.baidu.com/yeflower/blog/item/17f9fefa6f81bed6b58f31ac.html</a><br></p>
<div class=cnt id=blog_text>
<p>表现：当将一个应用程序部署到基于 Windows Mobile 6设备或模拟器时，输出消息类似于错误：部署和/或注册失败，错误为: 0x8973190e。 写入文件&#8220;%CSIDL_PROGRAM_FILES\MySample\MySample1.exe&#8221;时出错。错误 0x80070020: 另一个程序正在使用此文件，进程无法访问。当同一个应用程序以前已经部署到同一台设备或模拟器时，通常会出现这种问题。</p>
<p>原因：默认情况下，用于基于 Windows Mobile6的应用程序中的 X 按钮并没有关闭进程。它只是&#8220;最小化&#8221;应用程序窗口。当用户试图再次部署该应用程序时，&#8220;最小化&#8221;的实例会导致共享冲突并使部署失败。另一种可能的原因是用户中途强行终止调试会话。</p>
<p>解决办法：确保当再次部署时，设备或模拟器中的应用程序已经真正关闭。在基于 Windows Mobile 6的 模拟器中，要查看正在运行的进程，请转到 开始-&gt;设置-&gt;系统（内存）-&gt;运行的程序。</p>
<p>如果想要有一个按钮能真正关闭应用程序，请显式创建这样的按钮，或者将 Windows 窗体的 Minimize Box 属性设置为 False，这样X 按钮就成了能关闭应用程序的 OK 按钮。如果原因是手动终止调试会话，则可能需要软重启设备或模拟器。</p>
<p>其他问题：</p>
<p>ERROR: 错误 0x80070070: 磁盘空间不足。</p>
<p>解决：在 项目——属性——设备中，取消&#8220;部署.NET Compact Framework 的最新版本&#8221;的选项</p>
<p>&#160;</p>
<p>ERROR: 错误 部署和/或注册失败，另一个程序正在使用此文件</p>
<p>解决：在模拟器中选择File-&gt;Clear Saved State，然后重新运行即可</p>
<p>&#160;</p>
<p>资料来源:学网(<a href="http://www.xue5.com/"><u><font color=#0000ff>www.xue5.com</font></u></a>),原文地址:http://www.xue5.com/itedu/200707/128139.html</p>
</div>
<p><br>&nbsp;</p>
<img src ="http://www.cppblog.com/Aiscanf/aggbug/86439.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Aiscanf/" target="_blank">Aiscanf</a> 2009-06-01 18:15 <a href="http://www.cppblog.com/Aiscanf/articles/86439.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>