﻿<?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++博客-My C++-随笔分类-嵌入式开发</title><link>http://www.cppblog.com/finehai/category/11216.html</link><description>当时只道是寻常~</description><language>zh-cn</language><lastBuildDate>Tue, 24 Apr 2012 18:22:15 GMT</lastBuildDate><pubDate>Tue, 24 Apr 2012 18:22:15 GMT</pubDate><ttl>60</ttl><item><title>【转】谨献给嵌入式初学者</title><link>http://www.cppblog.com/finehai/archive/2012/04/24/172595.html</link><dc:creator>Bluesea</dc:creator><author>Bluesea</author><pubDate>Tue, 24 Apr 2012 06:09:00 GMT</pubDate><guid>http://www.cppblog.com/finehai/archive/2012/04/24/172595.html</guid><wfw:comment>http://www.cppblog.com/finehai/comments/172595.html</wfw:comment><comments>http://www.cppblog.com/finehai/archive/2012/04/24/172595.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/finehai/comments/commentRss/172595.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/finehai/services/trackbacks/172595.html</trackback:ping><description><![CDATA[<span style="font-size: 12pt;"> </span><div><p><span style="font-size: 12pt;">谨献给为了知识执着的嵌入式初学者，欢迎高手补充讨论 </span></p> <p><span style="font-size: 12pt;">实践当然是最锻炼人的方式，但是我想在校生很少有这样的机会，别说本科生，硕士生也未必有条件。所以我想学习嵌入式要从个人的知识背景和现实条件出发。订立合适的阶段目标，在允许的条件下多动手多思考。</span></p> <p><span style="font-size: 12pt;">一般情况下对于硬件设备是比较短缺的。但是可以从软件方面和嵌入式系统开发模式上下功夫，提醒大家一 点，嵌入式系统开发设计的内容知识很多，所以大家不要乱，在了解嵌入式系统开发的体系结构后，一步一步的下手，最容易上手的是linux下的C，比如 ucos（有开放源代码），虽然可能无法在硬件上仿真，但也不必着急。wince，palmos上手都很容易。无论对于初学者还是自以为是高手的人来说， 编程水平（这可不受硬件条件限制）绝对是没有止境的，有了较高的编程水平（嵌入式主要是C,当然OO的几种语言c++,java是发展趋势），等到有机会 的时候及时的补充硬件知识，会很快的成为高手。</span></p> <p><span style="font-size: 12pt;">还有，一定记住，学习嵌入式，&#8221;要想办法，不要找理由&#8220;。当年在dos下用tc编程时的条件，现在回想起来建筑就是奇迹。</span></p> <p><span style="font-size: 12pt;">我推荐一条发展道路吧，仅供参考，</span></p> <p><span style="font-size: 12pt;">1、C开发经验</span><br /><span style="font-size: 12pt;">条件：linux（这都有吧）</span><br /><span style="font-size: 12pt;">方法：随便，主要是掌握ansiC编程（不包括gtk,qt等图形可视化开发）</span></p> <p><span style="font-size: 12pt;">2、网络、操作系统、体系结构</span><br /><span style="font-size: 12pt;">条件：linux，各种书，算法、例程。</span><br /><span style="font-size: 12pt;">方法：通过C编程实现简单的网络等知识的算法和过程。</span></p> <p><span style="font-size: 12pt;">3、嵌入式系统概念</span><br /><span style="font-size: 12pt;">条件：各个嵌入式网站，讨论组，书籍</span><br /><span style="font-size: 12pt;">方法：少提问（尤其是等着天上掉馅饼，这主要是防止增长惰性，也解决不了实际问题），多思考。</span></p> <p><span style="font-size: 12pt;">4、嵌入式开发实践</span><br /><span style="font-size: 12pt;">条件：各种嵌入式系统开发工具的demo版（或者D版，如果有的话），包括编译器，仿真器。可以找高手们要，也可以下载。</span><br /><span style="font-size: 12pt;">方 法：这里有两个分支，一个是基于mcu/dsp的嵌入式系统开发，一个是象palmos,wince,ucos等rtos下的应用软件开发。对硬件感兴 趣，想成为真正高手的由第一个分支入手，以后进入第二个分支；如果十分厌烦硬件，只想停留在软件开发上的，可以只由第二个分支入手，以后就和pc上的开发 没有什么本质上的区别了，找份不错的工作应该没问题，可以不用进行下面的步骤了，感兴趣可以参考第6条。</span></p> <p><span style="font-size: 12pt;">5、硬件开发</span><br /><span style="font-size: 12pt;">条件：各种嵌入式芯片、存储器等电路器件，protel99等电路设计软件，电路板制作。</span></p> <p><span style="font-size: 12pt;">方法：这时候该有开发条件了，最起码是51系列，这个比较方便。电路的设计内容较多，不过看起来吓人，实际上比软件要简单的多。只要下功夫，实践会告诉你一切。</span><br /><span style="font-size: 12pt;">6、硬件工程/软件工程/项目管理</span><br /><span style="font-size: 12pt;">条件： 各个芯片详细资料和使用经验，软件工程知识，项目管理知识，培训，大型项目参与经验</span><br /><span style="font-size: 12pt;">方法：已经是高手了，但是学无止境，沾沾自喜于已有的知识是致命的。那个下一步。。。，你该是管理者了。</span></p> <p>&nbsp;</p><p><span style="font-size: 12pt;">补充几点. </span></p> <p><span style="font-size: 12pt;">要想成为高手中的高手,最好从钻研如下领域修炼:</span><br /><span style="font-size: 12pt;">1,分析一种RTOS的源代码--UCOS最容易;</span><br /><span style="font-size: 12pt;">2,分析一种通讯协议栈的实现方式--TCP/IP最实用;</span><br /><span style="font-size: 12pt;">3,精通一种DSP的开发集成环境--TI CCS2.1最优秀,精华在其内带的RTOS;</span><br /><span style="font-size: 12pt;">4,精通一种单片机的开发集成环境--keil C最经典;</span><br /><span style="font-size: 12pt;">5,精通一种MCU的开发集成环境--ADS 1.2最流行;</span></p><p><br /><span style="font-size: 12pt;">要想成为大师级人物再从如下领域开始修炼:</span><br /><span style="font-size: 12pt;">1,精通一种系统建模语言和工具--Telelogic tau SDL/UML suit最经典;</span><br /><span style="font-size: 12pt;">2,精通一种算法仿真工具--Matlab simulink 最便宜;</span><br /><span style="font-size: 12pt;">要想检验一下自己是否到达了至尊级人物，可以做如下的事：</span><br /><span style="font-size: 12pt;">动手搭建一套红外或者蓝牙通讯原型系统，模拟前端可以用现成的，基带用DSP，主控用个32BMCU，DSP和协议软件自己写。当然不可能做全，做个子集就可以了。</span><br /><span style="font-size: 12pt;">如果能到这个地步，打住吧，该改行去做市场了。做个一、二年市场，你不自己去创个业就太浪费了。</span></p></div><img src ="http://www.cppblog.com/finehai/aggbug/172595.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/finehai/" target="_blank">Bluesea</a> 2012-04-24 14:09 <a href="http://www.cppblog.com/finehai/archive/2012/04/24/172595.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>学习嵌入式Linux的笔记和体会</title><link>http://www.cppblog.com/finehai/archive/2012/04/24/172592.html</link><dc:creator>Bluesea</dc:creator><author>Bluesea</author><pubDate>Tue, 24 Apr 2012 06:01:00 GMT</pubDate><guid>http://www.cppblog.com/finehai/archive/2012/04/24/172592.html</guid><wfw:comment>http://www.cppblog.com/finehai/comments/172592.html</wfw:comment><comments>http://www.cppblog.com/finehai/archive/2012/04/24/172592.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/finehai/comments/commentRss/172592.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/finehai/services/trackbacks/172592.html</trackback:ping><description><![CDATA[<span style="font-size: 14pt;"> </span><div><span style="font-size: 12pt;">一个典型的桌面Linux系统包括3个主要的软件层---linux内核、C库和应用程序代码。</span><span style="font-size: 12pt;">内核是唯一可以完全控制硬件的层，内核驱动程序代表应用程序与硬件之间进行会话。内核之上是C库，负责把POSIX API转换为内核可以识别的形式，然后调用内核，从应用程序向内核传递参数。应用程序依靠驱动内核来完成特定的任务。 </span><br /><br /><span style="font-size: 12pt;">在设计嵌入式应用的时候，可以不按照这种层次，应用程序越过C库直接和内核会话，或者把应用和内核捆绑在一起，甚至可以把应用写为内核的一个线程，在内核中运行，虽然这样在移植上带来了困难，但考虑嵌入式系统对尺寸要求小的特点，是完全可行的。不过我们使用三层软件结构的模式来学习嵌入式linux将会是我们认识更清晰，简单可行并使应用具有弹性。 </span><br /><br /><strong style="font-size: 12pt;">快速入门</strong><br style="font-size: 12pt;" /><br /><span style="font-size: 12pt;">最简单的建立嵌入式Linux应用的方法就是从我们使用的桌面Linux入手，安装一个喜爱的版本，把我们的某个应用作为初始化的一部分，框架就算完成了。</span><br /><br /><span style="font-size: 12pt;">当然，嵌入式linux应用远比我们的桌面版本功能简单专一，它也许就是一个用于足彩的终端机，或是一个数码音频播放器，这些系统除了使用嵌入式CPU外，仅仅再需要一个串口，网口等少量的输入输出接口就可以完成它们特定的应用了。 </span><br /><br /><span style="font-size: 12pt;">在软件上，它可以按照三层的概念由内核装载器，定制的内核和较少的为特定任务设计的静态连接的应用程序组成。之所以使用静态连接的应用程序，是因为少量的静态连接程序所要的存储空间，比同样数量的动态连接的程序所占的空间小，这个平衡点需要我们在实际开发中去获取。也许你正在设计的是个PDA，它的应用程序较多，那么你很可能就要使用动态连接程序来减少存储空间。在你的/bin或者/sbin目录下，用厂列表看看bash,ifconfig,vi...，也许只用几十K，当你运行 ldd /bin/bash  时，你会看到它们都和好几个库文件相连。好了，这样看来，我们得把PC想像成一个嵌入式硬件平台，再重新制作一个特定功能的嵌入式linux。 </span><br /><br /><strong style="font-size: 12pt;">基础知识</strong><br /><br style="font-size: 12pt;" /><span style="font-size: 12pt;"> </span><p style="font-size: 12pt;">再进行实际操作之前，先来搞清楚几个基础知识。 <br /></p><p style="font-size: 12pt;"><br /></p><p style="font-size: 12pt;">内核装载器Loader，它的作用是把内核从外部存储器，移动到内存中。它只作这个事情，一旦完成了调入内核的工作，Loader就跳转到内核位置开始执行。不同架构有不同的 Loader，在x86结构的PC上，通常使用的loader有LILO,GRUB,syslinux,syslinux在嵌入式linux中也同样工 作。其他非x86架构的应用中，你必须使用专门的loader，或者自己编写loader来装入内核。也有不使用loader的情况，系统加电以后，内核 直接从烧录有映象的Flash上开始执行。 <br /></p><p style="font-size: 12pt;"><br /></p><p style="font-size: 12pt;">内核，一旦内核开始执行，它将通过驱动程序初始化所有硬件，这可以从我们的pc机监视器的输出看出 来，每个驱动程序都打印一些有关它的信息。初始化完成后，计算机就准备运行嵌入式应用。也许一个，也许是多个应用程序组成了嵌入式应用，但通常首先调用的 是init(通过loader 向核心传入init=/program  可以定制首先运行的程序)。桌面linux中，init会读取/etc/inittab文件，来决定执行级别和哪些脚本和命令。嵌入式应用中，可以根据实 际的情况决定是否使用标准的init执行方式，也许这个init是个静态程序，它能够完成我们的嵌入应用的特定任务，那完全不用考虑inittab了。 <br /></p><p style="font-size: 12pt;"><br /></p><p style="font-size: 12pt;">initrd 文件系统，initrd以一种把内核从存储介质装入到内存的相同的机制来装入一个小型文件系统。这个文件系统最好是以压缩的方式存储在介质上的，解压缩到 RAM盘上。通过使用initrd,包含有核心驱动和启动脚本的小文件系统，就可以直接从介质上和内核一起启动起来，内核届压缩这个文件系统，并执行这个 文件系统上叫做/linuxrc的脚本文件，这个脚本通常会把启动过程中所需要的驱动程序装入。脚本退出以后，initrd文件系统也卸下了，启动过程进 入真正初始化过程。对于嵌入式来讲，可以将需要的应用软件都运行在这个initrd文件系统上，只要/linxrc文件不结束，内核启动过程的其他部分就不会继续。&nbsp;</p><p style="font-size: 12pt;"><br />做个试验： <br />cp /boot/initrd-2.4.20.img /tmp <br />cd /tmp <br />mv initrd-2.4.2-.img initrd.img.gz <br />gunzip initrd.img.gz <br />mount -o loop initrd.img /mnt <br />cd /mnt <br />ls <br />cat linuxrc 可以看到里面执行了加载了两个模块的操作，你在启动linxu的时候会看见屏幕打印信息。 <br /></p><p style="font-size: 12pt;"><br /></p><p style="font-size: 12pt;"><br /><strong>入门试验，制作一个简单的应用</strong><br /><br />我们使用一张软盘启动一台假象的只有一个串口，键盘输入，显示输出的x86架构的linux系统，执行的特定应用就是运行minicom，通过串口拨号。需 要软件: minicom-xx.src.tar.gz 和 syslinux-xx.tar.gz，xx代表版本号  ，开始之前，在主目录建立一个目录，来释放这两个软件包：&nbsp;</p><p style="font-size: 12pt;"><br />cd <br />mkdir -p project/minilinux <br />cd project/minilinux <br />tar zxvf minicom-xx.src.tar.gz <br />tar zxvf syslinux-xx.tar.gz <br /><br />1、裁减linux内核(需要系统安装内核文件包) <br /><br />配置内核的时候，我们需要选择这些：摸块编入内核，386处理器、物理内存off、支持ELF、标准PC软盘、支持RAM盘(4096)、支持 initial RAM disk (initrd)、虚你终端、虚拟终端控制台、标准串口、ext2文件系统、控制台驱动，VGA text  console、DOS FAT、MSDOS文件系统，其他的都可以不要，这样内核编出来较小。&nbsp;</p><p style="font-size: 12pt;"><br />步骤: <br />cd /usr/src/linux <br />make mrproper <br />make xconfig <br />make dep &amp;&amp; make bzImage <br />得到 /usr/src/linux/arch/i386/boot/目录的内核文件bzIamge。 <br /><br />2、编译一个静态的minicom，把它作为将来的linuxrc&nbsp;</p><p style="font-size: 12pt;"><br />cd minicom-xx/src <br />vi Makefile <br />修改下面这行 <br />minicom: $(minicom_OBJECTS) $(minicom_DEPENDENCIES) <br />rm -f minicom 下面的行加上 -static，连接为静态程序 <br />(LINK) -static $(minicom_LDFLAGS) $(minicom_OBJECTS) $(minicom_LDADD) $(LIBS) <br /><br />vi minicom.c <br />找到 if (real_uid==0 &amp;&amp; dosetup==0 ) 删除这个判断条件语句，主要是用于权限判断的，因为这个嵌入应用不关注权限问题，否则会出错。 <br />make <br />得到可执行程序，用ldd 检查一下是不是静态程序。 <br /><br />3、准备initrd压缩文件image.gz&nbsp;</p><p style="font-size: 12pt;"><br />dd if=/dev/zero of=image bs=1k count=4096 <br />losetup /dev/loop0 image <br />mke2fs -m 0 /dev/loop0 <br />mounmt -t ext2 /dev/loop0 /mnt/ <br />mkdir -p /mnt/dev <br />mkdir -p /mnt/usr/share/terminfo/l/ <br />cd /dev <br />cp -a consle null tty tty0 zero mem /mnt/dev <br />cp -P /usr/share/terminfo/l/linux /mnt/usr/share/terminfo/l/linux <br />cp ~/project/minilinux/mincom/src/minicom /mnt/linuxrc <br />umount /mnt <br />losetup -d /dev/loop0 <br />sync <br />gzip -9 image <br /></p><p style="font-size: 12pt;"><br /></p><p style="font-size: 12pt;"><br />4、制作软盘引导，并拷贝文件 bzimage image.gz 到软盘 <br /><br />A.使用grub <br />fdformat /dev/fd0 <br />mke2fs /dev/fd0 <br />mount /mnt/fd0 /mnt/floppy <br />mkdir -p /mnt/floppy/boot/grub <br />cp /boot/grub/stage1 /boot/grub/stage2 /mnt/floppy/boot/grub <br />执行 grub，在软盘上创建引导 <br />grub &gt; root (fd0) <br />grub &gt; setup (fd0) <br />grub &gt; quit <br /><br />cp /usr/src/linux/arch/i386/boot/bzImge /mnt/floppy <br />cp ~/porject/minilinux/image.gz /mnt/floppy <br /><br />编辑 /mnt/floppy/boot/grub/grub.conf <br />default =0 <br />timeout-=10 <br />title minilinux <br />root (fd0) <br />kernel /bzImage <br />initrd /image.gz <br /><br />卸下软盘 <br />umount /mnt/floppy <br /><br /><br />B. 使用syslinux <br />fdformat /dev/fd0 <br />mkfs.msdos /dev/fd0 <br />mount -t msdos /dev/fd0 /mnt/floppy <br /><br />cp /usr/src/linux/arch/i386/boot/bzImge /mnt/floppy <br />cp ~/porject/minilinux/image.gz /mnt/floppy <br /><br />cp syslinux-xx/ldlinxu.sys /mnt/floppy <br />cat &gt; /mnt/floppy/syslinux.cfg <br />LABEL linux <br />KERNEL bzimage <br />APPEND initrd=image.gz <br /><br />umont /mnt/floppy <br />syslinux-xx/syslinux /dev/fd0 <br />sync <br /><br />5、用软盘启动计算机，如果幸运，minicom的运行画面出现在屏幕上。 <br /><br />到此，我们的单应用嵌入式linux做好了，但它还很简陋，没有什么实际用途，但通过这个实验，可以了解嵌入式系统的大致结构和开发过程。在进行实际的嵌入 式开发时，通常要在PC机上借助嵌入式linux开发工具包，如：uclinux,bluecat等，对相应的硬件平台(目标机)进行软件编写编译，调试成功后，将内核及应用程序写入到目标机的存储器中，从而完成整个应用。</p></div><img src ="http://www.cppblog.com/finehai/aggbug/172592.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/finehai/" target="_blank">Bluesea</a> 2012-04-24 14:01 <a href="http://www.cppblog.com/finehai/archive/2012/04/24/172592.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[原]连接移动设备时蓝屏</title><link>http://www.cppblog.com/finehai/archive/2009/08/21/93992.html</link><dc:creator>Bluesea</dc:creator><author>Bluesea</author><pubDate>Fri, 21 Aug 2009 02:11:00 GMT</pubDate><guid>http://www.cppblog.com/finehai/archive/2009/08/21/93992.html</guid><wfw:comment>http://www.cppblog.com/finehai/comments/93992.html</wfw:comment><comments>http://www.cppblog.com/finehai/archive/2009/08/21/93992.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/finehai/comments/commentRss/93992.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/finehai/services/trackbacks/93992.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 曾经遇到在笔记本上连接移动设备，之后电脑一启动就出现蓝屏，可能会遇到如下的错误信息：<br><br><span style="COLOR: #0000ff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0x000000FC (ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY)<br></span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;经查找发现此问题是由于设备驱动(在此为ActiveSync)与数据执行保护 (DEP) 功能不兼容造成的，解决办法是关闭 DEP 功能，步骤如下：
<ol>
    <li>重新启动计算机。
    <li>在重新启动的过程中，按 F8。<br><br><strong>注意</strong>：在配置为启动多个操作系统的计算机上，请在显示&#8220;启动&#8221;菜单时按 F8。
    <li>使用箭头键选择一个安全模式选项，然后按 Enter。
    <li>单击&#8220;开始&#8221;，单击&#8220;运行&#8221;，键入 <span class=userInput>cmd</span>，然后单击&#8220;确定&#8221;。
    <li>在命令提示符下键入以下内容，然后按 Enter：
    <div class=indent jQuery1250819919734="46"><span class=userInput><br>bootcfg /raw &#8220;/noexecute=alwaysoff /fastdetect&#8221; /id 1</span></div>
    <strong>注意</strong>：如果有多个启动条目或启动选项，则可能必须手动修改计算机中的 Boot.ini 文件。为此，请按照下列步骤操作：
    <ol>
        <li type=a>单击&#8220;开始&#8221;，单击&#8220;运行&#8221;，键入 <span class=userInput>sysdm.cpl</span>，然后单击&#8220;确定&#8221;。
        <li type=a>在&#8220;高级&#8221;选项卡上，单击&#8220;启动和故障恢复&#8221;下的&#8220;设置&#8221;。
        <li type=a>在&#8220;启动和故障恢复&#8221;对话框中，单击&#8220;编辑&#8221;。
        <li type=a>将 <strong>/noexecute</strong> 选项改为以下内容：
        <div class=indent jQuery1250819919734="47"><span class=userInput>/noexecute=alwaysoff</span></div>
        <li type=a>在&#8220;文件&#8221;菜单上，单击&#8220;保存&#8221;，然后单击&#8220;退出&#8221;。
        <li type=a>单击&#8220;确定&#8221;两次。 </li>
    </ol>
    <li>重新启动计算机。 </li>
</ol>
<p>参考资料：<a href="http://support.microsoft.com/kb/886348/zh-cn">http://support.microsoft.com/kb/886348/zh-cn</a></p>
<img src ="http://www.cppblog.com/finehai/aggbug/93992.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/finehai/" target="_blank">Bluesea</a> 2009-08-21 10:11 <a href="http://www.cppblog.com/finehai/archive/2009/08/21/93992.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++ Builder 访问USB 口的方法 </title><link>http://www.cppblog.com/finehai/archive/2009/08/07/92558.html</link><dc:creator>Bluesea</dc:creator><author>Bluesea</author><pubDate>Fri, 07 Aug 2009 09:43:00 GMT</pubDate><guid>http://www.cppblog.com/finehai/archive/2009/08/07/92558.html</guid><wfw:comment>http://www.cppblog.com/finehai/comments/92558.html</wfw:comment><comments>http://www.cppblog.com/finehai/archive/2009/08/07/92558.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/finehai/comments/commentRss/92558.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/finehai/services/trackbacks/92558.html</trackback:ping><description><![CDATA[<p>下面是访问 USB 口必备的函数:&nbsp;&nbsp;<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">vcl.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">dir.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">setupapi.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">C:/WINDDK/3790/inc/ddk/w2k/usbdi.h</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">C:/WINDDK/3790/inc/ddk/w2k/devioctl.h</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">initguid.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">---------------------------------------------------------------------------<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;下面必须为驱动程序的&nbsp;GUID&nbsp;值,&nbsp;这里我乱写的数</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">DEFINE_GUID(USB_DRIVER_GUID,&nbsp;</span><span style="COLOR: #000000">0x12345678</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">0xabcd</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">0x1122</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">0x33</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">0x44</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">0x55</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">0x66</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">0x77</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">0x88</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">0x99</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">0x00</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">---------------------------------------------------------------------------</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">HANDLE&nbsp;OpenOneDevice(HDEVINFO&nbsp;hDvcInfo,&nbsp;PSP_INTERFACE_DEVICE_DATA&nbsp;DvcInfoData,&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">sDevNameBuf)<br><img id=Codehighlighter1_553_1265_Open_Image onclick="this.style.display='none'; Codehighlighter1_553_1265_Open_Text.style.display='none'; Codehighlighter1_553_1265_Closed_Image.style.display='inline'; Codehighlighter1_553_1265_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_553_1265_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_553_1265_Closed_Text.style.display='none'; Codehighlighter1_553_1265_Open_Image.style.display='inline'; Codehighlighter1_553_1265_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_553_1265_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_553_1265_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;HANDLE&nbsp;hOut&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;INVALID_HANDLE_VALUE;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;ULONG&nbsp;&nbsp;iReqLen&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;SetupDiGetInterfaceDeviceDetail(hDvcInfo,&nbsp;DvcInfoData,&nbsp;NULL,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">iReqLen,&nbsp;NULL);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;ULONG&nbsp;iDevDataLen&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;iReqLen;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">sizeof(SP_FNCLASS_DEVICE_DATA)&nbsp;+&nbsp;512;</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;PSP_INTERFACE_DEVICE_DETAIL_DATA&nbsp;pDevData&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;(PSP_INTERFACE_DEVICE_DETAIL_DATA)malloc(iDevDataLen);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;pDevData</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">cbSize&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(SP_INTERFACE_DEVICE_DETAIL_DATA);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(SetupDiGetInterfaceDeviceDetail(hDvcInfo,&nbsp;DvcInfoData,&nbsp;pDevData,&nbsp;iDevDataLen,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">iReqLen,&nbsp;NULL))<br><img id=Codehighlighter1_1038_1229_Open_Image onclick="this.style.display='none'; Codehighlighter1_1038_1229_Open_Text.style.display='none'; Codehighlighter1_1038_1229_Closed_Image.style.display='inline'; Codehighlighter1_1038_1229_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_1038_1229_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1038_1229_Closed_Text.style.display='none'; Codehighlighter1_1038_1229_Open_Image.style.display='inline'; Codehighlighter1_1038_1229_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_1038_1229_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_1038_1229_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strcpy(sDevNameBuf,&nbsp;pDevData</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">DevicePath);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hOut&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;CreateFile(pDevData</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">DevicePath,&nbsp;GENERIC_READ</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">GENERIC_WRITE,&nbsp;FILE_SHARE_READ</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">FILE_SHARE_WRITE,&nbsp;NULL,&nbsp;OPEN_EXISTING,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;NULL);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;free(pDevData);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;hOut;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">---------------------------------------------------------------------------</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">HANDLE&nbsp;OpenUsbDevice(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;GUID&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">pGuid,&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">sDevNameBuf)<br><img id=Codehighlighter1_1404_2123_Open_Image onclick="this.style.display='none'; Codehighlighter1_1404_2123_Open_Text.style.display='none'; Codehighlighter1_1404_2123_Closed_Image.style.display='inline'; Codehighlighter1_1404_2123_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_1404_2123_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1404_2123_Closed_Text.style.display='none'; Codehighlighter1_1404_2123_Open_Image.style.display='inline'; Codehighlighter1_1404_2123_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_1404_2123_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_1404_2123_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;HANDLE&nbsp;hOut&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;INVALID_HANDLE_VALUE;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;HDEVINFO&nbsp;hDevInfo&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;SetupDiGetClassDevs(pGuid,&nbsp;NULL,&nbsp;NULL,&nbsp;DIGCF_PRESENT</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">DIGCF_INTERFACEDEVICE);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;SP_INTERFACE_DEVICE_DATA&nbsp;deviceInfoData;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;deviceInfoData.cbSize&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">&nbsp;(SP_INTERFACE_DEVICE_DATA);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;ULONG&nbsp;nGuessCount&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;MAXLONG;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(ULONG&nbsp;iDevIndex</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;&nbsp;iDevIndex</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">nGuessCount;&nbsp;iDevIndex</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">)<br><img id=Codehighlighter1_1745_2064_Open_Image onclick="this.style.display='none'; Codehighlighter1_1745_2064_Open_Text.style.display='none'; Codehighlighter1_1745_2064_Closed_Image.style.display='inline'; Codehighlighter1_1745_2064_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_1745_2064_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1745_2064_Closed_Text.style.display='none'; Codehighlighter1_1745_2064_Open_Image.style.display='inline'; Codehighlighter1_1745_2064_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_1745_2064_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_1745_2064_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(SetupDiEnumDeviceInterfaces(hDevInfo,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;pGuid,&nbsp;iDevIndex,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">deviceInfoData))<br><img id=Codehighlighter1_1838_1960_Open_Image onclick="this.style.display='none'; Codehighlighter1_1838_1960_Open_Text.style.display='none'; Codehighlighter1_1838_1960_Closed_Image.style.display='inline'; Codehighlighter1_1838_1960_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_1838_1960_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1838_1960_Closed_Text.style.display='none'; Codehighlighter1_1838_1960_Open_Image.style.display='inline'; Codehighlighter1_1838_1960_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_1838_1960_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_1838_1960_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">((hOut</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">OpenOneDevice(hDevInfo,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">deviceInfoData,&nbsp;sDevNameBuf))&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;INVALID_HANDLE_VALUE)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">break</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(GetLastError()&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;ERROR_NO_MORE_ITEMS)&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">No&nbsp;more&nbsp;items</span><span style="COLOR: #008000"><br><img id=Codehighlighter1_2036_2059_Open_Image onclick="this.style.display='none'; Codehighlighter1_2036_2059_Open_Text.style.display='none'; Codehighlighter1_2036_2059_Closed_Image.style.display='inline'; Codehighlighter1_2036_2059_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_2036_2059_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_2036_2059_Closed_Text.style.display='none'; Codehighlighter1_2036_2059_Open_Image.style.display='inline'; Codehighlighter1_2036_2059_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_2036_2059_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_2036_2059_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">break</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;SetupDiDestroyDeviceInfoList(hDevInfo);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;hOut;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">---------------------------------------------------------------------------</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">bool</span><span style="COLOR: #000000">&nbsp;GetUsbDeviceFileName(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;GUID&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">pGuid,&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">sDevNameBuf)<br><img id=Codehighlighter1_2267_2423_Open_Image onclick="this.style.display='none'; Codehighlighter1_2267_2423_Open_Text.style.display='none'; Codehighlighter1_2267_2423_Closed_Image.style.display='inline'; Codehighlighter1_2267_2423_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_2267_2423_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_2267_2423_Closed_Text.style.display='none'; Codehighlighter1_2267_2423_Open_Image.style.display='inline'; Codehighlighter1_2267_2423_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_2267_2423_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_2267_2423_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;HANDLE&nbsp;hDev&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;OpenUsbDevice(pGuid,&nbsp;sDevNameBuf);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(hDev&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;INVALID_HANDLE_VALUE)<br><img id=Codehighlighter1_2358_2405_Open_Image onclick="this.style.display='none'; Codehighlighter1_2358_2405_Open_Text.style.display='none'; Codehighlighter1_2358_2405_Closed_Image.style.display='inline'; Codehighlighter1_2358_2405_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_2358_2405_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_2358_2405_Closed_Text.style.display='none'; Codehighlighter1_2358_2405_Open_Image.style.display='inline'; Codehighlighter1_2358_2405_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_2358_2405_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_2358_2405_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CloseHandle(hDev);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">false</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">---------------------------------------------------------------------------</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">HANDLE&nbsp;OpenMyDevice()<br><img id=Codehighlighter1_2525_2614_Open_Image onclick="this.style.display='none'; Codehighlighter1_2525_2614_Open_Text.style.display='none'; Codehighlighter1_2525_2614_Closed_Image.style.display='inline'; Codehighlighter1_2525_2614_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_2525_2614_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_2525_2614_Closed_Text.style.display='none'; Codehighlighter1_2525_2614_Open_Image.style.display='inline'; Codehighlighter1_2525_2614_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_2525_2614_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_2525_2614_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;DeviceName[MAXPATH]&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">""</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;OpenUsbDevice(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">USB_DRIVER_GUID,&nbsp;DeviceName);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">---------------------------------------------------------------------------</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">HANDLE&nbsp;OpenMyDevPipe(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">PipeName)<br><img id=Codehighlighter1_2737_3064_Open_Image onclick="this.style.display='none'; Codehighlighter1_2737_3064_Open_Text.style.display='none'; Codehighlighter1_2737_3064_Closed_Image.style.display='inline'; Codehighlighter1_2737_3064_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_2737_3064_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_2737_3064_Closed_Text.style.display='none'; Codehighlighter1_2737_3064_Open_Image.style.display='inline'; Codehighlighter1_2737_3064_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_2737_3064_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_2737_3064_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;DeviceName[MAXPATH]&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">""</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(GetUsbDeviceFileName(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">USB_DRIVER_GUID,&nbsp;DeviceName))<br><img id=Codehighlighter1_2832_3031_Open_Image onclick="this.style.display='none'; Codehighlighter1_2832_3031_Open_Text.style.display='none'; Codehighlighter1_2832_3031_Closed_Image.style.display='inline'; Codehighlighter1_2832_3031_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_2832_3031_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_2832_3031_Closed_Text.style.display='none'; Codehighlighter1_2832_3031_Open_Image.style.display='inline'; Codehighlighter1_2832_3031_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_2832_3031_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_2832_3031_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strcat(DeviceName,</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">\\</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strcat(DeviceName,PipeName);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;CreateFile(DeviceName,&nbsp;GENERIC_WRITE</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">GENERIC_READ,&nbsp;FILE_SHARE_WRITE</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">FILE_SHARE_READ,&nbsp;NULL,&nbsp;OPEN_EXISTING,&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,&nbsp;NULL);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;INVALID_HANDLE_VALUE;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">---------------------------------------------------------------------------&nbsp;</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>//有了上面的函数就可以访问&nbsp;USB&nbsp;口了:&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">打开&nbsp;USB&nbsp;口读写,&nbsp;由驱动程序的&nbsp;Pipe&nbsp;名确定&nbsp;</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>HANDLE&nbsp;hPipe&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;OpenMyDevPipe(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">MyPipe1</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">驱动程序里面的&nbsp;Pipe&nbsp;名,&nbsp;对应访问某个端点的&nbsp;I/O,&nbsp;这里我乱写的,&nbsp;需要与驱动一致</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(hPipe&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;INVALID_HANDLE_VALUE)&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">打开&nbsp;Pipe&nbsp;成功</span><span style="COLOR: #008000"><br><img id=Codehighlighter1_3340_3554_Open_Image onclick="this.style.display='none'; Codehighlighter1_3340_3554_Open_Text.style.display='none'; Codehighlighter1_3340_3554_Closed_Image.style.display='inline'; Codehighlighter1_3340_3554_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_3340_3554_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_3340_3554_Closed_Text.style.display='none'; Codehighlighter1_3340_3554_Open_Image.style.display='inline'; Codehighlighter1_3340_3554_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;</span><span id=Codehighlighter1_3340_3554_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_3340_3554_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;ReadFile(hPipe,&nbsp;Buffer,&nbsp;BufSize,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">nBytesRead,&nbsp;NULL);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">从&nbsp;hPipe&nbsp;里读取数据到&nbsp;Buffer&nbsp;里<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">WriteFile(hPipe,&nbsp;Buffer,&nbsp;BytesToWrite,&nbsp;&amp;nBytesWritten,&nbsp;NULL);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">把&nbsp;Buffer&nbsp;里面的&nbsp;BytesToWrite&nbsp;字节写入&nbsp;hPipe</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;CloseHandle(hPipe);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">使用&nbsp;DeviceIoControl&nbsp;访问&nbsp;USB&nbsp;设备</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>HANDLE&nbsp;hDevice&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;OpenMyDevice();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(hDevice&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;INVALID_HANDLE_VALUE)&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">打开设备成功</span><span style="COLOR: #008000"><br><img id=Codehighlighter1_3668_3864_Open_Image onclick="this.style.display='none'; Codehighlighter1_3668_3864_Open_Text.style.display='none'; Codehighlighter1_3668_3864_Closed_Image.style.display='inline'; Codehighlighter1_3668_3864_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_3668_3864_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_3668_3864_Closed_Text.style.display='none'; Codehighlighter1_3668_3864_Open_Image.style.display='inline'; Codehighlighter1_3668_3864_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;</span><span id=Codehighlighter1_3668_3864_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_3668_3864_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">这些&nbsp;DeviceIoControl&nbsp;功能都是由设备定义的,&nbsp;具体看设备和驱动的资料</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(DeviceIoControl(hDevice,&nbsp;IOCTL_READ_xxxx,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">IOBlock,&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(IOBLOCK),&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">c,&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">nBytes,&nbsp;NULL))<br><img id=Codehighlighter1_3820_3837_Open_Image onclick="this.style.display='none'; Codehighlighter1_3820_3837_Open_Text.style.display='none'; Codehighlighter1_3820_3837_Closed_Image.style.display='inline'; Codehighlighter1_3820_3837_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_3820_3837_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_3820_3837_Closed_Text.style.display='none'; Codehighlighter1_3820_3837_Open_Image.style.display='inline'; Codehighlighter1_3820_3837_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_3820_3837_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_3820_3837_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">成功</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;CloseHandle(hDevice);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000">&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p>&nbsp;</p>
<p>USB 设备、USB 驱动、USB 应用程序</p>
<p>1.USB 设备硬件部分<br>&nbsp; a.这个硬件的标识是用的 Vender ID 和 Product ID, 即&#8220;厂家标识&#8221;和&#8220;产品标识&#8221;<br>&nbsp; b.这个硬件规定了各个 End Point (端点) 的性质, 读/写 及 类型 (Control/Interrupt/Bulk/Isochronous)<br>&nbsp; c.这个硬件的固件里面有 DeviceIoControl 的实现部分, 规定了这个函数的具体参数和动作 <br>2.USB 设备驱动<br>&nbsp;①硬件接口<br>&nbsp; a.需要识别 Vender ID 和 Product ID<br>&nbsp; b.对每个 EndPoint 的每个 I/O 分配一个 Pipe, 并且起一个名字作为软件接口<br>&nbsp; c.做 DeviceIoControl 的接口<br>&nbsp;②软件接口<br>&nbsp; a.GUID, 驱动程序的标识, 每个驱动程序使用不同的 GUID, GUID 是识别驱动的, 与硬件无关 (驱动程序升级版本 GUID 不能修改)<br>&nbsp; b.硬件接口里面的 b: Pipe 名字是软件接口, 这个 Pipe 名字纯粹由驱动定义的, 和硬件无关, 升级驱动不能改 Pipe 的名字<br>&nbsp; c.硬件接口里面的 c 的各个参数也是软件的接口, 这些参数是由硬件带来的, 不是驱动规定的, 当然也可以在驱动里面转义, 隐藏设备的真实情况<br>&nbsp;③这个驱动程序是用 WinDDK 编译的, 可以用文本编辑器或其他开发工具的编辑器编程序代码, 然后调用 WinDDK 编译</p>
<p>3.读写 USB 口的程序<br>&nbsp;①与驱动的接口<br>&nbsp; a.利用驱动程序里面的 GUID 找出设备的文件名, 用 CreateFile 函数打开设备。我前面的程序里面的 OpenUsbDevice 就是这个作用<br>&nbsp; b.通过 a.得到的设备文件名和驱动程序里面的 Pipe 名打开 Pipe, 访问这个 Pipe 对应的 USB 端点 (读写数据)<br>&nbsp; c.使用 a.的 CreateFile 得到的句柄, 通过 DeviceIoControl 实现设备规定的动作<br>&nbsp;②有关需要的资料<br>&nbsp; a.Vender ID, Product ID 和 GUID 一般在驱动程序的 .inf 文件里面能看到, 如果找不到就需要和厂家联系<br>&nbsp; b.Pipe 的名字是驱动程序规定的, 需要有驱动程序的资料才能知道<br>&nbsp; c.DeviceIoControl 的参数需要有驱动程序的资料或者硬件资料才能知道<br>&nbsp;③这个程序一般用 C/C++ 直接编写, 如果使用其他语言(VB/PB等)需要调用 C/C++ 编的 DLL</p>
<p><br>其他相关内容:</p>
<p>USB 驱动程序可以到注册表里面找到： <br>"HKEY_LOCAL_MACHINE\\SYSTEM\\ControlSet001\\Enum\\USB\\Vid_厂家标识&amp;Pid_产品标识\\驱动程序"</p>
<p>里面的 ClassGUID 就是驱动程序的 GUID 标识, 例如 {36FC9E60-C465-11CF-8056-444553540000}<br>相当于程序的: DEFINE_GUID(USB_DRIVER_GUID, 0x36FC9E60,0xC465,0x11CF,0x80,0x56,0x44,0x45,0x53,0x54,0x00,0x00);<br>另外在这个注册表键里面还可找到有关设备的其他描述, 例如 DeviceDesc = "USB Mass Storage Device" 等</p>
<img src ="http://www.cppblog.com/finehai/aggbug/92558.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/finehai/" target="_blank">Bluesea</a> 2009-08-07 17:43 <a href="http://www.cppblog.com/finehai/archive/2009/08/07/92558.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[QT]Qt 嵌入式图形开发（入门篇）</title><link>http://www.cppblog.com/finehai/archive/2009/07/17/90334.html</link><dc:creator>Bluesea</dc:creator><author>Bluesea</author><pubDate>Fri, 17 Jul 2009 06:06:00 GMT</pubDate><guid>http://www.cppblog.com/finehai/archive/2009/07/17/90334.html</guid><wfw:comment>http://www.cppblog.com/finehai/comments/90334.html</wfw:comment><comments>http://www.cppblog.com/finehai/archive/2009/07/17/90334.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/finehai/comments/commentRss/90334.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/finehai/services/trackbacks/90334.html</trackback:ping><description><![CDATA[一、Qt/Embedded 开发环境的安装<br>一般来说，居于Qt/Embedded开发的应用程序最终会发布到安装有嵌入式Linux操作系统的小型设备上，所以使用装有Linux操作系统的PC机或者工作站来完成Qt/Embedded开发当然是最理想的环境，尽管Qt/Embedded也可以安装在Unix和Windows系统上。下面我们将介绍如何在一台装有Linux操作系统的机器上建立Qt/Embedded开发环境。首先，您需要拥有三个软件安装包：tmake工具安装包， Qt/Embedded 安装包，Qt的X11版的安装包。<br>由于上述这些软件安装包有许多不同的版本，您要注意由于版本的不同导致这些软件在使用时可能造成的冲突，为此我们将告诉您一些基本的安装原则：当您选择或下载了 Qt/Embedded 的某个版本的安装包之后，您下一步要选择安装的Qt for X11的安装包的版本必须比您最先下载的Qt/Embedded 的版本要旧，这是因为Qt for X11的安装包的两个工具uic和designer产生的源文件会和Qt/Embedded的库一起被编译链接，本着&#8220;向前兼容&#8221;的原则， Qt for X11的版本应比Qt/Embedded的版本旧。<br>我们将以下面所列版本的安装包，一步一步介绍Qt/Embedded开发环境建立的过程（这<br>些软件可以免费从trolltech的WEB或FTP服务器上下载）：<br>◆ tmake 1.11 或更高版本；（生成Qt/Embedded应用工程的Makefile文件）<br>◆ Qt/Embedded 2.3.7；（Qt/Embedded 安装包）<br>◆ Qt 2.3.2 for X11； （Qt的X11版的安装包, 它将产生x11开发环境所需要的两个工具）<br>1、安装tmake<br>在Linux 命令模式下运行以下命令：<br>tar xfz tmake-1.11.tar.gz<br>export TMAKEDIR=$PWD/tmake-1.11<br>export TMAKEPATH=$TMAKEDIR/lib/qws/linux-x86-g++<br>export PATH=$TMAKEDIR/bin:$PATH<br>2. 安装Qt/Embedded 2.3.7<br>在Linux 命令模式下运行以下命令：<br>tar xfz qt-embedded-2.3.7.tar.gz<br>cd qt-2.3.7<br>export QTDIR=$PWD<br>export QTEDIR=$QTDIR<br>export PATH=$QTDIR/bin:$PATH<br>export LD_LIBRARY_PATH=$QTDIR/lib:$LD_LIBRARY_PATH<br>./configure -qconfig -qvfb -depths 4,8,16,32<br>make sub-src<br>cd ..<br>上述命令 ./configure -qconfig -qvfb -depths 4,8,16,32 指定Qt 嵌入式开发包生成虚拟缓冲帧工具qvfb，并支持4，8，16，32 位的显示颜色深度。另外我们也可以在configure 的参数中添加－system－jpeg 和gif，使Qt/Embedded 平台能支持jpeg、gif格式的图形。上述命令 make sub-src 指定按精简方式编译开发包，也就是说有些Qt 类未被编译。Qt 嵌入式开发包有5 种编译范围的选项，使用这些选项，可控制Qt 生成的库文件的大小，但是您的应用所使用到的一些Qt 类将可能因此在Qt 的库中找不到链接。编译选项的具体用法可运行./configure －help 命令查看。<br>3. 安装Qt/X11 2.3.2<br>在Linux 命令模式下运行以下命令：<br>tar xfz qt-x11-2.3.2.tar.gz<br>cd qt-2.3.2<br>export QTDIR=$PWD<br>export PATH=$QTDIR/bin:$PATH<br>export LD_LIBRARY_PATH=$QTDIR/lib:$LD_LIBRARY_PATH<br>./configure -no-opengl<br>Make<br>make -C tools/qvfb<br>mv tools/qvfb/qvfb bin<br>cp bin/uic $QTEDIR/bin<br>cd ..<br>根据开发者本身的开发环境，也可以在configure 的参数中添加别的参数，比如-no-opengl 或-no-xfs，可以键入./configure -help 来获得一些帮助信息。
<p>二、认识Qt/Embedded 开发环境<br>Qt/Embedded 的开发环境可以取代那些我们熟知的UNIX 和WINDOWS 开发工具。它提供了几个跨平台的工具使得开发变得迅速和方便，尤其是它的图形设计器。Unix 下的开发者可以在PC 机或者工作站使用虚拟缓冲帧，从而可以仿真一个和嵌入式设备的显示终端大小，象素相同的显示环境。嵌入式设备的应用可以在安装了一个跨平台开发工具链的不同的平台上编译。最通常的做法是在一个UNIX系统上安装跨平台的带有libc库的GNU c++编译器和二进制工具。在开发的许多阶段，一个可替代的做法是使用Qt的桌面版本，例如Qt/X11或是Qt/Windows来进行开发。这样开发人员就可以使用他们熟悉的开发环境，例如微软的Visual C++ 或者 Borland C++；在UNIX操作系统下，许多环境也是可用的，例如Kdevelop，它也支持交互式开发。如果Qt/Embedded 的应用是在UNIX 平台下开发的话，那么它就可以在开发的机器上以一个独立的控制台或者虚拟缓冲帧的方式来运行，对于后者来说，其实是有一个X11的应用程序虚拟了一个缓冲帧。通过指定显示设备的宽度，高度和颜色深度，虚拟出来的缓冲帧将和物理的显示设备在每个像素上保持一致。这样每次调试应用时开发人员就不用总是刷新嵌入式设备的FLASH 存储空间，从而加速了应用的编译、链接和运行周期。运行Qt 的虚拟缓冲帧工具的方法是：在Linux 的图形模式下运行命令：<br>qvfb (回车)<br>当Qt 嵌入式的应用程序要把显示结果输出到虚拟缓冲帧时，我们在命令行运行这个程序时，在程序名后加上-qws 的选项。例如： $&gt; hello -qws</p>
<p>2．1 QT 的支撑工具<br>Qt 包含了许多支持嵌入式系统开发的工具，其中一些工具我们会在别的地方介绍。有两个最实用的工具（除了上面我们提到的虚拟缓冲帧）是 qmake 和Qt designer(图形设计器)。qmake 是一个为编译Qt/Embedded 库和应用而提供的Makefile 生成器。它能够根据一个工程文件（.pro）产生不同平台下的Makefile 文件。qmake 支持跨平台开发和影子生成（shadow builds），影子生成是指当工程的源代码共享给网络上的多台机器时，每台机器编译链接这个工程的代码将在不同的子路径下完成，这样就不会覆盖别人的编译链接生成的文件。qmake 还易于在不同的配置之间切换。开发者可以使用Qt 图形设计器可视化地设计对话框而不需编写一行代码。使用Qt图形设计器的布局管理可以生成具有平滑改变尺寸的对话框，qmake 和Qt 图形设计器是完全集成在一起的。</p>
<p>2．2 信号与插槽<br>信号与插槽机制提供了对象间的通信机制，它易于理解和使用，并完全被Qt 图形设计器所支持。图形用户接口的应用需要对用户的动作做出响应。例如，当用户点击了一个菜单项或是工具栏的按钮时，应用程序会执行某些代码。大部分情况下，我们希望不同类型的对象之间能够进行通信。程序员必须把事件和相关代码联系起来，这样才能对事件做出响应。以前的工具开发包使用的事件响应机制是易崩溃的，不够健壮的，同时也不是面向对象的。Trolltech 已经创立了一种新的机制，叫做&#8220;信号与插槽&#8221;。信号与插槽是一种强有力的对象间通信机制，它完全可以取代原始的回调和消息映射机制；信号与插槽是迅速的，类型安全的，健壮的，完全面向对象并用C++来实现的一种机制。<br>在以前，当我们使用回调函数机制来把某段响应代码和一个按钮的动作相关联时，我们通常把那段响应代码写成一个函数，然后把这个函数的地址指针传给按钮，当那个按钮被按下时，这个函数就会被执行。对于这种方式，以前的开发包不能够确保回调函数被执行时所传递进来的函数参数就是正确的类型，因此容易造成进程崩溃，另外一个问题是，回调这种方式紧紧的绑定了图形用户接口的功能元素，因而很难把开发进行独立的分类。Qt的信号与插槽机制是不同的。Qt的窗口在事件发生后会激发信号。例如一个按钮被点击时会激发一个&#8220;clicked&#8221;信号。程序员通过建立一个函数（称作一个插槽），对象1图一一些信号与插槽连接的抽象图然后调用connect()函数把这个插槽和一个信号连接起来，这样就完成了一个事件和响应代码的连接。信号与插槽机制并不要求类之间互相知道细节，这样就可以相对容易的开发出代码可高重用的类。信号与插槽机制是类型安全的，它以警告的方式报告类型错误，而不会使系统产生崩溃。<br>例如，如果一个退出按钮的clicked() 信号被连接到了一个应用的退出函数－<br>信号1<br>信号2<br>插槽1<br>插槽2<br>插槽1<br>插槽2<br>插槽3<br>插槽1<br>信号1<br>信号1<br>对象3<br>对象4<br>connect( 对象1, 信号1, 对象2, 插槽1 )<br>connect( 对象1, 信号1, 对象2, 插槽2 )<br>connect( 对象1, 信号2, 对象4, 插槽1 )<br>connect( 对象3, 信号1, 对象4, 插槽3 )<br>对象2<br>quit() 插槽。那么一个用户点击退出键将使应用程序终止运行。上述的连接过程用代码写出来就是这样connect( button, SIGNAL(clicked()), qApp, SLOT(quit()) );我们可以在Qt应用程序的执行过程中增加或是减少信号与插槽的连接。信号与插槽的实现扩展了C++的语法，同时也完全利用了C++面向对象的特征。信号与插槽可以被重载或者重新实现，它们可以定义为类的公有，私有或是保护成员。</p>
<p>2．2．1 信号与插槽的例子<br>如果一个类要使用信号与插槽机制，它就必须是从QObject或者QObject的子类继承，而且在类的定义中必须加上Q_OBJECT宏。信号被定义在类的信号部分，而插槽则定义在public slots, protected slots 或者 private slots 部分。<br>下面定义一个使用到信号与插槽机制的类。<br>class BankAccount : public QObject<br>{<br>Q_OBJECT<br>public:<br>BankAccount() { curBalance = 0; }<br>int balance() const { return curBalance; }<br>public slots:<br>void setBalance( int newBalance );<br>signals:<br>void balanceChanged( int newBalance );<br>private:<br>int curBalance;<br>};<br>和大部分的C++的类一样，BankAccount类有一个构造函数，还有一个取值的函数balance()，一个设置值的函数setBalance( int newBalance )。这个类有一个信号balanceChanged(),这个信号声明了它在BankAccount类的成员curBalance的值被改变时产生。信号不需要被实现，当信号被激发时，和该信号连接的插槽将被执行。上面用来设置值的函数setBalance( int newBalance )定义在类的&#8220;public slots&#8221;部分，因此它是一个插槽。插槽是一个需要实现的标准的成员函数，它可以像其它函数一样被调用，也可以和信号相连接。<br>下面就是该插槽函数setBalance( int newBalance )的实现代码：<br>void BankAccount::setBalance( int newBalance )<br>{<br>if ( newBalance != curBalance )<br>{<br>curBalance = newBalance;<br>emit balanceChanged( curBalance );<br>}<br>}<br>其中的一段代码<br>emit balanceChanged( curBalance );<br>它的作用是当curBalance 的值被改变后，将新的curBalance 的值作为参数去激活balanceChanged（）信号。对于关键词&#8220;emit&#8221;，它和信号、插槽一样是由Qt 提供的，这些关键词都会被c＋＋的预处理机制转换为c＋＋代码。一个对象的信号可以被多个不同的插槽连接，而多个信号也可以被连接到相同的插槽。当信号和插槽被连接起来时，应当确保它们的参数类型是相同的，如果插槽的参数个数小于和它连接在一起的信号的参数个数，那么从信号传递插槽的多余的参数将被忽略。</p>
<p>2．2．2 元对象编译器<br>信号与插槽机制是以纯C++代码来实现的，实现的过程使用到了Qt 开发工具包提供的预处理器和元对象编译器（moc）。moc 读取应用程序的头文件，并产生支持信号与插槽的必要的代码。开发者没必要编辑或是浏览这些自动产生的代码，当有需要时，qmake 生成的Makefile 文件里会显式的包含了运行moc 的规则。除了可以处理信号与插槽机制之外，moc 还支持翻译机制，属性系统和运行时的信息。</p>
<p>2．3 窗体<br>Qt 拥有丰富的满足不同需求的窗体（按钮，滚动条等等），Qt 的窗体使用起来很灵活，为了满足特别的要求，它很容易就可以被子类化。窗体是Qwidget类或它子类的实例，客户自己的窗体类需要从Qwidget它的子类继承。<br>图二 摘录的Qwidget 类的继承图<br>一个窗体可以包含任意数量的子窗体，子窗体可以显示在父窗体的客户区，一个没父窗体的窗体我们称之为顶级窗体（一个&#8220;窗口&#8221;），一个窗体通常有一个边框和标题栏作为装饰。Qt 并未对一个窗体有什么限制，任何类型的窗体可以是顶级窗体，任何类型的窗体可以是别的窗体的子窗体。在父窗体显示区域的子窗体的位置可以通过布局管理自动的进行设置，也可以人为的指定。当父窗体无效，隐藏或被删除后，它的子窗体都会进行同样的动作。标签，消息框，工具栏等等等，并未被限制使用什么颜色，字体和语言。Qt的文本呈现窗体可以使用HTML子集显示一个多语言的宽文本。</p>
<p>2．3．1 一个Hello 的例子<br>下面是一个显示&#8220;Hello Qt/Embedded!&#8221;的程序的完整的源代码：<br>图三 Hello Qt/Embedded<br>＃i nclude &lt;qapplication.h&gt;<br>＃i nclude &lt;qlabel.h&gt;<br>int main( int argc, char **argv )<br>{<br>QApplication app( argc, argv );<br>QLabel *hello = new QLabel( "&lt;font color=blue&gt;Hello"<br>" &lt;i&gt;Qt/Embedded!&lt;/i&gt;&lt;/font&gt;", 0 );<br>app.setMainWidget( hello );<br>hello-&gt;show();<br>return app.exec();<br>}</p>
<p>2．3．2 通用窗体<br>下面是一些主要的Qt 窗体的截屏图，这些窗体使用了窗口样式。<br>图四 使用了QHBox 进行排列一个标签和一个按钮<br>图五 使用了QbuttonGroup的两个单选框和两个复选框<br>图六 使用了QgroupBox进行排列的的日期类QDateTimeEdit, 一个行编辑框类QLineEdit, 一个文本编辑类QTextEdit 和一个组合框类QComboBox<br>图七 以QGrid排列的一个 QDial, 一个QProgressBar, 一个QSpinBox, 一个QScrollBar, 一个QLCDNumber和一个QSlider<br>图八 以QGrid排列的一个QIconView, 一个 QListView, 一个 QListBox 和一个 QTable有些时候在进行字符输入时，我们希望输入的字符满足了某种规则才能使输入被确认。Qt提供了解决的办法，例如QComboBox, QLineEdit 和 QspinBox 的字符输入可以通过Qvalidator的子类来进行约束和有效性检查。通过继承QScrollView ，QTable, QListView, QTextEdit 和其它窗体就能够显示大量的数据，并且自动的拥有了一个滚动条。许多Qt创建的窗体能够显示图像，例如按钮，标签，菜单项等等。Qimage类支持几种图形格式的输入、输出和操作，它目前支持的图形格式有BMP, GIF*, JPEG, MNG, PNG, PNM, XBM和 XPM。</p>
<p>2．3．3 画布<br>QCanvas 类提供了一个高级的平面图形编程接口，它可以处理大量的像线条、矩形、椭圆、文本、位图、动画等这些画布项，画布项可以较容易的做成交互式的（例如做成支持用户移动的）。画布项是QcanvasItem子类的实例，它们比窗体类Qwidget更显得轻量级，它们能够被快速的移动，隐藏和显示。 Qcanvas可以更有效的支持冲突检测，它能够列出一个指定区域里面的所有的画布项。QcanvasItem可以被子类化，从而可以提供更多的客户画布项类型，或者扩展已有的画布项的功能。Qcanvas对象是由QcanvasView进行绘制的，QcanvasView对象可以以不同的译文、比例、旋转角度，剪切方式去显示同一个画布。Qcanvas 对象是理想的数据表现方式，它已经被消费者用于绘制地图和显示网络拓扑结构。它也可用于制作快节奏的且有大量角色的平面游戏。图九 在Qtopia 中用QCanvas 实现的小行星游戏</p>
<p>2．3．4 客户窗体<br>通过对Qwidget或者它的子类进行子类化，我们可以建立自己的客户窗体或者对话框。下面是一个完整的源代码例子，它示例了如何通过子类化窗体，绘制一个模拟的时钟。AnalogClock 窗体类是Qwidget的子类，它显示当前时间，并且可以自动地更新时间。<br>图十 模拟钟窗体<br>在 analogclock.h头文件中, AnalogClock 以这样地形式定义：:<br>＃i nclude &lt;qwidget.h&gt;<br>class AnalogClock : public QWidget<br>{<br>public:<br>AnalogClock( QWidget *parent = 0, const char *name = 0 );<br>protected:<br>virtual void timerEvent( QTimerEvent *event );<br>virtual void paintEvent( QPaintEvent *event );<br>};<br>AnalogClock 类继承了Qwidget, 它有一个典型的窗体类构造函数，这个函数有父窗口对象指针和名字指针两个参数。(如果设置了名字的话，测试和调试起来就会容易些) timerEvent() 函数是从QObject （Qwidget的父类）对象继承而来的，这个函数会被系统定期调用。paintEvent() 函数是从QWidget 继承而来的并且当窗体需要重画时这个函数就会被调用。timerEvent() 和 paintEvent() 函数是&#8220;事件句柄&#8221;的两个例子。应用对象以重载父类对象的虚拟函数events (QEvent objects) 的形式接收系统的事件。大约有超过50个的系统事件是较常用的，例如 MouseButtonPress, MouseButtonRelease, KeyPress, KeyRelease, Paint, Resize 和Close. 对象可以对发给它们的事件做出响应或者筛选一些事件后再发送给别的对象。analogclock.cpp 文件是定义在analogclock.h中的函数的实现源文件<br>＃i nclude &lt;qdatetime.h&gt;<br>＃i nclude &lt;qpainter.h&gt;<br>＃i nclude "analogclock.h"<br>AnalogClock::AnalogClock( QWidget *parent, const char *name )<br>: QWidget( parent, name )<br>{<br>startTimer( 12000 );<br>resize( 100, 100 );<br>}<br>void AnalogClock::timerEvent( QTimerEvent * )<br>{<br>update();<br>}<br>void AnalogClock::paintEvent( QPaintEvent * )<br>{<br>QCOORD hourHand[8] = { 2, 0, 0, 2, -2, 0, 0, -25 };<br>QCOORD minuteHand[8] = { 1, 0, 0, 1, -1, 0, 0, -40 };<br>QTime time = QTime::currentTime();<br>QPainter painter( this );<br>painter.setWindow( -50, -50, 100, 100 );<br>painter.setBrush( black );<br>for ( int i = 0; i &lt; 12; i++ )<br>{<br>painter.drawLine( 44, 0, 46, 0 );<br>painter.rotate( 30 );<br>}<br>painter.save();<br>painter.rotate( 30 * (time.hour() % 12) + time.minute() / 2 );<br>painter.drawConvexPolygon( QPointArray(4, hourHand) );<br>painter.restore();<br>painter.save();<br>painter.rotate( 6 * time.minute() );<br>painter.drawConvexPolygon( QPointArray(4, minuteHand) );<br>painter.restore();<br>}<br>构造函数设置窗口的尺寸大小为100 x 100，并且告诉系统每隔12秒调用一次timerEvent()函数，从而对模拟钟的窗体进行刷新。在 timerEvent()函数中, 通过调用QWidget的函数 update()就可以告诉Qt，窗体需要立即重画，紧接着Qt就会产生一个绘制事件并且调用paintEvent()函数。在paintEvent() 函数中，一个Qpainter对象用于在窗体上绘制12个刻度以及分针，时针。Qpainter类提供了一种统一的方式用于绘制窗体，位图，矢量图等，它提供了绘制点，线，椭圆，多边形，弧，贝塞尔曲线等功能，一个Qpainter的坐标系可以被转变，缩放，旋转，和剪切，这样对象就可以根据它在窗口或者窗体上的位置绘制出一个剪切的视图。剪切可以使窗体绘制时减少闪烁。使用QPainter 的子类QdirectPainter可以锁定和直接访问帧缓冲区域。<br>文件 analogclock.h 和 analogclock.cpp 完全的定义和实现了AnalogClock 客户窗体类，这个窗体是现在就可以使用的。<br>＃i nclude &lt;qapplication.h&gt;<br>＃i nclude "analogclock.h"<br>int main( int argc, char **argv )<br>{<br>QApplication app( argc, argv );<br>AnalogClock *clock = new AnalogClock;<br>app.setMainWidget( clock );<br>clock-&gt;show();<br>return app.exec();<br>}</p>
<p>2．3．5 主窗口<br>QMainWindow 类是为应用的主窗口提供一个摆放相关窗体的框架。一个主窗口包含了一组标准窗体的集合。主窗口的顶部包含一个菜单栏，它的下方放置着一个工具栏，工具栏可以移动到其它的停靠区域。主窗口允许停靠的位置有顶部，左边，右边和底部。工具栏可以被拖放到一个停靠的位置，从而形成一个浮动的工具面板。主窗口的下方，也就是在底部的停靠位置之下有一个状态栏。主窗口的中间区域可以包含其它的窗体。提示工具和&#8220;这是什么&#8221;帮助按钮以旁述的方式阐述了用户接口的使用方法。对于小屏幕的设备，使用Qt图形设计器定义的标准的Qwidget模板比使用主窗口类更好一些。典型的模板包含有菜单栏，工具栏，可能没有状态栏（在必要的情况下，可以用任务栏，标题栏来显示状态）</p>
<p>2．3．6 菜单<br>弹出式菜单QpopupMenu类以垂直列表的方式显示菜单项，它可以是单个的（例如上下文相关菜单），可以以菜单栏的方式出现，或者是别的弹出式菜单的子菜单出现。每个菜单项可以有一个图标，一个复选框和一个加速器（快捷键），菜单项通常对应一个动作（例如存盘），分隔器通常显示成一条竖线，它用于把一组相关联的动作菜单分立成组。<br>下面是一个建立包含有New，Open 和Exit 菜单项的文件菜单的例子。<br>QPopupMenu *fileMenu = new QPopupMenu( this );<br>fileMenu-&gt;insertItem( "&amp;New", this, SLOT(newFile()), CTRL+Key_N );<br>fileMenu-&gt;insertItem( "&amp;Open...", this, SLOT(open()), CTRL+Key_O );<br>fileMenu-&gt;insertSeparator();<br>fileMenu-&gt;insertItem( "E&amp;xit", qApp, SLOT(quit()), CTRL+Key_Q );<br>当一个菜单项被选中，和它相关的插槽将被执行。加速器(快捷键)很少在一个没有键盘输入的设备上使用，Qt/Embedded 的典型配置并未包含对加速器的支持。上面出现的代码 &#8220;&amp;New&#8221;意思是在桌面机器上以&#8220;New&#8221;的方式显示出来，但是在嵌入式设备上，它只会显示为&#8220;New&#8221;。 QmenuBar类实现了一个菜单栏，它会自动的设置几何尺寸并在它的父窗体的顶部显示出来，如果父窗体的宽度不够宽以致不能显示一个完整的菜单栏，那么菜单栏将会分为多行显示出来。Qt内置的布局管理能够自动的调整菜单栏。Qt的菜单系统是非常灵活的，菜单项可以被动态的使能，失效，添加或者删除。通过子类化QcustomMenuItem，我们可以建立客户化外观和功能的菜单项。</p>
<p>2．3．7 工具栏<br>QtoolButton 类实现了一个带有图标，3维边框和可选标签的工具栏按钮。切换工具栏按钮具有开、关的特征，其它的按钮则执行一个命令。不同的图标用来表示按钮的活动，无效、使能模式，或者是开或关的状态。如果你仅为按钮指定了一个图标，那么Qt会使用可视提示来表现按钮不同的状态，例如按钮失效时显示灰色。工具栏按钮通常以一排的形式显示在工具栏上，对于一个有几组工具栏的应用，用户可以随便的到处移动这些工具栏，工具栏差不多可以包含所有的窗体，例如 QComboBoxes 和 QspinBoxes。</p>
<p>2．3．8 旁述<br>现代的应用主要使用旁述的方式去解释用户接口的用法。Qt 提供了两种旁述的方式： &#8220;提示栏&#8221;和&#8220;这是什么&#8221;帮助按钮。 &#8220;提示栏&#8221;是小的，通常是黄色的矩形，当鼠标在窗体的一些位置游动时它就会自动出现。它主要用于解释工具栏按钮，特别是那些缺少文字标签说明的工具栏按钮的用途。下面就是如何设置一个&#8220;存盘&#8221;按钮的提示的代码。<br>QToolTip::add( saveButton, "Save" );<br>当提示字符出现之后，你还可以在状态栏显示更详细的文字说明。对于一些没有鼠标的设备（例如那些使用触点输入的设备），就不会有鼠标的光标在窗体上进行游动，这样就不能激活提示栏。对于这些设备也许就需要使用&#8220;这是什么&#8221;帮助按钮，或者使用一种姿态来表示输入设备正在进行游动，例如用按下或者握住的姿态来表示现在正在进行游动。 &#8220;这是什么&#8221;帮助按钮和提示栏有些相似，只不过前者是要用户点击它才会显示旁述。在小屏幕设备上，要想点击&#8220;这是什么&#8221;帮助按钮，具体的方法是，在靠近应用的X 窗口的关闭按钮&#8220;x&#8221;附近你会看到一个&#8220;？&#8221;符号的小按钮，这个按钮就是&#8220;这是什么&#8221;帮助按钮。一般来说，&#8220;这是什么&#8221;帮助按钮按下后要显示的提示信息应该比提示栏要多一些。下面是设置一个存盘按钮的&#8220;这是什么&#8221;文本提示信息的方法:<br>QWhatsThis::add( saveButton, "Saves the current file." );<br>QToolTip 和 QWhatsThis 类提供了虚拟函数以供开发者重新实现更多的特定的用途。Qtopia并未使用上述提及的两种帮助（旁述）机制。它在应用窗口的标题栏上放置一个&#8220;？&#8221;符号的按钮来代替上述的旁述机制，这个&#8220;？&#8221;按钮可以启动一个浏览器来显示和当前应用相关的HTML页面。Qtopia使用按下和握住的姿态来调用上下文菜单（右击）和属性对话框。</p>
<p>2．3．9 动作<br>应用程序通常提供给用户几种不同的方式去执行特别的动作。例如，大部分应用提供了一个&#8220;Save&#8221;动作给用于存盘的菜单(File|Save)以及工具栏（一个&#8220;软盘&#8221;图标的工具栏按钮）和快捷键(Ctrl+S)。Qaction类可以让上述过程变得简洁，它允许程序员在一个地方定义一个动作，然后把这个动作加入到菜单或者工具栏，这个过程与把菜单项加入到菜单的道理是一样的。<br>下面的代码实现了一个&#8220;Save&#8221;菜单项和一个&#8220;Save&#8221;工具按钮，旁述系统和快捷键可<br>以很容易的添加进去，但是我们没添加，因为它们很少在嵌入式设备上使用。<br>QAction *saveAct = new QAction( this );<br>saveAct-&gt;setText( "Save" );<br>saveAct-&gt;setIconSet( QPixmap("save.png") );<br>connect( saveAct, SIGNAL(activated()), this, SLOT(save()) );<br>saveAct-&gt;addTo( fileMenu );<br>saveAct-&gt;addTo( toolbar );<br>除了不用复制代码，使用Qaction 还可以确保菜单的状态与工具栏按钮的状态保持一致，必要的时候还可显示提示栏。使一个动作（Action）失效将导致和该动作相关联的菜单项以及工具按钮的失效。同样的，如果用户切换一个工具按钮的状态，那么相关的菜单项的也会跟着被选中或不选中。</p>
<p>2．4 对话框<br>使用Qt 图形设计器这个可视化设计工具用户可以建立自己的对话框。Qt 使用布局管理自动的设置窗体与别的窗体之间相对的尺寸和位置，这样可以确保对话框能够最好的利用屏幕上的可用空间。使用布局管理意味着按钮和标签可以根据要显示的文字自动的改变自身大小，而用户完全不用考虑文字是那一种语言。</p>
<p>2. 4. 1 布局<br>Qt 的布局管理用于组织管理一个父窗体区域内的子窗体。它的特点是可以自动的设置子窗体的位置和大小，并可判断出一个顶级窗体的最小和缺省的尺寸，当窗体的字体或内容变化后，它可以重置一个窗体的布局。使用布局管理，开发者可以编写独立于屏幕大小和方向之外的程序，从而不需要浪费代码空间和重复编写代码。对于一些国际化的应用程序，使用布局管理，可以确保按钮和标签在不同的语言环境下有足够的空间显示文本，不会造成部分文字被剪掉。布局管理使得提供部分用户接口组件，例如输入法和任务栏变得更容易。我们可以通过一个例子说明这一点，当Qtopia的用户正在输入文字时，输入法会占用一定的文字空间，应用程序这时也会根据可用的屏幕尺寸的变化调整自己。<br>图十 Qtopia 的布局管理<br>Qt提供了三种用于布局管理的类：QHBoxLayout, QVBoxLayout 和 QgridLayout。<br>图十一 QHBoxLayout, QVBoxLayout 和 QGridLayout 的布局效果<br>QHBoxLayout 布局管理把窗体按照水平方向从左至右排成一行<br>QVBoxLayout 布局管理把窗体按照垂直方向从上至下排成一列<br>QGridLayout 布局管理以网格的方式来排列窗体，一个窗体可以占据多个网格。<br>在多数情况下，布局管理在管理窗体时执行最优化的尺寸，这样窗口看起来就更好看而且可以尺寸变化会更平滑。使用以下的机制可以简化窗口布局的过程：<br>1、 为一些子窗口设置一个最小的尺寸，一个最大的或者固定的尺寸。<br>2、 增加拉伸项（stretch items）或者间隔项 (spacer item)。拉伸项和间隔项可以填充一个排列的空间。<br>3、 改变子窗口的尺寸策略，程序员可以调整窗体尺寸改变时的一些策略。子窗体可以被设置为扩展，紧缩和保持相同尺寸等策略。<br>4、 改变子窗口的尺寸提示。QWidget::sizeHint() 和 QWidget::minimumSize-Hint() 函数返回一个窗体根据自身内容计算出的首选尺寸和首选最小尺寸,我们在建立窗体时可考虑重新实现这两个函数。<br>5、设置拉伸比例系数。设置拉伸比例系数是指允许开发者设置窗体之间占据空间大小的比例系数，例如我们设定可用空间的2/3 分配给窗体A，剩下的1/3 则分配给窗体B。布局管理也可按照从右至左，从下到上的方式来进行。当一些国际化的应用需要支持从右至左阅读习惯的语言文字（例如阿拉伯和希伯来）时，使用从右至左的布局排列是更方便的。布局是可以嵌套的和随意进行的。下面是一个对话框的例子，它以两种不同尺寸大小来显示：<br>图十二 小的对话框和大的对话框<br>这个对话框使用了三种排列方式。QVBoxLayout管理一组按钮，QHBoxLayout管理一个显示国家名称的列表框和右边那组按钮， QVBoxLayout管理窗体上剩下的组件&#8220;Now pleaseselect a country&#8221;标签。在&#8220;&lt; Prev&#8221;和&#8220;Help&#8221;按钮之间放置了一个拉伸项（stretch items），使得两者之间保持了一定比例的间隔。<br>建立这个对话框窗体和布局管理的实现代码如下：<br>QVBoxLayout *buttonBox = new QVBoxLayout( 6 );<br>buttonBox-&gt;addWidget( new QPushButton("Next &gt;", this) );<br>buttonBox-&gt;addWidget( new QPushButton("&lt; Prev", this) );<br>buttonBox-&gt;addStretch( 1 );<br>buttonBox-&gt;addWidget( new QPushButton("Help", this) );<br>QListBox *countryList = new QListBox( this );<br>countryList-&gt;insertItem( "Canada" );<br>/* &#8230; */<br>countryList-&gt;insertItem( "United States of America" );<br>QHBoxLayout *middleBox = new QHBoxLayout( 11 );<br>middleBox-&gt;addWidget( countryList );<br>middleBox-&gt;addLayout( buttonBox );<br>QVBoxLayout *topLevelBox = new QVBoxLayout( this, 6, 11 );<br>topLevelBox-&gt;addWidget( new QLabel("Now please select a country", this) );<br>topLevelBox-&gt;addLayout( middleBox );<br>使用Qt 图形设计器设计的这个对话框，显示如下<br>图十三 Qt 图形设计器中使用了布局的对话框</p>
<p>2. 4. 2 Qt 图形设计器<br>Qt 图形设计器是一个具有可视化用户接口的设计工具。Qt 的应用程序可以完全用源代码来编写，或者使用Qt 图形设计器来加速开发工作。启动Qt 图形设计器的方法是：<br>在Linux 命令模式下，键入以下命令(假设Qt X11 安装在/usr/local 下)：<br>cd qt-2.3.2/bin<br>./designer<br>这样就可以启动一个与Windows 下的Delphi 相类似界面。 下图是使用Qt 图形设计器设计一个表单的截屏图。<br>图十四 Qt 图形设计器<br>开发者点击工具栏上的代表不同功能的子窗体/组件的按钮，然后把它放到一个表单上面，这样就可以把一个子窗体/组件放到表单上了。开发者可以使用属性对话框来设置子窗体的属性。精确的设置子窗体的位置和尺寸大小是没必要的。开发者可以选择一组窗体，然后对他们进行排列。例如，我们选定了一些按钮窗体，然后使用&#8220;水平排列（lay out horizontally）&#8221;选项对它们进行一个接一个的水平排列。这样做使得设计工作变得更快，而且完成后的窗体将能够按照属性设置的比例填充窗口的可用尺寸范围。使用Qt 图形设计器进行图形用户接口的设计可以消除应用的编译，链接和运行时间，同时使得修改图形用户接口的设计变得更容易。Qt 图形设计器的预览功能可以使开发者能够在开发阶段看到各种样式的图形用户界面，包括客户样式的用户界面。通过Qt集成的功能强大的数据库类，Qt 图形设计器还可提供生动的数据库数据浏览和编辑操作。<br>开发者可以建立同时包含有对话框和主窗口的应用，其中主窗口可以放置菜单，工具栏，旁述帮助等等的子窗口部件。Qt 图形设计器提供了几种表单模板，如果窗体会被多个不同的应用反复使用，那么开发者也可建立自己的表单模板，以确保窗体的一致性。Qt 图形设计器使用向导来帮助人们更快更方便的建立包含有工具栏、菜单和数据库等方面的应用。程序员可以建立自己的客户窗体，并把它集成到Qt 图形设计器中。Qt 图形设计器设计的图形界面以扩展名&#8220;ui&#8221;的文件进行保存，这个文件有良好的可读性，这个文件可被uic（Qt 提供的用户接口编译工具）编译成为C＋＋的头文件和源文件。Qmake 工具在它为工程生成的Makefile 文件中自动的包含了uic 生成头文件和源文件的规则。另一种可选的做法是，在应用程序运行期间载入ui 文件，然后把它转变为具备原先全部功能的表单。这样开发者就可以在程序运行期间动态修改应用的界面，而不需重新编译应用，另一方面，也使得应用的文件尺寸减小了。</p>
<p>2. 4. 3 建立对话框<br>Qt 为许多通用的任务提供了现成的包含了实用的静态函数的对话框类，下边是一些Qt 的标准的对话框的截屏图。QmessageBox类是一个用于向用户提供信息或是给用户进行一些简单选择（例如 &#8220;yes&#8221;或&#8220;no&#8221;）的对话框类。<br>图十五 一个QMessageBox 对话框<br>progressDialog对话框包含了一个进度栏和一个&#8220;Cancel&#8221;按钮图十六 一个QprogressDialog 对话框Qwizard类提供了一个向导对话框的框架<br>图十七 一个向导类<br>Qt提供的对话框还包括QColorDialog, QFileDialog, QFontDialog 和QprintDialog。这些类通常适用于桌面应用，一般不会在Qt/Embedded中编译使用它们。</p>
<p>2．5 外形与感觉<br>Qt 桌面应用随着执行环境（例如Windows XP, Mac OS X, Linux）的不同而具有不同的样式，或者叫做外形与感觉。Qt/Embedded 的应用可以使用不同操作环境提供的样式，也可以以静态或插件的方式使用客户样式。开发者可以设计自己窗体的样式和窗口装饰。</p>
<p>2．5．1 窗体样式<br>一个样式是一个实现Qt窗体外形与视觉效果的类Qstyle的子类。Qt/Embedded 程序员可以自由的使用和修改目前存在的样式，也可以使用Qt样式设计引擎实现自己的样式。目前Qt/Embedded提供的样式类型有 EmbeddedareWindows, Motif, MotifPlus,CDE, Platinum 和 SGI。样式可以被动态的设置到一个应用中，甚至可以设置到特定的窗体上。<br>图十八 以不同样式建立的下拉框<br>通过给一组相关的应用编写一个客户样式，可以让这些应用的外观具有与众不同的感觉。建立客户样式可以通过子类化QStyle，QcommonStyle或者 QcommonStyle的派生类来实现。通过重新实现现有样式基类的一两个虚函数可以很容易对现有样式做一些小的修改。一个样式可以编译成为一个插件，在Qt 图形设计器中，把样式做成插件的话，开发者就可以以设备的客户样式来预览设计出来的表单。样式插件使得开发者不需重新编译就可改变设备的外观。<br>图十九 Qstyle 的继承图<br>Qt 发布的窗体都是样式已知的，当它们的样式改变后，窗体会自动重绘。客户窗体和对话框大多数都是Qt原先发布的窗体和布局的重新整合。它们也是自动的获得原先的样式。在少数场合，当有必要写一个外观上很随意的窗体时，开发者可以使用QStyle去写一些用户接口元素，而不是直接的绘制固有的矩形。</p>
<p>2．5．2 窗口装饰<br>顶级窗口的装饰是由一个标题栏和一个框架组成的。Qt/Embedded 包括了这些窗口样式：BeOS, Hydro, KDE 和 Windows。<br>图二十 不同的平台上的窗口风格<br>如果需要的话，我们可以配置不同的窗口使用不同的窗口装饰。通过子类化QWSDecoration,我们可以建立客户的装饰样式，并且把它们以插件的形式进行发布。为了在窗口管理器之外进行更多的控制行为，开发者需要子类化QWSManager。</p>
<p>2．6 国际化<br>Qt/Embedded 完全支持Unicode，一个国际标准的字符集。开发者在他们的应用中可以自由的混合使用被Unicode字符集支持的语言，例如阿拉伯文，英文，中文，希伯来文，日文和俄文等。为了有助于公司将产品推向国际市场，Qt还提供了将应用翻译成支持多种语言环境的工具。</p>
<p>2．6．1 Unicode<br>Qt 使用QString 存储Unicode 编码的字符串，Qstring 取代了粗糙的const char *；它提供了用于处理Qstring 和const char *之间相互转换的构造函数和操作符。因为Qt 使用了隐式共享(写时复制)技术来减少内存的使用,所以直接复制Qstring 的值是不会产生问题的。为有效率的存储ASII 码字符串，Qt 还提供了QCString 类。Qt 为所有要显示在屏幕上的文本，包括最简单的文字标签到最复杂的宽文本编辑器，提供了一个强大的Unicode 文本呈现引擎。这个引擎支持一些先进的特征，例如特殊的间隔线、双向写和区别标记。它几乎支持世界上所有的书写系统，包括阿拉伯文，中文，古斯拉夫文，英文，希腊文，希伯来文，日文，韩文，拉丁和越南文。体现这个引擎的最优化性能的常用的例子就是：在带有加速功能的文字的下方显示一条下划线（例如 File）。QtextCodec 的子类用于处理不同编码类型的字符集之间的转换。Qt 3.0 支持37 种不同的编码方式，包括中文的Big5 和GBK,日文的EUC-JP、JIS 和Shift-JIS，俄罗斯的KOI8-R和ISO 8859 系列。它们可以以库的一部分或者插件的形式编译，或者使用&#8220;feature&#8221;机制去除这些编译。</p>
<p>2．6．2 应用的翻译<br>Qt 提供了相应的工具和函数用于帮助开发者以他们的本地语言推出应用。要使一个字符串可以被翻译，你需要把这个字符串作为一个参数放到tr（）函数中调用。例如：<br>saveButton-&gt;setText( tr("Save") );<br>Qt 尝试寻找字符串"Save"的译文，如果找到的话，就会把它的译文显示出来，如果找不到，就用原来的字符串"Save"进行显示。例如我们把英文作为源语言，现在我们要把这个源语言翻译成中文，即中文为翻译的目标语言，以此类推。这样当我们调用tr（）函数后，函数的参数的原先的缺省编码就会转变为 Unicode 编码。Tr()函数的通常用法为：<br>Context::tr("source text", "comment")<br>上面的 &#8220;Context&#8221; 是指一个QObject 对象的子类的名称。如果在一个包含了tr（）成员函数的类的上下文环境中使用tr（）函数时，&#8220;Context&#8221;通常可以省略掉。例如：<br>Context：：func1（）<br>{<br>setText( tr("Save") );<br>}<br>&#8220;source text&#8221;是指要翻译的文本的内容 &#8220;comment&#8221;是一个可选项，它用于给手工翻译者提供一些额外的信息。说了半天，还有一个重要的内容我们没谈，就是tr（）函数如何寻找到译文。我们要把一个源字符串翻译为和它对应的译文（目标语言的字符串）时，我们需要让Qt 知道这些译文放在哪里。Qt 规定了译文存储在QTranslator 对象中，这个对象是从一个内存映射文件（扩展名为pm）中读取译文。每个pm 文件包含了某种语言的译文信息。所以开发者需要建立一个pm 文件来存储应用中需要翻译的字符串的译文。Qt 提供了3 种工具帮助人们建立译文存储文件（.pm 文件），这3 个工具是lupdate, QtLinguist 和 lrelease.<br>1、lupdate 自动地从源代码文件（.cpp）和界面接口文件（.ui）中获取所有需要翻译的对象，即上述的（&#8220;Context&#8221;）；同时还获取要翻译的所有的字符串（源语言的字符串），即上述的&#8220;source text&#8221;;&#8220;comment&#8221;选项如果被使用的话，也会被纳入收集的范围。当这些信息收集完毕后，lupdate 最后会生成一个.ts 文件（翻译源文件），这个文件是直接可阅读的。<br>2、开发者使用Qt Linguist 工具提供的良好的人机界面打开一个.ts 文件（翻译源文件），然后开发者根据每一个source text 填写上相对应的译文，这样一个.ts 文件（翻译源文件）就包含了完整的&#8220;Context&#8221;，&#8220;source text&#8221;和译文信息。<br>3、最后通过运行lrelease 去把一个.ts 文件（翻译源文件）压缩为一个.pm 文件（译文存储文件），生成的.pm 文件可用在嵌入式设备上。<br>在一个应用的生存期间里，上述的步骤有可能根据需要会被反复执行。多次运行lupdate 是很安全的，你可以重复使用已经存在的译文（.pm）文件，或者当你不想使用某些翻译文件时你可以标记这些翻译源文件为旧文件，而不需要删除它们。</p>
<img src ="http://www.cppblog.com/finehai/aggbug/90334.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/finehai/" target="_blank">Bluesea</a> 2009-07-17 14:06 <a href="http://www.cppblog.com/finehai/archive/2009/07/17/90334.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>