WinCE驱动开发问题精华集锦

 如何让系统加载自己写的驱动程序?  
两种办法: 
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/。这和real player相似,都需要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
文章出处:http://www.diybl.com/course/3_program/c++/cppsl/200883/134547.html

你可能感兴趣的:(api,Flash,null,文档,dll,WinCE)