<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>iT人 -  theiter &#187; WindowsMobile</title>
	<atom:link href="http://www.theiter.com/category/mobile-tech/windowsmobile/feed" rel="self" type="application/rss+xml" />
	<link>http://www.theiter.com</link>
	<description>关注IT技术，研究移动开发技术，记录IT人的生活</description>
	<lastBuildDate>Sun, 04 Dec 2011 14:28:30 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.5</generator>
		<item>
		<title>MRssReader问题解答与相关资源</title>
		<link>http://www.theiter.com/2010/03/mrssreader%e9%97%ae%e9%a2%98%e8%a7%a3%e7%ad%94%e4%b8%8e%e7%9b%b8%e5%85%b3%e8%b5%84%e6%ba%90.html</link>
		<comments>http://www.theiter.com/2010/03/mrssreader%e9%97%ae%e9%a2%98%e8%a7%a3%e7%ad%94%e4%b8%8e%e7%9b%b8%e5%85%b3%e8%b5%84%e6%ba%90.html#comments</comments>
		<pubDate>Thu, 25 Mar 2010 06:05:19 +0000</pubDate>
		<dc:creator>theiter</dc:creator>
				<category><![CDATA[WindowsMobile]]></category>
		<category><![CDATA[reader]]></category>
		<category><![CDATA[rss]]></category>
		<category><![CDATA[rssreader]]></category>

		<guid isPermaLink="false">http://www.theiter.com/2010/03/mrssreader%e9%97%ae%e9%a2%98%e8%a7%a3%e7%ad%94%e4%b8%8e%e7%9b%b8%e5%85%b3%e8%b5%84%e6%ba%90.html</guid>
		<description><![CDATA[之前发布了一个RSS阅读器（WM版本）。一些朋友提了些宝贵的建议，这篇文章打算解释一下相关的问题同时我还会把自己订阅的一些feeds放上来，大家可以直接导入到MRssReader里面。 首先就几个问题做一下解释： 1.如何订阅一些被屏蔽的博文？ MRssReader支持代理模式。在“参数”-&#62;“连接”-&#62;“代理”，可以添加Http代理或者Socket代理。大家可以在网上找一些比较好用的代理，例如http://www.proxycn.com/。 2.如何与Google Reader同步？ 在“参数”-&#62;“同步”填写你的Google Reader用户名和密码；在频道界面更新就会同步GoogleReader的订阅内容到MRssReader上。 3.为什么阅读时不显示图片？ 在“参数”-&#62;“缓存”界面把“缓存图片”项选上，就会在更新的时候下载图片。 4.如何离线阅读？ 在“参数”-&#62;“缓存”界面把“缓存文章供离线时阅读”项选上，就会在更新的时候下载文章到本地，当你选择“离线阅读”模式时，MRssReader就会打开本地缓存的内容而无需联网下载内容。 5.能不能在程序安装之后添加一些默认的Feeds？ 当前版本没有实现该功能，暂且只能通过导入OPML文件批量添加Feeds。计划在下个版本中添加本功能。 下面是我自己订阅的一些Feeds分享给大家。点击这里下载： 转载请注明： 转载自iT人 &#8211; theiter 本文链接地址: MRssReader问题解答与相关资源]]></description>
			<content:encoded><![CDATA[<p>之前发布了一个<a href="http://www.theiter.com/2010/01/mrssreader阅读器终于发布了.html" target="_blank">RSS阅读器（WM版本）</a>。一些朋友提了些宝贵的建议，这篇文章打算解释一下相关的问题同时我还会把自己订阅的一些feeds放上来，大家可以直接导入到MRssReader里面。</p>
<p>首先就几个问题做一下解释：</p>
<p>1.如何订阅一些被屏蔽的博文？</p>
<p>MRssReader支持代理模式。在“参数”-&gt;“连接”-&gt;“代理”，可以添加Http代理或者Socket代理。大家可以在网上找一些比较好用的代理，例如<a title="http://www.proxycn.com/" href="http://www.proxycn.com/">http://www.proxycn.com/</a>。</p>
<p>2.如何与Google Reader同步？</p>
<p>在“参数”-&gt;“同步”填写你的Google Reader用户名和密码；在频道界面更新就会同步GoogleReader的订阅内容到MRssReader上。</p>
<p>3.为什么阅读时不显示图片？</p>
<p>在“参数”-&gt;“缓存”界面把“缓存图片”项选上，就会在更新的时候下载图片。</p>
<p>4.如何离线阅读？</p>
<p>在“参数”-&gt;“缓存”界面把“缓存文章供离线时阅读”项选上，就会在更新的时候下载文章到本地，当你选择“离线阅读”模式时，MRssReader就会打开本地缓存的内容而无需联网下载内容。</p>
<p>5.能不能在程序安装之后添加一些默认的Feeds？</p>
<p>当前版本没有实现该功能，暂且只能通过导入OPML文件批量添加Feeds。计划在下个版本中添加本功能。</p>
<p>下面是我自己订阅的一些Feeds分享给大家。点击这里下载：<a class="downloadlink" href="http://www.theiter.com/wp-content/plugins/download-monitor/download.php?id=theiter-newsfeeds.opml" title=" downloaded 258 times" >theiter-newsfeeds (258)</a>
<div style="margin-top: 15px">
<p><strong>转载请注明：</strong> 转载自<a href="http://www.theiter.com/">iT人 &#8211;  theiter</a></p>
<p><strong>本文链接地址:</strong> <a href="http://www.theiter.com/2010/03/mrssreader%e9%97%ae%e9%a2%98%e8%a7%a3%e7%ad%94%e4%b8%8e%e7%9b%b8%e5%85%b3%e8%b5%84%e6%ba%90.html">MRssReader问题解答与相关资源</a></p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.theiter.com/2010/03/mrssreader%e9%97%ae%e9%a2%98%e8%a7%a3%e7%ad%94%e4%b8%8e%e7%9b%b8%e5%85%b3%e8%b5%84%e6%ba%90.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>微软推出Android应用软件为哪般</title>
		<link>http://www.theiter.com/2010/03/%e5%be%ae%e8%bd%af%e6%8e%a8%e5%87%baandroid%e5%ba%94%e7%94%a8%e8%bd%af%e4%bb%b6%e4%b8%ba%e5%93%aa%e8%88%ac.html</link>
		<comments>http://www.theiter.com/2010/03/%e5%be%ae%e8%bd%af%e6%8e%a8%e5%87%baandroid%e5%ba%94%e7%94%a8%e8%bd%af%e4%bb%b6%e4%b8%ba%e5%93%aa%e8%88%ac.html#comments</comments>
		<pubDate>Fri, 05 Mar 2010 09:16:30 +0000</pubDate>
		<dc:creator>theiter</dc:creator>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Symbian]]></category>
		<category><![CDATA[WindowsMobile]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[移动开发]]></category>
		<category><![CDATA[barcode 条形码]]></category>
		<category><![CDATA[Microsoft Tag]]></category>
		<category><![CDATA[手机资讯]]></category>
		<category><![CDATA[智能手机]]></category>

		<guid isPermaLink="false">http://www.theiter.com/2010/03/%e5%be%ae%e8%bd%af%e6%8e%a8%e5%87%baandroid%e5%ba%94%e7%94%a8%e8%bd%af%e4%bb%b6%e4%b8%ba%e5%93%aa%e8%88%ac.html</guid>
		<description><![CDATA[今天媒体纷纷报道，微软推出第一款Android平台软件（Microsoft Tag Reader）。先看看媒体的报道： 据国外媒体今日报道，微软面向Android平台发布了首个手机应用Tag。 该应用此前已经推出了Windows Mobile和iPhone(手机上网)等版本，它可以将用户的 手机变成一个条形码扫描器，通过摄像头来解读2D条形码信息。但Android用户此前已经可以通过Barcode Reader和谷歌Goggles来扫描条形码信息。 业内人士认为，考虑到微软与谷歌在手机操作系统及其他领域的竞争关系，微软针对Android平台发布Tag的确有些出人意料。 作为两家在智能手机操作系统上有直接竞争关系的公司，微软推出该软件确实会引起广泛的关注。但是如果仔细研究Microsoft Tag服务和之前发布的相关软件就很容易理解了。 首先，微软之前已经发布的多个移动平台的Microsoft Tag reader软件，包括Symbian，WindowMobile，iPhone，BlackBerry等等。 那么，Microsoft Tag服务是什么呢？ Microsoft Tag技术允许用户把手机当成“移动条形码阅读器”来使用，用户只要将手机摄像头对准条形码，然后拍照，这时手机中的Tag应用就会对条码所含信息进行解释。Microsoft Tag不仅仅具备QRCode相关的能力，更重要的是它基于一种叫做“高容量彩色条码”(HCCBs = High Capacity Color Barcode)的技术，而这个HCCBs是由Microsoft Research研究出来滴！Microsoft Tag保存了信息的唯一编号！这个唯一编号对应的原始信息则保存在微软的服务器上。这样一来，就可以保存非常多的信息，而且可以统计到每一个Tag的使用情况。非常适合用于出版物、电子产品等等场合（其实就是一种二维条码，微软自己二维条码）。 读到这里大家可能就已经明白了，原来微软的重点是在他们的Microsoft Tag服务，支持越多的平台，对其Microsoft Tag服务的推广和应用当然越有利。 虽然到目前为止微软的Microsoft Tag服务还没有明确的商业模式，但是基于移动互联网的条码搜索等业务应该是未来移动应用的一个方向，目前包括谷歌公司在内的其他公司都在积极研究移动设备读取条形码这项技术（Google shopper for Android）。 转载请注明： 转载自iT人 &#8211; theiter 本文链接地址: 微软推出Android应用软件为哪般]]></description>
			<content:encoded><![CDATA[<p>今天媒体纷纷报道，微软推出第一款Android平台软件（<a href="http://www.microsoft.com/tag/content/download/">Microsoft Tag Reader</a>）。先看看媒体的报道：</p>
<blockquote><p>据国外媒体今日报道，微软面向Android平台发布了首个手机应用Tag。</p>
<p>该应用此前已经推出了Windows Mobile和iPhone(手机上网)等版本，它可以将用户的<br />
手机变成一个条形码扫描器，通过摄像头来解读2D条形码信息。但Android用户此前已经可以通过Barcode Reader和谷歌Goggles来扫描条形码信息。</p>
<p>业内人士认为，考虑到微软与谷歌在手机操作系统及其他领域的竞争关系，微软针对Android平台发布Tag的确有些出人意料。</p></blockquote>
<p>作为两家在智能手机操作系统上有直接竞争关系的公司，微软推出该软件确实会引起广泛的关注。但是如果仔细研究<a href="http://www.microsoft.com/tag/">Microsoft Tag</a>服务和之前发布的相关软件就很容易理解了。</p>
<p>首先，微软之前已经发布的多个移动平台的<a href="http://www.microsoft.com/tag/content/download/">Microsoft Tag reader</a>软件，包括Symbian，WindowMobile，iPhone，BlackBerry等等。</p>
<p>那么，<a href="http://www.microsoft.com/tag/">Microsoft Tag</a>服务是什么呢？</p>
<p><a href="http://www.microsoft.com/tag/">Microsoft Tag</a>技术允许用户把手机当成“移动条形码阅读器”来使用，用户只要将手机摄像头对准条形码，然后拍照，这时手机中的Tag应用就会对条码所含信息进行解释。<a href="http://www.microsoft.com/tag/">Microsoft Tag</a>不仅仅具备<a href="http://www.theiter.com/2009/11/qr码简介.html">QRCode</a>相关的能力，更重要的是它基于一种叫做“高容量彩色条码”(HCCBs = High Capacity Color Barcode)的技术，<strong><span style="color: #0000ff;">而这个HCCBs是由Microsoft Research研究出来滴！</span></strong><a href="http://www.microsoft.com/tag/">Microsoft Tag</a>保存了信息的唯一编号！这个唯一编号对应的原始信息则保存在微软的服务器上。这样一来，就可以保存非常多的信息，而且可以统计到每一个Tag的使用情况。非常适合用于出版物、电子产品等等场合（其实就是一种二维条码，微软自己二维条码）。</p>
<p>读到这里大家可能就已经明白了，原来微软的重点是在他们的<strong><span style="color: #0000ff;">Microsoft Tag服务</span></strong>，支持越多的平台，对其<strong><span style="color: #0000ff;">Microsoft Tag服务</span></strong>的推广和应用当然越有利。</p>
<p>虽然到目前为止微软的<strong><span style="color: #0000ff;">Microsoft Tag服务</span></strong>还没有明确的商业模式，但是基于移动互联网的条码搜索等业务应该是未来移动应用的一个方向，目前包括谷歌公司在内的其他公司都在积极研究移动设备读取条形码这项技术（<a href="http://www.theiter.com/2010/02/google-shopper-for-android.html">Google shopper for Android</a>）。
<div style="margin-top: 15px">
<p><strong>转载请注明：</strong> 转载自<a href="http://www.theiter.com/">iT人 &#8211;  theiter</a></p>
<p><strong>本文链接地址:</strong> <a href="http://www.theiter.com/2010/03/%e5%be%ae%e8%bd%af%e6%8e%a8%e5%87%baandroid%e5%ba%94%e7%94%a8%e8%bd%af%e4%bb%b6%e4%b8%ba%e5%93%aa%e8%88%ac.html">微软推出Android应用软件为哪般</a></p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.theiter.com/2010/03/%e5%be%ae%e8%bd%af%e6%8e%a8%e5%87%baandroid%e5%ba%94%e7%94%a8%e8%bd%af%e4%bb%b6%e4%b8%ba%e5%93%aa%e8%88%ac.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WaitForSingleObject 与 EnterCriticalSection 性能比较</title>
		<link>http://www.theiter.com/2009/12/waitforsingleobject-%e4%b8%8e-entercriticalsection-%e6%80%a7%e8%83%bd%e6%af%94%e8%be%83.html</link>
		<comments>http://www.theiter.com/2009/12/waitforsingleobject-%e4%b8%8e-entercriticalsection-%e6%80%a7%e8%83%bd%e6%af%94%e8%be%83.html#comments</comments>
		<pubDate>Thu, 24 Dec 2009 01:57:13 +0000</pubDate>
		<dc:creator>theiter</dc:creator>
				<category><![CDATA[WindowsMobile]]></category>
		<category><![CDATA[Wince]]></category>
		<category><![CDATA[windows]]></category>
		<category><![CDATA[多线程]]></category>
		<category><![CDATA[线程同步]]></category>

		<guid isPermaLink="false">http://www.xlbren.org/?p=221</guid>
		<description><![CDATA[摘要 在 Microsoft Windows 平台上有几种以原子方式锁定代码和数据的不同方法。此白皮书的主要目的是向开发人员简要介绍 Windows 中进行锁定的不同方法以及与这些锁定有关的相应性能开销。因为未来架构将是多核架构，因此此信息非常适用。 简介 多线程软件应用对于提升英特尔内核架构的性能至关重要。锁定代码通常是多线程应用中运行最频繁的代码。确定要使用的锁定方法与确定应用中并行处理一样重要。此白皮书的主要目的是向开发人员简要介绍 Windows 中进行锁定的不同方法以及与这些锁定有关的相应性能开销。Window 的某些锁定 API 可能会跳转至操作系统内核。此白皮书将详细说明跳转至内核的 API 以及相应的加入条件。 使用两种不同的锁定内核说明表示不同粒度的锁定的影响。第一种锁定内核模拟锁定和取消锁定动态链接列表（通常用于通过内存管理器维护一个空闲列表）的场景。对于多线程应用，首先需要锁定此列表，线程才能尝试分配或释放内存。第二种锁定内核表示更加精细地锁定，因为它仅获取已获得锁定的线程的 ThreadID，更新全局变量，然后释放锁定。通过采用 1 至 64 的线程数，对高、低争用场景下不同锁定的性能进行测试。每一线程获取执行 10,000,000 次某一运算的锁定，然后释放此锁定。对于这些实验，Windows XP 操作系统计时从 10 毫秒更改为 1 毫秒。 WaitForSingleObject 和 EnterCriticalSection Microsoft Windows 平台中两种最常用的锁定方法为 WaitForSingleObject 和 EnterCriticalSection。WaitForSingleObject 是一个过载 Microsoft API，可用于检查和修改许多不同对象（如事件、作业、互斥体、进程、信号、线程或计时器）的状态。WaitForSingleObject 的一个不足之处是它会始终获取内核的锁定，因此无论是否获得锁定，它都会进入特权模式 (环路 0)。此 API 还进入 Windows 内核，即使指定的超时为 0，亦如此。此锁定方法的另一不足之处在于，它一次只能处理 64 个尝试对某个对象进行锁定的线程。WaitForSingleObject 的优点是它可以全局进行处理，这使得此 API 能够用于进程间的同步。它还具有为操作系统提供锁定对象信息的优势，从而可以实现公平性及优先级倒置。 [...]]]></description>
			<content:encoded><![CDATA[<p>摘要 </p>
<p>在 Microsoft Windows 平台上有几种以原子方式锁定代码和数据的不同方法。此白皮书的主要目的是向开发人员简要介绍 Windows 中进行锁定的不同方法以及与这些锁定有关的相应性能开销。因为未来架构将是多核架构，因此此信息非常适用。 </p>
<p> <span id="more-221"></span>
</p>
<p>简介   <br />多线程软件应用对于提升英特尔内核架构的性能至关重要。锁定代码通常是多线程应用中运行最频繁的代码。确定要使用的锁定方法与确定应用中并行处理一样重要。此白皮书的主要目的是向开发人员简要介绍 Windows 中进行锁定的不同方法以及与这些锁定有关的相应性能开销。Window 的某些锁定 API 可能会跳转至操作系统内核。此白皮书将详细说明跳转至内核的 API 以及相应的加入条件。 </p>
<p>使用两种不同的锁定内核说明表示不同粒度的锁定的影响。第一种锁定内核模拟锁定和取消锁定动态链接列表（通常用于通过内存管理器维护一个空闲列表）的场景。对于多线程应用，首先需要锁定此列表，线程才能尝试分配或释放内存。第二种锁定内核表示更加精细地锁定，因为它仅获取已获得锁定的线程的 ThreadID，更新全局变量，然后释放锁定。通过采用 1 至 64 的线程数，对高、低争用场景下不同锁定的性能进行测试。每一线程获取执行 10,000,000 次某一运算的锁定，然后释放此锁定。对于这些实验，Windows XP 操作系统计时从 10 毫秒更改为 1 毫秒。   <br />WaitForSingleObject 和 EnterCriticalSection    <br />Microsoft Windows 平台中两种最常用的锁定方法为 WaitForSingleObject 和 EnterCriticalSection。WaitForSingleObject 是一个过载 Microsoft API，可用于检查和修改许多不同对象（如事件、作业、互斥体、进程、信号、线程或计时器）的状态。WaitForSingleObject 的一个不足之处是它会始终获取内核的锁定，因此无论是否获得锁定，它都会进入特权模式 (环路 0)。此 API 还进入 Windows 内核，即使指定的超时为 0，亦如此。此锁定方法的另一不足之处在于，它一次只能处理 64 个尝试对某个对象进行锁定的线程。WaitForSingleObject 的优点是它可以全局进行处理，这使得此 API 能够用于进程间的同步。它还具有为操作系统提供锁定对象信息的优势，从而可以实现公平性及优先级倒置。 </p>
<p>通过对关键代码段实施 EnterCriticalSection 和 LeaveCriticalSection API 调用，可以使用 EnterCriticalSection。此 API 具有 WaitForSingleObject 所不具备的优点，因为只有存在锁定争用时，才会进入内核。如果不存在锁定争用，则此 API 会获取用户空间锁定，并且在未进入特权模式的情况下返回。如果存在争用，则此 API 在内核中所采用的路径将与 WaitForSingleObject 极其相似。在低争用的情况下，由于 EnterCriticalSection 不进入内核，因此锁定开销非常低。 </p>
<p>不足之处是 EnterCriticalSection 无法进行全局处理，因此无法为线程获取锁定的顺序提供任何保证。EnterCriticalSection 是一种阻塞调用，意味着只有线程获得对此关键区段的访问权限时，该调用才会返回。Windows 引入了 TryEnterCriticalSection，TryEnterCriticalSection 是一种非阻塞调用，无论获得锁定与否都会立即返回。此外，EnterCriticalSection 还允许开发人员使用自旋计数对关键区段进行初始化，在回退前线程会按此自旋计数尝试获取锁定。通过使用 API InitializeCriticalSectionAndSpinCount，完成初始化。自旋计数可以在此调用中进行设置，也可以在注册表中进行设置，以根据不同操作系统及其相应的线程量程对自旋进行更改。 </p>
<p>如果存在锁定争用，则 EnterCriticalSection 和 WaitForSingleObject 都会进入内核。如果实现程度过高，从用户模式到特权模式的转换开销将会非常大。 </p>
<p>EnterCriticalSection 和 WaitForSingleObject API 调用在对使用数千个周期的运算进行锁定时，通常不会影响性能。在这些情况下，锁定调用本身的开销不会如此突出。会导致性能降低的情况是粒度锁定，获得和释放此锁定要花费数百个周期。在这些情况下，使用用户级别锁定则非常有益。 </p>
<p>为了说明在低争用的情况下 WaitForSingleObject 调用与 EnterCriticalSection 调用的开销情况，我们分别在 1 个和 2 个线程上运行了内存管理锁定内核。在低争用的情况下，存在加速比 (WaitForSingleObject_Time / EnterCriticalSection_Time) 大约为 5 倍的性能之差。在 2 个线程持续争用的情况下，使用 EnterCriticalSection 和使用 WaitForSingleObject 之间的差别最小。在低争用的情况下存在性能差距的原因如下：WaitForSingleObject 在每次调用时都进入内核，而 EnterCriticalSection 只有当存在锁定争用时，才进入内核。</p>
<p>线程数量&#160;&#160;&#160; EnterCriticalSection 时间（毫秒）&#160;&#160;&#160; WaitForSingleObject 时间（毫秒）&#160;&#160;&#160; 加速比    <br />1个线程（无争用）&#160;&#160; 1781&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 9187&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 5.2    <br />2 个线程（争用）&#160;&#160;&#160; 53594&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 58156&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 1.1 </p>
<p align="center">图1</p>
<p>图 1：显示了在具有 1 个和 2 个线程的情况下，EnterCriticalSection 和 WaitForSingleObject 所对应的内存管理内核情况。EnterCriticalSection 在 1 个线程（无争用）的情况下速度较快，因为如果获得锁定，EnterCriticalSection 不会跳转至内核（特权模式）。 </p>
<p>下图 2 说明了 EnterCriticalSection 和 WaitForSingleObject 在高争用时的开销情况，所采用的线程数介于 1 至 64 之间。在本实验中，我们在向动态链接列表中推入值和从中弹出值的同时，锁定和取消锁定该列表。目的是模拟内存分配器空闲列表，为了分配或释放内存，需频繁锁定该列表。内核会主动根据环境切换争用锁定的线程，因此在两次实验中，CPU 平均负载都是 22%。很明显，在高争用情况下，利用 EnterCriticalSection 和 WaitForSingleObject 的开销并无太大差别。 </p>
<p><a href="http://www.theiter.com/wp-content/uploads/2009/12/image7.png"><img style="border-bottom: 0px;border-left: 0px;float: none;margin-left: auto;border-top: 0px;margin-right: auto;border-right: 0px" border="0" alt="image" src="http://www.theiter.com/wp-content/uploads/2009/12/image_thumb7.png" width="490" height="287" /></a> </p>
<p>图 2：显示了在具有 1 到 64 条线程的情况下，EnterCriticalSection 和 WaitForSingleObject 所对应的内存管理内核情况。在高争用情况下，与 WaitForSingleObject 和 EnterCriticalSection 所关联的开销并无太大差别。 </p>
<p>利用英特尔® VTune 分析器通过基于事件的采样来收集时钟滴答事件，这对于确定 EnterCriticalSection 和 WaitForSingleObject 的争用情况将有所帮
<div style="margin-top: 15px">
<p><strong>转载请注明：</strong> 转载自<a href="http://www.theiter.com/">iT人 &#8211;  theiter</a></p>
<p><strong>本文链接地址:</strong> <a href="http://www.theiter.com/2009/12/waitforsingleobject-%e4%b8%8e-entercriticalsection-%e6%80%a7%e8%83%bd%e6%af%94%e8%be%83.html">WaitForSingleObject 与 EnterCriticalSection 性能比较</a></p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.theiter.com/2009/12/waitforsingleobject-%e4%b8%8e-entercriticalsection-%e6%80%a7%e8%83%bd%e6%af%94%e8%be%83.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>如何在WM上创建接入点</title>
		<link>http://www.theiter.com/2009/12/%e5%a6%82%e4%bd%95%e5%9c%a8wm%e4%b8%8a%e5%88%9b%e5%bb%ba%e6%8e%a5%e5%85%a5%e7%82%b9-2.html</link>
		<comments>http://www.theiter.com/2009/12/%e5%a6%82%e4%bd%95%e5%9c%a8wm%e4%b8%8a%e5%88%9b%e5%bb%ba%e6%8e%a5%e5%85%a5%e7%82%b9-2.html#comments</comments>
		<pubDate>Wed, 09 Dec 2009 07:00:23 +0000</pubDate>
		<dc:creator>theiter</dc:creator>
				<category><![CDATA[WindowsMobile]]></category>
		<category><![CDATA[3G]]></category>
		<category><![CDATA[GPRS]]></category>
		<category><![CDATA[wm]]></category>

		<guid isPermaLink="false">http://www.xlbren.com/?p=177</guid>
		<description><![CDATA[最近需要做点与网络连接相关的东西，研究了下WM上创建接入点的方法，把一些自己对该知识点的理解和一些代码片段记录下来。 【相关知识点】 接入点对应的注册表项： 1.HKEY_CURRENT_USER\Comm\RasBook 2.HKEY_LOCAL_MACHINE\Comm\ConnMgr\Providers\{7C4B7A38-5FF7-4bc1-80F6-5DA7870BB1AA}\Connections 注册表项： HKEY_CURRENT_USER\Comm\RasBook HKEY_LOCAL_MACHINE\Comm\ConnMgr\Providers\{7C4B7A38-5FF7-4bc1-80F6-5DA7870BB1AA}\Connections RasBook 注册表示例 Connections注册表示例 OMA Client Provisioning XML 【创建接入点】 方法一：RasSetEntryProperties 方法二：DMProcessConfigXML 示例代码一：(创建一个Modern拨号连接) ……. rc = RasValidateEntryName(NULL, entryName); if (rc != ERROR_SUCCESS) { if (rc == ERROR_ALREADY_EXISTS) { // ok, just need to reset the parameters } } memset(&#38;rasEntry, 0, sizeof(RASENTRY)); // Num values rasEntry.dwSize                = sizeof (RASENTRY); rasEntry.dwfOptions            [...]]]></description>
			<content:encoded><![CDATA[<p>最近需要做点与网络连接相关的东西，研究了下WM上创建接入点的方法，把一些自己对该知识点的理解和一些代码片段记录下来。</p>
<p><span id="more-177"></span></p>
<p>【相关知识点】<br />
接入点对应的注册表项：<br />
1.HKEY_CURRENT_USER\Comm\RasBook<br />
2.HKEY_LOCAL_MACHINE\Comm\ConnMgr\Providers\{7C4B7A38-5FF7-4bc1-80F6-5DA7870BB1AA}\Connections</p>
<p>注册表项：<br />
HKEY_CURRENT_USER\Comm\RasBook</p>
<p><a href="http://www.theiter.com/wp-content/uploads/2009/12/image5.png"><img style="margin-left: auto; margin-right: auto; border: 0px none currentColor;" src="http://www.xlbren.org/wp-content/uploads/2009/12/image_thumb5.png" border="0" alt="image" width="577" height="137" /></a></p>
<p>HKEY_LOCAL_MACHINE\Comm\ConnMgr\Providers\{7C4B7A38-5FF7-4bc1-80F6-5DA7870BB1AA}\Connections</p>
<p><a href="http://www.theiter.com/wp-content/uploads/2009/12/image6.png"><img style="margin-left: auto; margin-right: auto; border: 0px none currentColor;" src="http://www.xlbren.org/wp-content/uploads/2009/12/image_thumb6.png" border="0" alt="image" width="575" height="136" /></a></p>
<p><a href="http://www.theiter.com/wp-content/uploads/2009/12/image2.png"><img style="margin-left: auto; margin-right: auto; border: 0px none currentColor;" src="http://www.xlbren.org/wp-content/uploads/2009/12/image_thumb2.png" border="0" alt="image" width="558" height="98" /></a> RasBook 注册表示例</p>
<p><a href="http://www.theiter.com/wp-content/uploads/2009/12/image3.png"><img style="margin-left: auto; margin-right: auto; border: 0px none currentColor;" src="http://www.xlbren.org/wp-content/uploads/2009/12/image_thumb3.png" border="0" alt="image" width="564" height="281" /></a> Connections注册表示例</p>
<p>OMA Client Provisioning XML</p>
<p><a href="http://www.theiter.com/wp-content/uploads/2009/12/image4.png"><img style="margin-left: auto; margin-right: auto; border: 0px none currentColor;" src="http://www.xlbren.org/wp-content/uploads/2009/12/image_thumb4.png" border="0" alt="image" width="588" height="376" /></a></p>
<p>【创建接入点】<br />
方法一：RasSetEntryProperties<br />
方法二：DMProcessConfigXML</p>
<p>示例代码一：(创建一个Modern拨号连接)<br />
…….<br />
rc = RasValidateEntryName(NULL, entryName);<br />
if (rc != ERROR_SUCCESS)<br />
{<br />
if (rc == ERROR_ALREADY_EXISTS)<br />
{<br />
// ok, just need to reset the parameters<br />
}<br />
}<br />
memset(&amp;rasEntry, 0, sizeof(RASENTRY));</p>
<p>// Num values<br />
rasEntry.dwSize                = sizeof (RASENTRY);<br />
rasEntry.dwfOptions            = RASEO_DisableLcpExtensions;// |RASEO_ModemLights|RASEO_SwCompression; //RASEO_RemoteDefaultGateway<br />
// use the PPP addr as the default gateway<br />
// don&#8217;t use LCP extension<br />
// show in tray icon once connected<br />
// enable software compression<br />
rasEntry.dwfNetProtocols    = RASNP_Ip;        // TCP/IP<br />
rasEntry.dwFramingProtocol    = RASFP_Ppp;    // PPP</p>
<p>// Strings<br />
strcpy (rasEntry.szAreaCode, _T(&#8220;&#8221;));<br />
strcpy (rasEntry.szLocalPhoneNumber, _T(&#8220;1&#8243;));<br />
strcpy (rasEntry.szScript, _T(&#8220;&#8221;));<br />
strcpy (rasEntry.szAutodialDll, _T(&#8220;&#8221;));<br />
strcpy (rasEntry.szAutodialFunc, _T(&#8220;&#8221;));<br />
strcpy (rasEntry.szDeviceType, _T(&#8220;&#8221;));<br />
strcpy (rasEntry.szDeviceName, _T(&#8220;&#8221;));<br />
strcpy (rasEntry.szX25PadType,  _T(&#8220;&#8221;));<br />
strcpy (rasEntry.szX25Address,  _T(&#8220;&#8221;));<br />
strcpy (rasEntry.szX25Facilities, _T(&#8220;&#8221;));<br />
strcpy (rasEntry.szX25UserData,  _T(&#8220;&#8221;));<br />
strcpy (rasEntry.szDeviceType,DEV_TYPE);</p>
<p>if (get_dev_name(devName, DEV_NAME))<br />
strcpy (rasEntry.szDeviceName, devName);<br />
else<br />
strcpy (rasEntry.szDeviceName, DEV_NAME);</p>
<p>// Call RAS function<br />
pszPbkPath = NULL;    // Default phone book<br />
rc = RasSetEntryProperties(pszPbkPath, entryName, &amp;rasEntry, sizeof (RASENTRY), NULL, 0);<br />
if (rc)<br />
{</p>
<p>rc = RasSetEntryProperties(pszPbkPath, entryName, &amp;rasEntry, sizeof (RASENTRY), NULL, 0);<br />
}</p>
<p>memset(&amp;dialParm, 0, sizeof(RASDIALPARAMS));</p>
<p>dialParm.dwSize = sizeof (RASDIALPARAMS);</p>
<p>strcpy (dialParm.szEntryName,  entryName);<br />
strcpy (dialParm.szPhoneNumber,  _T(&#8220;&#8221;));<br />
strcpy (dialParm.szCallbackNumber, _T(&#8220;&#8221;));<br />
strcpy (dialParm.szUserName, userName);<br />
strcpy (dialParm.szPassword, password);<br />
strcpy (dialParm.szDomain,  _T(&#8220;&#8221;));</p>
<p>dwError = RasSetEntryDialParams(pszPbkPath, &amp;dialParm, FALSE);<br />
……</p>
<p>注：以上代码只是创建了一个连接，但是在系统连接设置里面不可见（只会在HKEY_CURRENT_USER\Comm\RasBook对应条目下添加相关的注册表项），如果希望其可以在系统连接设置里面可见，需在HKEY_LOCAL_MACHINE\Comm\ConnMgr\Providers\{7C4B7A38-5FF7-4bc1-80F6-5DA7870BB1AA}\Connections对应的条目下添加上述表格中列出的注册表项。如果你只是想在代码中临时使用该接入点，而不希望用户对其进行手动配置，就没有必要添加这些注册表项了。另外以上的例子只是我创建一个Modern拨号连接的参数，要创建其他类型的连接，应该修改对应的参数。</p>
<p>示例代码er：<br />
DWORD retVal = 0;</p>
<p>LPCWSTR strFavoriteXmlFort =<br />
L&#8221;&lt;wap-provisioningdoc&gt;&#8221;<br />
L&#8221;&lt;characteristic type=\&#8221;CM_Networks\&#8221;&gt;&#8221;<br />
L&#8221; &lt;characteristic type=\&#8221;%s\&#8221;&gt;&#8221;<br />
L&#8221; &lt;parm name=\&#8221;DestId\&#8221; value=\&#8221;%s\&#8221; /&gt;&#8221;      // 1<br />
<br />
60;    L&#8221; &lt;/characteristic&gt;&#8221;<br />
L&#8221;&lt;/characteristic&gt;&#8221;<br />
L&#8221;&lt;characteristic type=\&#8221;CM_PPPEntries\&#8221;&gt; &#8221; //此处的可以根据实际情况选择类型<br />
L&#8221;&lt;characteristic type=\&#8221;%s\&#8221;&gt;&#8221;<br />
L&#8221;&lt;parm name=\&#8221;DestId\&#8221; value=\&#8221;%s\&#8221;/&gt;&#8221;   //此处的DestId是“1”处定义的ID<br />
L&#8221;&lt;parm name=\&#8221;CountryCode\&#8221; value=\&#8221;%s\&#8221;/&gt;&#8221;<br />
L&#8221;&lt;parm name=\&#8221;AreaCode\&#8221; value=\&#8221;%s\&#8221;/&gt;&#8221;<br />
L&#8221;&lt;parm name=\&#8221;Phone\&#8221; value=\&#8221;%s\&#8221;/&gt;&#8221;<br />
L&#8221;&lt;parm name=\&#8221;UserName\&#8221; value=\&#8221;%s\&#8221;/&gt;&#8221;<br />
L&#8221;&lt;parm name=\&#8221;Password\&#8221; value=\&#8221;%s\&#8221;/&gt;&#8221;<br />
L&#8221;&lt;parm name=\&#8221;Domain\&#8221; value=\&#8221;%s\&#8221;/&gt;&#8221;<br />
L&#8221;&lt;parm name=\&#8221;DeviceType\&#8221; value=\&#8221;%s\&#8221;/&gt;&#8221;  //modem<br />
L&#8221;&lt;parm name=\&#8221;DeviceName\&#8221; value=\&#8221;%s\&#8221;/&gt;&#8221;<br />
L&#8221;&lt;parm name=\&#8221;Enabled\&#8221; value=\&#8221;%s\&#8221;/&gt;&#8221;<br />
L&#8221;&lt;parm name=\&#8221;RequirePw\&#8221; value=\&#8221;%s\&#8221;/&gt;&#8221;<br />
L&#8221;&lt;/characteristic&gt;&#8221;<br />
L&#8221;&lt;/characteristic&gt;&#8221;<br />
L&#8221;&lt;/wap-provisioningdoc&gt;&#8221;;<br />
CString strXml;<br />
strXml.Format(strFavoriteXmlFort,<br />
lpNetWorkName,<br />
connInfo-&gt;lpDestId,<br />
lpConnName,<br />
connInfo-&gt;lpDestId,<br />
connInfo-&gt;lpConntryCode,<br />
connInfo-&gt;lpAreaCode,<br />
connInfo-&gt;lpPhone,<br />
connInfo-&gt;lpUserName,<br />
connInfo-&gt;lpPassword,<br />
connInfo-&gt;lpDomain,<br />
connInfo-&gt;lpDeviceType,<br />
connInfo-&gt;lpDeviceName,<br />
connInfo-&gt;lpEnabled,<br />
connInfo-&gt;lpRequirePw<br />
);</p>
<p>LPWSTR pszwXMLout = NULL;<br />
HRESULT hr = DMProcessConfigXML(strXml, CFGFLAG_PROCESS, &amp;pszwXMLout);<br />
retVal = hr;</p>
<p>if ( pszwXMLout )<br />
{<br />
delete [] pszwXMLout;<br />
pszwXMLout = NULL;<br />
}</p>
<p>return retVal;</p>
<p>注：以上代码在系统连接里面创建了一个名为“lpNetWorkName”的NetWork项，在该项目下面创建了一个名为“lpConnName”的连接。该连接的类型可以根据实际情况选择不同类型（CM_GPRSEntries，CM_PPPEntries，CM_VPNEntries&#8230;），根据实际的网络情况和设备类型选择类型很重要，比如，我在一个只支持3G网络的手机上创建了一个CM_GPRSEntries类型的连接（EntryType不对），这样该连接是不可用的。另，两处的“DestId”一定要为一致，否则该连接在新建的lpNetWorkName项下不可见。</p>
<p>My Site: http://<a href="http://www.xlbren.com">www.xlbren.com</a>
<div style="margin-top: 15px">
<p><strong>转载请注明：</strong> 转载自<a href="http://www.theiter.com/">iT人 &#8211;  theiter</a></p>
<p><strong>本文链接地址:</strong> <a href="http://www.theiter.com/2009/12/%e5%a6%82%e4%bd%95%e5%9c%a8wm%e4%b8%8a%e5%88%9b%e5%bb%ba%e6%8e%a5%e5%85%a5%e7%82%b9-2.html">如何在WM上创建接入点</a></p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.theiter.com/2009/12/%e5%a6%82%e4%bd%95%e5%9c%a8wm%e4%b8%8a%e5%88%9b%e5%bb%ba%e6%8e%a5%e5%85%a5%e7%82%b9-2.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Windows CE驱动程序结构概述</title>
		<link>http://www.theiter.com/2008/10/windows-ce%e9%a9%b1%e5%8a%a8%e7%a8%8b%e5%ba%8f%e7%bb%93%e6%9e%84%e6%a6%82%e8%bf%b0.html</link>
		<comments>http://www.theiter.com/2008/10/windows-ce%e9%a9%b1%e5%8a%a8%e7%a8%8b%e5%ba%8f%e7%bb%93%e6%9e%84%e6%a6%82%e8%bf%b0.html#comments</comments>
		<pubDate>Thu, 30 Oct 2008 15:03:00 +0000</pubDate>
		<dc:creator>theiter</dc:creator>
				<category><![CDATA[WindowsMobile]]></category>
		<category><![CDATA[wm]]></category>

		<guid isPermaLink="false">http://www.xlbren.com/?p=82</guid>
		<description><![CDATA[转自：http://blog.mcuol.com/User/iwillbeback008/Article/10045_1.htm Windows CE驱动程序结构概述 Windows CE的驱动程序可以从多种角度进行区分。 1．从加载以及接口方式来区分 可以分为本机设备驱动（Built-In Driver）、可加载驱动（Loadable Driver）以及混合型驱动。 （1）本机设备驱动 本机设备驱动即Native Device Drivers。这些驱动程序在系统启动时，在GWES的进程空间内被加载，因此它们不是以独立的DLL形式存在。这些驱动对应的设备通常在系统启动时就被要求加载，如果没有串口，也没有LCD的话，整个系统就不能和用户信息交流。另外，流驱动程序也能作为本机设备驱动而存在。 （2）可加载驱动 也被称为流驱动。 这些驱动可以在系统启动时或者和启动后的任何时候由设备管理器动态加载。通常它们以DLL动态链接库的形式存在，系统加载它们后，这些驱动程序也只是以用户态的角色运行。可加载驱动程序通过文件操作API来从设备管理器和应用程序获得命令。 在Windows CE中典型的可加载驱动有以下各类： n&#160;&#160;&#160;&#160; PCMCIA driver（PCMCIA.dll） n&#160;&#160;&#160;&#160; Serial driver（SERIAL.dll） n&#160;&#160;&#160;&#160; ATAFLASH driver（ATA.dll） n&#160;&#160;&#160;&#160; Ethernet driver（NE2000.dll，SMSC100FD.dll） （3）混合型驱动 这类驱动综合了前两种驱动的特性。它同时使用了stream接口和custom-purpose接口。 混合型驱动主要是提供custom-purpose 接口，但是由于需要和系统中只允许使用stream接口的那些模块进行交互，因此也必须提供stream接口。例如，PC card socket驱动同时拥有两套接口。 2．从驱动层次上分 可以分为独立驱动和层次型驱动。图9-1是这两种驱动在系统中的位置。 图9-1&#160; 独立驱动和层次型驱动在系统中的位置 （1）独立驱动程序 可以将驱动程序编写成同时包含MDD和PDD层的独立驱动。独立驱动的代码应当包括中断服务例程和平台相关处理函数。使用独立驱动的好处在于可以省去MDD和PDD层驱动之间的信息传递，这一点在实时处理中非常重要。另外，如果设备的操作和MDD驱动层的接口描述相吻合，可以使用独立驱动程序提高处理性能。 （2）层次型驱动 层次型驱动分为两层，较上层的Model Device Driver（MDD）和比较下层的Platform Dependent Driver（PDD）。MDD实现的是和平台无关的功能，它描述了一个通用的驱动程序框架。而PDD是和硬件以及平台相关的代码组成。MDD调用PDD中特定的接口来获取硬件相关的信息。当使用层次型驱动的时候，一般只需要基于相近的样列驱动程序，针对特定的硬件修改PDD程序，MDD建立的框架可继续使用。由于层次间接口的层层调用以及消息的传递，使得处理速度相对独立驱动程序要慢，因此在时间要求苛刻的环境下，层次型驱动显得不是很适合。 一般MDD将完成以下任务。 n&#160;&#160;&#160;&#160; 连接PDD层，并且定义它要使用到的Device Driver Service Provider Interface（DDSI）函数集； [...]]]></description>
			<content:encoded><![CDATA[<p>转自：<a href="http://blog.mcuol.com/User/iwillbeback008/Article/10045_1.htm">http://blog.mcuol.com/User/iwillbeback008/Article/10045_1.htm</a></p>
<p>Windows CE驱动程序结构概述 </p>
<p>Windows CE的驱动程序可以从多种角度进行区分。    <br />1．从加载以及接口方式来区分 </p>
<p>可以分为本机设备驱动（Built-In Driver）、可加载驱动（Loadable Driver）以及混合型驱动。 </p>
<p>（1）本机设备驱动 </p>
<p>本机设备驱动即Native Device Drivers。这些驱动程序在系统启动时，在GWES的进程空间内被加载，因此它们不是以独立的DLL形式存在。这些驱动对应的设备通常在系统启动时就被要求加载，如果没有串口，也没有LCD的话，整个系统就不能和用户信息交流。另外，流驱动程序也能作为本机设备驱动而存在。 </p>
<p>（2）可加载驱动 </p>
<p>也被称为流驱动。 </p>
<p>这些驱动可以在系统启动时或者和启动后的任何时候由设备管理器动态加载。通常它们以DLL动态链接库的形式存在，系统加载它们后，这些驱动程序也只是以用户态的角色运行。可加载驱动程序通过文件操作API来从设备管理器和应用程序获得命令。 </p>
<p>在Windows CE中典型的可加载驱动有以下各类： </p>
<p>n&#160;&#160;&#160;&#160; PCMCIA driver（PCMCIA.dll） </p>
<p>n&#160;&#160;&#160;&#160; Serial driver（SERIAL.dll） </p>
<p>n&#160;&#160;&#160;&#160; ATAFLASH driver（ATA.dll） </p>
<p>n&#160;&#160;&#160;&#160; Ethernet driver（NE2000.dll，SMSC100FD.dll） </p>
<p>（3）混合型驱动 </p>
<p>这类驱动综合了前两种驱动的特性。它同时使用了stream接口和custom-purpose接口。 </p>
<p>混合型驱动主要是提供custom-purpose 接口，但是由于需要和系统中只允许使用stream接口的那些模块进行交互，因此也必须提供stream接口。例如，PC card socket驱动同时拥有两套接口。    <br />2．从驱动层次上分 </p>
<p>可以分为独立驱动和层次型驱动。图9-1是这两种驱动在系统中的位置。 </p>
<p><a href="http://www.theiter.com/wp-content/uploads/2009/11/image71.png"><img style="border-bottom: 0px;border-left: 0px;float: none;margin-left: auto;border-top: 0px;margin-right: auto;border-right: 0px" border="0" alt="image" src="http://www.theiter.com/wp-content/uploads/2009/11/image_thumb71.png" width="346" height="178" /></a> </p>
<p>图9-1&#160; 独立驱动和层次型驱动在系统中的位置 </p>
<p>（1）独立驱动程序 </p>
<p>可以将驱动程序编写成同时包含MDD和PDD层的独立驱动。独立驱动的代码应当包括中断服务例程和平台相关处理函数。使用独立驱动的好处在于可以省去MDD和PDD层驱动之间的信息传递，这一点在实时处理中非常重要。另外，如果设备的操作和MDD驱动层的接口描述相吻合，可以使用独立驱动程序提高处理性能。 </p>
<p>（2）层次型驱动 </p>
<p>层次型驱动分为两层，较上层的Model Device Driver（MDD）和比较下层的Platform Dependent Driver（PDD）。MDD实现的是和平台无关的功能，它描述了一个通用的驱动程序框架。而PDD是和硬件以及平台相关的代码组成。MDD调用PDD中特定的接口来获取硬件相关的信息。当使用层次型驱动的时候，一般只需要基于相近的样列驱动程序，针对特定的硬件修改PDD程序，MDD建立的框架可继续使用。由于层次间接口的层层调用以及消息的传递，使得处理速度相对独立驱动程序要慢，因此在时间要求苛刻的环境下，层次型驱动显得不是很适合。 </p>
<p>一般MDD将完成以下任务。 </p>
<p>n&#160;&#160;&#160;&#160; 连接PDD层，并且定义它要使用到的Device Driver Service Provider Interface（DDSI）函数集； </p>
<p>n&#160;&#160;&#160;&#160; 向设备管理器提供Device Driver Interface（DDI）接口集； </p>
<p>n&#160;&#160;&#160;&#160; 处理复杂的事件，如中断等等。 </p>
<p>每一种MDD驱动都处理不同种类的设备。DDI是由MDD层驱动以及独立型驱动提供给设备管理器的一组接口集。DDSI是由PDD向MDD层提供的接口集。公司的设备可以用同样的DDI。 </p>
<p>在开发过程中，MDD层驱动是不需要被修改的。微软公司不保证被修改的MDD能在系统中正确运行的。和MDD层驱动不同的是，PDD层驱动必须被修改成和特定硬件相匹配的代码。程序员可以自己开发一个PDD程序，多数情况下建议开发者在Platform Builder提供的样例驱动程序上进行修改。例如，Platform Builder提供了Wavedev驱动程序，它的代码位于%WINCEROOT%\public\common\oak\drivers\WAVEDEV下，这是一个容易理解的流接口层次型驱动程序。此样例audio驱动程序仅提供了播放及录音功能，只提供播放功能的结构框架，播放功能和音频设备的交互还需要PDD层来解决。</p>
<div style="margin-top: 15px">
<p><strong>转载请注明：</strong> 转载自<a href="http://www.theiter.com/">iT人 &#8211;  theiter</a></p>
<p><strong>本文链接地址:</strong> <a href="http://www.theiter.com/2008/10/windows-ce%e9%a9%b1%e5%8a%a8%e7%a8%8b%e5%ba%8f%e7%bb%93%e6%9e%84%e6%a6%82%e8%bf%b0.html">Windows CE驱动程序结构概述</a></p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.theiter.com/2008/10/windows-ce%e9%a9%b1%e5%8a%a8%e7%a8%8b%e5%ba%8f%e7%bb%93%e6%9e%84%e6%a6%82%e8%bf%b0.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>串口驱动分析</title>
		<link>http://www.theiter.com/2008/10/%e8%bd%ac%ef%bc%9a%e4%b8%b2%e5%8f%a3%e9%a9%b1%e5%8a%a8%e5%88%86%e6%9e%90.html</link>
		<comments>http://www.theiter.com/2008/10/%e8%bd%ac%ef%bc%9a%e4%b8%b2%e5%8f%a3%e9%a9%b1%e5%8a%a8%e5%88%86%e6%9e%90.html#comments</comments>
		<pubDate>Thu, 30 Oct 2008 08:38:00 +0000</pubDate>
		<dc:creator>theiter</dc:creator>
				<category><![CDATA[WindowsMobile]]></category>
		<category><![CDATA[wm]]></category>

		<guid isPermaLink="false">http://www.xlbren.com/?p=113</guid>
		<description><![CDATA[串口驱动分析 Auth：nasiry 串口驱动分析 http://nasiry.cnblogs.com/archive/2005/04/12/136175.aspx Auth：nasiry date： 2005年4月12日 abort： windowsCE.net 420串口驱动分析 相关资料 虽然串口通讯已经是普遍的标准而且广为大家熟知，但驱动中涉及的部分内容也可能在平时的应用中并不是很常用到，在这里做一个简单的介绍待后面说明到具体代码的时候可以连贯一些。 串行通讯接口是目前十分流行的通讯接口之一。由于其电气界面的简单性使其在计算机领域的应用相当的广泛。在这里提到的串行通讯接口主要是指UART(通用串行)和IRDA两种。通常的串行连接电气连接上有3wire和9wire两种。3wire的接线方式下定义了发送、接收和地三根连接。其用途就如名称一样分别用于发送、接收。下面是通常3wire连接的结构框图 通常在串行接口控制器上会有两个FIFO用作接收和发送的缓冲，当接收到数据后会直接将接收到的数据置入该缓冲器，并同时由控制电路向本地总线发出通知，以便让本地总线将缓冲器内的数据读走，这样在响应(等待和读取)的过程中仍然能通过缓冲器来接收数据。而发送发送的过程刚刚相反，本地总线可一直向发送缓冲写入数据直到器填满为止，而无需对每个数据的发送进行等待。这就是基本的收发流程(这部分逻辑流程相信大家是最熟悉的)。这一点在3wire和9wire中都是相同的。但是我们考虑下面的情况，如果接收一方的响应由于某种原因的干扰(如处理器被其他中断服务占用)的时候可能就来不及相应之前ReceiveFIFO就可能被填满了，这样后续发送过来的数据就会丢失，这样在需要数据可靠传输的情况下串行通讯的弊端也就显示出来了。如需要数据的可靠传输就需要对数据流的收发进行控制。在9wire中将串行连接定义为如下形式: &#160; 也就是说在原3wire的基础上增加了DCD,DTR,DSR,RTS,CTS,DELL六个控制线。其中RTS/CTS用于流控制，另外的DCD和DELL则留作连接modem使用。有了专门的硬件流控制引脚也就使得流控制成为可能，以完成收发两端的匹配使得数据可以可靠的传输。用RTS/CTS（请求发送/清除发送）流控制时，应将通讯两端的RTS、CTS线对应相连).在发送端准备发送数据之前设置RTS(Request to send)也就使发送请求线，若接收端以作好接收准备，就启动响应的CTS（Clear to send）引线。这样，收发双发就进入数据传输状态，在此过程中如若接收端处理数据的速度低于发送端的发送速度，接收一端还可以设置CTS引线恢复原来阻塞得状态以暂时中断数据传输，之后若需要恢复数据传输恢复CTS状态即可。这样UART的传输即实现了流控制，保障了数据传输的完备性。 在这里还要说一下软件流控制，虽然硬件已经可以完成流控制的任务但很多少时候受到连线数的限制不能使用硬件流控制也就设计了专门的软件流控制的方法。现在回到3线传输的情景，若接收端接收数据过程中缓冲器的负载到达某一限制(也就是留出一定的缓冲空间)时接收端向发送端发送一个特殊的标示位(接收停止位)，当发送端收到该标示的时候就停止发送，直到接收端缓冲器低于另一限制后发送标示(接收许可位)给发送端，这样就可以控制数据流的传输起停。这种软件流控制是在给缓冲器留余量来完成的，在收发双端处理器速度差很大的时候就不太适用了，就必须要用硬件流控制。 其他几个引脚都是与modem相关的，DSR数据装置准备好（Data set ready)用于表明MODEM处于可以使用的状态。DTR数据终端准备好(Data terminal ready)表明数据终端可以使用。这两个信号用于检查Modem是否连接。DELL脚当有电话拨入时Modem将会设置这个引脚。DCD信号是当Modem接收到数字载波信号的时候被设置，用于了解Modem接收信号的情况。 至于剩下的奇偶效验和停止位设置就只是需要针对寄存器设置无需软件干涉就可以完成了。下面我们来看具体的驱动程序。 架构 在wince中串口的驱动实现是有固定模型的，ce中的串口模型遵循ISO/OSI网络通讯模型(7层)，就是说串口属于CE网络模块的一个部分。其中rs232界面(或其它的物理介质)实现网络的物理层，而驱动和serialAPI共同组成数据链路层，其它部分都没有做定义。在典型的应用中,serialAPI与间接通过TAPI或直接与ActiveSync交互，组成CE网络的一部分。而红外本身的协议就相对复杂的多，它有专门的一套模型来描述其使用规则，对红外设备本身了解不多也就不能深入下去。在串口的这一侧，整个驱动模型也是相当的复杂的，但所幸的是驱动仅仅使用到SerialAPI这一层，在这个层次上串口的行为还是相对简单的。 我们这里仅仅涉及上面所提到的Serial/irda Driver这部分(绿色部分)。在wince提供的驱动例程中串口/红外驱动采用分层结构设计，MDD提供框架性的实现，负责提供OS所需的基本实现，并将代码设计与具体的硬件设计无关。而PDD提供了对硬件操作相应的代码。这些代码通过结构HWOBJ来相互联系。对于MDD+PDD的整体驱动来看，串口驱动模型是作为Stream来实现的。 两者合一以达到实现驱动的目的。DDSI就是指这两个部分之间的接口，这个接口并非受到强制的物理/逻辑关系来约束，而是人为的规定的。在涉及到一种特定硬件我们进行针对实现的时候往往需要的是了解硬件的物理特性和控制逻辑，然后根据DDSI的约束就来进行实现。对于这里描述的驱动模型而言结合关键在于结构指针HWOBJ的使用和具体实现。在实际的驱动应用中仅仅需要实现HWOBJ相关的一系列函数，而无需从驱动顶层完全开发。串口驱动模型作为一种常用驱动模型在windowsCE中常常用于串口/红外/USB Client的具体实现。该驱动模型中对全功能的串口进行了定义，除了常用的TX和RX引线定义以外，针对DTR、RTS等功能引脚都进行了支持，使得用该模型设计的串口驱动支持流控制、具备驱动Modem等设备的能力。 事实上，如果需要的话完全可 以将该驱动一 转载请注明： 转载自iT人 &#8211; theiter 本文链接地址: 串口驱动分析]]></description>
			<content:encoded><![CDATA[<p><![CDATA[
<p>串口驱动分析 Auth：nasiry    <br />串口驱动分析 </p>
<p><a href="http://nasiry.cnblogs.com/archive/2005/04/12/136175.aspx">http://nasiry.cnblogs.com/archive/2005/04/12/136175.aspx</a></p>
<p>Auth：nasiry </p>
<p>date： 2005年4月12日    <br />abort： windowsCE.net 420串口驱动分析 相关资料 </p>
<p>虽然串口通讯已经是普遍的标准而且广为大家熟知，但驱动中涉及的部分内容也可能在平时的应用中并不是很常用到，在这里做一个简单的介绍待后面说明到具体代码的时候可以连贯一些。 </p>
<p>串行通讯接口是目前十分流行的通讯接口之一。由于其电气界面的简单性使其在计算机领域的应用相当的广泛。在这里提到的串行通讯接口主要是指UART(通用串行)和IRDA两种。通常的串行连接电气连接上有3wire和9wire两种。3wire的接线方式下定义了发送、接收和地三根连接。其用途就如名称一样分别用于发送、接收。下面是通常3wire连接的结构框图 </p>
<p><a href="http://www.theiter.com/wp-content/uploads/2009/11/image151.png"><img style="border-right-width: 0px;float: none;border-top-width: 0px;border-bottom-width: 0px;margin-left: auto;border-left-width: 0px;margin-right: auto" border="0" alt="image" src="http://www.theiter.com/wp-content/uploads/2009/11/image_thumb131.png" width="354" height="304" /></a> </p>
<p>通常在串行接口控制器上会有两个FIFO用作接收和发送的缓冲，当接收到数据后会直接将接收到的数据置入该缓冲器，并同时由控制电路向本地总线发出通知，以便让本地总线将缓冲器内的数据读走，这样在响应(等待和读取)的过程中仍然能通过缓冲器来接收数据。而发送发送的过程刚刚相反，本地总线可一直向发送缓冲写入数据直到器填满为止，而无需对每个数据的发送进行等待。这就是基本的收发流程(这部分逻辑流程相信大家是最熟悉的)。这一点在3wire和9wire中都是相同的。但是我们考虑下面的情况，如果接收一方的响应由于某种原因的干扰(如处理器被其他中断服务占用)的时候可能就来不及相应之前ReceiveFIFO就可能被填满了，这样后续发送过来的数据就会丢失，这样在需要数据可靠传输的情况下串行通讯的弊端也就显示出来了。如需要数据的可靠传输就需要对数据流的收发进行控制。在9wire中将串行连接定义为如下形式:</p>
<p><a href="http://www.theiter.com/wp-content/uploads/2009/11/image161.png"><img style="border-right-width: 0px;float: none;border-top-width: 0px;border-bottom-width: 0px;margin-left: auto;border-left-width: 0px;margin-right: auto" border="0" alt="image" src="http://www.theiter.com/wp-content/uploads/2009/11/image_thumb141.png" width="575" height="160" /></a>&#160; </p>
<p>也就是说在原3wire的基础上增加了DCD,DTR,DSR,RTS,CTS,DELL六个控制线。其中RTS/CTS用于流控制，另外的DCD和DELL则留作连接modem使用。有了专门的硬件流控制引脚也就使得流控制成为可能，以完成收发两端的匹配使得数据可以可靠的传输。用RTS/CTS（请求发送/清除发送）流控制时，应将通讯两端的RTS、CTS线对应相连).在发送端准备发送数据之前设置RTS(Request to send)也就使发送请求线，若接收端以作好接收准备，就启动响应的CTS（Clear to send）引线。这样，收发双发就进入数据传输状态，在此过程中如若接收端处理数据的速度低于发送端的发送速度，接收一端还可以设置CTS引线恢复原来阻塞得状态以暂时中断数据传输，之后若需要恢复数据传输恢复CTS状态即可。这样UART的传输即实现了流控制，保障了数据传输的完备性。 </p>
<p>在这里还要说一下软件流控制，虽然硬件已经可以完成流控制的任务但很多少时候受到连线数的限制不能使用硬件流控制也就设计了专门的软件流控制的方法。现在回到3线传输的情景，若接收端接收数据过程中缓冲器的负载到达某一限制(也就是留出一定的缓冲空间)时接收端向发送端发送一个特殊的标示位(接收停止位)，当发送端收到该标示的时候就停止发送，直到接收端缓冲器低于另一限制后发送标示(接收许可位)给发送端，这样就可以控制数据流的传输起停。这种软件流控制是在给缓冲器留余量来完成的，在收发双端处理器速度差很大的时候就不太适用了，就必须要用硬件流控制。 </p>
<p>其他几个引脚都是与modem相关的，DSR数据装置准备好（Data set ready)用于表明MODEM处于可以使用的状态。DTR数据终端准备好(Data terminal ready)表明数据终端可以使用。这两个信号用于检查Modem是否连接。DELL脚当有电话拨入时Modem将会设置这个引脚。DCD信号是当Modem接收到数字载波信号的时候被设置，用于了解Modem接收信号的情况。 </p>
<p>至于剩下的奇偶效验和停止位设置就只是需要针对寄存器设置无需软件干涉就可以完成了。下面我们来看具体的驱动程序。 </p>
<p>架构 </p>
<p>在wince中串口的驱动实现是有固定模型的，ce中的串口模型遵循ISO/OSI网络通讯模型(7层)，就是说串口属于CE网络模块的一个部分。其中rs232界面(或其它的物理介质)实现网络的物理层，而驱动和serialAPI共同组成数据链路层，其它部分都没有做定义。在典型的应用中,serialAPI与间接通过TAPI或直接与ActiveSync交互，组成CE网络的一部分。而红外本身的协议就相对复杂的多，它有专门的一套模型来描述其使用规则，对红外设备本身了解不多也就不能深入下去。在串口的这一侧，整个驱动模型也是相当的复杂的，但所幸的是驱动仅仅使用到SerialAPI这一层，在这个层次上串口的行为还是相对简单的。 </p>
<p><a href="http://www.theiter.com/wp-content/uploads/2009/11/image171.png"><img style="border-right-width: 0px;border-top-width: 0px;border-bottom-width: 0px;border-left-width: 0px" border="0" alt="image" src="http://www.theiter.com/wp-content/uploads/2009/11/image_thumb151.png" width="304" height="304" /></a> <a href="http://www.theiter.com/wp-content/uploads/2009/11/image181.png"><img style="border-right-width: 0px;border-top-width: 0px;border-bottom-width: 0px;border-left-width: 0px" border="0" alt="image" src="http://www.theiter.com/wp-content/uploads/2009/11/image_thumb161.png" width="304" height="304" /></a> </p>
<p>我们这里仅仅涉及上面所提到的Serial/irda Driver这部分(绿色部分)。在wince提供的驱动例程中串口/红外驱动采用分层结构设计，MDD提供框架性的实现，负责提供OS所需的基本实现，并将代码设计与具体的硬件设计无关。而PDD提供了对硬件操作相应的代码。这些代码通过结构HWOBJ来相互联系。对于MDD+PDD的整体驱动来看，串口驱动模型是作为Stream来实现的。 </p>
<p>两者合一以达到实现驱动的目的。DDSI就是指这两个部分之间的接口，这个接口并非受到强制的物理/逻辑关系来约束，而是人为的规定的。在涉及到一种特定硬件我们进行针对实现的时候往往需要的是了解硬件的物理特性和控制逻辑，然后根据DDSI的约束就来进行实现。对于这里描述的驱动模型而言结合关键在于结构指针HWOBJ的使用和具体实现。在实际的驱动应用中仅仅需要实现HWOBJ相关的一系列函数，而无需从驱动顶层完全开发。串口驱动模型作为一种常用驱动模型在windowsCE中常常用于串口/红外/USB Client的具体实现。该驱动模型中对全功能的串口进行了定义，除了常用的TX和RX引线定义以外，针对DTR、RTS等功能引脚都进行了支持，使得用该模型设计的串口驱动支持流控制、具备驱动Modem等设备的能力。 </p>
<p>事实上，如果需要的话完全可<br />
以将该驱动一
<div style="margin-top: 15px">
<p><strong>转载请注明：</strong> 转载自<a href="http://www.theiter.com/">iT人 &#8211;  theiter</a></p>
<p><strong>本文链接地址:</strong> <a href="http://www.theiter.com/2008/10/%e8%bd%ac%ef%bc%9a%e4%b8%b2%e5%8f%a3%e9%a9%b1%e5%8a%a8%e5%88%86%e6%9e%90.html">串口驱动分析</a></p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.theiter.com/2008/10/%e8%bd%ac%ef%bc%9a%e4%b8%b2%e5%8f%a3%e9%a9%b1%e5%8a%a8%e5%88%86%e6%9e%90.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Windows mobile下文件关联程序</title>
		<link>http://www.theiter.com/2008/02/windows-mobile%e4%b8%8b%e6%96%87%e4%bb%b6%e5%85%b3%e8%81%94%e7%a8%8b%e5%ba%8f.html</link>
		<comments>http://www.theiter.com/2008/02/windows-mobile%e4%b8%8b%e6%96%87%e4%bb%b6%e5%85%b3%e8%81%94%e7%a8%8b%e5%ba%8f.html#comments</comments>
		<pubDate>Sat, 23 Feb 2008 14:57:00 +0000</pubDate>
		<dc:creator>theiter</dc:creator>
				<category><![CDATA[WindowsMobile]]></category>
		<category><![CDATA[wm]]></category>

		<guid isPermaLink="false">http://www.xlbren.com/?p=74</guid>
		<description><![CDATA[1.添加注册表项（假设文件类型为abc） 在HKEY_CLASSES_ROOT建名为 &#34;.abc” 的子目录，并在该目录下建： Name=Default，Data=abcfile的项； 在HKEY_CLASSES_ROOT建名为 &#34;abcfile”（与上一步骤中&#34;Data=abcfile”的&#34;abcfile”名称一致）的子目录；在该目录下建两个子目录：DefaultIcon和Shell，如果对文件显示图标没有要求，DefaultIcon采用默认值，Shell往下再建Open目录，Open往下再建Command目录，在这里来指定文件关联到哪个程序，如&#34;\Program Files\abc.exe&#34; &#34;%1&#34;，注意，必须要加上引号； 2.实现对应的abc.exe程序来处理*.abc文件（GetCommandLine()这个函数将会返回文件的路径）； 转载请注明： 转载自iT人 &#8211; theiter 本文链接地址: Windows mobile下文件关联程序]]></description>
			<content:encoded><![CDATA[<p>1.添加注册表项（假设文件类型为abc）   <br />在HKEY_CLASSES_ROOT建名为 &quot;.abc” 的子目录，并在该目录下建： Name=Default，Data=abcfile的项；    <br />在HKEY_CLASSES_ROOT建名为 &quot;abcfile”（与上一步骤中&quot;Data=abcfile”的&quot;abcfile”名称一致）的子目录；在该目录下建两个子目录：DefaultIcon和Shell，如果对文件显示图标没有要求，DefaultIcon采用默认值，Shell往下再建Open目录，Open往下再建Command目录，在这里来指定文件关联到哪个程序，如&quot;\Program Files\abc.exe&quot; &quot;%1&quot;，注意，必须要加上引号； </p>
<p><a href="http://www.theiter.com/wp-content/uploads/2009/11/image4.png"><img style="border-bottom: 0px;border-left: 0px;float: none;margin-left: auto;border-top: 0px;margin-right: auto;border-right: 0px" border="0" alt="image" src="http://www.theiter.com/wp-content/uploads/2009/11/image_thumb4.png" width="488" height="262" /></a> </p>
<p>2.实现对应的abc.exe程序来处理*.abc文件（GetCommandLine()这个函数将会返回文件的路径）；</p>
<div style="margin-top: 15px">
<p><strong>转载请注明：</strong> 转载自<a href="http://www.theiter.com/">iT人 &#8211;  theiter</a></p>
<p><strong>本文链接地址:</strong> <a href="http://www.theiter.com/2008/02/windows-mobile%e4%b8%8b%e6%96%87%e4%bb%b6%e5%85%b3%e8%81%94%e7%a8%8b%e5%ba%8f.html">Windows mobile下文件关联程序</a></p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.theiter.com/2008/02/windows-mobile%e4%b8%8b%e6%96%87%e4%bb%b6%e5%85%b3%e8%81%94%e7%a8%8b%e5%ba%8f.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WindowsMobile 调用DirectShow进行视频操作</title>
		<link>http://www.theiter.com/2008/02/windowsmobile-%e8%b0%83%e7%94%a8directshow%e8%bf%9b%e8%a1%8c%e8%a7%86%e9%a2%91%e6%93%8d%e4%bd%9c.html</link>
		<comments>http://www.theiter.com/2008/02/windowsmobile-%e8%b0%83%e7%94%a8directshow%e8%bf%9b%e8%a1%8c%e8%a7%86%e9%a2%91%e6%93%8d%e4%bd%9c.html#comments</comments>
		<pubDate>Sat, 23 Feb 2008 14:54:00 +0000</pubDate>
		<dc:creator>theiter</dc:creator>
				<category><![CDATA[WindowsMobile]]></category>
		<category><![CDATA[wm]]></category>

		<guid isPermaLink="false">http://www.xlbren.com/?p=71</guid>
		<description><![CDATA[既然您已经了解了基础知识，现在该看看 Windows Mobile 5.0 软件中多媒体支持的更高级的用法了。一个最有趣的开发是在 Windows Mobile 5.0 软件中包含 DirectShow API。查看该 API 的主要原因是您需要对应用程序中使用的多媒体进行更多的控制。如果前面描述的高级支持不足以满足应用程序的需求，DirectShow 提供更多的控制和更大的灵活性。DirectShow 是一个本机 API，因此可以通过本机工具集 (Visual C++) 使用，如本文后面的代码示例所示。 如果想在托管代码中访问 DirectShow，一个解决方案是将 DirectShow 的使用打包到一个本机 DLL 中，托管代码可以使用平台调用来调用该 DLL。这对于媒体捕获这样的功能而言可能是个很好的解决方案，这些功能并不依赖于用户界面组件（如媒体播放）。另一个解决方案是使用 .NET Compact Framework 2.0 中包括的 COM 互操作性来包装 DirectShow COM 组件。有一个称为 DirectShowNET 库的有趣项目，它为桌面计算机上的 DirectShow 提供托管包装，但目前没有可用于 .NET Compact Framework 的版本。 一个不错的常用方法是利用托管代码来实现用户界面、业务逻辑、数据库访问和基本的照相机交互。然后，由于需要更多的控制和灵活性，您可以使用媒体播放器控件进行媒体播放，使用 DirectShow 进行媒体捕获（功能包装在一个本机 DLL 中，通过平台调用从托管代码调用）。 开发过程中，DirectShow 在内部称为 Quartz，Quartz 还是主 DLL 的名称。1996 [...]]]></description>
			<content:encoded><![CDATA[<p>既然您已经了解了基础知识，现在该看看 Windows Mobile 5.0 软件中多媒体支持的更高级的用法了。一个最有趣的开发是在 Windows Mobile 5.0 软件中包含 DirectShow API。查看该 API 的主要原因是您需要对应用程序中使用的多媒体进行更多的控制。如果前面描述的高级支持不足以满足应用程序的需求，DirectShow 提供更多的控制和更大的灵活性。DirectShow 是一个本机 API，因此可以通过本机工具集 (Visual C++) 使用，如本文后面的代码示例所示。 </p>
<p>如果想在托管代码中访问 DirectShow，一个解决方案是将 DirectShow 的使用打包到一个本机 DLL 中，托管代码可以使用平台调用来调用该 DLL。这对于媒体捕获这样的功能而言可能是个很好的解决方案，这些功能并不依赖于用户界面组件（如媒体播放）。另一个解决方案是使用 .NET Compact Framework 2.0 中包括的 COM 互操作性来包装 DirectShow COM 组件。有一个称为 DirectShowNET 库的有趣项目，它为桌面计算机上的 DirectShow 提供托管包装，但目前没有可用于 .NET Compact Framework 的版本。 </p>
<p>一个不错的常用方法是利用托管代码来实现用户界面、业务逻辑、数据库访问和基本的照相机交互。然后，由于需要更多的控制和灵活性，您可以使用媒体播放器控件进行媒体播放，使用 DirectShow 进行媒体捕获（功能包装在一个本机 DLL 中，通过平台调用从托管代码调用）。 </p>
<p>开发过程中，DirectShow 在内部称为 Quartz，Quartz 还是主 DLL 的名称。1996 年 7 月，它首次作为 Microsoft ActiveMovie 版本 1.0 发布，当时它针对媒体播放提供了一个 ActiveX 控件，该控件除了支持音频文件外，还支持 Motion Picture Experts Group (MPEG) 1、影音交叉存取技术（Audio-Video Interleaved，AVI）和 QuickTime 视频。DirectShow SDK 作为 Microsoft DirectX SDK 的一部分由来已久，但 DirectShow SDK 现在包括在平台 SDK 中，它为开发 DirectShow 筛选器和应用程序提供工具和信息。 </p>
<p>Windows Mobile 5.0 软件的 DirectShow 是用于流媒体的一种体系结构，它提供多媒体流的高质量播放和捕获。它支持很多格式，如波形 (WAV)、MP3（MPEG Audio Layer-3）、AVI、高级数据流格式（Advanced Streaming Format，ASF）和 MPEG。 </p>
<p>DirectShow 与 Windows Mobile 5.0 支持的其他两种 DirectX 技术（DirectDraw 和 Direct3D）相集成。DirectShow 使用任何可用的视频和音频加速硬件，也支持不使用加速硬件的系统。 </p>
<p>DirectShow 简化了媒体播放和格式转换，但对于需要自定义解决方案的应用程序而言，它还提供对基础流控制体系结构的访问。例如，您可以创建自己的组件来支持新媒体格式或自定义效果。您可以使用 DirectShow 编写的应用程序示例包括：AVI 和 MP3 播放器、AVI 到 ASF 的转换器，以及音频/视频捕获和编辑应用程序。DirectShow 基于 COM 并提供大量 COM 组件。要扩展 DirectShow，您需要实现自己的 COM 组件。 </p>
<p>筛选器和筛选器图形 </p>
<p>DirectShow 的主构造块是一个称为筛选器的组件。筛选器是一个在多媒体流上执行操作的软件（实际上是一个 COM）组件。例如，筛选器可以读取文件，从视频捕获设备获取视频，解码各种流格式，以及将数据传递到图形卡或声卡。 </p>
<p>筛选器接收输入和产生输出，信息通过筛选器针在筛选器之间传递。一个针是一个筛选器端口，它可以是输入端口也可以是输出端口。如果筛选器解码 WMV 视频，则输入是 WMV 编码的流，输出是一系列未压缩的视频帧。在 DirectShow 中，一个应用程序通过将筛选器链连接在一起来执行任何任务，这样一个筛选器的输出就成为另一个筛选器的输入。一组连接的筛选器称为一个筛选器图形，图 18 显示一个用于播放带声音的视频文件的筛选器图形。</p>
<p><a href="http://www.theiter.com/wp-content/uploads/2009/11/image1.png"><img style="border-bottom: 0px;border-left: 0px;float: none;margin-left: auto;border-top: 0px;margin-right: auto;border-right: 0px" border="0" alt="image" src="http://www.theiter.com/wp-content/uploads/2009/11/image_thumb1.png" width="248" height="58" /></a>&#160; </p>
<p>图 18. 典型视频文件的筛选器图形 </p>
<p>筛选器图形必须遵循某些原则，第一个原则是需要一个源筛选器。这是数据的最初来源，无论它是文件、流媒体的 URL，还是诸如内置照相机这样的设备。然后，源筛选器的输出运行通过任意数量的转换筛选器。转换筛选器是这样的中间筛选器：它们接收某种类型的输入数据，修改传入的数据，然后将修改的数据传递到其输出。图的最后一部分是输出程序筛选器。输出程序筛选器是筛选器图形中处理的任何数据的最终目的地。输出程序可以代表以下内容：用于在屏幕上显示视频的窗口、用来发出声音的声卡，或者用来将数据存储到磁盘的筛选器编写器。 </p>
<p>在图 18 中，这些筛选器如下所示： </p>
<p>&#160; <br />•&#160;&#160;&#160; <br />文件源筛选器从文件系统读取视频文件。 </p>
<p>•&#160;&#160;&#160; <br />拆分器筛选器将文件内容解析为两个流：一个压缩的视频流和一个音频流。 </p>
<p>•&#160;&#160;&#160; <br />视频解码器筛选器对视频帧进行解码。 </p>
<p>•&#160;&#160;&#160; <br />视频输出程序筛选器使用 DirectDraw 或图形设备接口 (GDI) 将这些帧绘制到显示器。 </p>
<p>•&#160;&#160;&#160; <br />声音设备筛选器使用 DirectSound 播放音频流。 </p>
<p>请注意，图 18 中筛选器边缘的小正方形表示每个筛选器的针。 </p>
<p>DirectShow SDK 附带一个名为 GraphEdit 的工具，用于处理筛选器图形。图 19 显示 GraphEdit 工具已经呈现的 WMV 视频文件。 </p>
<p><a href="http://www.theiter.com/wp-content/uploads/2009/11/image2.png"><img style="border-bottom: 0px;border-left: 0px;float: none;margin-left: auto;border-top: 0px;margin-right: auto;border-right: 0px" border="0" alt="image" src="http://www.theiter.com/wp-content/uploads/2009/11/image_thumb2.png" width="248" height="151" /></a> </p>
<p>图 19. GraphEdit 工具中 .wmv 文件的筛选器图形。 </p>
<p>可以使用 GraphEdit 工具呈现文件、生成自定义图形、测试自定义筛选器、逐步（一帧接一帧）显示一个图形，以及处理类似的任务。如果要在应用程序中使用的图形已经确认在 GraphEdit 中运行，使用该工具将节省大量开发时间。（需要牢记的重要一点是，如果筛选器图形无法在 GraphEdit 中工作，它也无法在您的应用程序中工作。）GraphEdit 甚至可以将一个完整的筛选器图形保存为一个文件（.grf 扩展名），应用程序稍后可以加载该文件。 </p>
<p>DirectShow 应用程序结构 </p>
<p>DirectShow 应用程序进行的第一个操作是使用最重要的 COM 组件，即 Filter Graph Manager。为了使应用程序开发人员免于管理筛选器及其交互的复杂任务，该组件作为一个高级构造可以简化对筛选器图形及其筛选器的控制。您可以通过将筛选器连接在一起来使用 Filter Graph Manager 生成筛选器图形，然后应用程序可以进行诸如 Run、Pause 和 Stop 这样的简单调用，以便通过筛选器图形控制数据流。在筛选器图形的处理过程中，Filter Graph Manager 还将事件通知传递给应用程序。如需对流过程进行更多控制，也可以通过这些筛选器的 COM 接口直接访问它们。在任何情况下，很好地了解 COM 在使用 DirectShow 时都很有帮助。 </p>
<p>简言之，DirectShow 应用程序的典型步骤是：    <br />•&#160;&#160;&#160; <br />创建 Filter Graph Manager 实例。 </<br />
p>
<p</p>
<p>>•&#160;&#160;&#160; <br />使用 Filter Graph Manager 实例生成一个筛选器图形，方法是直接使用呈现功能或筛选器。 </p>
<p>•&#160;&#160;&#160; <br />通过对 Filter Graph Manager 实例进行高级调用来控制媒体流，并响应 Filter Graph Manager 实例引发的事件。 </p>
<p>处理完成后，释放 Filter Graph Manager 实例以及使用的所有筛选器。 </p>
<p>当使用 DirectShow 播放媒体时，需要注意的重要一点是，它使用单独的线程运行筛选器图形。在 DirectShow 筛选器图形的执行过程中，您会看到创建并运行了若干个线程，因为 DirectShow 为 Filter Graph Manager 创建一个线程，然后为筛选器图形中的每个筛选器都创建一个单独的线程。因此，应用程序将在 DirectShow 播放该媒体文件时继续运行，在大多数应用程序中，这对用户界面响应是件好事。然而，您需要为 DirectShow 线程留出足够的时间运行。例如，如果应用程序的主线程在播放媒体文件的同时进行大量处理，由于这些线程的优先级较低，媒体播放时将时断时续。 </p>
<p>视频播放 </p>
<p>简单任务（如显示视频文件）以及一些基本的控制台应用程序代码如下所示：   <br />#include     <br />void __cdecl main(void)    <br />{    <br />&#160; IGraphBuilder *pGraphBuilder;    <br />&#160; IMediaControl *pMediaControl;    <br />&#160; CoInitialize(NULL);    <br />&#160; CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC,     <br />&#160;&#160;&#160; IID_IGraphBuilder, (void **)&amp;pGraphBuilder);    <br />&#160; pGraphBuilder-&gt;QueryInterface(IID_IMediaControl,    <br />&#160;&#160;&#160; (void **)&amp;pMediaControl);    <br />&#160; pGraphBuilder-&gt;RenderFile(L&quot;test.wmv&quot;, NULL);    <br />&#160; pMediaControl-&gt;Run();    <br />&#160; MessageBox(NULL, &quot;Click OK to end playback.&quot;, &quot;DirectShow&quot;, MB_OK);    <br />&#160; pMediaControl-&gt;Release();    <br />&#160; pGraphBuilder-&gt;Release();    <br />&#160; CoUninitialize();    <br />} </p>
<p>上述代码示例首先声明和初始化 COM 库，然后该 COM 库用于创建 Filter Graph Manager 实例，该实例引用了图形生成器 (IGraphBuilder) 和媒体控件 (IMediaControl) 接口。图形生成器通过呈现（使用 RenderFile 方法）视频文件 (test.wmv) 来创建筛选器图形，然后媒体控件接口 (pMediaControl) 启动（使用 Run 方法）筛选器图形处理。显示一个消息框以防止应用程序关闭，但这不会影响视频的呈现，因为筛选器图形运行在单独的线程上。当该用户在消息框中点击 OK 时，接口引用随 COM 库一起释放。 </p>
<p>更复杂的解决方案是使用以下代码侦听来自 Filter Graph Manager 实例的事件。   <br />#include     <br />void __cdecl main(void)    <br />{    <br />&#160; IGraphBuilder *pGraphBuilder;    <br />&#160; IMediaControl *pMediaControl;    <br />&#160; IMediaEvent&#160;&#160; *pMediaEvent;    <br />&#160; CoInitialize(NULL);    <br />&#160; CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC,     <br />&#160;&#160;&#160; IID_IGraphBuilder, (void **)&amp;pGraphBuilder);    <br />&#160; pGraphBuilder-&gt;QueryInterface(IID_IMediaControl,    <br />&#160;&#160;&#160; (void **)&amp;pMediaControl);    <br />&#160; pGraphBuilder-&gt;QueryInterface(IID_IMediaEvent,    <br />&#160;&#160;&#160; (void **)&amp;pMediaEvent);    <br />&#160; pGraphBuilder-&gt;RenderFile(L&quot;test.wmv&quot;, NULL);    <br />&#160; pMediaControl-&gt;Run();    <br />&#160; long eventCode;    <br />&#160; pMediaEvent-&gt;WaitForCompletion(INFINITE, &amp;eventCode);    <br />&#160; pMediaControl-&gt;Release();    <br />&#160; pGraphBuilder-&gt;Release();    <br />&#160; CoUninitialize();    <br />} </p>
<p>请注意，上述代码除了以粗体显示的新加内容外，几乎与之前的基本代码示例相同。在此处，您创建一个对事件 (IMediaEvent) 接口的引用，它用于等待筛选器图形处理完成。然而，在实际应用程序中，您应该避免使用 INFINITE，因为它可能会导致应用程序无限期阻塞。 </p>
<p>如果不指定其他内容，该播放在单独的弹出窗口中进行。但在许多情况中，您可能想使播放窗口成为应用程序的子窗口。要指定播放窗口的所有者、类型和位置，可以使用以下代码（从上面代码示例修改而来）。   <br />#include     <br />void __cdecl main(void)    <br />{    <br />&#160; IGraphBuilder *pGraphBuilder;    <br />&#160; IMediaControl *pMediaControl;    <br />&#160; IMediaEvent&#160;&#160; *pMediaEvent;    <br />&#160; IVideoWindow&#160; *pVideoWindow;    <br />&#160; CoInitialize(NULL);    <br />&#160; CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC,     <br />&#160;&#160;&#160; IID_IGraphBuilder, (void **)&amp;pGraphBuilder);    <br />&#160; pGraphBuilder-&gt;QueryInterface(IID_IMediaControl,    <br />&#160;&#160;&#160; (void **)&amp;pMediaControl);    <br />&#160; pGraphBuilder-&gt;QueryInterface(IID_IMediaEvent,    <br />&#160;&#160;&#160; (void **)&amp;pMediaEvent);    <br />&#160; pGraphBuilder-&gt;QueryInterface(IID_IVideoWindow,    <br />&#160;&#160;&#160; (void **)&amp;pVideoWindow);    <br />&#160; pGraphBuilder-&gt;RenderFile(L&quot;test.wmv&quot;, NULL);    <br />&#160; pVideoWindow-&gt;put_Owner((OAHWND)g_hwnd);    <br />&#160; pVideoWindow-&gt;put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS);    <br />&#160; RECT rect;    <br />&#160; GetClientRect(g_hWnd, &amp;rect);    <br />&#160; pVideoWindow-&gt;SetWindowPosition(0, 0, rect.right, rect.bottom);    <br />&#160; pMediaControl-&gt;Run();    <br />&#160; long eventCode;    <br />&#160; pMediaEvent-&gt;WaitForCompletion(INFINITE, &amp;eventCode);    <br />&#160; pVideoWindow-&gt;Release();    <br />&#160; pMediaControl-&gt;Release();    <br />&#160; pGraphBuilder-&gt;Release();    <br />&#160; CoUninitialize();    <br />} </p>
<p>改动的内容还是用粗体表示。首先，设置典型子窗口的所有者和样式。然后，将视频播放窗口的大小和位置设置为与主应用程序窗口 (g_hWnd) 的客户端区域（在 rect 中加载）的大小和位置相同。 </p>
<p>请注意，在前面的代码示例中，排除了错误处理以便容易阅读。为完整起见，包括错误处理的相同代码如下所示。   <br />#include     <br />void __cdecl main(void)    <br />{    <br />&#160; IGraphBuilder *pGraphBuilder;    <br />&#160; IMediaControl *pMediaControl;    <br />&#160; IMediaEvent&#160;&#160; *pMediaEvent;    <br />&#160; IVideoWindow&#160; *pVideoWindow;    <br />&#160; HRESULT hr = CoInitialize(NULL);    <br />&#160; if(FAILED(hr))    <br />&#160; {    <br />&#160;&#160;&#160; printf(&quot;ERROR: Couldn&#8217;t initialize COM library!&quot;);    <br />&#160;&#160;&#160; return;    <br />&#160; }    <br />&#160; hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC,     <br />&#160;&#160;&#160; IID_IGraphBuilder, (void **)&amp;pGraphBuilder);    <br />&#160; if(FAILED(hr))    <br />&#160; {    <br />&#160;&#160;&#160; printf(&quot;ERROR: Couldn&#8217;t create Filter Graph Manager instance!&quot;);    <br />&#160;&#160;&#160; return;    <br />&#160; }    <br />&#160; pGraphBuilder-&gt;QueryInterface(IID_IMediaControl,    <br />&#160;&#160;&#160; (void **)&amp;pMediaControl);    <br />&#160; pGraphBuilder-&gt;QueryInterface(IID_IMediaEvent,    <br />&#160;&#160;&#160; (void **)&amp;pMediaEvent);    <br />&#160; pGraphBuilder-&gt;QueryInterface(IID_IVideoWindow,    <br />&#160;&#160;&#160; (void **)&amp;pVideoWindow);    <br />&#160; hr = pGraphBuilder-&gt;RenderFile(L&quot;test.wmv&quot;, NULL);    <br />&#160; if(SUCCEEDED(hr))    <br />&#160; {    <br />&#160;&#160;&#160; pVideoWindow-&gt;put_Owner((OAHWND)g_hwnd);    <br />&#160;&#160;&#160; pVideoWindow-&gt;put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS);    <br />&#160;&#160;&#160; RECT rect;    <br />&#160;&#160;&#160; GetClientRect(g_hWnd, &amp;rect);    <br />&#160;&#160;&#160; pVideoWindow-&gt;SetWindowPosition(0, 0, rect.right, rect.bottom);    <br />&#160;&#160;&#</p>
<p>160; hr = pMediaControl-&gt;Run();    <br />&#160;&#160;&#160; if(SUCCEEDED(hr))    <br />&#160;&#160;&#160; {    <br />&#160;&#160;&#160;&#160;&#160; long eventCode;    <br />&#160;&#160;&#160;&#160;&#160; pMediaEvent-&gt;WaitForCompletion(INFINITE, &amp;eventCode);    <br />&#160;&#160;&#160; }    <br />&#160;&#160;&#160; else    <br />&#160;&#160;&#160;&#160;&#160; printf(&quot;ERROR: Couldn&#8217;t run filter graph!&quot;);    <br />&#160; }    <br />&#160; else    <br />&#160;&#160;&#160; printf(&quot;ERROR: Couldn&#8217;t render video file!&quot;);    <br />&#160; pVideoWindow-&gt;Release();    <br />&#160; pMediaControl-&gt;Release();    <br />&#160; pGraphBuilder-&gt;Release();    <br />&#160; CoUninitialize();    <br />} </p>
<p>要接收 Filter Graph Manager 引发的事件，需要以下两个全局声明。   <br />#define WM_FILTERGRAPHNOTIFY WM_APP + 1    <br />IMediaEventEx *g_pMediaEventEx = NULL; </p>
<p>请注意，常量 WM_FILTERGRAPHNOTIFY 可设置为任何值，WM_APP + 1 就是一个示例。在播放该流（运行筛选器图形）之前，请使用以下代码。   <br />g_pGraphBuilder-&gt;QueryInterface(IID_IMediaEventEx,    <br />&#160; (void **)&amp;g_pMediaEventEx);    <br />g_pMediaEventEx-&gt;SetNotifyWindow((OAHWND)g_hWnd,    <br />&#160; WM_FILTERGRAPHNOTIFY, 0); </p>
<p>上述代码指示 Filter Graph Manager 使用第二个参数 (WM_FILTERGRAPHNOTIFY) 的消息标识将事件发送到主应用程序窗口 (g_hWnd)。请注意，SetNotifyWindow 调用的第三个参数将作为窗口消息 (WM_FILTERGRAPHNOTIFY) 的 lParam 参数返回到应用程序。在前面的示例代码中不使用该参数，因此它设为零。然而，该参数可用于传递实例数据和事件。 </p>
<p>现在，可以将以下代码添加到应用程序的消息循环（通常在 WndProc 函数中）。   <br />case WM_FILTERGRAPHNOTIFY:    <br />&#160; HandleFilterGraphEvent();    <br />&#160; break; </p>
<p>然后，可以使用以下代码处理事件。   <br />void HandleFilterGraphEvent()    <br />{    <br />&#160; if (g_pMediaEventEx == NULL)    <br />&#160;&#160;&#160; return;    <br />&#160; long eventCode;    <br />&#160; LONG_PTR param1, param2;    <br />&#160; HRESULT hr;    <br />&#160; while(SUCCEEDED(g_pMediaEventEx-&gt;GetEvent(&amp;eventCode,    <br />&#160;&#160;&#160; ¶m1, ¶m2, 0)))    <br />&#160; {    <br />&#160;&#160;&#160; g_pMediaEventEx-&gt;FreeEventParams(eventCode, param1, param2);    <br />&#160;&#160;&#160; switch(eventCode)    <br />&#160;&#160;&#160; {    <br />&#160;&#160;&#160;&#160;&#160; case EC_COMPLETE:    <br />&#160;&#160;&#160;&#160;&#160; case EC_USERABORT:    <br />&#160;&#160;&#160;&#160;&#160; case EC_ERRORABORT:    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; g_pMediaControl-&gt;Stop();    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; long eventCode;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; g_pMediaEvent-&gt;WaitForCompletion(INFINITE, &amp;eventCode);    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; g_pMediaEventEx-&gt;SetNotifyWindow(NULL, 0, 0);    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; g_pMediaEventEx-&gt;Release();    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; g_pMediaEventEx = NULL;    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; // Do other clean-up (releases, etc.)    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; PostQuitMessage(0);    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; return;    <br />&#160;&#160;&#160; }    <br />&#160; }     <br />} </p>
<p>如果没有设置事件指针，将退出该处理，然后检索该队列上的所有事件。GetEvent 方法的第四个参数是等待事件的时间（以毫秒为单位）。因为来自 Filter Graph Manager 的事件已经在队列中，所以该参数可以设为零，这意味着不等待。请注意，EC_COMPLETE 事件不会自动停止筛选器图形的处理，因此在接收到该事件时停止该筛选器图形是一个好做法。 </p>
<p>该介绍将使您能够在自己的应用程序中开始实现媒体播放，因此，现在本文将解决更复杂的捕获视频和声音的任务。 </p>
<p>视频捕获 </p>
<p>创建针对视频和音频捕获的筛选器图形比创建针对播放的筛选器更复杂。图 20 显示带有声音的视频捕获的典型筛选器图形。 </p>
<p><a href="http://www.theiter.com/wp-content/uploads/2009/11/image3.png"><img style="border-bottom: 0px;border-left: 0px;float: none;margin-left: auto;border-top: 0px;margin-right: auto;border-right: 0px" border="0" alt="image" src="http://www.theiter.com/wp-content/uploads/2009/11/image_thumb3.png" width="248" height="83" /></a> </p>
<p>图 20. 带有声音的视频捕获的筛选器图形 </p>
<p>为了帮助创建和控制筛选器图形，DirectShow 提供了一个名为 Capture Graph Builder 的组件。就像对播放筛选器图形一样，首先创建一个 Filter Graph Manager 实例。然后，创建 Capture Graph Builder 实例并将两者相连。该本机代码如下所示。   <br />IGraphBuilder *pGraphBuilder;    <br />ICaptureGraphBuilder2 *pCaptureGraphBuilder;    <br />CoCreateInstance(CLSID_FilterGraph, 0, CLSCTX_INPROC_SERVER,    <br />&#160; IID_IGraphBuilder, (void**)&amp;pGraphBuilder);    <br />CoCreateInstance(CLSID_CaptureGraphBuilder, NULL,    <br />&#160; CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2,    <br />&#160; (void**)&amp;pCaptureGraphBuilder);    <br />pCaptureGraphBuilder-&gt;SetFiltergraph(pGraphBuilder); </p>
<p>因为它将节省一些编码工作（特别是关于 COM 的代码），您可以使用以下活动模板库 (ATL) 代码。   <br />CComPtr&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; pGraphBuilder;    <br />CComPtr pCaptureGraphBuilder;    <br />pCaptureGraphBuilder.CoCreateInstance(CLSID_CaptureGraphBuilder);    <br />pGraphBuilder.CoCreateInstance(CLSID_FilterGraph);    <br />pCaptureGraphBuilder-&gt;SetFiltergraph(pGraphBuilder); </p>
<p>继续 ATL，下一步是使用以下代码初始化视频捕获筛选器（如前面的图 20 所示）。   <br />CComPtr&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; pVideoCapture;    <br />CComPtr pPropertyBag;    <br />DEVMGR_DEVICE_INFORMATION&#160;&#160;&#160; di;    <br />CPropertyBag&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; PropBag;    <br />CComVariant&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; varCamName;    <br />GUID guidCamera = { 0xCB998A05, 0x122C, 0&#215;4166, 0&#215;84, 0x6A,    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 0&#215;93, 0x3E, 0x4D, 0x7E, 0x3C, 0&#215;86 };    <br />di.dwSize = sizeof(di);    <br />HANDLE handle = FindFirstDevice(DeviceSearchByGuid, &amp;guidCamera, &amp;di);    <br />FindClose(handle);    <br />pVideoCapture.CoCreateInstance(CLSID_VideoCapture));     <br />pVideoCapture.QueryInterface(&amp;pPropertyBag));    <br />varCamName = di.szLegacyName;    <br />PropBag.Write(L&quot;VCapName&quot;, &amp;varCamName);&#160;&#160; <br />pPropertyBag-&gt;Load(&amp;PropBag, NULL);    <br />pPropertyBag.Release();    <br />pGraphBuilder-&gt;AddFilter(pVideoCapture, L&quot;Video capture source&quot;); </p>
<p>第一个照相机捕获设备通过 FindFirstDevice 函数检索，该函数的第二个参数设置为 DEVCLASS_CAMERA_GUID（对应于在前面的代码中硬编码的 GUID [CB998A05-122C-4166-846A-933E4D7E3C86]），该检索方式是查找捕获设备的最可靠方式。属性包实例（PropBag 是实现 IPropertyBag 接口的自定义类 [CPropertyBag] 的实例）用于将捕获设备名称信息传递到捕获筛选器，然后该视频捕获筛选器添加到筛选器图形。 </p>
<p>下一步是初始化音频捕获筛选器，为此您可以使用以下代码。   <br />CComPtr pAudioCaptureFilter;    <br />pAudioCaptureFilter.CoCreateInstance(CLSID_AudioCapture);    <br />pAudioCaptureFilter.QueryInterface(&amp;pPropertyBag);    <br />pPropertyBag-&gt;Load(NULL, NULL);    <br />pGraphBuilder-&gt;AddFilter(pAudioCaptureFilter, L&quot;Audio Capture F<br />
il</p>
<p>ter&quot;); </p>
<p>创建音频捕获筛选器并将其添加到筛选器图形。现在应该初始化视频编码器并将其添加到筛选器图形。您可以借助于DMO Wrapper 筛选器在筛选器图形中使用 DirectX 媒体对象 (DMO) 实例。要使用 DMO Wrapper 筛选器用 WMV 9 DMO 对视频进行编码，可以使用以下代码。   <br />CComPtr&#160;&#160;&#160;&#160;&#160;&#160; pVideoEncoder;    <br />CComPtr pVideoWrapperFilter;    <br />pVideoEncoder.CoCreateInstance(CLSID_DMOWrapperFilter);    <br />pVideoEncoder.QueryInterface(&amp;pVideoWrapperFilter);    <br />pVideoWrapperFilter-&gt;Init(CLSID_CWMV9EncMediaObject,    <br />&#160; DMOCATEGORY_VIDEO_ENCODER);    <br />pGraphBuilder-&gt;AddFilter(pVideoEncoder, L&quot;WMV9 DMO Encoder&quot;); </p>
<p>WMV 9 编码器加载到 DMO Wrapper 筛选器中之后，就该加载 ASF 多路复用器和设置多路复用器的名称了（使用对多路复用器的文件接收接口的引用）。进行此操作的代码如下所示。   <br />CComPtr&#160;&#160;&#160;&#160; pAsfWriter;    <br />CComPtr pFileSink;    <br />pAsfWriter.CoCreateInstance(CLSID_ASFWriter);    <br />pAsfWriter-&gt;QueryInterface(IID_IFileSinkFilter, (void**) &amp;pFileSink);    <br />pFileSink-&gt;SetFileName(L&quot;My Documentstest.asf&quot;, NULL); </p>
<p>现在已经创建了该图形中需要的所有筛选器。下一步是使用以下代码将这些筛选器的针连接在一起。   <br />pCaptureGraphBuilder-&gt;RenderStream(&amp;PIN_CATEGORY_CAPTURE,    <br />&#160; &amp;MEDIATYPE_Video, pVideoCapture, pVideoEncoder, pAsfWriter );    <br />pCaptureGraphBuilder-&gt;RenderStream(&amp;PIN_CATEGORY_CAPTURE,    <br />&#160; &amp;MEDIATYPE_Audio, pAudioCaptureFilter, NULL, pAsfWriter );    <br />pCaptureGraphBuilder-&gt;RenderStream(&amp;PIN_CATEGORY_PREVIEW,    <br />&#160; &amp;MEDIATYPE_Video, pVideoCapture, NULL, NULL ); </p>
<p>视频捕获通过视频编码器连接到多路复用器，然后音频捕获也连接到多路复用器。最后，视频捕获筛选器的预览针连接到视频输出程序。不需要指定视频输出程序（作为最后一个参数），因为它是默认指定的。 </p>
<p>既然已经对这些筛选器进行了初始化，将这些筛选器添加到筛选器图形并且连接了所有针，现在就已经准备好使用下面的代码来捕获数据了。   <br />CComPtr pMediaControl;    <br />CComPtr&#160;&#160; pMediaEvent;    <br />CComPtr pMediaSeeking;    <br />pCaptureGraphBuilder-&gt;ControlStream(&amp;PIN_CATEGORY_CAPTURE,    <br />&#160; &amp;MEDIATYPE_Video, pVideoCapture, 0, 0 , 0, 0);    <br />pCaptureGraphBuilder-&gt;ControlStream(&amp;PIN_CATEGORY_CAPTURE,    <br />&#160; &amp;MEDIATYPE_Audio, pAudioCaptureFilter, 0, 0, 0, 0);    <br />pGraphBuilder.QueryInterface(&amp;pMediaControl);    <br />pMediaControl-&gt;Run();    <br />Sleep(1000);    <br />LONGLONG dwStart = 0;    <br />LONGLONG dwEnd = MAXLONGLONG;    <br />OutputDebugString(L&quot;Starting to capture the first file&quot; );    <br />pCaptureGraphBuilder-&gt;ControlStream(&amp;PIN_CATEGORY_CAPTURE,    <br />&#160; &amp;MEDIATYPE_Video, pVideoCapture, &amp;dwStart, &amp;dwEnd, 0, 0);    <br />pCaptureGraphBuilder-&gt;ControlStream(&amp;PIN_CATEGORY_CAPTURE,    <br />&#160; &amp;MEDIATYPE_Audio, pAudioCaptureFilter, &amp;dwStart, &amp;dwEnd, 0, 0);    <br />Sleep(5000);    <br />OutputDebugString(L&quot;Stopping the capture&quot;);    <br />pGraphBuilder.QueryInterface(&amp;pMediaSeeking);    <br />pMediaSeeking-&gt;GetCurrentPosition(&amp;dwEnd);    <br />pCaptureGraphBuilder-&gt;ControlStream(&amp;PIN_CATEGORY_CAPTURE,    <br />&#160; &amp;MEDIATYPE_Video, pVideoCapture, &amp;dwStart, &amp;dwEnd, 1, 2);    <br />pCaptureGraphBuilder-&gt;ControlStream(&amp;PIN_CATEGORY_CAPTURE,    <br />&#160; &amp;MEDIATYPE_Audio, pAudioCaptureFilter, &amp;dwStart, &amp;dwEnd, 1, 2);    <br />OutputDebugString(L&quot;Wating for the control stream events&quot;);    <br />pGraphBuilder.QueryInterface(&amp;pMediaEvent);    <br />long lEventCode;    <br />LONG_PTR lParam1, lParam2;    <br />do    <br />{    <br />&#160; pMediaEvent-&gt;GetEvent(&amp;lEventCode, &amp;lParam1, &amp;lParam2, INFINITE);    <br />&#160; pMediaEvent-&gt;FreeEventParams(lEventCode, lParam1, lParam2);    <br />&#160; if(lEventCode == EC_STREAM_CONTROL_STOPPED)    <br />&#160; {    <br />&#160;&#160;&#160; OutputDebugString(L&quot;Received a control stream stop event&quot;);    <br />&#160;&#160;&#160; count++;    <br />&#160; }    <br />} while(count &lt; 2);    <br />OutputDebugString(L&quot;The file has been captured&quot;); </p>
<p>该捕获图形由视频和音频控制流阻塞，然后在实际捕获数据之前允许它运行一秒。该延迟为捕获图形提供了时间，以确保分配它所有的缓冲区以及同步所有进程。一个捕获进行 5 秒，然后停止。视频和音频的控制流用于停止该流，最后，一个循环等待一个标志该流停止的事件。 </p>
<p>下面的代码片段显示一种更明确的方式来捕获图形正在运行的时刻（与等待 1 秒相比）。   <br />OAFilterState state = State_Stopped;    <br />pMediaControl-&gt;Run();&#160; <br />while(state != State_Running)&#160; <br />&#160; pMediaControl-&gt;GetState(100, &amp;state); </p>
<p>GetState 方法的第一个参数是超时（以毫秒为单位），因此该代码每 1/10 秒将尝试一次，以查看该捕获图形是否已经启动且正在运行。 </p>
<p>有关视频捕获的更多详细信息，请参阅 Windows Mobile 5.0 Pocket PC SDK 附带的 CameraCapture 示例。 </p>
<p>自定义筛选器 </p>
<p>正如前面提到的，基本上有三种筛选器类型：源筛选器、转换筛选器和输出程序筛选器。源筛选器提供来自源的原始多媒体数据，如文件、URL 或类似照相机的实时源。源筛选器可以将原始数据传递到分析器或拆分器筛选器，也可以自己进行分析或拆分。输出程序筛选器接受完全处理的数据并在显示器或扬声器上进行呈现，它们包括编写文件的筛选器。源筛选器和输出程序筛选器之间的所有筛选器都是转换筛选器。转换筛选器使用原始数据或部分处理的数据，并在将其传递到下一个筛选器之前进行处理。有许多不同类型的转换筛选器；一些筛选器将字节流解析为示例或帧，而其他筛选器进行压缩或解压缩，甚至进行格式转换。 </p>
<p>虽然 DirectShow 包括大量用于播放、转换和捕获许多不同媒体格式的现成筛选器，但是开发人员可以生成自己的自定义筛选器以便处理自定义或标准数据格式。实现自定义筛选器时，它可能是一个转换筛选器。它可能是一个将效果（如淡入或淡出）添加到视频流的筛选器。 </p>
<p>DirectShow SDK 包括大量自定义筛选器，SDK 文档提供针对编写自定义筛选器的优秀介绍。以下来自 SDK 文档的摘要提供创建转换筛选器的基本步骤：    <br />•&#160;&#160;&#160; <br />确定筛选器是必须复制媒体示例还是适当地处理它们。媒体流中进行的复制越少越好。然而，某些筛选器需要一个复制操作；该要求影响基类的选择。 </p>
<p>•&#160;&#160;&#160; <br />确定使用哪些基类并从基类派生筛选器类（如果需要，也可以派生针类）。在该步骤中，为筛选器创建一个或多个标头。在许多情况中，可以使用转换基类，从正确的转换筛选器类派生类，以及重写几个成员函数。在其他情况中，可以使用更通用的基类。这些类实现了大部分的连接和协商机制；但这些类也提供在重写更多成员函数的开销方面的灵活性。 </p>
<p>•&#160;&#160;&#160; <br />添加实例化筛选器所需的代码。该步骤需要将静态 CreateInstance 成员函数添加到派生的类中，该类还是一个全局数组，包含筛选器名称、CLSID 和指向该成员函数的指针。 </p>
<p>•&#160;&#160;&#160; <br />调用 NonDelegatingQueryInterface 函数在您的筛选器中分布任何唯</p>
<p>一的接口。该步骤强调实现接口的 COM 方面，而不是基类中的其他方面。 </p>
<p>•&#160;&#160;&#160; <br />重写基类成员函数。该步骤包括编写对于筛选器而言唯一的转换函数，以及重写连接过程所需的几个成员函数，如设置分配器大小或提供媒体类型。</p>
<div style="margin-top: 15px">
<p><strong>转载请注明：</strong> 转载自<a href="http://www.theiter.com/">iT人 &#8211;  theiter</a></p>
<p><strong>本文链接地址:</strong> <a href="http://www.theiter.com/2008/02/windowsmobile-%e8%b0%83%e7%94%a8directshow%e8%bf%9b%e8%a1%8c%e8%a7%86%e9%a2%91%e6%93%8d%e4%bd%9c.html">WindowsMobile 调用DirectShow进行视频操作</a></p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.theiter.com/2008/02/windowsmobile-%e8%b0%83%e7%94%a8directshow%e8%bf%9b%e8%a1%8c%e8%a7%86%e9%a2%91%e6%93%8d%e4%bd%9c.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Windows CE 用 inf 制作Cab安装包时应注意的几个问题</title>
		<link>http://www.theiter.com/2008/02/windows-ce-%e7%94%a8-inf-%e5%88%b6%e4%bd%9ccab%e5%ae%89%e8%a3%85%e5%8c%85%e6%97%b6%e5%ba%94%e6%b3%a8%e6%84%8f%e7%9a%84%e5%87%a0%e4%b8%aa%e9%97%ae%e9%a2%98.html</link>
		<comments>http://www.theiter.com/2008/02/windows-ce-%e7%94%a8-inf-%e5%88%b6%e4%bd%9ccab%e5%ae%89%e8%a3%85%e5%8c%85%e6%97%b6%e5%ba%94%e6%b3%a8%e6%84%8f%e7%9a%84%e5%87%a0%e4%b8%aa%e9%97%ae%e9%a2%98.html#comments</comments>
		<pubDate>Sat, 23 Feb 2008 14:50:00 +0000</pubDate>
		<dc:creator>theiter</dc:creator>
				<category><![CDATA[WindowsMobile]]></category>
		<category><![CDATA[wm]]></category>

		<guid isPermaLink="false">http://www.xlbren.com/?p=64</guid>
		<description><![CDATA[1.如果安装的目标目录已经存在则在卸载的时候不会删除 2.如果在inf中写的注册表项已经存在则在卸载的时候不会删除 3.如果在安装过程中中不希望用户选择安装路径则不用指明InstallDir 就可实现 转载请注明： 转载自iT人 &#8211; theiter 本文链接地址: Windows CE 用 inf 制作Cab安装包时应注意的几个问题]]></description>
			<content:encoded><![CDATA[<p>1.如果安装的目标目录已经存在则在卸载的时候不会删除    <br />2.如果在inf中写的注册表项已经存在则在卸载的时候不会删除     <br />3.如果在安装过程中中不希望用户选择安装路径则不用指明InstallDir 就可实现</p>
<div style="margin-top: 15px">
<p><strong>转载请注明：</strong> 转载自<a href="http://www.theiter.com/">iT人 &#8211;  theiter</a></p>
<p><strong>本文链接地址:</strong> <a href="http://www.theiter.com/2008/02/windows-ce-%e7%94%a8-inf-%e5%88%b6%e4%bd%9ccab%e5%ae%89%e8%a3%85%e5%8c%85%e6%97%b6%e5%ba%94%e6%b3%a8%e6%84%8f%e7%9a%84%e5%87%a0%e4%b8%aa%e9%97%ae%e9%a2%98.html">Windows CE 用 inf 制作Cab安装包时应注意的几个问题</a></p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.theiter.com/2008/02/windows-ce-%e7%94%a8-inf-%e5%88%b6%e4%bd%9ccab%e5%ae%89%e8%a3%85%e5%8c%85%e6%97%b6%e5%ba%94%e6%b3%a8%e6%84%8f%e7%9a%84%e5%87%a0%e4%b8%aa%e9%97%ae%e9%a2%98.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

