要增加联系人,无论如何要打开对象数据库.所以监听的应用程序打开一个对象数据库句柄,注册一个事件窗口,然后其它进程或线程改变数据库时就会通知注册的窗口,这其实是为了程序员自己对记录加锁用的事件.
因为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;
}
至于是删除了还是增了还是修改你可以具体处理相应的参数.
测试时先打开数据库,从开始->找到联系人管理工具增加一个联系人,退出联系人工具会看到这个窗口弹出一条消息.修改,删除也是一样.如果打开数据库后就关闭,虽然这个程序的窗口还在,但在联系人工具中修改,增加,删除都没有收到消息.
所以这不是注册真正的事件,只是在打开数据库时得到其它进程和线程修改数据库的通知,为了安全起见.但如果你一直打开着数据库就可以监听数据库的变化.
对于需要监听其它对象的数据同样适用.