應用程式常需存取使用者的通訊錄資料 (姓名、Email、暱稱等)。Windows 系統內建 Outlook Express (OE) 與 Office 套件的 Outlook 2000 (OL2K) 儲存機制截然不同,本文提供兩套完整的 VC++ 實作程式碼。
OE 使用 Windows Address Book (WAB),儲存於 .wab 檔案,透過 WAB32.dll 介面存取。
WAB32.dll (通常位於 Program Files\Common Files\System\)WABOpen 函數指標WABOpen 取得 IAddrBook 與 IWABObject 介面GetPAB)GetContentsTable)QueryRows) 並解析屬性標籤
#include <wab.h>
typedef HRESULT (WINAPI *fWABOpen)(LPADRBOOK*, LPWABOBJECT*, LPWAB_PARAM, DWORD);
void CGetEmailDlg::OnOK() {
HINSTANCE hLib = LoadLibrary("WAB32.DLL"); // 建議用完整路徑
if (!hLib) return;
fWABOpen pWABOpen = (fWABOpen)GetProcAddress(hLib, "WABOpen");
if (!pWABOpen) { FreeLibrary(hLib); return; }
LPADRBOOK pAdrBook = NULL;
LPWABOBJECT pWABObj = NULL;
HRESULT hr = pWABOpen(&pAdrBook, &pWABObj, NULL, 0);
if (FAILED(hr)) { FreeLibrary(hLib); return; }
// 取得 PAB 容器
ULONG cbEntryID; LPENTRYID pEntryID;
hr = pAdrBook->GetPAB(&cbEntryID, &pEntryID);
if (FAILED(hr)) { pWABObj->Release(); pAdrBook->Release(); FreeLibrary(hLib); return; }
// 開啟容器
LPUNKNOWN pUnk = NULL; ULONG ulObjType;
hr = pAdrBook->OpenEntry(cbEntryID, pEntryID, NULL, MAPI_BEST_ACCESS, &ulObjType, &pUnk);
pWABObj->FreeBuffer(pEntryID);
if (FAILED(hr) || ulObjType != MAPI_ABCONT) { /* 清理 */ return; }
IABContainer* pCont = (IABContainer*)pUnk;
LPMAPITABLE pTable = NULL;
hr = pCont->GetContentsTable(0, &pTable);
if (FAILED(hr)) { /* 清理 */ return; }
ULONG cRows;
pTable->GetRowCount(0, &cRows);
SRowSet* pRows = NULL;
hr = pTable->QueryRows(cRows, 0, &pRows);
if (SUCCEEDED(hr)) {
for (ULONG i = 0; i < pRows->cRows; i++) {
SRow* pRow = &pRows->aRow[i];
CString str;
for (ULONG j = 0; j < pRow->cValues; j++) {
SPropValue* pProp = &pRow->lpProps[j];
switch (pProp->ulPropTag) {
case PR_DISPLAY_NAME_A: str += " 姓名: " + CString((char*)pProp->Value.lpszA); break;
case PR_EMAIL_ADDRESS_A: str += " Email: " + CString((char*)pProp->Value.lpszA); break;
case PR_NICKNAME_A: str += " 暱稱: " + CString((char*)pProp->Value.lpszA); break;
case PR_ADDRTYPE_A: str += " 類型: " + CString((char*)pProp->Value.lpszA); break;
}
}
m_ListEmail.AddString(str);
pWABObj->FreeBuffer(pRow);
}
pWABObj->FreeBuffer(pRows);
}
// 清理介面與庫
pTable->Release(); pCont->Release(); pAdrBook->Release(); pWABObj->Release();
FreeLibrary(hLib);
}
wab.h,若 WABTAGS.H 編譯錯誤,請參考範例附帶的修正版本mapi32.libOL2K 公開標準 COM 介面,透過 #import 匯入型別庫最為便利。
#import "C:\\Program Files\\Microsoft Office\\Office\\mso9.dll" named_guids
#import "C:\\Program Files\\Microsoft Office\\Office\\MSOUTL9.olb" \
no_namespace exclude("_IRecipientControl", "_DRecipientControl")
路徑請依實際 Office 安裝位置調整
_ApplicationPtr pApp;
_NameSpacePtr pNs;
MAPIFolderPtr pFolder;
_ItemsPtr pItems;
_ContactItemPtr pContact;
try {
hr = pApp.CreateInstance(__uuidof(Application));
if (FAILED(hr)) { MessageBox("Outlook 實例建立失敗"); return; }
// 取得預設聯絡人資料夾
pFolder = pApp->GetNamespace(_bstr_t("MAPI"))->GetDefaultFolder(olFolderContacts);
if (!pFolder) { MessageBox("找不到預設聯絡人資料夾"); return; }
// 或讓使用者選擇資料夾
// pFolder = pApp->GetNamespace(_bstr_t("MAPI"))->PickFolder();
// if (!pFolder || pFolder->GetDefaultItemType() != olContactItem) return;
pItems = pFolder->GetItems();
if (!pItems) { MessageBox("無法取得聯絡人項目"); return; }
pContact = pItems->GetFirst();
m_ListEmail.ResetContent();
while (pContact) {
CString str;
str = (char*)(_bstr_t)pContact->GetFullName();
str += " <";
str += (char*)(_bstr_t)pContact->GetEmail1Address();
str += ">";
m_ListEmail.AddString(str);
pContact = pItems->GetNext();
}
}
catch (_com_error& e) {
MessageBox((char*)e.Description());
}
| 特性 | Outlook Express (WAB) | Outlook 2000 (COM) |
|---|---|---|
| 部署需求 | 系統內建,無額外安裝 | 需安裝 Office 2000 |
| 程式複雜度 | 較高 (MAPI 介面) | 較低 (#import 智慧指標) |
| 效能 | 直接存取 .wab 檔 | 透過 Outlook 進程 |
| 資料完整度 | 基本欄位 | 完整聯絡人物件模型 |