如何成功调用MAPI API的IOlkAccountManager::SetOrder方法
关于Outlook账户顺序设置时SetOrder API触发Access Violation崩溃的问题
我在应用中编写了以下代码用于设置Outlook账户顺序,但程序出现崩溃。我看到GetOrder API可成功返回所有已配置账户的详情(即3个账户及其账户ID),但将相同指针传入SetOrder API时,程序触发Access Violation异常崩溃。
hResult = ::CoCreateInstance(CLSID_OlkAccountManager, NULL, CLSCTX_INPROC, IID_IOlkAccountManager, (LPVOID *)lpManager.getptr()); if (SUCCEEDED(hResult)) { // this should sync Outlook Accounts with MAPI transports LOG_ADDIN(_T("Forcing Outlook accounts syncronization with new personas data")); hResult = lpManager->Init(&accHelper, OLK_ACCOUNT_NO_FLAGS); if (SUCCEEDED(hResult)) { DWORD *piAccount = new DWORD; DWORD **piAccounts = new DWORD*[*piAccount]; hResult = lpManager->GetOrder(&CLSID_OlkMail, piAccount, piAccounts); hResult = lpManager->SetOrder(&CLSID_OlkMail, piAccount, piAccounts); } }
问题根源
你的代码存在未初始化内存的致命问题:
DWORD *piAccount = new DWORD;仅分配了内存,但未初始化*piAccount的值,此时它是随机垃圾值。- 用这个垃圾值创建数组
DWORD **piAccounts = new DWORD*[*piAccount];,会导致数组大小不可控,要么后续GetOrder写入时越界,要么内存分配异常,最终触发内存访问错误。
正确实现流程
按照Outlook IOlkAccountManager接口规范,调用GetOrder和SetOrder的正确步骤是:
- 先调用一次
GetOrder,传入piAccount地址、piAccounts传NULL,获取账户总数量。 - 根据返回的数量分配足够内存存储账户ID数组。
- 再次调用
GetOrder,传入分配好的数组指针,获取实际账户ID列表。 - 按需调整顺序后,调用
SetOrder完成设置。
修正后的代码示例
hResult = ::CoCreateInstance(CLSID_OlkAccountManager, NULL, CLSCTX_INPROC, IID_IOlkAccountManager, (LPVOID *)lpManager.getptr()); if (SUCCEEDED(hResult)) { LOG_ADDIN(_T("Forcing Outlook accounts syncronization with new personas data")); hResult = lpManager->Init(&accHelper, OLK_ACCOUNT_NO_FLAGS); if (SUCCEEDED(hResult)) { DWORD accountCount = 0; DWORD* accountIDs = nullptr; // 第一步:获取账户总数 hResult = lpManager->GetOrder(&CLSID_OlkMail, &accountCount, NULL); if (SUCCEEDED(hResult) && accountCount > 0) { // 第二步:分配足够内存存储账户ID accountIDs = new DWORD[accountCount]; if (accountIDs) { // 第三步:获取实际账户ID列表 hResult = lpManager->GetOrder(&CLSID_OlkMail, &accountCount, &accountIDs); if (SUCCEEDED(hResult)) { // 此处可按需调整accountIDs中的账户顺序 // 第四步:调用SetOrder设置新顺序 hResult = lpManager->SetOrder(&CLSID_OlkMail, accountCount, accountIDs); // 可在此处检查SetOrder的返回结果 } // 释放内存,避免泄漏 delete[] accountIDs; } } } }
额外注意事项
- 始终检查内存分配是否成功(
new可能返回NULL,尤其是账户数量较大时)。 - 接口调用完成后务必释放分配的内存。
SetOrder的第二个参数是账户数量(DWORD值),而非指针,注意和GetOrder的参数格式区分。
内容的提问来源于stack exchange,提问作者amol surywanshi
相关产品推荐
相关产品推荐

