710 likes | 990 Views
设备管理器和 GWES. www.up-tech.com 博创科技 嵌入互动. 主要内容. 设备管理的基本概念 WinCE 的设备管理 设备管理器的具体实现 GWES 的概念和功能 从应用程序调用 GWES. 1 、设备管理的基本概念. 设备的分类. 按设备的使用特性: 存储设备 输入输出设备 终端设备 。。。 按设备的从属关系 系统设备 用户设备. 设备管理的任务. 选择和分配输入输出设备以便进行数据传输操作 控制输入输出设备和 CPU 之间交换数据
E N D
设备管理器和GWES www.up-tech.com 博创科技 嵌入互动
主要内容 • 设备管理的基本概念 • WinCE的设备管理 • 设备管理器的具体实现 • GWES的概念和功能 • 从应用程序调用GWES
设备的分类 • 按设备的使用特性: • 存储设备 • 输入输出设备 • 终端设备 • 。。。 • 按设备的从属关系 • 系统设备 • 用户设备
设备管理的任务 • 选择和分配输入输出设备以便进行数据传输操作 • 控制输入输出设备和CPU之间交换数据 • 为用户提供一个友好的透明接口,把用户和设备硬件特性分开,使得用户在编制应用程序时不必涉及具体设备,系统按用户要求控制设备工作。另外这个接口还为新增加的用户设备提供一个和系统核心相连接的入口,以便用户开发新的设备管理程序。 • 提高设备和设备之间、CPU和设备之间,以及进程和进程之间的并行操作度,以使操作系统获得最佳效果。
设备管理的功能 • 提供和进程管理系统的接口。当进程要求设备资源时,该接口将进程要求转达给设备管理程序。 • 进行设备分配。按照设备类型和相应的分配算法把设备和其他有关的硬件分配给请求该设备的进程,并把为分配到所请求设备获取他有关硬件的进程放入到等待队列。 • 实现设备和设备、设备和CPU等之间的并行操作。 • 进行缓冲区管理。
对设备的控制方式 • 程序直接控制方式 • 中断方式
设备管理器的概念 • 设备管理器是在 Windows CE 操作系统下运行的进程,它跟踪已加载的驱动程序和它们的接口。它连续不断地运行并且从内核中启动。 • 设备管理器可以在设备接口变得可用和不可用时通知用户。用户或系统本身可以使设备接口变得可用或不可用。 • 另外,设备管理器通知内核设备接口支持文件操作(例如,CreateFile)访问公开流接口的设备。 • 设备管理器向设备驱动程序发送电源通知回调并提供电源管理服务。
设备管理器和注册表 • 设备管理器控制注册表中的 Active 项。 • 只有设备管理器应当访问 Active 项以获取读取或写入访问权限。 • 可以通过设备驱动程序的初始化函数的参数间接访问 Active 项。
设备管理器和注册表 • 设备管理器搜索 HKEY_LOCAL_MACHINE\Drivers\RootKey 注册表项,以确定用于开始驱动程序加载过程的项。 • RootKey 的默认值是 Drivers,但是它通常等于 Drivers\BuiltIn。 • 设备管理器调用 ActivateDeviceEx 以加载由 Dll 子项的值指定的驱动程序。Dll 子项的值默认情况下为 BusEnum.dll(也称为总线枚举器)。 • 加载 BusEnum.dll 会使所有设备驱动程序加载。由 ActivateDeviceEx 加载的设备可以从它的 Active 注册表项中读取它的激活句柄。
驱动程序的命名 • 设备管理器将总线名称与驱动程序相关联。未命名的设备也可以具有总线名称,因为即使应用程序可能无法访问驱动程序,驱动程序也可能被其他驱动程序或系统实体(例如,电源管理器)访问。总线名称可以具有与正规设备名称不同的 ACL。 • 设备管理器跟踪由驱动程序公布的接口,并且支持基于全局唯一标识符 (GUID) 搜索驱动程序。IClass 接口可以将接口 GUID 与驱动程序的旧式名称、$device 名称或 $bus 名称(例如,“COM1 :”、“$device\com1”或“$bus\pci_0_3_0”)相关联。
公布驱动程序的接口 • 驱动程序可以通过调用 DMAdvertiseInterface 以编程方式公布接口。DMAdvertiseInterface 使驱动程序能够将更多可搜索的 GUID 添加到它们的关联列表中。DMAdvertiseInterface 由 Devmgr.dll 公开,后者还实现了大多数设备管理器功能。因为只有设备管理器可以加载 Devmgr.dll,所以只有设备驱动程序可以调用 DMAdvertiseInterface。如果设备驱动程序在卸载时没有公布它的接口的不可用性,则设备管理器会自动清除接口公布通知。
设备管理器组成 • 设备管理器由 Device.exe 和 Devmgr.dll 组成。Device.exe 包含 Devmgr.dll,后者实现了核心设备管理器功能。 • 因为设备管理器由两个单独的模块组成,所以设备驱动程序可以直接与设备管理器链接并调用特定的函数而不会引起系统调用的开销。
设备管理器的体系结构 • 一般操作系统的设备管理都采用分层的管理模式。WinCE在模块组成和划分方面更加具体而实用。 • WinCE设备管理部分采取了类似Windows 2000/XP的结构,大大的简化了中断处理、I/O访问以及内部管理的机制。 • WinCE的设备管理包括四个部分。
设备管理器的体系结构 • 设备管理器:设备管理器是WinCE设备管理的核心机构,他主要负责跟踪、维护系统的设备信息并对设备资源进行调配。 • I/O资源管理:I/O资源管理器是设备管理模块内部的重要组成部分,他跟踪了设备驱动程序装载前从注册表信息中初始化所需的系统资源。 • 电源管理器: • 支撑和管理例程库
设备加载 • 设备加载的代码被放入device.c的InitDevices函数中 • 此函数已工作了以下一些工作: • 打开注册表 • 读出注册表的HKEY_LOCAL_MACHINE\Drivers\RootKey键 • 激活里面列出的设备 • 具体实现如下:
设备加载 InitDevices(VOID)//此函数的目的是为了初始化内置的驱动程序,不需要入口函数 { … // Open HLM\Drivers key // status = RegOpenKeyEx(//打开指定的键 HKEY_LOCAL_MACHINE, DEVLOAD_DRIVERS_KEY, 0, 0, &RootKey); // 查找root键键值,如果没找到则使用当前默认的root键,否则打开新的root键 ValLen = sizeof(RootKeyPath);
设备加载 status = RegQueryValueEx(//查询roots RootKey, DEVLOAD_ROOTKEY_VALNAME, NULL, &ValType, (PUCHAR)RootKeyPath, &ValLen); // Close previous root key RegCloseKey(RootKey);//关闭 (void) ActivateDevice(RootKeyPath, 0);//将此值传给ActiveDevice函数来加载设备 }
设备加载 • 由上面的代码可以看出,设备加载的过程依赖于注册表,任何新的设备必须首先在注册表中声明,随后才能被加载 • 设备加载的核心是ActiveDeviceEx,此函数没有被公开 • 如果在应用程序中加载一个新的设备,可以调用ActiveDeviceEx,这和设备管理器加载设备的过程是相同的。
设备管理器中的WinMain • 设备管理器表现为device.exe,这是由源程序编译得到的可执行文件,设备管理器运行在用户模式。对于可执行文件,一般都存在一个主函数。设备管理器的主函数放在device.c中,为WinMain。 • WinMain函数完成设备的初始化和加载过程,整个过程分为三个阶段。
设备管理器中的WinMain • 第一阶段:构造基本的数据结构 • 第二阶段:装载并初始化设备 • 第三阶段:记录下做过的工作,整理 • 具体代码分析见下:
设备管理器中的WinMain int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR lpCmdLine, int nCmShow) { HINSTANCE hCeddkDll;//cdddk.dll的实例句柄,实例句柄一般都指向某一个库文件 HANDLE hevBootPhase1;//事件句柄 //开始第一阶段的启动,构造各种基本的数据结构 // PHASE 1 g_BootPhase = 1;//全局变量,表明当前启动阶段为第一阶段 InitOOMSettings();//初始化OOM设置,什么是OOM? InitializeListHead(&g_DevChain);//常规状态的设备列表,WINCE的设备都被组织在连表中 InitializeListHead(&g_DyingDevs);//消亡状态的设备列表 InitializeListHead(&g_CandidateDevs);//正在加载的设备列表 g_hCleanEvt = CreateEvent(0,0,0,0);//此事件用于同步各个设备控制函数 g_hCleanDoneEvt = CreateEvent(0, 1, 1, 0); //manual reset, init state signalled g_hDevApiHandle = CreateAPISet("WFLD", NUM_FDEV_APIS, FDevApiMethods, FDevApiSigs); //创建API集合 g_hDevFileApiHandle = CreateAPISet("W32D", NUM_FAPIS, DevFileApiMethods, DevFileApiSigs);//同上 RegisterAPISet(g_hDevFileApiHandle, HT_FILE | REGISTER_APISET_TYPE);//注册API集合
设备管理器中的WinMain InitializeDeviceNotifications();//初始化设备通知结构,在这个结构里包含三个域,第一 //个是通知链表元素,第二个是广告(?)链表元素,第 //三个是临界区。在这个函数中分别对这三项进行了初始 //化。WINCE设备管理其中也是广泛应用了临界区,相比 //核心对象,临界区更快,大量使用临界区可以提高程序 //的速度 InitializeCriticalSection(&g_devcs);//设备临界区,全局变量 ResourceInitModule();//资源初始化模块 ResourceInitFromRegistry(TEXT("Drivers\\Resources"));//从注册表的项中初始化资源 SetPowerOffHandler((FARPROC)FS_PowerAllDevices);//设置电源处理函数为FS_PowerAllDevices RegisterAPISet(g_hDevApiHandle, SH_DEVMGR_APIS);//不知道怎么回事 StartDeviceNotifyThread();//开启设备通知线程
设备管理器中的WinMain // Calibrate stall counter that is used for StallExecution hCeddkDll = LoadLibrary (TEXT("ceddk.dll"));//加载ceddk。Dll if (NULL != hCeddkDll) {//如果加载成功 pCalibrateStallFn fnCalibrateStall = (pCalibrateStallFn)GetProcAddress(hCeddkDll, TEXT("CalibrateStallCounter"));//得到库中函数CalibrateStallCounter的地址 if (!fnCalibrateStall) {//如果没有此地址则释放库 DEBUGMSG(ZONE_BOOTSEQ, (L"GetProcAddress failed on ceddk.dll\r\n")); FreeLibrary(hCeddkDll); } else { fnCalibrateStall();//有则执行之 } } // Call the power manager initialization entry point PM_Init();//电源管理函数入口点,核心内容未公开 PM_SetSystemPowerState(NULL, POWER_STATE_ON, POWER_FORCE);//设置当前状态,核心内容未公开
设备管理器中的WinMain // See if we are going to have two boot phases hevBootPhase1 = OpenEvent(EVENT_ALL_ACCESS, FALSE, _T("SYSTEM/BootPhase1"));//打开事件 if (hevBootPhase1 != NULL) {//如果已打开 HANDLE hEvent; // Load phase 1 drivers from the boot registry DevloadInit();//加载设备 // Signal boot phase 1 complete SetEvent(hevBootPhase1);//第一阶段结束 CloseHandle(hevBootPhase1); // Wait for phase 2 of the boot to begin hEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, TEXT("SYSTEM/BootPhase2"));//打开第二阶段的事件
设备管理器中的WinMain if (hEvent) {//如果事件存在 DEBUGMSG(ZONE_BOOTSEQ, (TEXT("DEVICE: Started, waiting for boot phase 2\r\n"))); WaitForSingleObject(hEvent, INFINITE);//等待时间被释放 CloseHandle(hEvent); } // Load any new drivers from the persistent registry. Since the // registry may have changed, update the power state for any devices // that need it. DEBUGMSG(ZONE_BOOTSEQ, (TEXT("DEVICE: Second-phase driver load\r\n"))); g_BootPhase = 2;//进入第二阶段,装载并初始化设备 PM_SetSystemPowerState(NULL, POWER_STATE_ON, POWER_FORCE);//设置电源管理状态 InitDevices();//初始化设备 DEBUGMSG(ZONE_BOOTSEQ, (TEXT("DEVICE: Startup sequence complete\r\n"))); SignalStartedUsingReg(); // SignalStarted call with the right args
设备管理器中的WinMain else {//如果事件未打开 DEBUGMSG(ZONE_BOOTSEQ, (TEXT("DEVICE: No boot registry - skipping to boot phase 2\n"))); g_BootPhase = 2;//进入第二阶段 DevloadInit();//初始化设备 SignalStarted(_wtol(lpCmdLine)); }
设备管理器中的WinMain g_BootPhase = 3;//进入第三阶段 CELOG_DeviceFinished ();//记录 while (1) { WaitForSingleObject(g_hCleanEvt, INFINITE); // check for auto-deregister devs first as they may end up queuing // themselves on the dying devs list ProcessAutoDeregisterDevs();//处理自动取消注册的设备 ProcessDyingDevs();//处理死亡的设备 ProcessDyingOpens();//处理死亡的打开操作 DEBUGMSG(ZONE_DYING, (TEXT("DEVICE: Setting CleanDoneEvt in WinMain.\r\n"))); SetEvent(g_hCleanDoneEvt); }
设备管理器中的WinMain • 函数中用到了几个事件和链表,调用了几个函数 • 事件 • g_hCleanEvt • g_hCleanDoneEvt • 函数 • InitOOMSettings() • ProcessAutoDeregisterDevs() • ProcessDyingDevs() • ProcessDyingOpens() • StartDeviceNotifyThread() • 链表 • g_hDevchain • g_DyingDevs • g_lpOpenDevs • g_lpDydingOpens
设备管理器中的WinMain • 通过WinMain函数,WinCE初始化了与设备相关的所有数据结构和函数。 • 注册了API函数集,初始化了电源管理,声明了一些标准函数的接口。 • 设备管理器是整个WinCE管理设备的基础,在所有的设备运行之前,必须保证设备管理器的初始化成功,任何设备想要被加载,必须在注册表里声明自己,等到设备管理器的加载,或是由应用程序代替设备管理器完成相应的功能。 • 因为设备管理器也属于用户程序,所以应用程序可以部分代替设备管理器的功能。
GWES的概念 • 与Microsoft的桌面操作系统不同,Windows CE将Win32 API的用户界面(USER32)和图形设备接口(GDI32)合并成一个新的模块gwes.exe,成为GWES子系统。GWE是一个缩写词,其中G代表图形,W代表窗口管理,E代表事件管理。GWE字系统是用户、应用程序和操作系统之间的图形用户界面。
GWES的概念 • GWES支持组成WinCE图形用户界面的所有窗口、对话框、控件、菜单和资源,使用户能够通过执行菜单命令、单机按钮等操作来控制应用程序。GWE还以位图、光标、文本以及图标等形式为用户提供信息。即使不具备图形用户界面的基于WinCE的平台也使用了GWE的基本窗口和消息功能,这些功能提供了在用户、应用程序和操作系统之间进行通信的方法。
定制的GWES • WinCE是模块化的操作系统,OEM厂商可以针对于特定的平台选择软件模块来设计操作系统。 • WinCE提供了几种预先测试的组建配置放案,这些配置放案可以分为三类:最小配置、中等配置和完全配置。
中等配置下的GWES包含的功能 • 消息处理及用户输入 • 电源管理 • 提示性发光二极管 • GDI,包括MS True Type字体和光栅字体,文本绘制,调色板和打印。 • 可自定义的触摸屏和可校准的用户界面接口。 • 网络用户界面接口。 • 波形API管理器 • 输入方法管理器 • 窗口和对话框管理器 • 可自定义的用户界面接口。
GWES的组件模型 • 用户输入系统:接受来自键盘、鼠标和手写笔等设备的消息 • 事件管理器:管理消息和消息队列 • 窗口管理器:将消息相应发送到对应的窗口以实现特定的显示。
用户输入系统 • Windows CE.NET支持下列类型的用户输入:键盘,鼠标,触摸屏,软键盘,手写输入等等 • 每一个线程有一个特定的窗口称为活动窗口;焦点窗口能够接受来自键盘的消息;前台线程中的活动窗口是前台窗口 • 所有这些输入设备都被用户输入子系统管理起来。输入子系统还负责处理前台窗口、活动窗口、和焦点窗口。
键盘输入 • 键盘是许多计算机设备上的一种常用输入方法,Windows CE.NET提供了一种独立与设备的键盘模型,这使得可以由OEM自己决定Windows CE设备的键盘布局。 • 键盘驱动程序将每个扫描码翻译或映射为虚拟键码,虚拟键码是用于识别、与硬件无关的数字。 • 将扫描码翻译为虚键码之后,设备驱动程序创建一条包含了所有信息的键盘消息,并将这条消息放在系统的消息队列中。线程消息循环从队列中取出消息并将它发送给线程焦点窗口的窗口过程
触摸屏输入 • 在许多WinCE设备中,用户通过手写笔和触摸屏与应用程序交互,手写比喻触摸屏提供了一中直接且直观的鼠标替代物。 • 对应用程序而言,手写笔及触摸屏运行时所产生的时间与鼠标所产生的事件基本一致,可以说是鼠标事件的子集。当用户在屏幕上按下和松开手写笔时,应用程序像处理单击鼠标左键一样处理这些事件;当用户在屏幕上移动手写笔时,应用程序项处理鼠标移动事件一样处理它。
软键盘输入 • 有很多的WinCE设备因位置原因均没有键盘,WinCE为这类设备提供了一种通过触摸屏模拟键盘输入的输入方法,这种输入面板结构与软件界面与键盘类似,所以对用户来说也称为软键盘。 • 在用户访问输入面板时,WinCE创建一个专用的输入面板线程,这个线程创建输入面板窗口并初始化,然后线程进入消息循环,对来自输入面板的消息作出响应。
事件管理器 • WinCE是事件驱动的操作系统,消息通过MSG结构传递。WinCE的MSG结构包含六个成员,不支持消息钩子。 • 基于WinCE的编程要通过消息循环。消息循环是在Windows应用程序中的一种循环,他负责接收系统传送过来的消息,并且把它们发送到相应的窗口中,直到所有的消息都发送完毕,消息循环才结束。
显示管理 • GWES的显示管理部分囊括了几乎所有与显示有关的组件和接口。 • 实现了一整套GDI对象,其中包括画笔,画刷,位图、字体等 • 采用了与桌面式Windows完全不同的调色板管理机制 • 实现了显示驱动程序接口
GDI对象 • 画笔和画刷 • 位图 • 字体
GDI对象的使用方法 • 设备上下文 • SelectObject • DeleteObject
GWES的应用 • 消息的处理 • 响应键盘和鼠标消息 • 绘图函数
Windows消息的处理 • 消息的组成:一个消息由一个消息名称(UINT),和两个参数(WPARAM,LPARAM)。当用户进行了输入或是窗口的状态发生改变时系统都会发送消息到某一个窗口。 • 一个消息必须由一个窗口接收。在窗口的过程(WNDPROC)中可以对消息进行分析,对自己感兴趣的消息进行处理。 • Windows程序是事件驱动的,对于一个窗口,它的大部分例行维护是由系统维护的。每个窗口都有一个窗口过程对传入的消息进行处理,窗口过程选择不处理某个消息,系统将使用缺省消息处理函数。