Windows CE的显示设备驱动笔记

来源:互联网 发布:校园青春偶像网络剧 编辑:程序博客网 时间:2024/05/18 16:18

 

显示驱动概述
一、显示设备驱动接口(DDI)是Windows NT DDI的子集。
WinCE的显示驱动和NT的有三点不同:
1.CE的显示驱动功能单一,GDI不会去查询一个驱动的设备能力
2.对于一个复杂的操作,CE的显示驱动不会拒收并把它还给GDI让GDI将其分解成一系列简单的操作,因为CE的显示驱动自己具备这个功能(分解的功能?),GDI会在调用显示驱动之前将操作进行分解。
3.CE显示驱动最终会编译成用户态的动态链接库。
显示驱动总体架构
二、CE显示驱动整体的架构是分层的。GPE(简单图形引擎)处理默认绘制动作,担当显示驱动的模型设备驱动(MDD)。程序员负责开发和硬件相关的代码作为显示驱动的下层,称作平台相关驱动(PDD)。
GDI函数是通过Coredll.dll开放给应用程序的(当然这个dll所导出的不仅仅只是GDI接口,它的地位和功能大致等同于Windows 2000/XP中的GDI32.dll、USER32.dll和Kernel32.dll的合体),这个dll只是一个客户端空壳,它本身不包含GDI的具体实现代码,只负责把应用程序的GDI调用打包好后用LPC发给它的后台服务进程。对于GDI调用而言,对应的后台服务进程是GWES.exe。
GWES是负责处理图形、窗口和事件的子系统,主要的工作就是处理图形输出和用户交互。显示设备驱动就是被它加载的,并驻留在GWES的进程地址空间内。同时被GWES“罩”着的,还有打印机驱动,键盘驱动,鼠标驱动,触摸屏驱动这一班小弟。
显示驱动默认的名字叫做Ddi.dll,它本身所导出的函数只有DrvEnableDriver一个,但是这个函数返回了一个包含27个函数指针的数组。前面说过,显示驱动是被GWES调用的,因此这27个函数是提供给GWES的,当GWES想召唤显示驱动的时候它就用这27个函数中的某一个。做小弟的当然要对大哥吩咐的任务屁颠屁颠地去完成,因此我们编写显示驱动的主要任务也就是为这27个函数编写相应的实现代码。不过这27个函数并不都是用于显示设备的,其中有3个是专用于打印机驱动程序的,故而我们只要管好剩下的24个就ok了。
CE下所有的显示驱动都必须实现DDI函数集,这些函数用于初始化显示驱动以及把把图像用块传输(Blit)送往显示设备。
 
二、GPE是一个类库,已经实现了一些基本的绘画功能,并可以处理所有在显示DDI层内的通讯。程序员可以从GPE继承来为自己的硬件创建新的显示驱动——也只能被继承后使用,因为GPE类里包含了很多纯虚函数(ATI sample driver就使用了GPE类库,它的源代码放在%_WINCEROOT%/PUBLIC/COMMON/OAK/DRIVERS/DISPLAY路径下)。要使用GPE,硬件必须支持帧平面缓存,也就是说显示设备的所有存储单元形式上必须是一个单块的连续内存。
 
三、显示驱动的配置信息放在注册表的HKEY_LOCAL_MACHINE/Drivers/Display路径下,你的显示驱动的初始化例程应该在HKEY_LOCAL_MACHINE/Drivers/Display/Active路径下创建一个键,这样应用程序可以知道哪个显示设备是当前可用的。
 
四、GWES会把它当前正在使用的显示设备的驱动写在HKEY_LOCAL_MACHINE/System/GDI/Drivers/MainDisplay路径里。那么,GWES怎么知道加载哪个显示驱动程序呢?过程是这样的:第一步,GWES会去访问候选显示设备列表(这个列表放在HKEY_LOCAL_MACHINE/System/GDI/DisplayCandidates下面,一般是在Platform.reg里建好的),看看是否有驱动程序已经在本机上实例化,如果有的话,GWES会使用它找到的第一个已经实例化的驱动;第二步,GWES尝试加载Ddi.dll,这是缺省的显示驱动的名字。另外,还有一个专门的进程负责加载第二个驱动,加载第二个驱动很简单,只要把驱动程序名字(如“MyDDI.dll”)作为第一个参数去调用CreateDC就可以了。
 
ZZ:CE下的驱动有单块驱动/分层驱动和本地驱动/流式驱动之分。
单块驱动与分层驱动只是从代码的形式上、从实现的方式上所做的分类。分层驱动从代码上分为PDD与MDD,微软一般已经做好了MDD(可能还实现了PDD),我们只需要对PDD做些修改就能使用,比如音频的驱动,显示的驱动。单层驱动是把PDD与MDD写在一起,没有做严格的区分,通常这种驱动比较简单,比如ATADISK。
本地驱动和流式驱动是从驱动与系统其它模块(调用者)的接口形式上做的分类,也就是驱动模型上的分类。其实本地驱动这个名称不大恰当,叫专用驱动或其它名字可能更为合适。它是指调用它的模块给它有特定的接口,比如电源驱动和通用LED驱动。而串口、网卡等就是流接口驱动程序,DLL文件里可以导出各种流式接口函数。一个驱动程序可以是单体的流式驱动如ATADISK,也可以是分层的流式如OHCI。
主显示驱动程序
一、CE在系统自举的时候加载默认显示驱动或者主显示驱动。默认情况下加载的是Ddi.dll。如果注册表项HKEY_LOCAL_MACHINE/System/GDI/Drivers/Display存在,GWES会加载此注册表项所指定的显示驱动。
 
二、如果应用程序想创建一个到图形设备的连接,CreateDC是GDI所提供的唯一途径。这个函数会调用驱动程序的初始化函数,函数的返回值是设备环境。
设备驱动程序所提供的初始化函数有两个:
DrvEnableDriver:任务是向GWES返回一个函数指针数组,同时保存GWES向图形驱动程序所提供的支持函数集。本函数在驱动第一次被加载的时候调用,只调用一次。
DrvEnablePDEV:每次要创建DC的时候会调用此函数。一旦CreateDC被调用,GWES必定要调用DrvEnablePDEV,这两个调用是一一对应的。
 
三、把应用程序从显示设备上断开需要两个函数:
       DeleteDC:API层上相对于CreateDC的逆操作
       DrvDisablePDEV:DDI层上相对于DrvEnablePDEV的逆操作。
次显示驱动程序
一、次显示驱动程序仅仅在应用程序用次显示驱动的dll文件名作为参数调用CreateDC时才被加载。该函数会返回一个和次显示驱动相关联的DC的句柄。这个DC用起来和主显示驱动的DC没有什么区别,但是不能在窗口管理器函数中使用次显示驱动的DC。因为创建次显示驱动DC的时候窗口管理器并没有参与其中,因此在次显示设备上,应用程序必须包揽在次显示设备上所有的绘制任务。象窗口,菜单,对话框和滚动条这些东西都必须要自己画。当没有任何DC和次显示驱动相关连时,次显示驱动就会被卸载。
 
二、从主显示设备向次显示设备上复制的唯一办法是通过设备无关位图(DIB)。具体做法是,先创建一个和主DC兼容的DC,然后把DIB选进去,主DC把内容拷贝到DIB上,然后再把DIB选入和次DC兼容的DC,最后把DIB上的内容拷贝到次DC上。如果不这样做会触发异常因为一个显示驱动试图存取另一个显示设备的surface。
原创粉丝点击