POOM操作:IContact、IItem、IPOutlookItemCollection、IPoutlookApp操作
一.基礎知識
POOM是基於微軟COM技術的一套針對手機上(PIM)個人資訊管理的COM介面庫。因此開發人員除了熟悉Mobile開發的基本技術外,還必須對COM技術有一定瞭解和熟悉,知道基本COM使用方法即可。詳細的COM知識請參考相關COM書籍。下面的概念我認為必須掌握:
1. COM的初始化、卸載
2. 介面查詢、獲得
3. COM中字串操作
4. ISteam的使用(後續會在操作連絡人照片時就會使用到)
二.POOM對象介面類介紹
POOM不僅包含了對連絡人的操作,還包含了任務、約會提醒等關於個人資訊管理的內容。從SDK中就能很清晰的看到諸如ITask, IContact, IAppointment各種COM對象介面。在本文主要介紹連絡人相關的各類介面:
IPoutlookApp
所有POOM操作都必須首先通過它來的到對應的操作介面,在它的方法函數裡比較有用的是GetItemFromOid,這個函數能通過OID(唯一標示),就可以到底對應的對象介面,下面我們可以看到它的應用。在WM5上有了升級版IPoutlookApp2。
OID(唯一標示):在WM系統上是可以唯一表示一條記錄的符號,即我們熟悉的一條連絡人,一個約會資訊,它們在系統中有一個唯一的標示,不會改變,它們都儲存在系統的資料庫中。
IFolder
POOM中Contacts, Tasks, Appointments對象是以檔案夾概念的形式存在。所以需要通過它來訪問我們需要ITask, IContact, IAppointment對象介面。好比我們有一個風景照片的檔案夾,裡麵包含了都是風景照檔案,我們還有一個人物類的檔案夾,裡麵包含了都是人物的照片。我們會用到它的get_items方法函數。
IPOutlookItemCollection
為了進一步訪問對象介面IContact,還必須從IFolder中得到每一條記錄的集合,通過集合來最終訪問每一個記錄。
IItem
指的就是在PIM中通常的一條記錄。每條記錄都是可以通過IItem對象介面的方式來方法,它不區分類別(Task, Contact, Appointment都一樣對待),下文會有詳細介紹。
IContact
專門處理連絡人資訊的對象介面,本文就主要通過它來處理連絡人資料。在這裡我要指出(也許是我沒發現),在WM5版本後又提供了10左右的新的內容,但是在此對象介面中並沒有提供,但是可以IItem來處理。
簡要提下另外幾個對象介面
ITask:如果需要處理任務資訊,就使用它(沒具體使用過)
IAppointment:在處理約會資訊時,使用它,配合IRecurrencePattern就可以處理約會時的周期資訊了。
三.如何使用POOM
1.初始化及開啟POOM
POOM是基於COM技術,因此必須使用CoInitializeEx來初始化COM對象。在使用完POOM後不要忘記調用CoUninitialize()來卸載。
在初始化COM後,就可以來使用COM的一些基本介面函數了。通過CoCreateInstance來得到POOM應用對象,得到後還必須登入POOM-建立與POOM系統的一個對話過程,因此當使用完或者不在需要本次POOM相關操作後,就需要退出這次會話過程
HRESULT hr;
IPOutlookApp * m_polApp;
if (SUCCEEDED(CoInitializeEx( NULL, 0))) //初始化COM
{
// 得到IPOutlookApp對象
if(SUCCEEDED(CoCreateInstance(CLSID_Application,NULL, CLSCTX_INPROC_SERVER,
IID_IPOutlookApp, reinterpret_cast<void **>(&m_polApp)))){
if(FAILED(m_polApp->Logon(NULL))) { //建立一次會話
If(m_polApp)
m_polApp->Release();
return FALSE; }
}else
return FALSE;
}
……………….
……………….
If(m_polApp){
m_polApp->Logoff(); 結束會話
m_polApp->Release(); 釋放
m_polApp = NULL;
}
CoUninitialize(); //釋放COM
2.獲得某一類(Contact)資訊
本文主要討論的是POOM的Contact連絡人內容,所以這裡以Contact的內容來展示POOM具體操作,當然你可以操作Task或者Appointment。
在開啟POOM後接下去如何操作呢?
首先必須選擇需要進行什麼類型操作,是連絡人呢?還是任務、約會提醒?就如上面提到我們需要選擇一個檔案夾,通過它來進入我們的具體類型操作。可以通過GetDefaultFolder方法來得到某一檔案夾。
接著繼續調用get_Items方法得到一個IPOutlookItemCollection集合介面:
m_pFolder->get_Items(&m_pItems)
通過集合介面可以得到檔案夾中包含了多少條記錄,說通俗點就是有多少個連絡人、任務,約會。查看文檔你會發現還包含了許多有用的方法:查詢,排序等。對於簡單的操作最有用的就是包含了多少條資訊。
下面是完整代碼:
if(SUCCEEDED(m_polApp->GetDefaultFolder(olFolderContacts, &m_pFolder)))
if(SUCCEEDED (m_pFolder->get_Items(&m_pItems)))
if(SUCCEEDED (m_pItems->get_Count(&m_ItemCount)))
return TRUE;
3.進行IContact和IItem對象介面操作
a. IContact操作
讀者可能等的有點不耐煩了,怎麼還沒有看到如何實實在在的得到連絡人具體資訊。現在就馬上呈現。
通過IPOutlookItemCollection集合介面的Item方法來得到一個IContact對象介面。
if(FAILED(m_pItems->Item(index,reinterpret_cast<IDispatch **>(&pContact))))
{
return FALSE;
}
可以發現主要的參數是一個index的索引值,IPOutlookItemCollection集合以索引來定位某個具體的連絡人記錄。擁有了IContact介面就可以非常方便的來擷取需要連絡人資訊了。刪除記錄可以使用IContact對象介面的delete方法。
在這裡需要注意,如果刪除了一條位於中間的記錄,那麼index值對應的記錄就會發生變化,使之不對應。最好辦法是從後面開始刪除。
例如:
得到姓名:
BSTR pbstrbuf = NULL;
pContact->get_FirstName(&pbstrbuf);
pContact->get_MiddleName(&pbstrbuf);
pContact->get_LastName(&pbstrbuf);
得到手機號碼:
pContact->get_MobileTelephoneNumber(&pbstrbuf);
得到生日:
DATE mdate
pContact->get_Birthday(&mdate);
在IContact文檔裡詳細羅列了所有方法的內容
在這裡請不要忘記了對COM字串pbstrbuf記憶體的釋放,請調用下面函數:
SysFreeString(pbstrbuf);
知道了如何得到資訊,當然也要知道如何寫入資訊。使用IContact寫入資訊一樣方便,只需調用put_×××方法就可以了。最後不要忘記儲存調用:
pContact->Save();
如果忘了調用就白費功夫了。
b. IItem操作
如果讀者手裡拿著的WM5的手機,會發現在WM5上含有的“暱稱,立即訊息,公司電話”等資訊,怎麼在IContact沒有找到對應的方法呢(如果哪位讀者熟知並能找到,望請告訴本人,謝謝)?你問我為什麼,我也只能說不知道。幸運的是還有IItem,不過不要忘了上文提到了IItem對象介面,POOM還提供了全面的IItem對象介面的方法。
IItem提供了完善的處理介面,但同時它的易用性就降低。IItem介面中提供了GetProps和SetProps其實是對PIM資料庫操作的一種封裝,如果你熟悉資料庫操作,你會發現他們很像,如出一轍。請看如何使用GetProps來得到資料。
int dwlen =0;
HRESULT hr;
ULONG cbBuffer = 0;
CEPROPID rgPropId[1];
CEPROPVAL *buf=NULL;
HANDLE hHeap = GetProcessHeap();
rgPropId[0]= PIMPR_NICKNAME;
hr = pItem->GetProps(rgPropId, CEDB_ALLOWREALLOC , 1, &buf, &cbBuffer, hHeap);
if(FAILED(hr) || 0 == cbBuffer || buf == NULL)
return 0;
else
{ CEPROPVAL * ppropval = buf;
if(ppropval[0].wFlags!=CEDB_PROPNOTFOUND)
{
if(LOWORD(ppropval[0].propid) == CEVT_LPWSTR)
OutputDebugString(ppropval[0].val.lpwstr);
}
else
dwlen = 0;
LocalFree(buf);
HeapFree(hHeap, 0, buf);
}
讀者看到這裡可能比較頭痛,怎麼比IContact如此複雜的多。但是如果熟悉資料庫操作,這些還是不難的。因為設計到一些資料庫操作操作概念文件,這裡我簡單介紹下。
GetProps有兩種模式一種是POOM自己分配記憶體,還有一種是調用者來提供記憶體的分配。這裡我現在了前者,因此需要提供一個Heap控制代碼,使用GetProcessHeap來建立。
CEPROPID rgPropId[1]提供了調用者需要得到哪些內容,通過它來確定GetProps返回的是什麼資料(例如,姓名、號碼、地址等)。上述代碼使用PIMPR_NICKNAME,取得暱稱資訊。CEDB_PROPNOTFOUND進行判斷是否存在此資訊,不要忽略這點,因為資料庫格式決定了這種情況確實會發生,而不是給你一個Null 字元串。
相對於寫入操作,IItem提供的SetProps方法就簡單很多,只需給定資料,然後調用save儲存就完成了。
CEPROPVAL rgPropval[1] = {0};
rgPropval[0].propid = PIMPR_NICKNAME;
rgPropval[0].val.lpwstr = _T(“JUN”);
hr = pItem->SetProps(0, 1, rgPropval);
if(SUCCEEDED(hr))
hr = pItem->Save();
c. 照片-特殊資料處理
在連絡人資訊裡面有一個比較特殊的資訊類型-stream類型資料。WM5提供了連絡人照片功能,它的資料就是以stream方式儲存如果熟悉資料庫的讀者會發現,實質它是Blob二進位方式儲存與資料庫,因為資料庫中沒有stream類型。在這裡我們利用IItem的OpenProperty方法來進行照片的儲存
HRESULT hr = E_FAIL;
IStream *pStream = NULL;
CEPROPID propid = PIMPR_PICTURE;
ULONG cbRead = 0;
if(SUCCEEDED(hr = pItem->OpenProperty(propid, GENERIC_READ, &pStream)))
{ hr = pStream->Read(pserial, buflen, &cbRead);
pStream->Release();}
if(SUCCEEDED(hr)) return cbRead;
相應的寫入操作:
if(SUCCEEDED(hr = pItem->OpenProperty(propid, GENERIC_WRITE, &pStream)))
{hr = pStream->Write(pserial, buflen, &cbWritten);
if(SUCCEEDED(hr))
{ hr = pStream->Commit(0);
hr = pItem->Save();}
pStream->Release();}
}
上述代碼中使用了IStream介面來讀寫資料,在寫入後不要忘記調用IStream的Commit方法和IItem的Save方法儲存資料。
4.OID的提示
上文已經講解了OID的概念,在POOM中OID是一個比較重要的概念,在很多介面中都會發現有get_Oid方法。因為Oid是唯一的標示,所以它是不變。因此利用這個特點我們可以儲存它,而不會像記憶體位址一樣下次運行時就失去意義了。在有些應用中當需要對再次訪問過的記錄進行操作(修改,刪除)時,就不需要使用很傻的特定值搜尋來進行定位了,可以直接使用剛才儲存的OID來進行處理。
首先調用相應的get_Oid
LONG oid
IContact *pContact; //假設已經得到此介面
pContact ->get_Oid(&oid);
然後使之oid儲存至有效空間,當再此需要處理此記錄時,但又得不到pContact介面時,就可以調用IPOutlookApp的GetItemFromOid方法來直接得到IContact:
IContact *pContact = NULL;
if(S_OK=m_polApp->GetItemFromOid(oid,reinterpret_cast<IDispatch **>(&pContact)))
{ …… }
5.後期處理-儲存資料
按照上述處理,基本上可以得到所有的連絡人資訊。接下來可以使用File IO相關操作來儲存資料至檔案中,具體討論不在本文範圍內了。同樣還原備份資料時,先File IO然後進行POOM操作,上面已經有詳細的介紹。
四.結論
本文主要講解了如何使用POOM和與連絡人相關的對象介面來讀取或者寫入連絡人的各種資訊。希望本文讀者能領悟到POOM的其它操作(Task和Appointment),如能對讀者更深入的使用POOM起到拋磚引玉的作用,那就更好了。
時間倉促,再加上本人才疏學淺,在文中難免有錯漏之處,歡迎朋友們指正。