Chinaunix首页 | 论坛 | 博客
  • 博客访问: 231574
  • 博文数量: 68
  • 博客积分: 2010
  • 博客等级: 大尉
  • 技术积分: 612
  • 用 户 组: 普通用户
  • 注册时间: 2007-01-04 22:38
文章分类

全部博文(68)

文章存档

2010年(2)

2009年(12)

2008年(54)

我的朋友

分类: 数据库开发技术

2008-12-09 13:12:58

    因为近几日,需要进行数据库编程,用的是微软的EDB,但是在网上查询到它是不支持SQL语句的,自我感觉很是郁闷,不过,用还是要用的,在网上查了一些资料,列举出来,如下所示:
【学习笔记】WINCE数据库编程--CE自带数据库
2007年05月14日 星期一 下午 05:05
支持4种排序索引,新版本支持外部介质得存储。不支持锁定,但是可以通过提供消息来通知其他进程已经修改了数据库。
支持9种字段的数据类型
   iVal, uiVal, lVal, ulVal, filetime, lpwstr, blob, BoolVal,dblVal
1。装配数据库卷
数据库卷是可以存储WINCE数据库的特殊格式的文件。
   BOOL CeMountDBVol( PCEGUID pceguid, LPWSTR lpszDBVol, DWORD dwFlags );
数据库卷可以在同一时间被多个进程打开,系统会维护卷的引用计数。在最后一个进程卸下数据库卷之后,系统才卸下这个卷。
2。卸载数据库卷
BOOL CeUnmountDBVol( PCEGUID pceguid );
3。列举已装配的数据库卷
BOOL CeEnumDBVolumes( PCEGUID pceguid, LPWSTR lpBuf, DWORD dwNumChars );
4。创建数据库
(1)CeCreateDatabase
老API,只能创建存放在对象存储库中的数据库。
   CEOID CeCreateDatabase(
    LPWSTR lpszName,
    DWORD dwDbaseType,
    WORD wNumSortOrder,
    SORTORDERSPEC* rgSortSpecs
   );
(2)CeCreateDatabaseEx
   CEOID CeCreateDatabaseEx(
    PCEGUID pceguid,
    CEDBASEINFO* lpCEDBInfo
   );
5。打开数据库
(1)CeOpenDatabase
   HANDLE CeOpenDatabase(
    PCEOID poid, LPWSTR lpszName,
    CEPROPID propid, DWORD dwFlags,
    HWND hwndNotify
   );
参数lpszName为指定的数据库的名称,如果poid不为0的话将被忽略。dwFlags的取值可以是0或者CEDB_AUTOINCREMENT,如果是后者的话,那么每次从数据库中读取一个记录,都将导致数据库当前指针按照排序次序移动到下一条记录。
hwndNotify表示当另一个进程或线程更改了数据库时要通知的窗口句柄,这种基于消息的通知,允许用户在打开数据库的情况下监视它的变化。
(2)CeOpenDatabaseEx
   HANDLE CeOpenDatabaseEx(
    PCEGUID pceguid, PCEOID poid,
    LPWSTR lpszName, CEPROPID propid,
    DWORD dwFlags, CENOTIFYREQUEST *pRequest
   );
pRequest为指向CENOTIFYREQUEST结构的指针,该结构用于当其他进程或线程更改了数据库时发送通知消息到一个指定的窗口。
   typedef struct _CENOTIFYREQUEST{
    DWORD dwSize;
    HWND hWnd;
    DWORD dwFlags;
    HANDLE hHeap;
    DWORD dwParam;
   } CENOTIFYREQUEST;
在使用完该结构后,只需要调用CeFreeNotification函数来释放它即可。
   BOOL CeFreeNotification( PCENOTIFYREQUEST pRequest, PCENOTIFICATION pNotify );
6。删除数据库
CeDeleteDatabase和CeDeleteDatabaseEx
若要删除对象库中的数据库,可以用:
   BOOL CeDeleteDatabase( CEOID oidDbase );
要删除数据库卷中的数据库
   BOOL CeDeleteDatabaseEx( PCEGUID pguid, CEOID oid );
7。列举数据库
WINCE有两套API来列举数据库,一组用来列举对象存储库中的数据库,一组用来列举数据库卷中的数据库。每一组API函数都由两个函数组成, CeFindFirstDatabase用于查找第一个数据库并获取一个查找句柄,然后传递给CeFindNextDatabase函数继续查找数据库。 CeFindFirstDatabase函数只是进行搜索,并不返回数据库对象。
第一组查找API函数
   HANDLE CeFindFirstDatabase( DWORD dwDbaseType );
   CEOID CeFindNextDatabase( HANDLE hEnum );
第二组查找API函数
   HANDLE CeFindFirstDatabaseEx( PCEGUID pceguid, DWORD dwDbaseType );
   CEOID CeFindNextDatabaseEx( HANDLE hEnum, PCEGUID pceguid );
若pceguid被设置为NULL,那么将查找系统中所有被装载的数据库卷,若dwDbaseType被设置为0,那么将数据库卷或对象存储库中的所有数据库。
8。查找或移动记录
CeSeekDatabase函数查找数据库或移动数据库指针,该函数在查找记录的同时,还设置了数据库的当前指针。若查找到了相应的记录,则返回此记录对象标识,否则返回0值。
   CEOID CeSeekDatabase(
    HANDLE hDatabase, DWORD dwSeekType,
    DWORD dwValue, LPDWORD lpdwIndex
   );
9。写记录
   CEOID CeWriteRecordProps( HANDLE hDbase, CEOID oidRecord, WORD cPropID,
     CEPROPVAL * rgPropVal );
10。读取记录
   CEOID CeReadRecordProps(
    HANDLE hDbase, DWORD dwFlags,
    LPWORD lpcPropID, CEPROPID * rgPropID,
    LPBYTE *lplpBuffer, LPDWORD lpcbBuffer

   );
11。删除记录
   BOOL CeDeleteRecord( HANDLE hDatabase, CEOID oidRecord );
 
上边的是各种函数,真正涉及到监听的心得又是体会如下:

前几天对一个贴子进行讨论,在调试时有很多值得注意的地方,现在列举出来.

原来的问题是如何知道增加了一个联系人.

要增加联系人,无论如何要打开对象数据库.所以监听的应用程序打开一个对象数据库句柄,注册一个事件窗口,然后其它进程或线程改变数据库时就会通知注册的窗口,这其实是为了程序员自己对记录加锁用的事件.
因为CE的数据库不支持记录锁定,所以如果有其它进程或线程要修改数据会发一个通知给注册的窗口句柄.



监听窗口要一直保持着打开的句柄才能接收到消息,如果关闭了数据库句柄就不会收了消息了.即使你的窗口没有关闭也没有用,所以它不是注册一个真正的事件.

打开联系人数据库有以下几个注意点:
一是数据库卷,我不知道它所在的文件名是什么,只是卷的名称叫"SystemHeap",所以要牧举所有卷,找到名为"SystemHeap"的卷才是系统对象数据库所在的数据库卷:
 CEGUID ceguid;
 TCHAR szVolName[MAX_PATH +1];
 CREATE_INVALIDGUID(&ceguid);
 while(::CeEnumDBVolumes(&ceguid,szVolName,MAX_PATH)){
  if(wcsnicmp(L"SystemHeap",szVolName,10)==0){
   /////将当前数据库卷定位到SystemHeap上
   break;
  }
 }

得到这个guid.

另外一点,文档中说在打开数据库时,如果CEOID为0,则根据名字打开数据库,不是在调时传入0:
hdDB = ::CeOpenDatabaseEx(&ceguid,0,L"Contacts Database",0,0,pRequest);
这句根本打不开数据库.应该是先让ceoid为0,然后传入ceoid:
 CEOID ceoid;
 ceoid = 0;

 pRequest = (CENOTIFYREQUEST *) LocalAlloc(LPTR,sizeof(CENOTIFYREQUEST));
 pRequest->dwSize = sizeof(CENOTIFYREQUEST);
 pRequest->hwnd = this->m_hWnd;
 pRequest->hHeap = NULL;
 pRequest->dwFlags = CEDB_EXNOTIFICATION;

 /////打开联系人数据库,并注册事件
 hdDB = ::CeOpenDatabaseEx(&ceguid,&ceoid,L"Contacts Database",0,0,pRequest);

 if(hdDB == INVALID_HANDLE_VALUE){
  MessageBox(L"打开失败");
  return;
 }
 MessageBox(L"已经打开联系人数据库");

打开后要一直保持hdDB才能收到其它线程改变该数据库的消息.不能关闭.

然后就是处理WM_DBNOTIFICATION消息了,你在Main中GetMessage也行,我用MFC,直接注册这个消息:
h文件中声明消息处理涵数:
afx_msg LRESULT OnMessageAdd(WPARAM wparam, LPARAM lparam);
在cpp文件的消息映射中加上:
ON_MESSAGE(WM_DBNOTIFICATION,OnMessageAdd)
关加上实现代码:

LRESULT CContactsChangeListenerDlg::OnMessageAdd(WPARAM wparam, LPARAM lparam){
 PCENOTIFICATION pCeNotify=(CENOTIFICATION*)lparam;
 CeFreeNotification(pRequest, pCeNotify);
 MessageBox(L"有一个程序打开了数据库!");
 return TRUE;
}

至于是删除了还是增了还是修改你可以具体处理相应的参数.

测试时先打开数据库,从开始->找到联系人管理工具增加一个联系人,退出联系人工具会看到这个窗口弹出一条消息.修改,删除也是一样.如果打开数据库后就关闭,虽然这个程序的窗口还在,但在联系人工具中修改,增加,删除都没有收到消息.

所以这不是注册真正的事件,只是在打开数据库时得到其它进程和线程修改数据库的通知,为了安全起见.但如果你一直打开着数据库就可以监听数据库的变化.

对于需要监听其它对象的数据同样适用。

阅读(3650) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2009-07-15 11:13:02

EDB貌似很好用,真恶心我们的项目还要用自己学校开发的数据库,悲剧