1、1,Windows CE基础数据库编程,EDB概述 数据库操作相关API 案例:数据库操作综合示例,2,Windows CE基础数据库编程,EDB概述 数据库操作相关API 案例:数据库操作综合示例,3,EDB概述,在Windows CE中实现的数据库很简单,可以用其自带的数据库系统EDB,作为一个强有力的工具来组织一些不太复杂的数据,例如通讯录或任务列表。 EDB是Windows CE 5.0之后新增的数据库系统,是对CEDB的升级,新增如下功能: 支持事务处理功能 使用计划(schemas)定义数据库结构 支持最多16个字段排序 新增了“流”字段类型 多用户访问,4,基本知识,一个Wind
2、ows CE数据库由一系列的记录组成。记录可以包含任意数目的属性。这些属性可以是下表中数据类型中的一种。,5,Windows CE基础数据库编程,EDB概述 数据库操作相关API 案例:数据库操作综合示例,6,基本知识,数据库卷 数据库卷:是可以存储WINCE数据库的特殊格式的文件。 在WINCE中,如果想把数据库存储在文件中或需要随意拷贝或删除数据库文件,就需要使用数据库卷。与数据库卷对应的是对象存储库,在WINCE2.1以前的版本中数据库都是存放在对象存储库中的,对象存储库不支持拷贝,删除。 数据库卷可以存储在文件系统上而不是存储在对象存储库中,所以数据库信息也能够存储在PC卡或者类似的外
3、部存储设备上。,7,基本知识,使用 Windows CE 数据库时基本步骤: 装入可存储 Windows CE 数据库的卷。 创建数据库(仅限于首次使用时)。 创建会话对象 打开数据库。 在数据库中查找记录或位置,读取记录或写入记录。 关闭数据库 关闭会话对象 卸载数据库卷。,8,与数据库卷相关的API 与数据库相关的API 与记录相关的API,数据库操作相关API,9,与数据库卷相关的API 与数据库相关的API 与记录相关的API,数据库操作相关API,10,装配数据库卷,在WINCE中,如果想把数据库存储在文件中,也就是要使用数据库卷,则必须先装配数据库卷,并且在关闭数据库后,还应卸载数
4、据库卷。 装配数据库卷有两个意思: 新建数据库卷 打开已存在的数据库卷,11,装配数据库卷,BOOL CeMountDBVolEx(PCEGUID pGuid, /指向Guid的指针,数据库卷的标识LPWSTR lpszDBVol,/是装配卷的名称,这不是数据库的名称,而是包含一个或多个数据库的文件的名称。(*.vol)CEVOLUMEOPTIONS* pOptions, /设置新数据库卷的行为和性能DWORD dwFlags);/表示数据库卷被装载的方式如果函数成功的话,返回TRUE,guid被设值,以后会在其他数据库函数里用到。失败的话,调用GetLastError,返回错误。,12,卸载
5、数据库卷,BOOL CeUnmountDBVol (PCEGUID pGuid /表示要卸载的数据卷标识,一般来 说,该参数对应于CeMountDBVol函数中的pGuid); 如果成功卸载数据库卷,函数返回TRUE,否则FALSE. 系统会为每个卷维护一个引用计数,当一个进程装载卷时,引用计数增加1;当进程卸载卷时,引用计数减1。只有当引用计数变为零时系统才会真正卸载数据库卷。,13,列举已装载的数据库卷(8.18),BOOL CeEnumDBVolumes (PCEGUID pGuid, /在调用CeEnumDBVolumes函数前首先pGuid参数要设置为一个无效的值,可以用CREATE
6、_INVALIDEDBGUID宏来设定。LPWSTR pwszName, /用于存储找到的数据库卷名称DWORD cchMaxName/pwsz的长度); CeEnumDBVolumes 返回TRUE 如果一个已挂载的volume被发现,然后这个volume的标识和名称用pGuid和pwszName这2个参数来指向;反之,则返回FALSE值。,14,列举已装载的数据库卷,示例:计算Windows CE系统上的应用程序挂载的数据库卷的数量。CEGUID ceguid; TCHAR szVolumeNameCEDB_MAXDBASENAMELEN; INT nCnt = 0; CREATE_INV
7、ALIDGUID ( / Count the number of mounted volumes. ,15,与数据库卷相关的API 与数据库相关的API 与记录相关的API,数据库操作相关API,16,创建数据库,创建放在数据库卷中的数据库CEOID CeCreateDatabaseWithProps( PCEGUID pGuid, /指向已装配的数据库卷标识CEDBASEINFO *pInfo /指向CEDBASEINFO结构体指针,用来描述被创建的数据库名称、类型、排序方式以及数据库特征等信息。 DWORD cProps, /指定prgProps数组元素个数CEPROPSPEC* prgP
8、rops /字段描述数据,是指向CEPROPSPEC结构体的数组,必须定义这些字段,方可往里面写入数据 ); 若调用成功,返回数据库的对象标识OID,它唯一标识新创建数据库的ID值。如果返回值为NULL,则表示创建数据库失败。,17,创建数据库,typedef struct CEDBASEINFOEXWORD wVersion; /表示此结构体的版本,此值必须设置为2WORD wNumSortOrder; /表示在数据库中能够被激活的排序字段个数,最大值为16DWORD dwFlags; /看下面的介绍WCHAR szDbaseNameCEDB_MAXDBASENAMELEN; /数据库名,最
9、大32字符(包括最后一个0),必须被设定DWORD dwDbaseType;/确定数据库的类型标识,用来区分数据库的类别WORD wNumRecords; /返回数据库中记录数DWORD dwSize; /数据库的大小(字节) EDB中未使用FILETIME ftLastModified; /数据库上次被修改的时间 EDB中未使用SORTORDERSPEC rgSortSpecsCEDB_MAXSORTORDER;/用来存储排序字段的描述 CEDBASEINFOEX;,18,创建数据库,19,创建数据库,typedef struct CEPROPSPECWORD wVersion; /表示此结
10、构体的版本,此值必须设置为1CEPROPID propid; /用来表示数据库中的字段。32位值,低16位表示字段的数据类型,高16位是用户定义的值,用来标识字段DWORD dwFlags; /表示字段标志,DB_PROP_NOTNULL:此字段不能为空,DB_PROP_COMPRESSED:表示此字段将被压缩LPWSTR pwszPropName; /表示字段名称,如果设置为NULL,系统将分配一个内部名称DWORD cchPropName; /表示pwszPropName字符串的长度,最大值为CEDB_MAXDBASENAMELEN(128)CEPROPSPEC;,20,创建会话对象,ED
11、B支持事务功能,EDB数据库的使用都是基于一个会话(Session)链接。函数定义如下:HANDLE CeCreateSession(IN CEGUID* pGuid /表示数据库的GUID );若函数执行成功,则返回会话对象句柄,否则返回INVALID_HANDLE_VALUE。 在数据库使用完毕后,需要调用CloseHandle函数关闭会话对象。如果调用CloseHandle函数关闭会话对象时,此时事务中还有未提交的操作,那么所有操作将被回滚。,21,打开数据库,HANDLE CeOpenDatabaseInSession( HANDLE hSession, /表示会话对象句柄PCEGUI
12、D pceguid, /指向已装配的数据库卷标识PCEOID poid, /指向要被打开的数据库的ID值。如果使用数据库名称来打开数据库,LPWSTR lpwszName, /表示要被打开的数据库的名称。如果参数poid值不为0,那么参数lpszName将被忽略SORTORDERSPECEX* pSort, /指定数据库当前的排序方式CEPROPID propid, /指定打开数据库时使用哪种排序次序来排序数据库DWORD dwFlags, /取值0或CEDB_AUTOINCREMENT.如果指定的是0那么每次从数据库中读取一条记录数据库当前记录指针不会移动。如果是CEDB_AUTOINCRE
13、MENT表示读一次,当前记录指针会移动到下一条记录。CENOTIFYREQUEST* pReq) /该结构用于当其他进程或线程更改了数据库时发送通知消息到一个指定窗口 若调用成功,返回数据库句柄。如果返回值为NULL,则表示创建数据库失败。,22,打开数据库,typedef struct _SORTORDERSPECEX WORD wVersion; /结构体的版本,必须设置为2WORD wNumProps; /排序字段的个数,最大CEDB_MAXSORTPROP(16)WORD wKeyFlags; /排序标志,P260表8-6WORD wReserved; /保留 CEPROPID rgP
14、ropIDCEDB_MAXSORTPROP; /指定排序字段数组DWORD rgdwFlagsCEDB_MAXSORTPROP; /字段排序方式,P260表8-7 ;SORTORDERSPECEX, *PSORTORDERSPECEX;,23,打开数据库,typedef struct _CENOTIFYREQUEST DWORD dwSize; /指定CENOTIFYREQUEST结构的大小 HWND hwnd; /数据库变化时接收通知消息的窗口句柄DWORD dwFlags; /指定了用哪种方式来通知HANDLE hHeap; /Handle to a heap that is used t
15、o allocate the notification structure. If this is NULL, the system allocates memory in the default heap of the process. DWORD dwParam; /User-defined parameter that is returned in the CENOTIFICATION structure when an application is notified of a change. CENOTIFYREQUEST; /每次窗口收到WM_DBNOTIFICATION消息时,都必
16、须释放CENOTIFYREQUEST结构,24,打开数据库,DWORD dwFlags; /指定了用哪种方式来通知 0 : 窗口收到表现为DB_CEOID_xxx的消息。 CEDB_EXNOTIFICATION: 窗口将接收到一种全新的和更详细的通知方法。接收到WM_DBNOTIFICATION消息。当窗口接收到这个消息时,lParam参数会指向CENOTIFICATION结构。typedef struct _CENOTIFICATION DWORD dwSize; /表示该结构的大小DWORD dwParam; /存储在CENOTIFYREQUEST结构中的dwParam成员值UINT uT
17、ype; /表示发送WM_DBNOTIFICATION消息的类型。CEGUID guid; /表示发送消息的数据库卷的标识CEOID oid; /发生改变的对象的对象标识CEOID oidParent; /父对象的对象标识 CENOTIFICATION;,25,打开数据库,UINT uType; /表示发送WM_DBNOTIFICATION消息的类型。,26,事务操作,事务时很多数据库都具备的必要操作,通过事务功能可以使数据保持一致。事务操作的一般原理:首先开始一个事务,然后对数据库进行增、删、改等操作,最后提交事务或者回滚事务。 开始一个事务BOOL CeBeginTransaction(H
18、ANDLE hSession, 表示会话对象句柄CEISOLATIONLEVEL isoLevel 事务的隔 离等级); 事务开始成功,将返回TRUE,否则返回FALSE。一旦事务开始,所有针对此会话对象的操作都不会直接影响到数据库中,直到调用CeEndTransaction函数提交事务或者回滚事务。 结束一个事务BOOL CeEndTransaction(HANDLE hSession,会话对象句柄BOOL fCommit TRUE:提交事务 FALSE:回滚事务 );成功结束事务,函数返回TRUE,否则返回FALSE,27,删除数据库,CeDeleteDatabase函数可以删除数据库卷中
19、的数据库,定义如下:BOOL CeDeleteDatabase( PCEGUID pguid, /要删除的数据库所在的数据库卷标识,由CeMountDbVolEx函数获取CEOID oid /表示要删除的数据库对象标识,oid的值已经被CeCreateDatabaseWithProps()函数生成); 函数成功删除返回TRUE,否则返回FALSE。同样地,可以使用GetLastError函数获取函数执行的错误信息。,28,关闭数据库,BOOL CloseHandle( HANDLE hObject /打开数据库的句柄,由CeOpenDatabaseInSession函数生成 );,29,列举数
20、据库,CeFindFirstDatabaseEx 用于查找第一个数据库并获取一个查找句柄,然后传递给CeFindNextDatabaseEx函数以继续查找数据库。 HANDLE CeFindFirstDatabaseEx (PCEGUID pGuid, /指向已装配的数据库卷标识,如果参数pGuid被设置为NULL或者由CREATE_INVALIDGUID宏生成,那么将查找所有被装载的数据库卷中的数据库DWORD dwDbaseType /确定列举数据库的类型标识,如果参数dwDbaseType被设置为0,那么将列举已装载的数据库卷上的所有数据库。 ); 返回值为列举上下文的句柄表示成功。IN
21、VALID_HANDLE_VALUE表示失败。,30,列举数据库,列举数据库卷中的数据库 CEOID CeFindNextDatabaseEx (HANDLE hEnum, /Handle returned from CeFindFirstDatabaseEx. PCEGUID pGuid /保存查找到的数据库所在的数据库卷的GUID标识 ); 这个函数获取列举上下文中下一个数据库。返回一个有效的CEOID表示成功。0表示失败或是没有额外的数据库。 列举数据库的示例,31,与数据库卷相关的API 与数据库相关的API 与记录相关的API,数据库操作相关API,32,查找或移动记录的指针,CEO
22、ID CeSeekDatabaseEx( HANDLE hDatabase, /表示打开的数据库句柄 DWORD dwSeekType, /描述了如何完成查找操作 DWORD dwValue, /确定用于查找操作的值(可能是查找的偏移量,指向用于搜索的属性值,属性值在CEPROPVAL结构中描述),这个值由dwSeekType的值来决定 LPDWORD lpdwIndex /DWORD类型指针,CeSeekDatabase用于返回通过查找操作找到的记录的基于0的索引。 ); 返回记录的对象标识表示成功;0标识失败。 示例程序P269,33,查找或移动记录的指针,dwSeekType参数的取值,
23、34,查找或移动记录的指针,dwSeekType参数的取值,35,查找或移动记录的指针,CEPROPVAL结构 typedef struct _CEPROPVAL CEPROPID propid; /字段标识,高16位是应用程序定义的标识,低16位是预定义的常量,表示成员val所指定值的数据类型。 WORD wLenData; /未被使用 WORD wFlags; /wFlags定义的标志没有一个用于CeSeekDatabase函数,因此这个字段被设置为0 CEVALUNION val; /字段val是一个联合结构,在实际使用时,应该根据字段的类型选用相应的赋值 CEPROPVAL; 当CEP
24、ROPVAL结构用于查找, propid成员一定要被设置为CeOpenDatabaseEx函数调用时指定的排序字段标识,36,查找或移动记录的指针,typedef union _CEVALUNION short iVal; /两个字节有符号整数 USHORT uiVal; /两个字节无符号整数 long lVal; /四个字节有符号整数 ULONG ulVal; /四个字节无符号整数 FILETIME filetime; /日期时间结构 LPWSTR lpwstr; /以0结束的Unicode字符串 CEBLOB blob; /CEBLOB结构,可以用来存储大对象,例如图片或声音文件等 BOO
25、L boolVal /布尔值 double dblVal /8个字节的有符号值 CEVALUNION;,37,数据库API,与数据库卷相关的API 与数据库相关的API 与记录相关的API 查找或移动记录的指针 读记录 写记录 删除记录,38,读记录,读取当前记录的属性可以使用CeReadRecordProps,定义如下: CEOID CeReadRecordProps(HANDLE hDbase, /已打开的数据库句柄DWORD dwFlags, /0或者CEDB_ALLOWREALLOC LPWORD lpcPropID, /表示rgPropID指向CEPROPID结构的数量,即字段的数量
26、CEPROPID* rgPropID, /指向CEPROPID结构的数组,表示需要读取的字段,如果为NULL表示读取所有字段(lpcPropID为0)LPBYTE* lplpBuffer, /表示缓冲区,存储记录的信息LPDWORD lpcbBuffer);/表示lplpBuffer缓冲区的大小 若函数执行成功,将返回记录对象标识;反之则返回0。,39,数据库API,与数据库卷相关的API 与数据库相关的API 与记录相关的API 查找或移动记录的指针 读记录 写记录 删除记录,40,写记录,CeWriteRecordProps 用于向数据库中添加记录或更改记录 CEOID CeWriteRe
27、cordProps(HANDLE hDbase, /表示要写入的数据库句柄,此句柄将在打开数据库时获得CEOID oidRecord, /表示要写入记录的标识 ,如果参数值为0,表示添加一条新的记录,否则表示更改记录WORD cPropID, /表示要写入记录的字段个数,同时也表示rgPropVal数组的长度,该值必须大于0CEPROPVAL* rgPropVal);/写入的记录信息 如果记录写入成功,函数将返回指向记录对象的标识;如果写入失败,将返回0值。,41,数据库API,与数据库卷相关的API 与数据库相关的API 与记录相关的API 查找或移动记录的指针 读记录 写记录 删除记录,42,删除记录,BOOL CeDeleteRecord( HANDLE hDatabase, /表示要删除记录的数据库句柄 CEOID oidRecord /要删除记录的ID ); 如果记录删除成功,函数将返回TRUE,否则返回FALSE。 如果打开数据库时没有指定CEDB_AUTOINCREMENT 标志,并且删除的是当前记录,那么再次读取记录将发生错误。如果打开数据库时指定了CEDB_AUTOINCREMENT标志,那么删除记录后,当前记录指针将移动到被删除的记录的上一条记录。,43,休息,