设备管理器和 gwes

71
设设设设设设 设设设设设设 GWES GWES www.up-tech.com www.up-tech.com 设设设设 设设设设 设设设设 设设设设

Upload: adie

Post on 13-Jan-2016

256 views

Category:

Documents


4 download

DESCRIPTION

设备管理器和 GWES. www.up-tech.com 博创科技 嵌入互动. 主要内容. 设备管理的基本概念 WinCE 的设备管理 设备管理器的具体实现 GWES 的概念和功能 从应用程序调用 GWES. 1 、设备管理的基本概念. 设备的分类. 按设备的使用特性: 存储设备 输入输出设备 终端设备 。。。 按设备的从属关系 系统设备 用户设备. 设备管理的任务. 选择和分配输入输出设备以便进行数据传输操作 控制输入输出设备和 CPU 之间交换数据 - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 设备管理器和 GWES

设备管理器和设备管理器和 GWESGWES

www.up-tech.comwww.up-tech.com

博创科技 嵌入互动博创科技 嵌入互动

Page 2: 设备管理器和 GWES

主要内容主要内容

• 设备管理的基本概念• WinCE的设备管理• 设备管理器的具体实现• GWES的概念和功能• 从应用程序调用GWES

Page 3: 设备管理器和 GWES

11 、设备管理的基本概念、设备管理的基本概念

Page 4: 设备管理器和 GWES

设备的分类设备的分类• 按设备的使用特性:

– 存储设备– 输入输出设备– 终端设备– 。。。

• 按设备的从属关系– 系统设备– 用户设备

Page 5: 设备管理器和 GWES

设备管理的任务设备管理的任务

• 选择和分配输入输出设备以便进行数据传输操作• 控制输入输出设备和 CPU 之间交换数据• 为用户提供一个友好的透明接口,把用户和设备

硬件特性分开,使得用户在编制应用程序时不必涉及具体设备,系统按用户要求控制设备工作。另外这个接口还为新增加的用户设备提供一个和系统核心相连接的入口,以便用户开发新的设备管理程序。

• 提高设备和设备之间、 CPU 和设备之间,以及进程和进程之间的并行操作度,以使操作系统获得最佳效果。

Page 6: 设备管理器和 GWES

设备管理的功能设备管理的功能• 提供和进程管理系统的接口。当进程要求设备资

源时,该接口将进程要求转达给设备管理程序。• 进行设备分配。按照设备类型和相应的分配算法

把设备和其他有关的硬件分配给请求该设备的进程,并把为分配到所请求设备获取他有关硬件的进程放入到等待队列。

• 实现设备和设备、设备和 CPU 等之间的并行操作。• 进行缓冲区管理。

Page 7: 设备管理器和 GWES

对设备的控制方式对设备的控制方式• 程序直接控制方式• 中断方式

Page 8: 设备管理器和 GWES

22 、、 WinCEWinCE 的设备管理的设备管理

Page 9: 设备管理器和 GWES

设备管理器的概念设备管理器的概念

• 设备管理器是在 Windows CE 操作系统下运行的进程,它跟踪已加载的驱动程序和它们的接口。它连续不断地运行并且从内核中启动。

• 设备管理器可以在设备接口变得可用和不可用时通知用户。用户或系统本身可以使设备接口变得可用或不可用。

• 另外,设备管理器通知内核设备接口支持文件操作(例如, CreateFile)访问公开流接口的设备。

• 设备管理器向设备驱动程序发送电源通知回调并提供电源管理服务。

Page 10: 设备管理器和 GWES

设备管理器和注册表设备管理器和注册表• 设备管理器控制注册表中的 Active 项。• 只有设备管理器应当访问 Active 项以获取

读取或写入访问权限。• 可以通过设备驱动程序的初始化函数的参

数间接访问 Active 项。

Page 11: 设备管理器和 GWES

设备管理器和注册表设备管理器和注册表

• 设备管理器搜索 HKEY_LOCAL_MACHINE\Drivers\RootKey 注册表项,以确定用于开始驱动程序加载过程的项。

• RootKey 的默认值是 Drivers ,但是它通常等于 Drivers\BuiltIn 。

• 设备管理器调用 ActivateDeviceEx 以加载由 Dll 子项的值指定的驱动程序。 Dll 子项的值默认情况下为 BusEnum.dll (也称为总线枚举器)。

• 加载 BusEnum.dll 会使所有设备驱动程序加载。由 ActivateDeviceEx 加载的设备可以从它的 Active 注册表项中读取它的激活句柄。

Page 12: 设备管理器和 GWES

驱动程序的命名驱动程序的命名

• 设备管理器将总线名称与驱动程序相关联。未命名的设备也可以具有总线名称,因为即使应用程序可能无法访问驱动程序,驱动程序也可能被其他驱动程序或系统实体(例如,电源管理器)访问。总线名称可以具有与正规设备名称不同的 ACL 。

• 设备管理器跟踪由驱动程序公布的接口,并且支持基于全局唯一标识符 (GUID) 搜索驱动程序。 IClass 接口可以将接口 GUID 与驱动程序的旧式名称、 $device 名称或 $bus 名称(例如,“ COM1 :” 、“ $device\com1” 或“ $bus\pci_0_3_0” )相关联。

Page 13: 设备管理器和 GWES

公布驱动程序的接口公布驱动程序的接口

• 驱动程序可以通过调用 DMAdvertiseInterface 以编程方式公布接口。 DMAdvertiseInterface 使驱动程序能够将更多可搜索的 GUID 添加到它们的关联列表中。 DMAdvertiseInterface 由 Devmgr.dll 公开,后者还实现了大多数设备管理器功能。因为只有设备管理器可以加载 Devmgr.dll ,所以只有设备驱动程序可以调用 DMAdvertiseInterface 。如果设备驱动程序在卸载时没有公布它的接口的不可用性,则设备管理器会自动清除接口公布通知。

Page 14: 设备管理器和 GWES

设备管理器组成设备管理器组成

• 设备管理器由 Device.exe 和 Devmgr.dll 组成。 Device.exe 包含 Devmgr.dll ,后者实现了核心设备管理器功能。

• 因为设备管理器由两个单独的模块组成,所以设备驱动程序可以直接与设备管理器链接并调用特定的函数而不会引起系统调用的开销。

Page 15: 设备管理器和 GWES

设备管理器组件设备管理器组件组件 说明

devcore 提供核心设备管理器功能。

iorm 提供 I/O 资源管理器功能。 Iorm 是必需的组件且无法移除。Nopmif

pmif Pmif 提供了电源管理器 DLL 入口点的接口。Nopmif 提供了电源管理器入口点的存根版本。

Page 16: 设备管理器和 GWES

设备管理器的体系结构设备管理器的体系结构• 一般操作系统的设备管理都采用分层的管

理模式。 WinCE 在模块组成和划分方面更加具体而实用。

• WinCE 设备管理部分采取了类似 Windows 2000/XP 的结构,大大的简化了中断处理、I/O 访问以及内部管理的机制。

• WinCE 的设备管理包括四个部分。

Page 17: 设备管理器和 GWES

设备管理器的体系结构设备管理器的体系结构• 设备管理器 : 设备管理器是 WinCE 设备管理的核

心机构,他主要负责跟踪、维护系统的设备信息并对设备资源进行调配。

• I/O 资源管理: I/O 资源管理器是设备管理模块内部的重要组成部分,他跟踪了设备驱动程序装载前从注册表信息中初始化所需的系统资源。

• 电源管理器:• 支撑和管理例程库

Page 18: 设备管理器和 GWES

33 、设备管理器的具体实现、设备管理器的具体实现

Page 19: 设备管理器和 GWES

设备加载设备加载• 设备加载的代码被放入 device.c 的 InitDevi

ces 函数中• 此函数已工作了以下一些工作:

– 打开注册表– 读出注册表的 HKEY_LOCAL_MACHINE\Drive

rs\RootKey 键– 激活里面列出的设备

• 具体实现如下:

Page 20: 设备管理器和 GWES

设备加载设备加载

InitDevices(VOID)// 此函数的目的是为了初始化内置的驱动程序,不需要入口函数{

… // Open HLM\Drivers key // status = RegOpenKeyEx(// 打开指定的键 HKEY_LOCAL_MACHINE, DEVLOAD_DRIVERS_KEY, 0, 0, &RootKey);

// 查找 root 键键值,如果没找到则使用当前默认的 root 键,否则打开新的 root 键 ValLen = sizeof(RootKeyPath);

Page 21: 设备管理器和 GWES

设备加载设备加载status = RegQueryValueEx(// 查询 roots RootKey, DEVLOAD_ROOTKEY_VALNAME, NULL, &ValType, (PUCHAR)RootKeyPath, &ValLen); // Close previous root key RegCloseKey(RootKey);// 关闭 (void) ActivateDevice(RootKeyPath, 0);// 将此值传给 ActiveDevice 函数来加载设备}

Page 22: 设备管理器和 GWES

设备加载设备加载• 由上面的代码可以看出,设备加载的过程

依赖于注册表,任何新的设备必须首先在注册表中声明,随后才能被加载

• 设备加载的核心是 ActiveDeviceEx ,此函数没有被公开

• 如果在应用程序中加载一个新的设备,可以调用 ActiveDeviceEx ,这和设备管理器加载设备的过程是相同的。

Page 23: 设备管理器和 GWES

设备管理器中的设备管理器中的 WinMainWinMain

• 设备管理器表现为 device.exe ,这是由源程序编译得到的可执行文件,设备管理器运行在用户模式。对于可执行文件,一般都存在一个主函数。设备管理器的主函数放在 device.c 中,为 WinMain 。

• WinMain 函数完成设备的初始化和加载过程,整个过程分为三个阶段。

Page 24: 设备管理器和 GWES

设备管理器中的设备管理器中的 WinMainWinMain

• 第一阶段:构造基本的数据结构• 第二阶段:装载并初始化设备• 第三阶段:记录下做过的工作,整理• 具体代码分析见下:

Page 25: 设备管理器和 GWES

设备管理器中的设备管理器中的 WinMainWinMain

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 集合

Page 26: 设备管理器和 GWES

设备管理器中的设备管理器中的 WinMainWinMainInitializeDeviceNotifications();// 初始化设备通知结构,在这个结构里包含三个域,第一

// 个是通知链表元素,第二个是广告(?)链表元素,第 // 三个是临界区。在这个函数中分别对这三项进行了初始 // 化。 WINCE 设备管理其中也是广泛应用了临界区,相比 // 核心对象,临界区更快,大量使用临界区可以提高程序 // 的速度

InitializeCriticalSection(&g_devcs);// 设备临界区,全局变量 ResourceInitModule();// 资源初始化模块 ResourceInitFromRegistry(TEXT("Drivers\\Resources"));// 从注册表的项中初始化资源 SetPowerOffHandler((FARPROC)FS_PowerAllDevices);// 设置电源处理函数为 FS_Po

werAllDevices RegisterAPISet(g_hDevApiHandle, SH_DEVMGR_APIS);// 不知道怎么回事 StartDeviceNotifyThread();// 开启设备通知线程

Page 27: 设备管理器和 GWES

设备管理器中的设备管理器中的 WinMainWinMain

// 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);// 设置当

前状态,核心内容未公开

Page 28: 设备管理器和 GWES

设备管理器中的设备管理器中的 WinMainWinMain // See if we are going to have two boot phases hevBootPhase1 = OpenEvent(EVENT_ALL_ACCESS, FALSE, _T("SYSTEM/BootPha

se1"));// 打开事件 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/BootPhase

2"));// 打开第二阶段的事件

Page 29: 设备管理器和 GWES

设备管理器中的设备管理器中的 WinMainWinMain

if (hEvent) {// 如果事件存在 DEBUGMSG(ZONE_BOOTSEQ, (TEXT("DEVICE: Started, waiting for boot phas

e 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

Page 30: 设备管理器和 GWES

设备管理器中的设备管理器中的 WinMainWinMain

else {// 如果事件未打开 DEBUGMSG(ZONE_BOOTSEQ, (TEXT("DEVICE: No boot registry - skipping to bo

ot phase 2\n"))); g_BootPhase = 2;// 进入第二阶段 DevloadInit();// 初始化设备 SignalStarted(_wtol(lpCmdLine)); }

Page 31: 设备管理器和 GWES

设备管理器中的设备管理器中的 WinMainWinMaing_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); }

Page 32: 设备管理器和 GWES

设备管理器中的设备管理器中的 WinMainWinMain

• 函数中用到了几个事件和链表,调用了几个函数• 事件

– g_hCleanEvt– g_hCleanDoneEvt

• 函数– InitOOMSettings() – ProcessAutoDeregisterDevs()– ProcessDyingDevs()– ProcessDyingOpens()– StartDeviceNotifyThread()

• 链表– g_hDevchain– g_DyingDevs– g_lpOpenDevs– g_lpDydingOpens

Page 33: 设备管理器和 GWES

设备管理器中的设备管理器中的 WinMainWinMain

• 通过 WinMain 函数, WinCE 初始化了与设备相关的所有数据结构和函数。

• 注册了 API 函数集,初始化了电源管理,声明了一些标准函数的接口。

• 设备管理器是整个 WinCE 管理设备的基础,在所有的设备运行之前,必须保证设备管理器的初始化成功,任何设备想要被加载,必须在注册表里声明自己,等到设备管理器的加载,或是由应用程序代替设备管理器完成相应的功能。

• 因为设备管理器也属于用户程序,所以应用程序可以部分代替设备管理器的功能。

Page 34: 设备管理器和 GWES

44 、、 GWESGWES 的概念和功能的概念和功能

Page 35: 设备管理器和 GWES

GWESGWES 的概念的概念• 与 Microsoft 的桌面操作系统不同, Windo

ws CE 将 Win32 API 的用户界面 (USER32) 和图形设备接口 (GDI32) 合并成一个新的模块 gwes.exe ,成为 GWES 子系统。GWE 是一个缩写词,其中 G 代表图形,W 代表窗口管理, E 代表事件管理。 GWE 字系统是用户、应用程序和操作系统之间的图形用户界面。

Page 36: 设备管理器和 GWES

GWESGWES 的概念的概念• GWES 支持组成 WinCE 图形用户界面的所有窗

口、对话框、控件、菜单和资源,使用户能够通过执行菜单命令、单机按钮等操作来控制应用程序。 GWE 还以位图、光标、文本以及图标等形式为用户提供信息。即使不具备图形用户界面的基于 WinCE 的平台也使用了 GWE 的基本窗口和消息功能,这些功能提供了在用户、应用程序和操作系统之间进行通信的方法。

Page 37: 设备管理器和 GWES

定制的定制的 GWESGWES

• WinCE 是模块化的操作系统, OEM 厂商可以针对于特定的平台选择软件模块来设计操作系统。

• WinCE 提供了几种预先测试的组建配置放案,这些配置放案可以分为三类:最小配置、中等配置和完全配置。

Page 38: 设备管理器和 GWES

中等配置下的中等配置下的 GWESGWES 包含的功包含的功能能

• 消息处理及用户输入• 电源管理• 提示性发光二极管• GDI ,包括 MS True Type 字体和光栅字体,文本绘制,

调色板和打印。• 可自定义的触摸屏和可校准的用户界面接口。• 网络用户界面接口。• 波形 API 管理器• 输入方法管理器• 窗口和对话框管理器• 可自定义的用户界面接口。

Page 39: 设备管理器和 GWES

GWESGWES 的组件模型的组件模型• 用户输入系统:接受来自键盘、鼠标和手

写笔等设备的消息• 事件管理器:管理消息和消息队列• 窗口管理器:将消息相应发送到对应的窗

口以实现特定的显示。

Page 40: 设备管理器和 GWES

用户输入系统用户输入系统• Windows CE.NET 支持下列类型的用户输入:键

盘,鼠标,触摸屏,软键盘,手写输入等等• 每一个线程有一个特定的窗口称为活动窗口;焦

点窗口能够接受来自键盘的消息;前台线程中的活动窗口是前台窗口

• 所有这些输入设备都被用户输入子系统管理起来。输入子系统还负责处理前台窗口、活动窗口、和焦点窗口。

Page 41: 设备管理器和 GWES

键盘输入键盘输入

• 键盘是许多计算机设备上的一种常用输入方法,Windows CE.NET 提供了一种独立与设备的键盘模型,这使得可以由 OEM 自己决定 Windows CE 设备的键盘布局。

• 键盘驱动程序将每个扫描码翻译或映射为虚拟键码,虚拟键码是用于识别、与硬件无关的数字。

• 将扫描码翻译为虚键码之后,设备驱动程序创建一条包含了所有信息的键盘消息,并将这条消息放在系统的消息队列中。线程消息循环从队列中取出消息并将它发送给线程焦点窗口的窗口过程

Page 42: 设备管理器和 GWES

触摸屏输入触摸屏输入• 在许多 WinCE 设备中,用户通过手写笔和触摸屏

与应用程序交互,手写比喻触摸屏提供了一中直接且直观的鼠标替代物。

• 对应用程序而言,手写笔及触摸屏运行时所产生的时间与鼠标所产生的事件基本一致,可以说是鼠标事件的子集。当用户在屏幕上按下和松开手写笔时,应用程序像处理单击鼠标左键一样处理这些事件;当用户在屏幕上移动手写笔时,应用程序项处理鼠标移动事件一样处理它。

Page 43: 设备管理器和 GWES

软键盘输入软键盘输入• 有很多的 WinCE 设备因位置原因均没有键盘,

WinCE 为这类设备提供了一种通过触摸屏模拟键盘输入的输入方法,这种输入面板结构与软件界面与键盘类似,所以对用户来说也称为软键盘。

• 在用户访问输入面板时, WinCE 创建一个专用的输入面板线程,这个线程创建输入面板窗口并初始化,然后线程进入消息循环,对来自输入面板的消息作出响应。

Page 44: 设备管理器和 GWES

事件管理器事件管理器• WinCE 是事件驱动的操作系统,消息通过

MSG 结构传递。 WinCE 的 MSG 结构包含六个成员,不支持消息钩子。

• 基于 WinCE 的编程要通过消息循环。消息循环是在 Windows 应用程序中的一种循环,他负责接收系统传送过来的消息,并且把它们发送到相应的窗口中,直到所有的消息都发送完毕,消息循环才结束。

Page 45: 设备管理器和 GWES

显示管理显示管理• GWES 的显示管理部分囊括了几乎所有与

显示有关的组件和接口。• 实现了一整套 GDI 对象,其中包括画笔,

画刷,位图、字体等• 采用了与桌面式 Windows 完全不同的调色

板管理机制• 实现了显示驱动程序接口

Page 46: 设备管理器和 GWES

GDIGDI 对象对象• 画笔和画刷• 位图• 字体

Page 47: 设备管理器和 GWES

GDIGDI 对象的使用方法对象的使用方法• 设备上下文• SelectObject

• DeleteObject

Page 48: 设备管理器和 GWES

55 、从应用程序调用、从应用程序调用 GWESGWES

Page 49: 设备管理器和 GWES

GWESGWES 的应用的应用• 消息的处理• 响应键盘和鼠标消息• 绘图函数

Page 50: 设备管理器和 GWES

WindowsWindows 消息的处理消息的处理

• 消息的组成:一个消息由一个消息名称( UINT ),和两个参数( WPARAM , LPARAM )。当用户进行了输入或是窗口的状态发生改变时系统都会发送消息到某一个窗口。

• 一个消息必须由一个窗口接收。在窗口的过程( WNDPROC )中可以对消息进行分析,对自己感兴趣的消息进行处理。

• Windows 程序是事件驱动的,对于一个窗口,它的大部分例行维护是由系统维护的。每个窗口都有一个窗口过程对传入的消息进行处理,窗口过程选择不处理某个消息,系统将使用缺省消息处理函数。

Page 51: 设备管理器和 GWES

窗口过程的声明窗口过程的声明• LRESULT CALLBACK WndProc (HWND hwnd,

UINT message, WPARAM wParam, LPARAM lParam)

• 其中四个参数分别为:接受到消息的窗口句柄,消息码,消息的第一个参数,消息的第二个参数

• 在窗口过程中首先判断消息码得到消息的主类型,随后通过后两个参数得到消息的更进一步的信息。

Page 52: 设备管理器和 GWES

手动发送消息手动发送消息

• SendMessage 和 PostMessage– Windows 操作系统创建的所有窗口都有一个消息队列。应用程序

可以通过使用 函数 SendMessage 和 PostMessage 将消息放置到该队列中。这些函数允许应用程序传递一个标识执行操作的整数标志和两个被称为 WParam 与 LParam 的消息定义数据值。

– 除了有一个主要的不同点, SendMessage 和 PostMessage 函数基本上是一样的。 SendMessage 将消息放置到窗口消息队列中,并阻止消息直到窗口完成对它的处理。 PostMessage 将消息放置到窗口消息队列中并立即返回。

• 函数用法:– LRESULT SendMessage( HWND hWnd, UINT Msg, WPARAM

wParam, LPARAM lParam ); – BOOL PostMessage( HWND hWnd, UINT Msg, WPARAM wPar

am, LPARAM lParam );

Page 53: 设备管理器和 GWES

响应键盘和鼠标的消息响应键盘和鼠标的消息

• 几种键盘消息– WM_CHAR chCharCode = (TCHAR) wParam; lKeyData = lPara

m; – WM_KEYDOWN nVirtKey = (int) wParam; lKeyData = lParam; – WM_KEYUP nVirtKey = (int) wParam; lKeyData = lParam;

• 几种鼠标消息– WM_L(R)BUTTONDBLCLK/ WM_L(R)BUTTONDOWN/ WM_L

(R)BUTTONUP fwKeys = wParam; xPos = LOWORD(lParam); yPos = HIWORD(lParam);

– WM_MOUSEMOVE fwKeys = wParam; xPos = LOWORD(lParam); yPos = HIWORD(lParam);

– WM_MOUSEWHEEL fwKeys = LOWORD(wParam); zDelta = HIWORD(wParam); xPos = LOWORD(lParam); yPos = HIWORD(lParam);

Page 54: 设备管理器和 GWES

WinCEWinCE 绘图绘图• 创建设备上下文• 创建 GDI 设备对象• 选择 GDI 设备对象• 绘图操作• 将 GDI 设备对象选出• 删除自建的 GDI 对象• 删除设备上下文

Page 55: 设备管理器和 GWES

创建设备上下文创建设备上下文• 几个涉及到 DC的函数:

– HDC BeginPaint( HWND hwnd, LPPAINTSTRUCT lpPaint );

– HDC GetDC( HWND hWnd ); – HDC CreateCompatibleDC( HDC hdc );

• 前两个函数可以得到一个屏幕 DC , BeginPaint只能用于对 PAINT 消息的处理中

• 第三个函数用于创建一个与当前 DC 相兼容的 DC

Page 56: 设备管理器和 GWES

设备上下文简介设备上下文简介

• 当想要在图形输出设备(例如屏幕或打印机)上绘制图形时,必须首先获得设备上下文的句柄。先给出这个句柄, Windows 才允许程序使用设备,在 GDI 函数中将句柄作为一个参数传入,向 Windows 标明需要使用的设备。

• 设备上下文中包含许多属性,当 GDI 在不同的设备上工作时都要用到这些属性。使用这些属性可使 GDI 只关心起始和终止坐标的大小,而不必关心有关对象的其他属性,如颜色、背景等等,因为这些都是设备上下文的一部分。

• 设备上下文是连接 Windows 应用程序、设备驱动程序以及输出设备的纽带。

Page 57: 设备管理器和 GWES

GDIGDI 对象对象• GDI 对象是在绘图过程中的主体,只需要

操作 GDI 对象就可以完成常规的绘图过程。• GDI 对象的基类名为 GDIOBJ ,所有的 G

DI 类都是从此派生出来的。• 在 WinCE 下的绘图操作,实际上都是在操

作相应的 GDI 对象,由 GDI 对象将所有的工作进行转化并发送给驱动程序。

Page 58: 设备管理器和 GWES

画笔和画刷画笔和画刷• 画笔和画刷是最基本的用来绘图的工具。这就像

生活中画画一样。首先应该选择用什么样的笔(毛笔或铅笔),再选择画什么样的图形。

• 画笔是一种 GDI 对象,有线宽、线型、颜色等属性。 Windows GDI 提供了两种使用画笔的方法:使用系统备用画笔( Stock Pens )和自定义画笔。

• 画刷也是一种 GDI 对象,应用程序常使用逻辑画刷来填充 Rectangle , Ellipse , Polygon 等图形的内部区域。

Page 59: 设备管理器和 GWES

WinCEWinCE 中的画笔中的画笔• Windows 系统提供了三种备用画笔: BLACK_P

EN , WHITE_PEN 和 NULL_PEN 。如果使用备用画笔,则程序所做的事情就是用函数 GetStockObject 获得备用画笔的句柄,并将希望使用的备用画笔选入设备描述表(在默认情况下,设备描述表已经选入了 BLACK_PEN )中。

• hPen = GetStockObject(WHITE_PEN); • 上面一条语句得到备用画笔的句柄。

Page 60: 设备管理器和 GWES

WinCEWinCE 中的画刷中的画刷

• 一般的画刷是一个 8×8 的位图,利用水平和垂直的重复来填充这些图形的内部区域。有四种类型的逻辑画刷,分别为 solid , stock , hatch 和 pattern 。

• HBRUSH CreateSolidBrush( COLORREF crColor ); 创建一个实心画刷。

• HGDIOBJ GetStockObject( int fnObject ) 得到一个系统库存画刷。

• HBRUSH CreateHatchBrush( int fnStyle, COLORREF clrref ) 创建一个带纹理的画刷。

• HBRUSH CreatePatternBrush( HBITMAP hbmp ) 以为图作为标准创建一个画刷。

Page 61: 设备管理器和 GWES

使用画笔和画刷使用画笔和画刷• 首先创建一个自己的画笔或画刷• 随后将此对象选入设备上下文

– HGDIOBJ SelectObject( HDC hdc, GDIOBJ hgdiobj ) 将指定的 GDI 对象选入 dc 中,并且返回替换出来的对象的句柄。

• 进行相关的绘图操作

Page 62: 设备管理器和 GWES

常见的绘图操作和绘图函数常见的绘图操作和绘图函数

• 画点和画线– COLORREF SetPixel(HDC hdc, int nXPos, int nYPos, COLORR

EF crColor) – COLORRE GetPixel(HDC hdc, int nXPos, int nYPos ) – BOOL LineTo(HDC hdc, int nXEnd, int nYEnd)– BOOL MoveToEx (HDC hdc, int X, int Y, LPPOINT lpPoint)

• 绘制曲线– BOOL Arc( HDC hdc, int nLeftRect, int nTopRect, int nRightRect,

int nBottomRect, int nXStartArc, int nYStartArc, int nXEndArc, int nYEnd

Arc )

Page 63: 设备管理器和 GWES

常见的绘图操作和绘图函数常见的绘图操作和绘图函数

• 绘制填充区域– BOOL Rectangle( HDC hdc, int nLeftRect, int nTopRect,int nRig

htRect, int nBottomRect )– BOOL Ellipse( HDC hdc, int nLeftRect, int nTopRect,int nRightR

ect, int nBottomRect )– BOOL Pie( HDC hdc, int nLeftRect, int nTopRect, int nRightRect,

int nBottomRect, int nXStartArc, int nYStartArc, int nXEndArc, int nYEndArc )

– BOOL RoundRect(HDC hdc, int nLeftRect, int nTopRect,int nRightRect, int nBottomRect,int nWidth, int nHeight)

– BOOL Polygon(HDC hdc, CONST POINT *lpPoints, int nCount)

Page 64: 设备管理器和 GWES

GDIGDI 中的位图中的位图

• 位图是一个位数组,将这个位数组映射到输出设备上的矩形像素数组时,就可以创建图像,用位图可以创建、修改和存储图像。

• WinCE 支持两种类型的位图:设备相关位图( DDB )和设备无关位图( DIB )。设备相关位图没有自己的颜色表,因而只有在与创建位图的设备具有相同的显存结构的设备上才能正确的显示,另一方面,设备无关位图通常具有自己的颜色表,因而可以在多种设备上显示。

• 在基于 WinCE 应用程序中推荐使用 DIB 。

Page 65: 设备管理器和 GWES

创建创建 DIBDIB 的一般方法的一般方法

• HBITMAP CreateDIBSection( HDC hdc, const BITMAPINFO* pbmi, UINT iUsage, void* ppvBits, HANDLE hSection, DWORD dwOffset);• BITMAPINFO 定义了 DIB 的尺寸和颜色信息,这个结构

包括一个 BITMAPINFOHEADE 结构和多个 RGBQUAD结构组成

Page 66: 设备管理器和 GWES

创建创建 DDBDDB 的一般方法的一般方法

• HBITMAP CreateBitmap( int nWidth, int nHeight, UINT cPlanes, UINT cBitsPerPel, CONST VOID* lpvBits);• HBITMAP CreateCompatibleBitmap( HDC hdc, int nWidth, int nHeight);

Page 67: 设备管理器和 GWES

从图像文件创建位图从图像文件创建位图• HBITMAP SHLoadDIBitmap(

LPCTSTR szFileName

)• 这个函数从一个指定的文件中加载位图,文件格

式可以是 BMP 也可以是 JPEG ,函数执行后会返回一个位图句柄,当你不再需要这个位图时要调用 DeleteObject删除这个位图。

Page 68: 设备管理器和 GWES

GDIGDI 的字体的字体• 在 WinCE 中,字体是一组共享相同样式的

图案符号,字体由他的字样、样式和大小表示。

• 在 WinCE 中,字体被分为不同的族,同组内的字体共享相同的笔划宽度特征。同组内的字体有大小和样式进行区分。

Page 69: 设备管理器和 GWES

在程序中使用字体在程序中使用字体• 调用 EnumFontFamilies 生成可用字体列表• 用字体枚举函数的返回值初始化 LOGFON

T 结构成员• 用 CreateFontIndirect 创建逻辑字体,并将

已经初始化的 LOGFONT 结构体指针传入• 用 SelectObject 函数将逻辑字体选入当前

设备上下文

Page 70: 设备管理器和 GWES

内置的六种字体内置的六种字体• WinCE 提供了 6 种标准的逻辑字体,用 G

etStockObject 函数可以获得。• 六种内置的标准字体

– ANSI_FIXED_FONT 等宽字体– ANSI_VAR_FONT 等比例字体– DEVICE_DEFAULT_FONT 设备首选字体– OEM_FIXED_FONT OEM 等宽字体– SYSYTEM_FONT 系统字体

Page 71: 设备管理器和 GWES