使用账户管理 API (IOlkAccountManger) 列出 Outlook 电子邮件账户






3.64/5 (8投票s)
一篇关于如何使用 IOlkAccountManger 获取 Outlook 中配置的电子邮件账户的文章。

引言
本文展示了如何使用 账户管理 API 来获取 Outlook 中配置的电子邮件账户。
背景
撰写本文的原因是微软没有为所使用的接口提供头文件。此外,微软也没有记录账户的所有属性。
Using the Code
如果您想跳过技术细节,只想使用该功能,请按照以下步骤操作
- 在您的项目中添加这些文件
- AccountData.h - 包含用于保存账户数据的类
- AccountHelper.h - 包含类
CAccountHelper
的声明 - AccountHelper.cpp - 类
CAccountHelper
的实现 - AcctMgmt.h - 包含 CLSID/IID 和属性标签声明
- AcctMgmt.cpp - 包含实际提取账户数据的代码
- 配置您的项目以链接 mapi32.lib
- 在您的 *.h 或 *.cpp 文件中包含文件 AccountHelper.h
- 调用
GetAccounts
,将 Outlook 配置文件名传递给它,如下所示
TCHAR szProfile[] = _T("ProfileName"); // Add your outlook profile name here
AccountData *pAccountData = NULL; // This will contain the email account data
DWORD cAccountData = 0; // This will contain the count of the email account
if(FAILED(GetAccounts(szProfile, &cAccountData, &pAccountData)))
{
AfxMessageBox(_T("Failed to get account data"));
return;
}
else
{
for(DWORD i = 0 ; i <cAccountData; i++)
{
_tprintf(_T("Is Exchange account : %d"),pAccountData[i].lIsExchange);
_tprintf(_T("Email ID is : %s"),pAccountData[i].szEmailID);
_tprintf(_T("Incoming Server (POP/IMAP) is : %s"),
pAccountData[i].szIncomingServer);
_tprintf(_T("Outgoing Server is : %s"),pAccountData[i].szOutgoingServer);
_tprintf(_T("Account Stamp : %s"),pAccountData[i].szAccountStamp);
//similarly all other properties
}
}
幕后细节
如果您想自己实现此功能,您需要执行以下操作
- 首先实现接口
IOlkAccountHelper
。假设类名为CAccountHelper
- 登录到 MAPI,将配置文件名存储在一个变量中。您需要在类
CAccountHelper
中将其传递回 MAPI - 创建一个
IID_IOlkAccountManager
实例 - 创建
CAccountHelper
类的对象 - 调用
IOlkAccountManager:Init
,将您创建的CAccountHelper
对象传递给它 - 调用
IOlkAccountManager::EnumerateAccounts
以获取IOlkEnum
的接口 - 调用
IOlkEnum::GetCount
以获取账户数量 - 调用
IOlkEnum::Reset
- 在一个循环中,调用
IOlkEnum::GetNext
以检索所有账户
实际执行这些操作的 GetAccount
代码如下所示
HRESULT GetAccounts(LPWSTR lpwszProfile, DWORD* pcAccounts, AccountData** ppAccounts)
{
HRESULT hRes = S_OK;
LPMAPISESSION lpSession;
LPOLKACCOUNTMANAGER lpAcctMgr = NULL;
hRes = MAPILogonEx(0,
(LPTSTR)lpwszProfile,
NULL,
fMapiUnicode | MAPI_EXTENDED | MAPI_EXPLICIT_PROFILE |
MAPI_NEW_SESSION | MAPI_NO_MAIL | MAPI_LOGON_UI,
&lpSession);
if(FAILED(hRes))
{
AfxMessageBox(L"Failed to login to the selected profile");
}
hRes = CoCreateInstance(CLSID_OlkAccountManager,
NULL,
CLSCTX_INPROC_SERVER,
IID_IOlkAccountManager,
(LPVOID*)&lpAcctMgr);
if(SUCCEEDED(hRes) && lpAcctMgr)
{
CAccountHelper* pMyAcctHelper = new CAccountHelper(lpwszProfile, lpSession);
if(pMyAcctHelper)
{
LPOLKACCOUNTHELPER lpAcctHelper = NULL;
hRes = pMyAcctHelper->QueryInterface
(IID_IOlkAccountHelper, (LPVOID*)&lpAcctHelper);
if(SUCCEEDED(hRes) && lpAcctHelper)
{
hRes = lpAcctMgr->Init(lpAcctHelper, ACCT_INIT_NOSYNCH_MAPI_ACCTS);
if(SUCCEEDED(hRes))
{
LPOLKENUM lpAcctEnum = NULL;
hRes = lpAcctMgr->EnumerateAccounts(&CLSID_OlkMail,
NULL,
OLK_ACCOUNT_NO_FLAGS,
&lpAcctEnum);
if(SUCCEEDED(hRes) && lpAcctEnum)
{
DWORD cAccounts = 0;
hRes = lpAcctEnum->GetCount(&cAccounts);
if(SUCCEEDED(hRes) && cAccounts)
{
AccountData* pAccounts = new AccountData[cAccounts];
hRes = lpAcctEnum->Reset();
if(SUCCEEDED(hRes))
{
DWORD i = 0;
for (i = 0; i < cAccounts; i++)
{
LPUNKNOWN lpUnk = NULL;
hRes = lpAcctEnum->GetNext(&lpUnk);
if(SUCCEEDED(hRes) && lpUnk)
{
LPOLKACCOUNT lpAccount = NULL;
hRes = lpUnk->QueryInterface(IID_IOlkAccount,
(LPVOID*)&lpAccount);
if(SUCCEEDED(hRes) && lpAccount)
{
ACCT_VARIANT pProp = {0};
//suppress the use of outer hRes
HRESULT hRes = S_OK;
//Account ID
hRes = lpAccount->GetProp
(PROP_ACCT_ID, &pProp);
if(SUCCEEDED(hRes) && pProp.Val.dw)
{
pAccounts[i].lAccountID = pProp.Val.dw;
}
//Account Name
hRes = lpAccount->GetProp(PROP_ACCT_NAME,
&pProp);
if(SUCCEEDED(hRes) && pProp.Val.pwsz)
{
pAccounts[i].szAccountName =
pProp.Val.pwsz;
}
//Is Exchange account flag
hRes = lpAccount->GetProp
(PROP_ACCT_IS_EXCH, &pProp);
if(SUCCEEDED(hRes) && pProp.Val.dw)
{
pAccounts[i].lIsExchange = pProp.Val.dw;
}
else
{
pAccounts[i].lIsExchange = 0;
}
//Account Send Stamp
hRes = lpAccount->GetProp
(PROP_ACCT_SEND_STAMP, &pProp);
if(SUCCEEDED(hRes) && pProp.Val.pwsz)
{
pAccounts[i].szSendStamp = pProp.Val.pwsz;
lpAccount->FreeMemory
((LPBYTE)pProp.Val.pwsz);
}
//similarly retrieve all other properties.
//the sample code has the complete code
//it's been removed from here just for clarity
}
if(lpAccount)
lpAccount->Release();
lpAccount = NULL;
}
if(lpUnk)
lpUnk->Release();
lpUnk = NULL;
}
*pcAccounts = cAccounts;
*ppAccounts = pAccounts;
}
}
}
if(lpAcctEnum)
lpAcctEnum->Release();
}
}
if(lpAcctHelper)
lpAcctHelper->Release();
}
if(pMyAcctHelper)
pMyAcctHelper->Release();
}
if(lpAcctMgr)
lpAcctMgr->Release();
lpSession->Logoff(0,0,0);
lpSession->Release();
return hRes;
}
在演示应用程序中,我添加了两个按钮“显示账户对话框”和“显示添加账户向导”。
添加到接口的新方法具有此签名
HRESULT IOlkAccountManager::DisplayAccountList (
HWND hwnd,
DWORD dwFlags,
LPCWSTR lpwszReserved,
DWORD dwReserved,
const CLSID * pclsidReserved1,
const CLSID * pclsidReserved2
);
要使用它,当点击上述按钮时,我添加了这段代码
LPOLKACCOUNTMANAGER lpAcctMgr = NULL;
hRes = CoCreateInstance(CLSID_OlkAccountManager,
NULL,
CLSCTX_INPROC_SERVER,
IID_IOlkAccountManager,
(LPVOID*)&lpAcctMgr);
if(SUCCEEDED(hRes) && lpAcctMgr)
{
CAccountHelper* pMyAcctHelper = new CAccountHelper(szProfileName, lpSession);
if(pMyAcctHelper)
{
LPOLKACCOUNTHELPER lpAcctHelper = NULL;
hRes = pMyAcctHelper->QueryInterface(IID_IOlkAccountHelper,
(LPVOID*)&lpAcctHelper);
if(SUCCEEDED(hRes) && lpAcctHelper)
{
hRes = lpAcctMgr->Init(lpAcctHelper, ACCT_INIT_NOSYNCH_MAPI_ACCTS);
if(SUCCEEDED(hRes))
{
hRes = lpAcctMgr->DisplayAccountList(this->m_hWnd,dwFlags,0,0,0,0);
if(hRes == MAPI_E_INVALID_PARAMETER)
{
AfxMessageBox(L"dwReserved, pclsidReserved1 or
pclsidReserved2 were non-NULL.");
}
else if(hRes == E_ACCT_UI_BUSY)
{
AfxMessageBox(L"The account dialog class could not be created.");
}
else if( hRes == MAPI_E_USER_CANCEL)
{
AfxMessageBox(L"The Account Settings dialog box returned an error.");
}
else if(hRes == MAPI_E_CALL_FAILED)
{
AfxMessageBox(L"The Add New E-Mail property sheet
returned an error.");
}
}
else
{
AfxMessageBox(L"Failed to initialize IOlkAccountManager");
}
lpAcctHelper>Release();
}
else
{
AfxMessageBox(L"Failed to get Account Helper interface");
}
pMyAcctHelper->Release();
}
else
{
AfxMessageBox(L"Oops!!! Out of memory");
}
lpAcctMgr->Release();
}
else
{
AfxMessageBox(L"Ohhhhhhh No!!! failed to get IOlkAccountManager interface");
}
Exchange 账户的特殊处理
Exchange 账户没有传入或传出服务器。此外,exchange 账户的电子邮件 ID 也不符合我们看到的正常形式。要获取 exchange 账户的邮箱服务器或电子邮件 ID,您需要打开配置文件的全局配置文件部分。
邮箱服务器名称存储在属性标签中
PR_INTERNET_CONTENT_ID PROP_TAG(PT_UNICODE, 0x662A)
电子邮件 ID 通常存储在这些属性标签中
PROP_EXCHANGE_EMAILID PROP_TAG(PT_UNICODE, 0x663D) //email ID
PROP_EXCHANGE_EMAILID2 PROP_TAG(PT_UNICODE, 0x6641) //email ID
在某些 exchange 2000 账户中,您找不到这些属性。在这种情况下,您必须获取用户的 IMailUse
接口,然后查询 PR_SMTP_ADDRESS
属性。
参考文献
欲了解更多信息,您可以参考 账户管理 API 参考。
历史
- 2008年7月4日:初始版本
- 2008年8月27日:文章更新