在windows phone中,通话记录(Call Log)Api函数只提供只读访问, 如果只获取通话记录我们只需调用PhoneOpenCallLog 和PhoneGetCallLogEntry函数即可。而若想删除通话记录,则需要通过EDB的方式访问windows mobile的系统数据库。请注意WM5之后才支持EDB。关于EDB的更多介绍可以访问Microsoft MSDN,这里只要明确EDB为操作windows mobile phone的方式即可。顺便唠叨一句,WM5之前的版本通过RAPI或者CEDB来访问,可以在MSDN上找到几种方式的不同之处。
由于我想给系统优化软件Optidiy添加这个一键删除通话记录的功能,而且Optidiy是基于C#语言的,所以先是在C#下调用EDB函数。没错,EDB函数也是封装在Coredll.dll中。但是,在C#中调用EDB函数,我遇到了若干问题。比如,EDB数据类型的转译等。在起初的尝试中,我转译了部分EDB的数据类型、数据结构,但是函数总是调用不成功,总是有个NotSupportedException的异常。没办法,于是转战google、bing、baidu等搜索引擎,希望能找到解决办法,但是很遗憾。不过在此过程中,我得到一个信息,opennetcf2.3对于EDB获取Call Log(http://www.opennetcf.com/library/sdf/html/81c02576-086c-5042-d7dd-b62d24e90c0f.htm)的封装完美,所以我们可以借助opennetcf实现该功能。
但是,opennetcf的动态链接库对于该功能来说有些过于臃肿。于是,我想到用vs.net2008中vc++实现这个一键删除通话记录功能的动态链接库。虽然我们知道用EDB方式可以对通话记录进行编辑,但是我们首先要知道通话记录的存储所在。资料显示,windows mobile phone的通话记录(call Log)存储在"//pim.vol"卷的"clog.db"表中。这里的"卷"就是EDB中的库,"clog.db"就是该库中的一个表即为通话记录表,言外之意pim.vol还存在其它类似的表。没错,我们也可以通过pim.vol中的Contacts DataBase获取联系人信息。
那么接下来就是实现该功能的过程:
1、载入卷mount pim.vol 文件
CEGUID m_ceguid=CeMountDBVolEx(&m_ceguid, _T("//pim.vol"), 0 , OPEN_EXISTING)
可以理解为加载数据库
2、打开通话记录数据表, Open Call Log DataBase
HANDLE m_hCallLogDb = CeOpenDatabaseInSession(NULL, &m_ceguid, &m_ceoid, L"clog.db" , NULL, CEDB_AUTOINCREMENT, NULL)
3、遍历clog.db中的通话记录
CEOID m_callLogRecord = CeSeekDatabaseEx(m_hCallLogDb, CEDB_SEEK_END, 0, 0, NULL)//将表记录指针移动到最后一条记录
m_callLogRecord = CeSeekDatabaseEx(m_hCallLogDb, CEDB_SEEK_CURRENT, -1, 0, NULL);//将表记录指针移动到上一条记录
4、删除通话记录
CeDeleteRecord(m_hCallLogDb, m_callLogRecord);
5、保存删除结果,卸载pim.vol卷
CeFlushDBVol(&m_ceguid)
CeUnmountDBVol(&m_ceguid)
具体dll实现如下:
头文件, CallLogApi.h
extern "C" BOOL __declspec(dllexport) __stdcall DelAllCallLog();
源文件, CallLogApi.cpp
#define EDB
#include <Windbase.h>
extern "C"
{
#include <windbase_edb.h>
}
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
return TRUE;
}
#pragma warning(disable : 4995)
BOOL __declspec(dllexport) __stdcall DelAllCallLog()
{
CEGUID m_ceguid;
CREATE_INVALIDGUID(&m_ceguid);
CEOID m_ceoid=0;
HANDLE m_hCallLogDb;
CEOID m_callLogRecord;
if(CeMountDBVolEx(&m_ceguid, _T("//pim.vol"), 0 , OPEN_EXISTING))
{
m_hCallLogDb = CeOpenDatabaseInSession(NULL, &m_ceguid, &m_ceoid, L"clog.db" , NULL, CEDB_AUTOINCREMENT, NULL);
if(m_hCallLogDb != INVALID_HANDLE_VALUE)
{
//从最后一条记录开始删
m_callLogRecord = CeSeekDatabaseEx(m_hCallLogDb, CEDB_SEEK_END, 0, 0, NULL);
while(m_callLogRecord !=0)
{
CeDeleteRecord(m_hCallLogDb, m_callLogRecord);
m_callLogRecord = CeSeekDatabaseEx(m_hCallLogDb, CEDB_SEEK_CURRENT, -1, 0, NULL);
}
}
else
{
//处理错误
}
CloseHandle(m_hCallLogDb);
CeFlushDBVol(&m_ceguid);
CeUnmountDBVol(&m_ceguid);
}
return TRUE;
}
//注:这里只是一个测试DLL,所以返回值控制不是很严谨。
6、C#调用方式
[DllImport("CallLogApi.dll")]
public static extern bool DelAllCallLog();
自此,我们就实现了一键删除windows mobile phone通话记录功能了,该功能实现环境如下:
编译环境: windows xp sp3, vs.net 2008 vc++ c#
运行环境: dopod838 windows mobile 6.5
注: 编译的程序要在真实手机环境下测试运行,在模拟器下调用CeOpenDatabaseInSession会出错,GetLastError代码为120(系统不支持该功能),猜测为模拟下的pim.vol卷中不存在clog.db
GOOD LUCK!!!