在 ce 自制平台中如何添加自己的驱动?cec 文件和 reg,bib 文件有
何区别?看混了,不知道如何才能让驱动注册到平台中。另外,reg
和 bib 是我在编写驱动必须要自己写的么?
CE 的驱动分为本机驱动和流驱动,本机驱动你可以修改源码
(在%_WINCEROOT%/PUBLIC/COMMON/OAK/DRIVERS),然后 build 驱动源
码,之后用 PB 编译内核。流驱动是以 DLL 的形式被系统程序加载的。加载流
驱动要在注册表中添加信息,这和 cec 文件没关。如果你想把此驱动 DLL 和注
册信息作为一个整体给别人使用,那么就要做一个 cec 文件,PB 能够读取 cec
文件内容并加载到内核工程中。cec文件相当于安装程序。
我安装的是 evc4.0,我开发的系统要显示中文比如姓名什么的。在编
辑的时候是中文显示,但是到了输出时,显示的都是乱码。不知道应
该怎么去解决?
EVC的模拟器不支持中文。所以显示出来的都是乱码。1、你可以只显示英
文,调试结束后再改界面为中文。2、安装PB,PB的模拟器支持中文。
CStatic 及其控件的文字无法垂直居中显示,虽然在 evc 的资源编辑
器中可设置,但是一旦运行,却无法垂直居中显示?
这种情况正常,而且除此之外还不能右对齐。
获取设备 ID 的种类有哪些?
除了手机模块外,还有CF卡有序列号、硬盘有ID号、网卡有 MAC号等。
这几种方法属获取手机模块ID最简单。
在应用程序中,如何修改本机的 ip 地址等网络参数,并使之立即生
效?
网络设置保存在注册表中,位置[HKEY_LOCAL_MACHINE/Comm/网卡名称/Parms/TcpIp],例如常见的CS8900网卡设置:
[HKEY_LOCAL_MACHINE/Comm/CS89001/Parms/TcpIp]
"EnableDHCP"=dword:0
"DefaultGateway"="192.168.0.1"
"DNS"="111.111.111.111"
"UseZeroBroadcast"=dword:0
"IpAddress"="192.168.0.2"
"Subnetmask"="255.255.255.0"
设 置 之 后 要 生 效 有 两 种 办 法 : 一 种 是 热 启 动 , 调 用
KernelIoControl(IOCTL_HAL_REBOOT, NULL, 0, NULL, 0, NULL),热启动时间
很短暂;另外一种调用 DevieceIoControl API ,传递 IOCTL =
IOCTL_NDIS_REBIND_ADAPTER。
如何向控制面板中那样,修改系统声音的音量?
调用 API waveOutSetVolume(HWAVEOUT, dwVolume),一般参数1 为0。在
[HKEY_CURRENT_USER/ControlPanel/Volume]下是系统声音的注册表设置。
在应用程序中如何实现 jpg、gif 图片的显示?
有几种办法:
1、在 MSDN 中搜索标题为―Windows CE.NET Technical Frequently Asked
Questions‖的文档,其中有一个问题―How can I display JPEG, GIF, and other
graphics files?‖,下面就是答案。
2 、 如 果 安 装 了 Windows CE 5.0 , 一 个 例 子 源 码 位 于
WINCE500/PUBLIC/GDIEX/SDK/SAMPLES/SIMPLE。
3、用IWebBrowser 组件实现。
在应用程序中如何实现系统待机?
void GwesPowerOffSystem(void);
在 WINCE 下如何实现键盘钩子?
我写了一个简单的例子,把其中主要部分截取出来放到了我的FTP里。用户名以及密码均为winceuser,地址是ftp://211.95.73.26/[email protected]/SourceCode/
用钩子禁止系统键.rar。 (该地址的用户名或者密码已经不好用了! )
在 WINCE 中如何得到网卡 MAC 地址?
事实证明, 获得物理网卡的MAC地址并没有被统一成一个API或者IOCTL,
如果网卡驱动程序没有提供接口的话只能直接访问寄存器获得。读者可以参考目
录WINCE500/PUBLIC/COMMON/OAK/DRIVERS/NETCARD里的一些驱动源码。
Windows XP Embedded 和 Windows CE 有何区别?
简单地说 Windows XP Embedded采用 Windows XP内核,只能运行在 x86处
理器上,优点是能够运行PC上现有的应用软件,缺点是授权费太高,标价¥900
元;Windows CE采用 Windows CE内核,能够运行在多种处理器上,如x86、
ARM、SHX、MIPS 等,优点是授权费低,最低 Core 版标价¥30 元。缺点是需
要单独开发应用软件、定制内核,甚至开发BSP、Driver。
wince 下只是把调制解调器的驱动挂接在了 com1,如何将其驱动挂
接在 com2 上?
1、在HLM/drivers/buildin/com2/unimodem下复制和com1一样的数据。
2、在 HLM/ExtModems/HayesCompat 下改写 Port 为 COM2:,再改写
FriendlyName为"Hayes Compatible 在 COM2:"。
如何定制自己的外壳?
1、先开发一个外壳软件,假设名称为MyShell.exe。
2 、 删 除 注 册 表 [HKEY_LOCAL_MACHINE/init] 下 如 下 一 行 :
"Launch50"="explorer.exe"
3、在注册表[HKEY_LOCAL_MACHINE/init]下添加如下一行:"Launch50"
="MyShell.exe"
上述的―LaunchXX‖中的XX为序列数,内核依据这个序列数按由小到大的顺
序来分别执行所有子键列出的应用程序,具体数值应该为多少请参考帮助文档的说明。
如果原来的内核中添加了标准外壳(standard shell)组件,或者添加了其它
组件而这些组件需要依赖标准外壳,那么在PB中是无法删除标准外壳组件的,
解决办法一是保留explorer.exe在内核中,二是删除依赖标准外壳的组件。
我原来的工程是 x86 版本的,编译选项只有 x86,我如何能够编译
ARM 版本的?
两种办法:
1、用EVC新建一个工程的时候,建议复选―CPUs‖列表,这样发生了这种事
情也能够轻易通过选择―WCE Configuration‖工具栏中的 CPU 列表来编译不同
CPU版本的软件。
2、如果打开工程后 CPU 列表中只有 x86,而此时已经安装了 ARM 版本的
SDK,那么单击 EVC 菜单―build‖-―configurations‖,然后单击―add‖按钮来添加
CPU。
通常情况下 WINCE 采用串口 1作为调试时输出信息用途,要正式出
产品前如何去掉串口 1 的调试功能?
正常情况下串口1只有在编译debug版本的内核时才在BootLoader中初始化
串口 1 用于输出信息,而编译 release 版本会跳过此代码。而有些 BSP 设计成没
有宏定义,也就是说无论什么版本都会在BootLoader中初始化串口1,这样造成
WINCE 启动后串口1无法被应用程序使用。对于这种情况只能在BootLoader 源
码中删除初始化代码,如OEMInitDebugSerial。
基于 wince 的应用程序能建成 console project 么?
不能。
ARM 系统外扩一片 512K RAM,驱动程序经过映射可以使用这一段
RAM。
1、应用系统如何使用这一段RAM?要加一层驱动吗?
2、如果要将这一段RAM当作RAM盘存储系统,该如何作呢?应该要加文件系统吧,如何加呢?
解答这个问题前,先要说一下WINCE 的地址映射机制。对于包含MMU(存
储器管理单元)的处理器来说,如 ARM 和 x86,WINCE 要求OEM在定制内核
的时候填写一个虚拟地址与物理地址映射关系的表,称为OEMAddressTable,在
这个表中定义了所有物理设备的起始物理地址,对应的起始虚拟地址,地址空间
大小,RAM 就包括在其中(如果是 x86 平台还要求 RAM 起始虚拟地址从
0x80000000 开始)。如果有多片 RAM,应该在 OEMAddressTable 中将它们定义
在一起,使之地址连续。对于非OEM的开发者来说,他们拿到的是定制好的内
核,不能做任何修改,如果在产品中外扩一片 RAM,只能通过 API函数通知操
作系统增加一条虚拟地址与物理地址映射关系表项。相关 API 函数有两个,分
别是 CreateStaticMapping 和 VirtualCopy。它们的相同之处是都用于建立物理地
址和虚拟地址的映射关系。它们的不同之处是 CreateStaticMapping 映射的虚拟地
址范围在 0xC4000000 到 0xE0000000 之间,这个范围只能由内核访问,一般用
于ISR访问,因为ISR只能访问静态映射的虚拟地址空间,不能用VirtualCopy。
VirtualCopy 通常和 VirtualAlloc 配合使用,映射的虚拟地址空间在 0x80000000
以下,一般用于驱动程序和应用程序访问。
1、应用程序要访问这片RAM,和驱动程序访问方法一样,调用VirtualAlloc
和VirtualCopy。
2、可以做一个流驱动程序专门用于读写这片RAM,这样所有应用程序就可
以通过调用流驱动接口函数来访问,非要加文件系统也是可行的,通过修改注册
表就可以做到,但是麻烦一些。
我怎么能在 PB左边的定制平台加进我的驱动呢?
两种办法:
1、在platform.bib或者project.bib的 MODULES部分添加一条语句,例如:
MyDriver.dll C:/Driver/MyDriver.dll NK SH。这样编译内核的时候就会把你
的驱动 DLL 文件添加到内核中,如果有注册表需要设置,在 platform.reg 或者
project.reg中添加注册表内容。
2、通过制作.cec文件来添加驱动,制作.cec文件的优点是只需制作一次,以后就可以通过将.cec 文件导入到 PB 的 Catalog 中,象 PB 自带的 feature 一样通
过菜单―Addto OS Design‖添加到左边的内核工程中。
WINCE 有没有相对路径概念?如果没有如何得到当前模块的路
径?
1、WINCE 没有相对路径概念,只有绝对路径,所以凡是涉及到路径均为绝
对路径。
2、调用API GetModuleFileName,传递一个模块的实例句柄就能够得到模块
的绝对路径。
怎样让 POCKET WORD 打开*.dat 格式(里面都是数据)的文件?
两种办法:
1、调用 API ShellExecuteEx,在结构体 SHELLEXECUTEINFO 中添加.dat
文件的路径。
2、调用 API CreateProcess,在第二个参数中设置.dat 文件的路径。
x86 Rom Boot Loader 真的可以实现吗?它确实能代替 BIOS 启动计
算机?
Rom Boot 被设计存放在Flash/EEPROM中,也就是原来BIOS的位置,这样
当上电后CPU到固定地址执行代码,也就是执行了Rom Boot 的代码,它对整个
硬件系统进行初始化和检测,并且支持通过网卡从远程机器上下载 nk.bin或者从
本地IDE/ATA 硬盘的活动分区中寻找 nk.bin文件加载。Rom Boot 的优点就是引
导并且加载速度快,而且它自身完成了所有的操作,这样就不用 BIOS、 MSDOS,
更不用Loadcepc了。
对于 x86 Rom Boot Loader,如何 Build 得到 Romboot.rom?
1、在PB中打开一个内核工程(x86的) ;
2、单击PB菜单―Build‖-―Open Build Release Directory‖;
3、用cd命令进入%_WINCEROOT%/Platform/Geode/Romboot;
4、build。 如何设置、更改显示分辨率?
能否设置、更改显示分辨率由显示驱动程序决定,而没有统一的标准。例如
CEPC,在启动的时候可以通过设置 loadcepc.exe的参数/L来决定 WINCE 启动后
的显示分辨率,这是由于显示驱动―VGA Linear Framebuffer‖支持,而Geode可
以通过在定制内核时修改注册表项来决定 WINCE 启动后的显示分辨率。
几个硬件使用同一个 IRQ,那么发生中断的时候系统怎么判断到底
是哪一个硬件发生的中断呢?ISR 里面又应该怎么控制呢?
Windows CE支持多个设备中断共享一个IRQ,当一个共享IRQ发生时,CE
内核的异常处理程序检测设备特定的寄存器,因为大多数设备都有一个单独的寄
存器用于表示设备的活动状态,所以通过遍历共享这个 IRQ 的所有设备的寄存
器就可以判断哪个设备发生中断。nk.exe加载一个giisr.dll,这个.dll是微软提供
的,它其实是第一个可安装 ISR。默认 CE 内核就是调用这个 dll 来检测寄存器
状态的,当然OEM可以编写自己的.dll。
CE内部有一个ISR链,也就是可安装ISR。因为CE允许OEM添加自己的
ISR处理程序,所以ISR被设计成一个链表。排在前面的ISR比后面的ISR优先
处理中断,如果当前ISR能够处理当前中断,那就返回中断ID由IST 处理或者
返回 SYSINTR_NOP,如果当前 ISR 不能够处理当前中断,那就返回
SYSINTR_CHAIN让下一个ISR处理。
请问在 wince 中如何在内核中增加一个与/windows 同级的目录?
在 platform.dat 或者 project.dat 中添加语句。例如要创建根目录下子目录
Program Files,语句如下:
root:-Directory("ProgramFiles")
文件格式如下所示,我想把每行的 4 个值读到 4 个变量中,用 EVC
如何编程?
第一行:460.000, 3384672.357342, 521268.972763
第二行:475.117, 3384663.772419, 521281.415271 伪代码如下:
FILE *stream;
Stream = _wfopen(L"//a.txt", L"r+");
if(stream==NULL)
return;
fseek(stream, 0L, SEEK_SET);
while(!feof(stream))
{
fwscanf(stream, L"%s", WCHAR1);
fwscanf(stream, L"%f", float1);
fwscanf(stream, L"%f", float2);
fwscanf(stream, L"%f", float3);
}
fclose(stream);
GWES 组件的功能有哪些?
GWES 不仅负责 GDI、窗口、消息,还负责管理本机设备驱动程序,负责
加载显示、键盘鼠标、触摸屏驱动程序,而且 GWES 本身包含电源、LED 驱动
程序。
如何在 PB 中预先设定好存储内存和程序内存的大小,我想多划分一
些空间给程序内存?
两种办法:
1、在定制内核时在 config.bib 文件中设置 FSRAMPERCENT=number,具体
number 可参考标题为―FSRAMPERCENT‖的帮助文档。这种办法是修改内核的设
置,所以一直有效。
2、在应用程序中调用 API SetSystemMemoryDivision,如果函数返回
SYSMEM_CHANGED表示成功,如果返回SYSMEM_MUSTREBOOT 表示需要
热启动才能有效。这种办法需要每次启动后调用 API才有效。
如何取消鼠标光标?
通过取消 SYS 变 量 来 实 现 此 目 的 , 在 PB 命 令 行 下 键 入 ―set
SYSGEN_CURSOR=‖,然后回车确认。 EVC 下调用 TextOut 如何编译会出错?
类似这样的问题很多,这是因为EVC的帮助文档内容有错误。可能EVC的
帮助文档内容是从桌面 Windows 帮助文档复制过来的,所以很多 API 函数还有
例子代码都有错误,例如帮助文档中包含一个 API 函数的说明,但是实际编译
的时候提示没有这个 API,有的例子代码采用 ANSI 字符串,而 WINCE 的 API
都是宽字符版本,造成直接复制过来编译失败。
因为MFC for WINCE 的 CDC类中没有TextOut 成员函数,所以编译会出错,
可以用其它类成员函数ExtTextOut 或者DrawText 替换。
我如何将我的 dll 软件让现有的 ce系统认可?
尽管我也知道应该使用 signfile.exe 程序进行签名,但是我并不知道那个 ce
系统认可的签名应该是啥。如果你说的WINCE 系统内核已经加入了签名认证机
制,那么没有私钥对你的 DLL 文件签名肯定是无法运行在此内核中的,一般签
名密钥的密钥长度都是1024位,很难破解。
如果查看 WINCE 注册表中的内容?
两种办法:
1、建立同步后,用EVC自带的工具―Remote Registry Editor‖打开查看。
2、从网上下载注册表查看工具,放到 WINCE 设备中。
调用 directshow出现链接错误,如何解决?
player.obj:error LNK2001: unresolved external symbol _IID_IvideoWindow
player.obj:error LNK2001: unresolved external symbol _IID_ImediaControl
这是因为链接器没有找到合适的.lib文件。两种办法:
1、在EVC菜单Tools—options—directories里把 library files的路径重新调整
一下。如果你只安装了 EVC 自带的 Standard SDK 而没有其它 SDK,可以指定
WINCE 目录中的 .lib 文件路径,例如
D:/WINCE500/PUBLIC/DIRECTX/OAK/LIB/X86/RETAIL。注意CPU的类型。
2、安装SDK,前提是导出SDK的PB内核工程必须包括DirectShow或者其它组件。
在 PB 的 config.bib 文件中,“IMGFLASH”表示什么意思呢?
表示能够刷NK到ROM中,具体请查看标题为―IMG Environment Variables‖
的帮助文档。
x86 平台如何映射各种地址空间?如何编写中断服务例程?
如果是 x86 平台,可以调用 HalTranslateBusAddress 转换物理总线地址到物
理系统地址,调用HalTranslateSystemAddress转换物理系统地址到逻辑总线地址,
也可以不调用这两个函数,因为 x86 平台除 32 位物理地址外还有 16 位的 IO 地
址空间,对于16位的IO地址空间,可以直接调用 WRITE_PORT_UCHAR或者
READ_PORT_UCHAR 等函数直接读写端口。对于 32 位物理地址可以调用
VirtualAlloc 和VirtualCopy来映射。这样做思路清晰,简单明了。
在x86平台要实现ISR,有如下几个步骤(以 Geode BSP为例):
1、用SETUP_INTERRUPT_MAP 宏关联SYSINTR和IRQ。以―SYSINTR_‖
为前缀的常量由内核使用,用于唯一标识发生中断的硬件,又称为中断 ID。在
Nkintr.h 文件中预定义了一些 SYSINTR,OEM 可以在 Oalintr.h 文件中自定义
SYSINTR。
2、用 HookInterrupt 函数关联硬件中断号和 ISR。这里提到的硬件中断号为
物理中断号,IRQ 为逻辑中断号。在 InitPICs 函数的最后调用了 HookInterrupt
函数,如下:
for(i=64;i<80;i++)
HookInterrupt(i, (void *)PeRPISR);///用ISR关联16个中断号
3、调用 InterruptInitialize 函数关联 SYSINTR 和 IST 创建的事件对象,也是
IST 等待的事件对象。详细内容请参考Geode BSP源码。
在x86平台要实现可安装ISR,先调用LoadIntChainHandler 函数注册在注册
表中指定的 ISR DLL,然后填充 GIISR_INFO 结构体并调用 KernelLibIoControl
函数将此结构体传递给可安装 ISR。详细内容请参考 WINCE 帮助文档或者我著
的《Windows CE下驱动开发基础》。 修改了 WINCE 自带的驱动程序后如何编译?如果是自己开发的驱
动程序如何编译?
1、分为IDE方式和命令行方式。
IDE 方式的编译很简单,以 PB5.0 为例,打开定制内核的工程,在左边的
―workspace‖—―FileView‖中找到你已经修改了的目录,然后单击右键弹出菜单,
在菜单中选择―Build and Sysgen Current Project‖,这样PB就会编译指定的目录中
的项目源码文件,然后执行 sysgen 命令根据 source 文件中的内容生成目标文件
并复制到当前内核工程目录下。
命令行方式的编译需要打开―Build OS‖—―Open Release Directory‖,以cd命
令进入你已经修改的驱动程序目录中,然后键入―build –cfs‖,然后键入―sysgen –p
项目名称‖,一般项目名称为source文件中的―TARGETNAME‖。
2、如果想完全自己开发驱动程序,建议直接采用EVC或者PB来编写编译。
开发PCI设备驱动时, InterruptInitialize函数的第一参数是否是PCI
卡 配 置 空 间 信 息 中 的 InterruptLine 参数?是否需要在
HKLM/Drivers/BuiltIn/PCI/Template 加一個自己的 subkey,并填写
相应内容?如何填?
1、InterruptInitialize 的第一参数是 IRQ,也就是逻辑中断号,而不是物理中
断号,InterruptLine是指物理中断号。
2、需要在template下加自己的PCI设备的信息,例如:
[HKEY_LOCAL_MACHINE/Drivers/PCI/Template/Serial]
"Dll"="Com16550.Dll"
"Class"=dword:07
"SubClass"=dword:00
"ProgIF"=dword:02
"VendorID"=multi_sz:"0AF0","B320","B320"
"DeviceID"=multi_sz:"0020","0300","0302"
"Prefix"="COM"
而这些信息就来自于你执行pcienum.exe的结果。
编译器报错:error C2065: 'CFileFind' : undeclared identifier,如何
解决?
MFC for WINCE 版本没有 CFileFind 类,所以要查找文件只能调用 API FindFirstFile 和 FindNextFile。
如何设置 WINCE 系统字体、字号?如何设置自己开发的软件的字
体、字号?
1、系统字体通过注册表设置。如下:
[HKEY_LOCAL_MACHINE/System/GDI/SysFnt] ///系统字体
Wt=420
Ht=18
Nm=Arial
[HKEY_LOCAL_MACHINE/System/GWE/Menu/BarFnt] ///菜单栏字体
[HKEY_LOCAL_MACHINE/System/GWE/Menu/PopFnt] ///弹出窗口字体
[HKEY_LOCAL_MACHINE/System/GWE/Menu] ///菜单字体
HKEY_LOCAL_MACHINE/System/GWE/Button ///按钮字体
2 、 创 建 字 体 时 把 字 体 高 度 参 数 设 置 大 点 就 可 以 了 。 如
CFont::CreateFont(nHeight,...),也可以在 LOGFONT 结构中设置字体高度或者字
体种类。如果是控件,调用控件的SetFont 成员函数。如果是直接画,在OnPaint
响应函数中调用SelectObject 选字体到DC。
nk.bin和 nk.nb0 有什么区别?
这里提到的bin是一种二进制镜像格式,以片断(section)为单位组织数据,
每个片断都包括一个头,头里指定了起始地址,长度,校验值。Platform Builder
调用工具将 WINCE 内核所有文件以 bin 格式合并成一个文件,默认文件名为
nk.bin。BootLoader 又以同样的格式将 nk.bin 分解成多个文件放到 RAM 中。可
以在命令行中键入―viewbin nk.bin‖来查看 bin 文件中具体包括了哪些内容。键入
Cvrtbin命令转换.bin格式文件为.sre格式或者.abx格式。
nb0 格式是原始的二进制镜像,它不包括头,一般情况下将内核下载到设备
的 RAM中运行都采用 nb0 格式。要生成 nbx 格式的文件,需要在相关.bib文件
中确定如下值:ROMSTART、ROMWIDTH、ROMSIZE。 在不采用硬件计时器的情况下如何创建更精确的计时器?最精确周
期能否达到 1 毫秒?
对于精确值的要求不同,所采用的办法不同。以下阐述几种办法。
1、 在单线程中循环调用API Sleep函数, Sleep函数精确程度为如果Sleep(N),
那么实际睡眠时间在 N 到 N+1 毫秒之间。而且还要注意调用 Sleep 的线程优先
级的问题。如果任务过多并且此线程优先级低,那误差就更大些。
2、调用 API QueryPerformanceCounter 函数,举例如下:
LARGE_INTEGER liFrequency;
If (QueryPerformanceFrequency(&liFrequency)) //查询系统时钟的频
率,这里将返回 1000
{
liFrequency.QuadPart /= 1000;
LARGE_INTEGER liTimeOut;
if (QueryPerformanceCounter(&liTimeOut)) //得到截至到当前累计
发生的系统时钟中
断次数
{
liTimeOut.QuadPart += liFrequency.QuadPart; //计算下一秒到
来时总的中断
次数是多少
LARGE_INTEGER liCurrent;
Do
{
QueryPerformanceCounter(&liCurrent); //循环查询累计的
的中断次数
}while(liCurrent.QuadPart < liTimeOut.QuadPart);//到达下一秒
}
}
调用QueryPerformanceCounter 同调用Sleep在本质上都是一样的,都是在单
线程中无限循环等到周期一到执行任务,相比较 QueryPerformanceCounter 要比
Sleep更精确些,越精确就越要求线程的优先级,保障线程能够正常得到处理器。
3、以上办法难以保证周期精确到1毫秒并且 WINCE 系统稳定地运行,所以
要从中断入手。以 x86 平 台 为 例 , 先 在 Timer.c 中 将 默 认 的
SetTimer0(TIMER_COUNT)中的TIMER_COUNT /=2,SetTimer0函数负责设置
系统时钟的频率,默认1毫秒发生一次中断,如果除以2就是0.5毫秒发生一次
中断。然后在 fwpc.c 文件中修改 ISR 函数 PeRPISR,因为原来默认是 1 毫秒发生一次中断,在处理INTR_TIMER0时系统负责累计计数、管理线程的调度,返
回相应的 SYSINTR 值,而我们没有办法再添加代码返回自己定义的 SYSINTR
值,所以现在要修改原来的处理代码,例如设置一个BOOL型变量,TRUE就执
行原来默认的代码,而 FALSE 就返回我们自己定义的 SYSINTR 值,这样即不
影响原来的 ISR 处理,又加入了我们的中断响应代码。ISR 返回我们定义的
SYSINTR后 WINCE 内核激活相对应的EVENT事件,我们就可以在我们编写的
IST 里处理任务了。
flash 中存放了 BootLoader 和内核镜像,如何把剩余 flash 部分划分
为一个存储区域供应用程序读写?
以 WINCE 提供的驱动(FAT 文件系统和 MSFLASH 驱动)来举例说明。如
果采用默认common.reg中的注册表设置,那么MSFLASH驱动默认把整个 flash
作为存储区域来读写,这不符合问题的要求,所以必须告诉 MSFLASH 驱动程
序可供读写的区域的起始地址和长度。以下是一个注册表例子:
[HKEY_LOCAL_MACHINE/Drivers/BuiltIn/FASLD]
"Dll"="fasld.dll" ///实际 Flash 存储器的驱动程序
"Order"=dword:2 ///该驱动程序相对于其它驱动程序的加载顺序
"Prefix"="DSK" ///前缀
"Ioctl"=dword:4 ///IOCTL码,设备管理器加载驱动的时候调用 IOControl
函数,传递这个 IOCTL 码。
"Profile"="MSFlash" ///Profile 名称,也就是
[HLM/System/StorageManager/Profiles/MSFlash]
///当设备管理器加载此驱动程序的同时发送通知给系统,IClass(GUID)的
值表明这是一个存储设备的驱动程序。
"IClass"="{A4E7EDDA-E575-4252-9D6B-4195D48BB865}"
"MemBase"=dword:00000000 ///Flash 中可供读写区域的起始物理地址,也
就是 Flash 的首地址+偏移量
"MemLen"=dword:00000000 ///Flash 中可供读写区域的长度
[HKEY_LOCAL_MACHINE/System/StorageManager/Profiles/MSFlash]
"DefaultFileSystem"="FATFS" ///MSFlash 驱动默认采用的文件系统
"PartitionDriver"="mspart.dll" ///采用的分区驱动程序
"MountAsRoot"=dword:1 //此目录作为文件系统的根目录
"Folder"="NOR Flash" ///目录名称
"Name"="FLASH Disk Block Device" ///Flash 驱动名称
"PartitionDriverName"="MSPART" ///分区驱动名称
"AutoMount"=dword:1 ///自动装载检测到的分区
"AutoPart"=dword:1 ///自动分区 "AutoFormat"=dword:1 ///自动格式化分区
[HKEY_LOCAL_MACHINE/System/StorageManager/AutoLoad/MSFlash]
"DriverPath"="Drivers//BuiltIn//FASLD" ///Flash 驱动在注册表中的位置
"LoadFlags"=dword:1 ///这个值可以被设置为 0、1、2。1表示同步加载,
其它表示异步加载
"Order"=dword:0
[HKEY_LOCAL_MACHINE/System/StorageManager/FATFS]
"FriendlyName"="FAT FileSystem" ///文件系统名称
"Dll"="fatfsd.dll" ///文件系统驱动程序
"Flags"=dword:00000064 ///标志,详见帮助文档
"Paging"=dword:1 ///是否分页
"EnableCache"=dword:1 ///是否允许缓存数据
"CacheSize"=dword:0 ///指定缓存大小,0表示默认
驱动程序如何发通知给应用程序?
这里介绍一下常见的两种办法。
1、驱动程序调用 API SendNotifyMessage,发送特定的消息给应用程序,这
就要求应用程序要有消息循环机制并且要事先做好消息的处理。参数 1为窗口句
柄,可以设置 HWND_BROADCAST 表示广播消息。要注意的是不要在参数中
传递指针(虚拟地址),因为执行驱动程序的线程和应用程序并不在同一个进程
空间中。解决办法可以利用内存映射文件技术,比如在驱动程序中创建一个内存
映射文件对象,申请一块物理内存,然后把对象名称和内存长度传递给应用程序,
应用程序打开同名的内存映射文件对象,读取里面的数据。对象名称可以事先协
定好,也可以通过注册表来传递,内存长度是 32 位值,通过消息参数就可以传
递,也可以通过注册表来传递。另外一种解决办法是在定制内核时候预留一块物
理内存,这样驱动程序和应用程序都可以通过VirtualAlloc 和VirtualCopy来映射
到同一块物理内存,其原理同内存映射文件技术一样,但是这块物理内存不具备
通用性。最后一个办法是应用程序事先将一个缓冲区地址传递给驱动程序,驱动
程序调用 MapPtrToProcess 映射应用程序传递过来的地址,当驱动程序调用
SendNotifyMessage后应用程序可以直接到该地址中读取数据。
设备管理器就是调用此函数广播 WM_DEVICECHANGE 消息的。另外
WINCE的一个例子程序RNAApp在拨号连接建立的时候也是调用这个函数广播
WM_NETCONNECT 消息的。
2、驱动程序调用 API CeEventHasOccurred指明一个事件 A发生,在此之前应用程序调用 API CeRunAppAtEvent 将驱动程序指明的 A事件和一个应用程序
名称相关联,或者和一个事件 B 相关联。这样当 A 事件发生时,如果指明和一
个应用程序名称关联,那这个应用程序就会被启动。如果指明了和一个事件 B
相关联,那么等待事件 B 的线程将被激活。如果想了解当前系统内部所有驱动
程序支持哪些类似事件 A的事件,调用 API CeNotifyPublic_FilterEvent,在该 API
的帮助文档里也列举了常见的事件,例如
NOTIFICATION_EVENT_NET_CONNECT 和
NOTIFICATION_EVENT_NET_DISCONNECT。
EVC 创建的工程名称如果用中文就出错,该怎么办?
用 EVC 创建的工程名称如果为中文将导致资源文件打不开和编译出错,可
以改资源文件名称为英文,再编辑.rc 文件中的资源文件名称。但建议尽量不要
用中文为工程名称。
作为习惯,应该在EVC创建一个工程后,立刻在―project‖—―settings‖中设置
资源的语言属性,然后在―resource view‖中设置每个资源的语言属性,这些工作
做完后再修改资源就没有问题了。有人询问对话框的标题为乱码,其原因就是在
没有修改语言属性的情况下设置标题为中文。
WinCE 下如何读写几百兆的大文件呢?使用内存映射文件吗?
一般嵌入式设备配备 128MB 物理内存就算顶级的了,所以要读写几百 MB
的文件用内存映射文件技术是最好的选择了。映射文件之后读数据是非常容易
的,要注意的是写数据,内存映射方面的 API 没有提供改变文件长度的功能,
所以要在关闭映射文件对象后用文件API改变文件长度。
请问如何改系统调度的默认时间片值?
更改schedule.c文件中的dwDefaultThreadQuantum变量,然后重新编译该文
件并SYSGEN。调用 API CeGetThreadQuantum就知道更改是否生效。 如何让系统加载自己写的驱动程序?
两种办法:
1、在[HKEY_LOCAL_MACHINE/Drivers/BuiltIn]下添加注册键。
2、在应用程序中调用 ActivateDeviceEx。
在一些文件中用分号来表示注释,例如下面的内容
; @CESYSGEN IF SERVERS_MODULES_HTTPD
; @CESYSGEN ENDIF
在―CESYSGEN...‖前加了―@‖,有没有什么特别的含义?
在 WINCE 的一些文件中,用―;‖作为注释并在注释文字中用@CESYSGEN作
为标记,后面接条件语句。Cefilter.exe工具负责按照条件来筛选文件内容,所以
不要轻易地删除包含@CESYSGEN的注释语句。
通过串口建立 ActiveSync 联接,串口线用三线的可以吗?
不可以,因为用串口同步时要用到其余口的状态。
WINCE 是否支持 MAPI?
不支持。WINCE 自带的pmail.exe软件也不是很好用。建议自己开发邮件收
发软件。如果需要购买 WINCE 下邮件收发软件可以联系我。
如何旋转屏幕显示的内容?
例子代码如下(前提是显示驱动程序支持旋转):
DEVMODE devmode = {0};
devmode.dmSize = sizeof(DEVMODE);
devmode.dmDisplayOrientation = DMDO_90; ///垂直模式
devmode.dmFields = DM_DISPLAYORIENTATION;
ChangeDisplaySettingsEx(NULL, &devmode, NULL, 0, NULL); ///改变显示
的设置
Crect rcWorkArea(0, 0, 320, 240); ///整个屏幕尺寸
///设置客户区大小并广播消息,这样所有软件也就随之更改显示
SystemParametersInfo(SPI_SETWORKAREA, 0, (void*)&rcWorkArea,
SPIF_SENDCHANGE); 请问如何修改字形缓存的容量?
[HKEY_LOCAL_MACHINE/System/GDI/GLYPHCACHE]
"limit"=dword:0400
如何得到从 WINCE 启动开始到现在的时间?
调用 API GetTickCount,得到的值为32位整数,单位为毫秒。
如何调用 WINCE 的软键盘?
调用 API SipShowIM(SIPF_ON),前提是内核加入了软键盘组件。
基于 HIVE 的注册表,如何在系统关闭前保存注册表的数据到文件
system.hv?
调用 API RegFlushKey函数。
使用 VirtualAlloc 和 VirtualCopy 的时候需要注意哪些事项?
1、VirtualAlloc 的作用是申请虚拟地址空间,这肯定不是最终的目的,最终
目的可能是申请物理内存、映射寄存器、提交文件等。没有一个目的会在意虚拟
地址空间的位置,所以尽量传递参数 1 为 0,也就是让 WINCE 自动分配虚拟地
址空间。VirtualAlloc 分配地址空间实际上是以 64KB 为单位,所以要指定申请
的虚拟空间的首地址的话,参数1应该为64KB的整数倍,申请的长度也应该为
64KB的整数倍,即使你不需要那么大。
2、VirtualCopy 的主要作用是映射物理地址空间,如果参数 2 为物理地址,
那么最后一个参数要添加 PAGE_PHYSICAL,参数 2 必须是 256 的整数倍。如
果参数 2 为虚拟地址(0x80000000 以上),那么最后一个参数就不要添加
PAGE_PHYSICAL,WINCE 内核会根据这个虚拟地址找到对应的物理地址。
驱动程序和应用程序之间传递数据时何时调用 MapPtrToProcess?
因为设备管理器负责加载驱动程序DLL,这意味着当应用程序调用驱动程序
接口函数的时候,WINCE 内核会将调用驱动程序接口函数的线程转移到设备管理器的进程空间然后执行具体的驱动程序代码,应用程序和设备管理器处于两个
进程空间,这就造成设备管理器无法访问应用程序传递的指针(虚拟地址),所
以当我们在应用程序中传递指针给流驱动程序接口函数时,WINCE 内核从中作
了一个地址映射,例如ReadFile、WriteFile、DeviceIoControl函数的参数凡是指
针都经过了映射才传递给驱动程序,所以很多驱动程序开发者并不了解其中的奥
秘就可以编程了。但是如果参数是一个指向一个结构体的指针,而结构体里包括
一个或多个指针,那么WINCE 内核并不负责映射,所以就需要开发者在驱动程
序接口函数中调用 API函数MapPtrToProcess 来映射地址。例如:pPointer_retval
= MapPtrToProcess(pPointer, GetCallerProcess());
如何判断可插拔的设备是否存在?
1、通过查找注册表的值。凡是由 API ActivateDeviceEx加载的驱动程序都在
[HKEY_LOCAL_MACHINE/Drivers/Active]键下有注册键,通过查找―name‖或者
其它键值就能够找到。设备管理器就调用这个API。如果是PCI 设备,在注册表
[HLM/Drivers/BuiltIn/PCI/Instance] 下 查 找 关 键 字 , 例 如
[HLM/Drivers/BuiltIn/PCI/Instance/WaveDev1],说明音频驱动已经加载。
2、调用驱动程序接口函数,根据返回值或者执行结果来判断。
如何做到通过串口过来的一个信号启动自己开发的应用程序?
创建一个线程负责等待串口过来的信号,调用 API SetCommMask 设置要等
待的信号种类,具体可以等待的信号种类参见参数 2 的说明。然后再调用 API
WaitCommEvent 函数等待这个信号,接收之后再调用 API CreateProcess 启动应
用程序。
在 WINCE 中如何只能启动应用程序的一个实例?
常用的两种办法:
1、如果应用程序实例创建了窗口,可通过API FindWindow函数通过窗口类
名和窗口标题名称来查找,前提是系统内不会出现窗口名称重复的情况。
2、应用程序初始化的时候创建一个事件或互斥等内核对象,因为内核对象是由内核创建,名称在系统内唯一。
能不能自己编辑一个数字签名文件导入到手机上,这样就可以用这个
签名签自己的程序了?
WINCE 的内核签名机制的用途是限制非法的可执行模块EXE、DLL等在设
备上运行。要求内核的加载模块用公钥验证请求加载的 EXE、DLL 的签名是否
合法,而这个公钥是在定制内核的时候加进去的,所以除内核的定制者以外的人
无法修改这个验证机制。
我按照版主的文章《加密 WINCE 系统》里操作,提示错误如下:
Error 80090016 during CryptSignHash 1!
Error signing hash
这是因为传递了无效的钥容器名称,使 CryptoAPI 调用失败。应该在使用
signfile 工 具 之 前 创 建 一 个 钥 容 器 , 在 桌 面 Windows 中 调 用 API
CryptAcquireContext 创建一个指定名称的钥容器,接着再创建一个签名密钥对,
这时再使用 signfile 工具就可以了。我在文章里写成-kfulinlin 是因为我创建钥容
器的时候没有指定名称,系统就采用当前登录的用户名为容器名。
编译错误:CVTRES : fatal error CVT1102: out of memory; 42 bytes
required?
多数情况下出现这种错误是因EVC的 bug而起,应该在安装EVC之后就立
刻安装EVC的SP补丁。另外为了避开 BUG,使用EVC编程应该养成一些习惯,
比如定期备份工程所有文件,每次编译时采用Clean + Rebuild All,正调试时不
要关闭模拟器等等。
在 WINCE 下是否能够得到某一进程使用的物理内存总量?
目前没发现有这样一个 API 能够得到指定进程使用的物理内存总量。只有
GlobalMemoryStatus能够得到整个系统使用的物理内存总量。 应用程序如何控制 lcd 的亮度?如何获得电池的电量?
从常见的平台如 Geode、三星 ARM 系列来看,的确在驱动方面没有统一的
控制 LCD 或者其它种类屏幕亮度的接口函数,所以只能根据具体平台提供的接
口来做。从帮助文档来看微软的带有 DirectDraw 功能的显示驱动程序的确有标
准的增加亮度的接口函数,关于背景光参见标题为―Enabling a Backlight‖的帮助
文档。
获得电池电量有标准的接口函数 GetSystemPowerStatusEx,前提是驱动程序
和硬件都要支持。
WINCE 的 socket 函数好像不支持发送/接收超时?
是的,最早版本的 WINCE 支持选项SO_RCVTIMEO、SO_SNDTIMEO,后
来却不支持了。
WINCE 下如何设置窗口最大化和最小化?
WINCE 的帮助文档在介绍 API ShowWindow 函数的参数时指出
SW_MAXIMIZE, SW_MINIMIZE, SW_RESTORE, SW_SHOWDEFAULT,
SW_SHOWMAXIMIZED, SW_SHOWMINIMIZED, SW_SHOWMINNOACTIVE
都不被支持,但实际上并不完全是这样,具体来说:
SW_MAXIMIZE 比原来窗口大,但不是最大化
SW_MINIMIZE 编译成功,但是不起作用
SW_SHOWMAXIMIZED 最大化
SW_SHOWMINIMIZED 编译出错
SW_RESTORE 能恢复
SW_SHOWDEFAULT 编译出错
SW_SHOWMINNOACTIVE 编译出错
SW_HIDE 能够隐藏
如何用程序调用控制面板的触摸屏校对程序?
两种办法: 1、调用 API TouchCalibrate函数
2、调用 CreateProcess,参数 1 为 L"//windows//ctlpnl.exe",参数 2 为
L"cplmain.cpl,9"。
如何获得 U盘或者其它类型的存储器总容量和剩余可用容量?
调用 API GetStoreInfo 得到扇区数、每扇区字节数,相乘即是总容量。调用
API GetDiskFreeSpaceEx得到剩余可用容量。
三星 2440 头文件定义#define IIC_BASE 0xB1400000 //54000000,
datasheet 是 54000000,那么怎么转成 0xB1400000?
物理地址映射方法分为两种,一种静态映射另一种为动态映射。在
OEMAddressTable 中定义了物理地址与虚拟地址的映射关系属于静态映射,用
VirtualCopy 映射属于动态映射,采用哪种办法都可以。问题中提到的属于静态
映射,2440 的 BSP 在 map.a 文件中定义了 IIC 控制寄存器的物理起始地址和对
应的虚拟地址如下:
DCD 0x91400000, 0x54000000, 1;
在OEMAddressTable中定义的虚拟地址范围在 0x8000 0000—0x9FFF FFFF,
这部分可缓存,适合内核程序和应用程序使用,同时 WINCE 内核在 0xA000
0000—0xBFFF FFFF中映射了另一份,指向了同样的物理地址,这部分不可缓存,
适合驱动程序使用。三星 ARM 处理器带有 L1 级高速缓存,可缓存会提高执行
效率。对于特殊的设备寄存器适合映射到不可缓存的虚拟地址。
当驱动程序调用 VirtualCopy 对 0xB1400000 地址读写时,WINCE 自动将这
个地址减去0x2000 0000,也就是0x91400000,对应的物理地址就是0x54000000,
也就是IIC控制寄存器的物理起始地址。
基于 RAM 的注册表如何保存数据?
调用 API RegCopyFile 备份注册表。调用 API RegRestoreFile恢复注册表,然
后调用 KernelIoControl热启动使恢复生效。 如何隐藏和显示 winCE 下标准外壳的任务栏?
HANDLE hTaskBar = FindWindow(L"HHTaskBar", NULL);
ShowWindow(hTaskBar, SW_HIDE);
ShowWindow(hTaskBar, SW_SHOWNORMAL);
如何能让 WINCE 的 IE 浏览器播放 flash动画?
播放 flash 需要 Macromedia Flash Player SDK ,参见
http://www.adobe.com/products/flashplayer_sdk/。这和 realplayer 相似,都需要
WINCE 平台的SDK,都需要申请。
WINCE 下内核模式和用户模式有什么区别?
为了使读者能够详细了解 WINCE 的地址映射原理还有两种模式,在这里我
分几个部分说明:
1、WINCE 内核 nk.exe 的任务是管理操作系统核心功能。按照
OEMAddressTable 的映射要求,所有物理地址都映射到 0x80000000 以上,所以
对于内核程序nk.exe和内核模式下的线程来说,只要访问0x80000000以上的有
效虚拟地址经MMU就能够访问物理地址,无需再映射是内核模式的一个特点。
内核模式的第二个特点是没有地址访问限制,内核模式线程可以访问任何有效虚
拟地址,所谓有效虚拟地址是指有实际事物对应。
2、用户模式线程只能访问 0x80000000 以下的虚拟地址空间,WINCE6.0 之
前版本的内核为每个进程划分32MB的地址空间,在不调用特殊函数的情况下不
能相互访问,这样的设计使得 WINCE 系统更安全、更稳定,限制访问地址是用
户模式的第一个特点。第二个特点就是需要多一层映射,如果线程要访问物理内
存的话需要先映射到0x80000000以上,再经 MMU访问物理内存地址。
WINCE 的线程具有转移性(参考 API GetCallerProcess的说明,有一个很好的例
子),当应用程序的线程调用API或者调用驱动程序接口函数时,该线程会转移
到 gwes.exe、device.exe、filesys.exe 等进程中执行,转移是由 WINCE 内核操作
的,它会修改线程的上下文,记录线程的当前进程、调用者进程、拥有者进程三
个值。 3、如果在定制内核的时候选择了―Full Kernel Mode‖,那么在这个内核上运
行的所有线程都处于内核模式,即使调用 SetKMode(FALSE)后线程仍然具有内
核模式的特点,能够访问任何有效的虚拟地址。假设现有一个 64MB RAM 的
WINCE 产品, RAM映射从0x80000000 到0x84000000,如果线程处于内核模式,
它就直接可以访问这个范围的虚拟地址:
在OnButton1()中编写
DWORD oldMode = SetKMode(FALSE);
Volatile int *piTemp = (volatile int*)(0x20000000+0x84000000-0x00019000);
///或者(0x84000000-0x00019000)
*piTemp = 12345;
在 OnButton2()中编写
DWORD oldMode = SetKMode(FALSE);
Volatile int *piTemp = (volatile int*)(0x20000000+0x84000000-0x00019000);
///或者(0x84000000-0x00019000)
Int iTemp = *piTemp;
先只执行 OnButton1()然后关闭程序,再重启程序然后执行 OnButton2(),
iTemp仍然等于12345。结果说明了两点:内核模式线程可以直接访问0x80000000
以上的有效虚拟地址;我们写到RAM中的数据没有丢失,说明虚拟地址有效。
如果在定制内核的时候没有选择―Full Kernel Mode‖,那么在这个内核上运行的所
有线程都处于用户模式。可以调用SetKMode(TRUE)使调用线程暂时处于内核模
式,还是原来的假设环境,我再举个例子:
在 OnButton1()中编写
DWORD oldMode = SetKMode(TRUE);
Volatile int *piTemp = (volatile int*)(0x20000000+0x84000000-0x00019000);
///或者(0x84000000-0x00019000)
*piTemp = 12345;
在用户模式下,如果不调用SetKMode(TRUE),那么执行*piTemp = 12345一
定会弹出对话框,提示地址访问非法,如果调用SetKMode(TRUE)就不会提示地
址访问非法,而且在OnButton2()中仍然能得到12345这个值。
通过这两个例子我相信读者能够完全了解两种模式的区别了。
4、 WINCE 提供了两个函数SetKMode和SetProcPermissions,其中SetKMode
能够把调用线程切换到内核模式,还可以切换回用户模式。SetProcPermissions +
GetCurrentPermissions 添加当前进程访问权限给调用线程,SetProcPermissions
(0xFFFFFFFF)能让调用线程访问所有进程空间,但是调用线程仍然处于用户模式。SetKMode和SetProcPermissions函数使得用户模式的特点不那么明晰。
如上所说一个应用程序的线程可能转移到其它两个进程地址空间中读写数
据,而每一个线程在被创建的时候只有访问创建它的进程地址空间的权限,所以
驱 动 程 序 开 发 者 必 须 在 驱 动 程 序 读 写 数 据 前 调 用 SetKMode 或者
SetProcPermissions 增加调用此函数的线程访问其它进程空间的权限。如果一个
应用程序的线程只转移到一个进程地址空间,一般为设备管理器进程 device.exe,
这种情况下不必增加线程访问其它进程空间的权限,但如果驱动程序本身创建了
一个线程,那还是要调用 SetKMode 或者 SetProcPermissions 增加新的线程访问
其它进程的权限的,因为驱动程序创建线程时,当前进程为设备管理器,所以新
线程只具有访问设备管理器进程空间的权限,而不具备访问应用程序进程空间的
权限。
5、可能一个编写过简单的流驱动的初学者会很疑惑,因为开发一个简单的
流驱动程序根本不需要调用这些函数,也没有调用过 MapPtrToProcess,那是因
为如果标准流驱动接口函数的参数为指针(ReadFile、WriteFile、DeviceIoControl
参数都有指针),WINCE 内核会自动映射指针包含的地址,但仅此而已,其余任
何情况都要求开发者自行处理,比如流接口函数的参数是一个指向结构体的指针
PA,而结构体中包括指针 PB,PB 指针就必须在流接口函数中映射,映射后才
能访问,否则就会造成地址访问非法。所以结构体中每个指针都要映射。
为了让读者能了解其中的原因,我举个例子:
假设设备管理器被加载到Slot4,应用程序 A被加载到Slot8,A只有一个主
线程T, T开始执行,按照 WINCE 的规定,正获得CPU的进程必须映射到Slot0,
那么在执行代码的时候 A 的所有虚拟地址都被减去一个偏移值,也就是
8×0x02000000,A调用DeviceIoControl,传递一个指向一个结构体的指针B,而
这个结构体中包含一个指针 C,指针 C 包含的地址假设为 0x00030000,当执行
DeviceIoControl 时 WINCE 把设备管理器的进程地址空间映射到 Slot0,因为放
在注册表[HKLM/Drivers/BuiltIn]下的驱动程序是由设备管理器加载的,自然驱动
程序的代码段被加载到设备管理器进程空间,但是线程仍然是 T,此时T的当前
所在进程为设备管理器(CurrentProcess),A 变成了 T 的调用者进程
(CallerProcess),T 自动具有了访问调用者进程空间的权限。这时访问 Slot0 中的虚拟地址其实质就是访问设备管理器的进程地址空间,要把地址加上一个偏移
值,也就是4×0x02000000,所以 DeviceIoControl访问指针 C包含的地址时本应
该加上8×0x02000000,却加上4×0x02000000,结果地址并不是设备管理器的合
法区域,系统就会提示地址访问非法。而如果做了一个映射,指针 C 包含的地
址就会被加一个正确的偏移值,使地址处于 A的地址空间Slot8中,T此时具有
访问 A进程空间的权限,访问到正确的虚拟地址当然会得到正确的数据了。
为什么WINCE目录下的例子用build+sysgen能够编译成EXE文件,
而我添加的例子就不能编译呢?
如果这个例子是一个应用程序,那么肯定包括代码文件(.h .c .cpp)和资源
文件(.rc 和其它资源文件),build 工具根据 source 文件内容把代码文件编译成
lib文件,资源文件编译成.res文件,sysgen工具根据 makefile 文件内容将 source
文件中列出的需要链接的各个库文件合并成一个 EXE 文件。所以说关键在于
makefile 文件,WINCE 目录下凡是能够用 build+sysgen 编译的都在 makefile 中
有如何链接的设置,而我们添加的例子当然没有在 makefile 中找到如何链接的设
置,nmake工具就会提示不知道如何创建。
pcienum.exe 干什么用的?
如果你要开发某一个PCI设备的驱动程序,首先要知道这个PCI设备的信息
(如VendorID、DeviceID、BaseClass、SubClass)和PCI总线的信息。运行这个
pcienum.exe 就能得到相关信息。 pcienum.exe 提供了源码,位置
/Public/Common/Oak/Drivers/Ceddk/Test/Pcienum。
wince 下如何让操作系统进入待机模式?又如何把它激活?
通过注册表就可以设置,前提是你的驱动和硬件都支持。注册表项参见标题
为―GWES Suspend Time-outs‖的帮助文档。
[HKEY_LOCAL_MACHINE/System/CurrentControlSet/Control/Power]
"BattPowerOff"=dword:300
"ExtPowerOff"=dword:0
"WakeupPowerOff"=dword:60
"ScreenPowerOff"=dword:0 现有一个 GPRS 模块,如何通过 GPRS连接到 Internet?
1、先在内核中加入 WAN下面的几个组件,如 RAS/PPP、TAPI。WINCE 采
用unimodem驱动,所以不必担心没有 Modem驱动的支持。
2、WINCE 启动后新建一个拨号连接,比如名称叫―gprs1‖,输入用户名、密
码、电话号码。电话号码不同,所采用的模式不一样,例如―*99#‖是GPRS模式,
―17201‖是普通的数据模式,速度差很多,价钱也差很多。
3、开始连接,连接过程会在对话框中显示,直到显示―连接成功‖。
4、打开浏览器或者自己开发的通讯软件测试网络连接情况。
5、关闭连接。
6、保存[HKEY_CURRENT_USER/Comm/RasBook/gprs1]下的所有数据,添
加到project.reg中,重新编译后内核中就有了一个拨号连接―gprs1‖。
7、调用RAS函数可以修改拨号连接―gprs1‖的参数,如用户名、密码、电话
号码,但是不能修改硬件设置,如波特率、串口、数据位、停止位等。RAS 函
数还能够拨号、挂断。为了修改波特率可以多保存几个拨号连接,也可以直接调
用 TAPI 开发拨号软件,另外 WINCE 自带的拨号连接是有源码的,位置在
/PUBLIC/COMMON/OAK/DRIVERS/NETSAMP/CONNMC。
采用基于 HIVE 的注册表如何删除用户保存在注册表中的数据, 恢复
到出厂时的注册表?
用户修改的数据保存在 user.hv 文件中,直接删除一定失败,所以不能通过
删除文件实现恢复出厂设置。微软考虑到了这个问题,在 WINCE 启动过程中
filesys.exe 加载注册表时会调用 OEMIoControl 函数并传递一个 IOCTL,这个
IOCTL在pkfuncs.h中定义如下:
#define IOCTL_HAL_GET_HIVE_CLEAN_FLAG
CTL_CODE(FILE_DEVICE_HAL, 49, METHOD_BUFFERED, FILE_ANY_ACCESS)
filesys.exe 会 分 别 传 递 参 数 HIVECLEANFLAG_SYSTEM 和
HIVECLEANFLAG_USERS,如果返回值为TRUE 那么 filesys.exe清除原来的注
册表文件,如果返回值为 FALSE 那么 filesys.exe 保留原来的注册表文件。默认
WINCE 并没有实现这个 IOCTL,所以 OEM 要删除注册表文件就必须先编写这个 IOCTL 代 码 。 代 码 的 例 子 可 参 考 标 题 为
―IOCTL_HAL_GET_HIVE_CLEAN_FLAG‖的帮助文档。
另外必须在 ioctl.h 和 ioctl.c 两个文件中编写该代码。在 ioctl.c 文件中找到
const OAL_IOCTL_HANDLER g_oalIoCtlTable[],添加 IOCTL 和对应的处理函
数。要进一步了解这个全局数组,参见标题为―IOCTL Library‖的帮助文档。
如何在不删除必要组件的前提下减小内核文件长度?
要减小内核文件长度首先要在使用 PB 的定制内核向导中选择自定义,也就
是说对于每个组件都由自己来选择,而不是选择PB的标准配置。但减小内核文
件长度最有效最直接的办法是缩小字体,尤其对于东亚字体,采用字体压缩技术
并且选择合理的字库文件将明显缩小文件长度。
1、在定制内核时选择 AGFA AC3 Font Compression组件。SYSGEN变量为
SYSGEN_AGFA_FONT。
2、参考标题为―East Asian Font Versions‖的帮助文档,从中选择你需要的字
库文件加到内核中,从文档可以看出加 AC3 压缩比不加压缩在文件长度方面差
距很大。
如何得到 WAV 文件播放的总时间?
1、直接读取wav文件头信息,从文件起始地址偏移28个字节长度为 4个字
节保存的是每秒钟播放的字节数,从文件起始地址偏移 40 个字节长度为 4 个字
节保存的是声音数据的总的字节数,相除就是播放时间。
2、调用IGraphBuilder::RenderFile打开一个wav文件,然后通过IGraphBuilder
得到IMediaSeeking指针,再调用IMediaSeeking::GetDuration得到总的时间(结
果要除以10000000),IMediaSeeking::GetCurrentPosition得到当前播放时间。
如何在 Dialog-Based 程序中加入 menubar?
先调用CommandBar_Create再调用 CommandBar_InsertMenubar。 请问 MultiByteToWideChar 与_T、L、TEXT 的区别?
MultiByteToWideChar 函数转换的对象可以是常量也可以是变量。其它只能
转换常量。 _T 和TEXT会根据当前系统是否定义_UNICODE 宏来决定是否转换,
而 L就是转换成宽字符,当然也包括其他类型常量的转换。
在用 UBS 线缆通过 ActiveSync 同步有效的情况下,如何插上 USB
线缆后 WINCE 自动与 PC同步?
1、新建一个拨号连接,假设名称为―usb1‖,选择连接类型为―直接连接‖,并
在连接设备里选择通过USB线缆连接。
2、将注册表[HKEY_CURRENT_USER/Comm/RasBook/usb1]下的数据添加到
project.reg或者platform.reg中。
3、在[HKEY_CURRENT_USER/ControlPanel/Comm]下添加如下:
"AutoCnct"=dword:1 ///直接连接
"Cnct"="usb1" ///连接名称
4、重新编译内核。为了节省编译时间也可以在内核工程下搜索*.reg 文件,
将2、3步骤中的注册表数据添加其中,然后直接 make image。
如何通过进程句柄来获得该进程的主窗口句柄?
好像没有 API能够通过进程句柄直接获得主窗口的句柄,因为并非每个应用
程序都带 UI。但是可以反过来,先枚举当前系统所有主窗口,然后根据每个窗
口的句柄调用 GetWindowThreadProcessId 函数得到进程的 ID,再调用
OpenProcess得到进程句柄,与现有的进程句柄比较。
我做的显示驱动 DLL 已经编译成功了,但是在加载显示驱动的过程
中弹出话框,提示如下:
unhandled exception in gwes.exe (0xc0000005 access violation)
提示的错误——地址访问非法,表明你的驱动程序代码并没有在读写数据前
添加 SetKMode(TRUE)或者 SetProcPermissions(0xFFFFFFFF)函数让线程能够访
问任何进程的地址空间。你可以调用 IsBadReadPtr 和 IsBadWritePtr 函数检测地址是否能够合法访问。编写和 gwes 有关的驱动程序应该首先调用
SetKMode(TRUE)或者SetProcPermissions(0xFFFFFFFF)函数,这是一个好习惯。
请问在嵌入式系统中如何设置 GPRS 拔号用的 APN?
对一个拨号连接比如―我的连接‖单击鼠标右键,在弹出的菜单中选择―属性‖,
然后单 击 ―配置‖—―拨 号选 项‖ ,在 ―附 加设置 ‖中 添加 AT 命 令如
―+cgdcont=1,"ip","cmnet"‖。―cmnet‖位置即为 APN。
WINCE 的 IP Phone 功能如何?
WINCE 的 voip需要c-s-c结构,既需要服务器的中转,而skype采用第三代
p2p技术就不需要中转,但是在gprs下也做不到语音流畅。skype 有pocket pc版
本,但是无线方面需要wlan或者cdma。
三星 ARM 平台如何定义自己的中断 ID?
以S3C2410为例,在oalintr.h文件中定义中断ID,也称SYSINTR,例如#define
SYSINTR_MYINT (SYSINTR_FIRMWARE+20) , 最 大 值 不 能 超 过
SYSINTR_FIRMWARE+23。然后在armint.c文件中找到OEMInterruptHandler 函
数,用 if (IntPendVal == INTSRC_XXX)判断当前发生的中断源号,然后返回
SYSINTR_MYINT。内核分别调用 OEMInterruptDisable(禁止当前中断)、
OEMInterruptDone(中断处理结束)、OEMInterruptEnable(当前中断有效)三个
函数,参数都为中断ID,在这三个函数中用case SYSINTR_MYINT 判断当前要
处理的中断。
如何开发软件从 PC端复制文件到基于 WINCE 的设备?
调用RAPI(Remote Application Programming Interface)函数,此函数集由桌
面计算机调用,由基于WINCE 的设备执行。一旦连接上就可以在桌面计算机端
调用RAPI。通过注册表还可以限制RAPI 能够访问目录的范围。具体参考RAPI
和RDP(远程桌面协议)。 请问如何对 NandFlash分区、格式化?
你看看 WINCE420/PUBLIC/COMMON/OAK/DRIVERS/ETHDBG/
BOOTPART/bootpart.cpp,在Eboot中先要调用BP_LowLevelFormat(DWORD
dwStartBlock, DWORD dwNumBlocks, DWORD dwFlags)再flash的一个区域建立
空的MBR,然后连续两次调用BP_OpenPartition(DWORD dwStartSector, DWORD
dwNumSectors, DWORD dwPartType, BOOL fActive, DWORD dwCreationFlags)
函数来建立BINFS和 FAT 分区。建好后,将 nk.bin烧入 binfs 分区中。
要做个弹出对话框具有 always on top 属性,如何实现?
调用SetWindowPos(.., HWND_TOPMOST, ...., SWP_NOACTIVATE)。
s3c2410+WINCE 下网络 PING 一会就断,如何解决?
原因在于中断处理程序把已经产生的中断标志清除掉了,这样就丢失一次中
断。因为原驱动里配置中断为上升沿触发,一次中断丢失就导致不会再产生中断
信号跳变,因为只有在中断服务中读取了cs8900的Interrupt status queue寄存器
后,才会产生下一次中断!解决办法:
1、在cfw.c文件中全局定义BOOL Inited = FALSE
2、修改OEMInterruptEnable()中case SYSINTR_ETHER:下面的语句为:
if(Inited == FALSE)
{
s2410IOP->rEINTPEND = 0x200;
s2410INT->rSRCPND = BIT_EINT8_23;
if(s2410INT->rINTPND & BIT_EINT8_23)
s2410INT->rINTPND = BIT_EINT8_23;
Inited = TRUE;
}
s2410IOP->rEINTMASK &= ~0x200;
s2410INT->rINTMSK &= ~BIT_EINT8_23;
break;
注:本解决办法转载于 http://stoned.blogchina.com/stoned/3083045.html,非我
本人研究成果。 已经搜索到文件,如何用 CListBox以图标形式显示出来?
ClistCtrl ListCtrl;
CimageList ImageList;
ImageList.Create(IDB_BITMAP, 48, 2, RGB(0,0,0));
ListCtrl.SetImageList(&ImageList, LVSIL_NORMAL);
ListCtrl.InsertItem(iListIndex, strItem, 1);
如何改变控制面板中电源属性对话框的尺寸?
1、需要修改对话框的尺寸是因为对话框是以资源方式加载的,不会根据当
前系统显示分辨率而自我调节尺寸。
2、安装WINCE 后有一些组件(feature)的资源文件*.res就已经有了,如果
你不改变,那么build内核的时候PB只是把这些.res复制到工程目录下,然后与
*.obj合并成 EXE、DLL、CPL。所以修改了.rc 文件里面的对话框尺寸后要重新
编译.rc文件为.res文件,然后再覆盖原来 WINCE 自带的.res文件。
3、改变对话框尺寸有两种办法:一种方法是更改系统字体字号,系统字体
的字号变化会影响对话框的尺寸,但是缺点是所有系统字体有关的 UI都会改变。
另一种是在.rc文件中调整对话框尺寸,然后编译成.res文件,再将.res复制到对
应的语言目录里,比如目录名为 0804(中文),再执行 Rebuild 命令重新编译内
核,或者执行 sysgen+build。在研究中我发现.res 文件虽然能够直接用 EVC 打
开、修改、保存,但是和其它 Obj 链接成 EXE、DLL、CPL 后并不能运行,所
以还是建议读者用 CE 自带的 rc 工具编译最好。读者可在 PB 的命令行中键入
―rc/?‖了解rc.exe工具的用途和参数。
使用 EVC build 之后连接模拟器的时候,提示 download file 等了一
会又出现 download failed?
一般这样的问题从下面几个步骤解决:
1、如果之前能启动模拟器而现在不能,那么先clean然后重启计算机再build。
2、如果开发的主机为 WINXP+SP2,可能存在与EVC模拟器不兼容的情况,
检查C:/boot.ini,将/noexecute=optin改为/execute=optin。
3、检查你的模拟器是否能运行,假设你正用的SDK名称为 MYSDK,单击
菜单tools—configure platform manager,选择 MYSDK—MYSDK emulator,再单击properties—test,看看模拟器是否能够启动,如果能启动那问题就不大。
4、单击菜单build—update remote output files,看看模拟器是否能够启动。
5、如果上述办法均不行,关闭EVC然后重新建立一个新的工程,编译,看
看模拟器是否能够启动,如果能启动说明原来工程出了问题,最好恢复原工程的
备份。
如何设置能够自动拨号、禁止自动拨号?
在[HKEY_LOCAL_MACHINE/Comm/Autodial]下是自动拨号的注册表设置。
Enabled=DWORD:1 ///是否能够自动拨号
FailRetryWaitMS=DWORD ///如果失败再次拨号的等待时间
RasEntryName1=REG_SZ ///自动拨号采用的拨号连接名称
更多细节请参考标题为―Auto Dial Registry Settings‖的帮助文档。