【转】EVC /PB /WinCE开发问题
1. 在ce自制平台中如何添加自己的驱动?cec文件和reg,bib文件有何区别?看混了,不知道如何才能让驱动注册到平台中。另外,reg和bib是我在编写驱动必须要自己写的么 CE 的驱动分为本机驱动和流驱动,本机驱动你可以修改源码(在%_WINCEROOT%/PUBLIC/COMMON/OAK/DRIVERS),然后 build驱动源码,之后用PB编译内核。流驱动是以DLL的形式被系统程序加载的。加载流驱动要在注册表中添加信息,这和cec文件没关。如果你想把此驱动DLL和注册信息作为一个整体给别人使用,那么就要做一个cec文件,PB能够读取cec文件内容并加载到内核工程中。cec文件相当于安装程序。 2. 在应用程序中,如何向修改本机的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。 3. 如何定制自己的外壳 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在内核中,二是删除依赖标准外壳的组件。 4. 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映射的虚拟地址范围在0xC400 0000 到 0xE000 0000之间,这个范围只能由内核访问,一般用于ISR访问,因为ISR只能访问静态映射的虚拟地址空间,不能用VirtualCopy。VirtualCopy通常和VirtualAlloc配合使用,映射的虚拟地址空间在0x8000 0000以下,一般用于驱动程序和应用程序访问。 1、应用程序要访问这片RAM,和驱动程序访问方法一样,调用VirtualAlloc和VirtualCopy。 2、可以做一个流驱动程序专门用于读写这片RAM,这样所有应用程序就可以通过调用流驱动接口函数来访问,非要加文件系统也是可行的,通过修改注册表就可以做到,但是麻烦一些。 5..我怎么能在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一样通过菜单“Add to OS Design”添加到左边的内核工程中。 6. 如何在PB中预先设定好存储内存和程序内存的大小,我想多划分一些空间给程序内存? 两种办法: 1、在定制内核时在config.bib文件中设置FSRAMPERCENT = number,具体number可参考标题为“FSRAMPERCENT ”的帮助文档。这种办法是修改内核的设置,所有一直有效。 2、在应用程序中调用API SetSystemMemoryDivision,如果函数返回SYSMEM_CHANGED表示成功,如果返回SYSMEM_MUSTREBOOT表示需要热启动才能有效。这种办法需要每次启动后调用API才有效。 包含Pwindbas.h头文件 SetSystemMemoryDivision(512*2); //设置存储内存和程序内存,设置以后存储内存为4M 7. 修改了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来编写编译。 8. 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。 9. 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表示默认 10 驱动程序如何发通知给应用程序? 这里介绍一下常见的两种办法。 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。 11. 如何让系统加载自己写的驱动程序? 两种办法: 1、在[HKEY_LOCAL_MACHINE/Drivers/BuiltIn]下添加注册键。 2、在应用程序中调用ActivateDeviceEx。 12. 使用VirtualAlloc和VirtualCopy的时候需要注意哪些事项? 1、 VirtualAlloc的作用是申请虚拟地址空间,这肯定不是最终的目的,最终目的可能是申请物理内存、映射寄存器、提交文件等。没有一个目的会在意虚拟地址空间的位置,所以尽量传递参数1为0,也就是让WINCE自动分配虚拟地址空间。VirtualAlloc分配地址空间实际上是以64KB为单位,所以要指定申请的虚拟空间的首地址的话,参数1应该为64KB的整数倍,申请的长度也应该为64KB的整数倍,即使你不需要那么大。 2、 VirtualCopy的主要作用是映射物理地址空间,如果参数2为物理地址,那么最后一个参数要添加PAGE_PHYSICAL,参数2必须是256的整数倍。如果参数2为虚拟地址(0x80000000以上),那么最后一个参数就不要添加PAGE_PHYSICAL,WINCE内核会根据这个虚拟地址找到对应的物理地址。 13. 驱动程序和应用程序之间传递数据时何时调用MapPtrToProcess? 因为设备管理器负责加载驱动程序DLL,这意味着当应用程序调用驱动程序接口函数的时候,WINCE内核会将调用驱动程序接口函数的线程转移到设备管理器的进程空间然后执行具体的驱动程序代码,应用程序和设备管理器处于两个进程空间,这就造成设备管理器无法访问应用程序传递的指针(虚拟地址),所以当我们在应用程序中传递指针给流驱动程序接口函数时,WINCE内核从中作了一个地址映射,例如ReadFile、WriteFile、DeviceIoControl函数的参数凡是指针都经过了映射才传递给驱动程序,所以很多驱动程序开发者并不了解其中的奥秘就可以编程了。但是如果参数是一个指向一个结构体的指针,而结构体里包括一个或多个指针,那么WINCE内核并不负责映射,所以就需要开发者在驱动程序接口函数中调用API函数MapPtrToProcess来映射地址。例如:pPointer_retval = MapPtrToProcess(pPointer, GetCallerProcess()); 14. 如何隐藏和显示winCE下标准外壳的任务栏? HANDLE hTaskBar = FindWindow(L"HHTaskBar", NULL); ShowWindow(hTaskBar, SW_HIDE); ShowWindow(hTaskBar, SW_SHOWNORMAL); 15. wince下如何让操作系统进入待机模式?又如何把它激活? 通过注册表就可以设置,前提是你的驱动和硬件都支持。注册表项参见标题为“GWES Suspend Time-outs”的帮助文档。 [HKEY_LOCAL_MACHINE/System/CurrentControlSet/Control/Power] "BattPowerOff"=dword:300 "ExtPowerOff"=dword:0 "WakeupPowerOff"=dword:60 "ScreenPowerOff"=dword:0 16. 如何在不删除必要组件的前提下减小内核文件长度? 要减小内核文件长度首先要在使用PB的定制内核向导中选择自定义,也就是说对于每个组件都由自己来选择,而不是选择PB的标准配置。但减小内核文件长度最有效最直接的办法是缩小字体,尤其对于东亚字体,采用字体压缩技术并且选择合理的字库文件将明显缩小文件长度。 1、在定制内核时选择AGFA AC3 Font Compression组件。SYSGEN变量为SYSGEN_AGFA_FONT。 2、参考标题为“East Asian Font Versions”的帮助文档,从中选择你需要的字库文件加到内核中,从文档可以看出加AC3压缩比不加压缩在文件长度方面差距很大。 17. 三星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判断当前要处理的中断。