作者:金海建
背景:Windows Mobile默认情况下,SIM卡中的联系人会同步到contact DB中。这个工作是由cprog.exe(电话程序)来完成,当插卡开机,注册到网络后(或者手机使用中由飞行模式进入待机模式),cprog.exe会 删除数据库中带有SIM标志的联系人记录,然后从SIM卡中重新导入。由于项目需要,我们不让cprog.exe运行,那么完成联系人导入的工作,只能交 给自己的程序来处理。
涉及技术: POOM、EDB、SIM API
分析研究: 联系人数据库有四张表,分别是Contact Database、PIMNamedPropTags、PIMNamedPropVals和PINnamedPropValsIndexed
在pim.vol中
Contact Database数据库:存放联系人数据
0x10000066: 在pimstore.h的定义是PIMPR_OID,这个字段是Contact Database的OID,它会被PIMNamedPropV als和PINnamedPropValsIndexed引用到。比如OID是0x00000001,那么在PIMNamedPropVals的 0x00010013的值就是0x80000001。就是把OID最高位置1,变成PIMNamedPropVals的主键。这就建立了Contact Database、PIMNamedPropVals和PINnamedPropValsIndexed这三张表的关联了。
PIMNamedPropTags 存放扩展的字段,一般用get name的方式来得到其Tag的值.
0x0082001F:在pimstore.h的定义是PIMPR_FIRST_NAME
0x0096001F:在pimstore.h的定义是 PIMPR_MOBILE_TELEPHONE_NUMBER
0x0080001F:在pimstore.h的定义是PIMPR_FILEAS
0x001B0013:在pimstore.h的定义是PIMPR_SOURCE_ID, 表示什么类型的联系人,SIM卡联系人为0。
0x01020013:在pimstore.h的定义是PIMPR_CONTACT_TYPE, 表示是否是SIM卡联系人。1为SIM卡联系人
0x10100013:在pimstore.h的定义是PIMPR_DO_NOT_SYNC, 表示是否通过Activesync同Outlook中的联系人进行同步。SIM卡联系人这个值为零。
其他字段:SIM卡联系人只涉及到上面7个属性值(Property Type)、其他不做解释。
PIMNamedPropTags数据库: 这个数据库存放系统中没有定义微软没有定义出的Prop Type,而且它的Prop ID会随着不同的环境而不同,所以在写程序的时候,是根据上层提供相应的接口,根据它的Name得到Prop ID。它的每列有三个Prop Type(微软没有定义)。
0x0001001F:Property Name。
0x00020013:Property Name对应的Property ID。
0x00030013:未知,应该是保留的,该属性的值为零。
如果PINNamedPropTags数据中还没有建立有关SIM卡的Named PropTags。那么就需要自己来建立。我们可以设置一个默认的属性值。创建代码如下:
- typedef struct PIMNamedInfo_tag {
- TCHAR szTagName[128];
- DWORD dwTag;
- DWORD reserve;
- }PIMNamedInfo;
-
- PIMNamedInfo g_defaultSIMNamedInfo[] ={
- {TEXT("BusinessTelephoneNumberSimPos"), 0x80020013,0},
- {TEXT("Business2TelephoneNumberSimPos"), 0x80030013,0},
- {TEXT("MobileTelephoneNumberSimPos"), 0x80040013,0},
- {TEXT("HomeTelephoneNumberSimPos"), 0x80050013,0},
- {TEXT("Home2TelephoneNumberSimPos"), 0x80060013,0},
- {TEXT("CarTelephoneNumberSimPos"), 0x80070013,0},
- {TEXT("CompanyTelephoneNumberSimPos"), 0x80080013,0},
- {TEXT("RadioTelephoneNumberSimPos"), 0x80090013,0},
- {TEXT("AssistantTelephoneNumberSimPos"), 0x800A0013,0},
- {TEXT("PagerNumberSimPos"), 0x800B0013,0},
- {TEXT("BusinessFaxNumberSimPos"), 0x800C0013,0},
- {TEXT("HomeFaxNumberSimPos"), 0x800D0013,0},
- {TEXT("SIM_INDEX"), 0x800E0013,0}
- };
-
- BOOL SetDefaultSIMNamePropTags(){
- CEPROPVAL props[3];
- DWORD dwTotalRecords = 0;
- CEOID oidRec;
- BOOL fRet = TRUE;
- if(! m_hPIMNamedPropTagsDB || INVALID_HANDLE_VALUE == m_hPIMNamedPropTagsDB)
- {
- goto Cleanup;
- }
- DWORD dwTagID = 0x80000013;
- DWORD dwTagIncress = 0;
- for (int i=0; i < sizeof(g_defaultSIMNamedInfo)
- /sizeof(g_defaultSIMNamedInfo[0]); i++)
- {
- ZeroMemory(props, sizeof(props));
- props[0].propid = PIMPR_PIMNAMEDTAG_NAME;
- props[0].val.lpwstr = g_defaultSIMNamedInfo[i].szTagName;
- dwTagIncress = m_PIMNamedPropTags.size();
- g_defaultSIMNamedInfo[i].dwTag = (dwTagID | (dwTagIncress << 16));
- props[1].propid = PIMPR_PIMNAMEDTAG_VALUE;
- props[1].val.ulVal = g_defaultSIMNamedInfo[i].dwTag;
- props[2].propid = PIMPR_PIMNAMEDTAG_UNKOWN;
- props[2].val.ulVal = 0;
- oidRec = CeWriteRecordProps(m_hPIMNamedPropTagsDB, 0, 3, props);
- if (!(oidRec))
- {
- fRet = FALSE;
- goto Cleanup;
- }
- m_PIMNamedPropTags.push_back(g_defaultSIMNamedInfo[i]);
- }
- Cleanup:
- return fRet;
- }
其中我们同步SIM卡联系人需要用到的有两个Prop。一个是SIM_INDEX,这个就是存放联系人在SIM卡上的Index(索引)。 另一个是MobileTelephoneNumberSimPos, 按照字面意思是电话号码在SIM卡中的位置,大家可以看到上面代码中还有很多XXXSimPos的名字,估计是有些SIM卡的一条联系人可以有多个号码。 用这个Index来表示它的位置。
PIMNamedPropVals数据库:存储某个联系人Named Prop的值。
0x00010013: 对应与contact中的oid,并把最高位置1。这样就可以根据Contact DB某条记录的oid,到PIMNamedPropVals数据库中找到相应的Named Prop Value了。
0x00020013: 对应PIMNamedPropTags中的Prop ID。
0x00030041: BLOB值,不同Prop有不同的值。其中SIM_INDEX,是一个结构体
typedef struct PIMNAMEDVALUE_INFO_tag
{
WORD wIndex;
WORD wReserve;
}PIMNAMEDVALUE_INFO;
而MobileTelephoneNumberSimPos,这个值,设置成0就可以了。
PINnamedPropValsIndexed数据库:该数据库作用不是非常大(可有可无),估计是做快速索引用的。
0x00010013: 对应于contact中的oid,最高位为1
0x00020013: 制定该Value的类别,是号码类型,还是其他类型。号码类型,0x00030013设置为0x302A001F
0x00030041: BLOB值,字符串。号码或者email
0x00040013: 是否也存在SIM卡上。
代码示例:
- void ImportFormSIM(){
- HSIM hSim = NULL;
- DWORD dwUsedCount=0;
- DWORD dwUsed = 0, dwTotal = 0;
- SIMPHONEBOOKENTRY simPhoneEntry;
- if(FAILED(SimInitialize(NULL, NULL,0,&hSim)))
- goto Error;
- if(S_OK != SimGetPhonebookStatus(hSim, SIM_PBSTORAGE_SIM,
- &dwUsed, &dwTotal))
- {
- goto Error;
- }
- LoadNamedPropTags();
- for (int i=1; i <= dwTotal; i++)
- {
- if(dwUsedCount >= dwUsed)
- break;
- ZeroMemory(&simPhoneEntry, sizeof(simPhoneEntry));
- simPhoneEntry.cbSize = sizeof(simPhoneEntry);
- if(S_OK == SimReadPhonebookEntry(hSim,
- SIM_PBSTORAGE_SIM, i, &simPhoneEntry))
- {
- DWORD dwOID = WriteSIMContact2DB(&simPhoneEntry, i);
- dwUsedCount++;
- }
- }
- Error:
- if(hSim)
- SimDeinitialize(hSim);
- }
-
- BOOL WriteSIMContact2DB(SIMPHONEBOOKENTRY *psimPhoneEntry, int index){
- CEPROPVAL props[6];
- DWORD dwTotalRecords = 0;
- CEOID oidRec;
- BOOL fRet = TRUE;
- ZeroMemory(props, sizeof(props));
- if(! m_hDB || INVALID_HANDLE_VALUE == m_hDB)
- {
- goto Cleanup;
- }
- props[0].propid = PIMPR_FILEAS;
- props[0].val.lpwstr = psimPhoneEntry->lpszText;
- props[1].propid = PIMPR_FIRST_NAME;
- props[1].val.lpwstr = psimPhoneEntry->lpszText;
- props[2].propid = PIMPR_MOBILE_TELEPHONE_NUMBER;
- props[2].val.lpwstr = psimPhoneEntry->lpszAddress;
- props[3].propid = PIMPR_CONTACT_TYPE;
- props[3].val.ulVal = 1;
- props[4].propid = PIMPR_DO_NOT_SYNC;
- props[4].val.ulVal = 1;
- props[5].propid = PIMPR_SOURCE_ID;
- props[5].val.ulVal = 0;
- oidRec = CeWriteRecordProps(m_hDB, 0, 6, props);
- if (!(oidRec))
- {
- fRet = FALSE;
- goto Cleanup;
- }
- CEPROPVAL*pRecord = NULL;
- WORD wNumProps = 1 ;
- DWORD dwBufSize = 0;
- CEPROPID propID[1]={PIMPR_OID};
- dwBufSize = 0;
- CeReadRecordPropsEx(m_hDB, 0, &wNumProps, propID,
- (LPBYTE *)&pRecord, &dwBufSize, NULL);
- pRecord = (CEPROPVAL *) LocalAlloc(0, dwBufSize);
- CeReadRecordPropsEx(m_hDB, 0, &wNumProps, propID,
- (LPBYTE *)&pRecord, &dwBufSize, NULL);
- AddnamePropIndexed(pRecord[0].val.ulVal | 0X80000000,
- psimPhoneEntry->lpszAddress);
- AddNamedPropValues(pRecord[0].val.ulVal | 0X80000000, index);
- LocalFree(pRecord);
-
- Cleanup:
- if(fRet)
- return (pRecord[0].val.ulVal | 0X80000000);
- else
- return fRet;
- }
-
- BOOL AddNamedPropValues(CEOID ceOid, DWORD dwIndex){
- CEPROPVAL props[3];
- DWORD dwTotalRecords = 0;
- CEOID oidRec;
- BOOL fRet = TRUE;
- PIMNAMEDVALUE_INFO nameValue;
- nameValue.wIndex = 0;
- nameValue.wReserve = 0;
- ZeroMemory(props, sizeof(props));
- if(! m_hDB || INVALID_HANDLE_VALUE == m_hDB)
- {
- goto Cleanup;
- }
- props[0].propid = PIMPR_PIMNAMEDVALUS_VALUES_OID;
- props[0].val.ulVal = ceOid;
- props[1].propid = PIMPR_PIMNAMEDVALUS_VALUES_TAG;
- props[1].val.ulVal = GetIDOfNames(L"MobileTelephoneNumberSimPos");
- props[2].propid = PIMPR_PIMNAMEDVALUS_VALUES_INFO;
- props[2].val.blob.lpb = (BYTE *)&nameValue;
- props[2].val.blob.dwCount = sizeof(PIMNAMEDVALUE_INFO);
- oidRec = CeWriteRecordProps(m_hPIMNamedPropValsDB, 0, 3, props);
- if (!(oidRec))
- {
- fRet = FALSE;
- goto Cleanup;
- }
- nameValue.wIndex = dwIndex;
- nameValue.wReserve = 0;
- props[0].propid = PIMPR_PIMNAMEDVALUS_VALUES_OID;
- props[0].val.ulVal = ceOid;
- props[1].propid = PIMPR_PIMNAMEDVALUS_VALUES_TAG;
- props[1].val.ulVal = GetIDOfNames(L"SIM_INDEX");
- props[2].propid = PIMPR_PIMNAMEDVALUS_VALUES_INFO;
- props[2].val.blob.lpb = (BYTE *)&nameValue;
- props[2].val.blob.dwCount = sizeof(PIMNAMEDVALUE_INFO);
- oidRec = CeWriteRecordProps(m_hPIMNamedPropValsDB, 0, 3, props);
- if (!(oidRec))
- {
- fRet = FALSE;
- goto Cleanup;
- }
-
- Cleanup:
- return fRet;
- }
OK了。
(jinhaijian) |