在做sms备份的时候,我们首先考虑的是采用mapi的形式将sms的具体内容读出来在还原的时候写回去,事实证明,这种方法是可行但是不可取的!
这里先看看mapi是怎么读取的,这个过程中参考了无聊客写的东西,并得到我们老员工的指点。
定义以下两个宏,方便使用:
#define EXIT_ON_FAILED(_hr)/
if (FAILED(_hr))/
{ /
goto FuncExit; /
}
#define RELEASE_OBJ(s) /
if (s != NULL) /
{ /
s->Release(); /
s = NULL; /
}
初始化mapi :
HRESULT InitMAPI( )
{
CoInitializeEx(NULL, COINIT_MULTITHREADED);
MAPIInitialize(NULL);
// First logon to the store.
MAPILogonEx(NULL, NULL, NULL, NULL, &m_pSession);
if( !m_pSession )
return E_FAIL ;
return S_OK ;
}
// Get the message stores table
hr = m_pSession->GetMsgStoresTable(MAPI_UNICODE, &pStoresTable);
// 定义ULONG ProgColumns[] = { 2, PR_ENTRYID, PR_DISPLAY_NAME };来得到属性
hr = pStoresTable->SetColumns((LPSPropTagArray)&ProgColumns, 0);
EXIT_ON_FAILED(hr);
以上初始化mapi并获取store以及table!
下面使用QueryRows方法来获取我们需要的特定的store
while(SUCCEEDED(pStoresTable->QueryRows(1, 0, &pStoresRows)))
{
if (pStoresRows->cRows != 1)
break;
else if ((pStoresRows->aRow[0].cValues < 1)
|| (pStoresRows->aRow[0].lpProps[0].ulPropTag != PR_ENTRYID))
break ;
else
{
if (_tcsicmp(pStoresRows->aRow[0].lpProps[1].Value.lpszW, _T("SMS")) == 0)
//这里是获取SMS信息的,而其他的还有ActiveSyne、MMS(等等,如果有相应帐户的话...)
{
ULONG ulMesageType;
hr = m_pSession->OpenEntry(pStoresRows->aRow[0].lpProps[0].Value.bin.cb,
(LPENTRYID)pStoresRows->aRow[0].lpProps[0].Value.bin.lpb,
NULL,
NULL,
&ulMesageType,
(LPUNKNOWN*)&pSMSStore);
//得到该store后,后面要用该store来获取IMessage对象
EXIT_ON_FAILED(hr);
break;
}
FreeProws(pStoresRows);
pStoresRows = NULL;
}
}
if( pStoresRows )
{
FreeProws(pStoresRows);
pStoresRows = NULL;
}
RELEASE_OBJ( pStoresTable );
释放对象尽早做吧,下面就用得到的SMS store来获取SMS的属性以及其他的SMS的Folder.
ULONG ProgColumns_SubTree[] = { 1, PR_IPM_SUBTREE_ENTRYID };
SPropValue * pProgValue_SubFolders = NULL;
// Get Root Folder
hr = pSMSStore->GetProps((LPSPropTagArray) ProgColumns_SubTree, MAPI_UNICODE, &ulValues, &pProgValue_SubTree);
EXIT_ON_FAILED(hr);
hr = pSMSStore->OpenEntry(pProgValue_SubTree[0].Value.bin.cb, (LPENTRYID)pProgValue_SubTree[0].Value.bin.lpb,
NULL,
NULL,
NULL,
(LPUNKNOWN*)&pSMSFolder);
MAPIFreeBuffer(pProgValue_SubTree);
//has sub folder or not
hr = pSMSFolder->GetProps((LPSPropTagArray) ProgColumns_SubFolders, MAPI_UNICODE, &ulValues, &pProgValue_SubFolders);
if( pProgValue_SubFolders[0].Value.b > 0 )
//判断该foler 下是否有sub folder,有则进一步获取message
hr = pFolder->GetContentsTable(0, &pContentsTable);
hr = pContentsTable->SetColumns((LPSPropTagArray)&ProgColumns_Contents, 0);
//基本同上面,获取Table的方式有变,查错的步骤省略
hr = pFolder->OpenEntry( pRows->aRow[0].lpProps[0].Value.bin.cb,
(LPENTRYID)pRows->aRow[0].lpProps[0].Value.bin.lpb,
NULL,
MAPI_BEST_ACCESS,
&ulMesageType,
(LPUNKNOWN*)&pMessage);
//得到message,下面便可以对message操作了。
//SMS中,利用MAPI读出来的分两部分处理,一是联系人部分,另外是内容部分。SMS的内容存放在SUBJECT属性下,而到了OutLook信息中,SUBJECT部分则存放了信息的主题,而内容要采取Istream的方式读取。由于outlook的稍微复杂点,所以下面是写出了outlook的读取方式,存储在自己定义的BackupTemp结构体中
hr = pMessage->GetProps((LPSPropTagArray) ProgColomns, MAPI_UNICODE, &ulCount, &pProgValue);
if (SUCCEEDED(hr))
{
if (pProgValue[0].ulPropTag == PR_SENDER_EMAIL_ADDRESS)
wcscpy( pBackupTemp->bkupHeader.szAddress , pProgValue[0].Value.lpszW);
if (pProgValue[1].ulPropTag == PR_SUBJECT)
wcscpy( pBackupTemp->bkupHeader.szSubject , pProgValue[1].Value.lpszW);
if (pProgValue[2].ulPropTag == PR_MESSAGE_DELIVERY_TIME)
pBackupTemp->bkupHeader.ftEmailTime = pProgValue[2].Value.ft;
MAPIFreeBuffer(pProgValue);
}
hr = pMessage->OpenProperty( PR_BODY, &IID_IStream, MAPI_BEST_ACCESS, NULL,
(LPUNKNOWN*) &pStream);
if(hr == S_OK)
{
pStream->Read(pBackupTemp->bkupHeader.szBody, 1024*sizeof(WCHAR), &ulNumChars);
}
本方法下面读去mail的附件以及mms内容都比较的复杂,而且在还原的时候没办法兼顾所以对象的属性(一个pim联系人的属性就有四十多项),不适合备份!
接下来我要做的事情又与mapi有关,我会来完善这篇文章并不断地修正
另外读取pim.vol的办法我也会讲明,不过对于备份来讲,pim文件可以直接拷贝还原,所以就不需要那么麻烦了