设置脱机状态加载项
适用于:Outlook 2013 | Outlook 2016
若要实现脱机状态加载项,必须实现连接、初始化和其他设置功能。 在本主题中,使用示例脱机状态外接程序中的代码示例演示了这些连接、初始化和设置函数。 示例脱机状态加载项是一个 COM 加载项,它会将脱机状态菜单添加到 Outlook 并使用脱机状态 API。 通过“脱机状态”菜单,可以启用或禁用状态监视、检查当前状态以及更改当前状态。 有关下载和安装示例脱机状态加载项的详细信息,请参阅安装示例脱机状态加载项。 有关脱机状态 API 的详细信息,请参阅关于脱机状态 API。
设置脱机状态加载项后,必须实现监视和修改连接状态更改的函数。 有关详细信息,请参阅 使用脱机状态加载项监视连接状态更改。
On Connection 例程
每次加载加载项时都会调用 IDTExtensibility2.OnConnection 方法 。 它是外接程序的入口点,因此在外接程序启动时,将调用放入 OnConnection
函数的代码。 在以下示例中 OnConnection
, 函数调用 函数 HrInitAddin
。
CMyAddin::OnConnection () 示例
STDMETHODIMP CMyAddin::OnConnection(
IDispatch * Application,
ext_ConnectMode ConnectMode,
IDispatch * /*AddInInst*/,
SAFEARRAY * * /*custom*/)
{
Log(true,"OnConnection\n");
HRESULT hRes = S_OK;
m_spApp = Application;
m_ConnectMode = ConnectMode;
if (ConnectMode == ext_cm_AfterStartup)
hRes = HrInitAddin();
return hRes;
}
初始化外接程序例程
函数 HrInitAddin
调用 LoadLibraries
、 HrCacheProfileName
和 HrAddMenuItems
函数以完成脱机状态加载项的设置。
CMyAddin::HrInitAddin () 示例
HRESULT CMyAddin::HrInitAddin()
{
HRESULT hRes = S_OK;
LoadLibraries();
hRes = HrCacheProfileName();
Log(true,_T("HrCacheProfileName returned 0x%08X\n"),hRes);
hRes = HrAddMenuItems();
Log(true,_T("HrAddMenuItems returned 0x%08X\n"),hRes);
return hRes;
}
加载库例程
函数 LoadLibraries
加载动态链接库 (DLL) 加载项所需的文件。
LoadLibraries () 示例
void LoadLibraries()
{
Log(true,_T("LoadLibraries - loading exports from DLLs\n"));
HRESULT hRes = S_OK;
UINT uiRet = 0;
LONG lRet = 0;
BOOL bRet = true;
CHAR szSystemDir[MAX_PATH+1] = {0};
// Get the system directory path
// (mapistub.dll and mapi32.dll reside here)
uiRet = GetSystemDirectoryA(szSystemDir, MAX_PATH);
if (uiRet > 0)
{
CHAR szDLLPath[MAX_PATH+1] = {0};
hRes = StringCchPrintfA(szDLLPath, MAX_PATH+1, "%s\\%s",
szSystemDir, "mapistub.dll");
if (SUCCEEDED(hRes))
{
LPFGETCOMPONENTPATH pfnFGetComponentPath = NULL;
// Load mapistub.dll
hModMAPIStub = LoadLibraryA(szDLLPath);
if (hModMAPIStub)
{
// Get the address of FGetComponentPath from the mapistub
pfnFGetComponentPath = (LPFGETCOMPONENTPATH)GetProcAddress(
hModMAPIStub, "FGetComponentPath");
}
// If there is no address for FGetComponentPath yet
// try getting it from mapi32.dll
if (!pfnFGetComponentPath)
{
hRes = StringCchPrintfA(szDLLPath, MAX_PATH+1, "%s\\%s",
szSystemDir, "mapi32.dll");
if (SUCCEEDED(hRes))
{
// Load mapi32.dll
hModMAPI = LoadLibraryA(szDLLPath);
if (hModMAPI)
{
// Get the address of FGetComponentPath from mapi32
pfnFGetComponentPath = (LPFGETCOMPONENTPATH)GetProcAddress(
hModMAPI, "FGetComponentPath");
}
}
}
if (pfnFGetComponentPath)
{
LPSTR szAppLCID = NULL;
LPSTR szOfficeLCID = NULL;
HKEY hMicrosoftOutlook = NULL;
lRet = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
_T("Software\\Clients\\Mail\\Microsoft Outlook"),
NULL,
KEY_READ,
&hMicrosoftOutlook);
if (ERROR_SUCCESS == lRet && hMicrosoftOutlook)
{
HrGetRegMultiSZValueA(hMicrosoftOutlook, "MSIApplicationLCID", (LPVOID*) &szAppLCID);
HrGetRegMultiSZValueA(hMicrosoftOutlook, "MSIOfficeLCID", (LPVOID*) &szOfficeLCID);
}
if (szAppLCID)
{
bRet = pfnFGetComponentPath(
"{FF1D0740-D227-11D1-A4B0-006008AF820E}", szAppLCID, szDLLPath, MAX_PATH, true);
}
if ((!bRet || szDLLPath[0] == _T('\0')) && szOfficeLCID)
{
bRet = pfnFGetComponentPath(
"{FF1D0740-D227-11D1-A4B0-006008AF820E}", szOfficeLCID, szDLLPath, MAX_PATH, true);
}
if (!bRet || szDLLPath[0] == _T('\0'))
{
bRet = pfnFGetComponentPath(
"{FF1D0740-D227-11D1-A4B0-006008AF820E}", NULL, szDLLPath, MAX_PATH, true);
}
delete[] szOfficeLCID;
delete[] szAppLCID;
if (hMicrosoftOutlook) RegCloseKey(hMicrosoftOutlook);
}
hModMSMAPI = LoadLibrary(szDLLPath);
if (hModMSMAPI)
{
pfnHrOpenOfflineObj = (HROPENOFFLINEOBJ*) GetProcAddress(
hModMSMAPI,
"HrOpenOfflineObj@20");
pfnMAPIFreeBuffer = (LPMAPIFREEBUFFER) GetProcAddress(
hModMSMAPI,
"MAPIFreeBuffer");
}
}
}
}
缓存配置文件名称例程
函数 HrCacheProfileName
调用 IMAPISupport::OpenProfileSection 函数以打开当前会话的配置文件部分,然后设置按钮处理程序的配置文件。
CMyAddin::HrCacheProfileName () 示例
HRESULT CMyAddin::HrCacheProfileName()
{
HRESULT hRes = S_OK;
_NameSpacePtr spSession = m_spApp->GetNamespace("MAPI");
IUnknown* lpMAPIObject = NULL;
LPMAPISESSION lpMAPISession = NULL;
// use the raw accessor
hRes = spSession->get_MAPIOBJECT(&lpMAPIObject);
if (SUCCEEDED(hRes) && lpMAPIObject)
{
hRes = lpMAPIObject->QueryInterface(IID_IMAPISession,(LPVOID*)&lpMAPISession);
}
if (SUCCEEDED(hRes) && lpMAPISession)
{
LPPROFSECT lpPSGlobal = NULL;
hRes = lpMAPISession->OpenProfileSection((LPMAPIUID)pbGlobalProfileSectionGuid, NULL, 0, &lpPSGlobal);
if (SUCCEEDED(hRes) && lpPSGlobal)
{
LPSPropValue lpProfileName = NULL;
// Asking for PR_PROFILE_NAME_W here - this might not work with earlier versions of Outlook
SPropTagArray staga = {1,PR_PROFILE_NAME_W};
ULONG cVal = 0;
hRes = lpPSGlobal->GetProps(&staga,0,&cVal,&lpProfileName);
if (SUCCEEDED(hRes) && 1 == cVal && lpProfileName && PR_PROFILE_NAME_W == lpProfileName->ulPropTag)
{
m_InitButtonHandler.SetProfile(lpProfileName->Value.lpszW);
m_GetStateButtonHandler.SetProfile(lpProfileName->Value.lpszW);
m_SetStateButtonHandler.SetProfile(lpProfileName->Value.lpszW);
}
if (pfnMAPIFreeBuffer) pfnMAPIFreeBuffer(lpProfileName);
}
if (lpPSGlobal) lpPSGlobal->Release();
}
if (lpMAPISession) lpMAPISession->Release();
return hRes;
}
添加菜单项例程
函数 HrAddMenuItems
定义在 Outlook 中加载加载项时创建的 “脱机状态 ”菜单下显示的菜单选项,然后调用 DispEventAdvise
每个菜单项。
CMyAddin::HrAddMenuItems () 示例
HRESULT CMyAddin::HrAddMenuItems()
{
Log(true,"HrAddMenuItems\n");
HRESULT hRes = S_OK;
if (!m_fMenuItemsAdded)
{
try
{
_ExplorerPtr spExplorer = m_spApp->ActiveExplorer();
_CommandBarsPtr spCmdBars = spExplorer->__CommandBars;
CommandBarPtr spMainBar = spCmdBars->ActiveMenuBar;
CommandBarControlsPtr spMainCtrls = spMainBar->Controls;
try { m_spMyMenu = spMainCtrls->GetItem("Offline State"); } catch (_com_error) {}
if (m_spMyMenu == NULL)
{
m_spMyMenu = spMainCtrls->Add((long)msoControlPopup,vtMissing,vtMissing,vtMissing, true);
m_spMyMenu->Caption = "Offline State";
}
CommandBarControlsPtr spMyMenuCtrls = m_spMyMenu->Controls;
try { m_spInitButton = spMyMenuCtrls->GetItem("&Init Monitor"); } catch (_com_error) {}
if (m_spInitButton == NULL)
{
m_spInitButton = spMyMenuCtrls->Add((long)msoControlButton, vtMissing, vtMissing, vtMissing, true);
m_spInitButton->Caption = "&Init Monitor";
m_spInitButton->FaceId = MY_INIT_BUTTON;
}
try { m_spDeinitButton = spMyMenuCtrls->GetItem("&Deinit Monitor"); } catch (_com_error) {}
if (m_spDeinitButton == NULL)
{
m_spDeinitButton = spMyMenuCtrls->Add((long)msoControlButton, vtMissing, vtMissing, vtMissing, true);
m_spDeinitButton->Caption = "&Deinit Monitor";
m_spDeinitButton->FaceId = MY_DEINIT_BUTTON;
}
try { m_spGetStateButton = spMyMenuCtrls->GetItem("&GetCurrentState"); } catch (_com_error) {}
if (m_spGetStateButton == NULL)
{
m_spGetStateButton = spMyMenuCtrls->Add((long)msoControlButton, vtMissing, vtMissing, vtMissing, true);
m_spGetStateButton->Caption = "&GetCurrentState";
m_spGetStateButton->FaceId = MY_GETSTATE_BUTTON;
}
try { m_spSetStateButton = spMyMenuCtrls->GetItem("&SetCurrentState"); } catch (_com_error) {}
if (m_spSetStateButton == NULL)
{
m_spSetStateButton = spMyMenuCtrls->Add((long)msoControlButton, vtMissing, vtMissing, vtMissing, true);
m_spSetStateButton->Caption = "&SetCurrentState";
m_spSetStateButton->FaceId = MY_SETSTATE_BUTTON;
}
// Set up advise
_com_util::CheckError(m_InitButtonHandler.DispEventAdvise(m_spInitButton));
_com_util::CheckError(m_DeinitButtonHandler.DispEventAdvise(m_spDeinitButton));
_com_util::CheckError(m_GetStateButtonHandler.DispEventAdvise(m_spGetStateButton));
_com_util::CheckError(m_SetStateButtonHandler.DispEventAdvise(m_spSetStateButton));
}
catch (_com_error)
{
hRes = E_FAIL;
}
if (SUCCEEDED(hRes))
{
m_fMenuItemsAdded = true;
}
}
return hRes;
}