Setting Up an Offline State Add-in
Applies to: Office 2010 | Outlook 2010 | Visual Studio
In this article
On Connection Routine
CMyAddin::OnConnection() Example
Initialize Add-in Routine
CMyAddin::HrInitAddin() Example
Load Libraries Routine
LoadLibraries() Example
Cache Profile Name Routine
CMyAddin::HrCacheProfileName() Example
Add Menu Items Routine
CMyAddin::HrAddMenuItems() Example
To implement an offline state add-in, you must implement connection, initialization, and other setup functions. In this topic, these connection, initialization, and setup functions are demonstrated by using code examples from the Sample Offline State Add-in. The Sample Offline State Add-in is a COM add-in that adds an Offline State menu to Outlook and uses the Offline State API. Through the Offline State menu, you can enable or disable state monitoring, check the current state, and change the current state. For more information about downloading and installing the Sample Offline State Add-in, see Installing the Sample Offline State Add-in. For more information about the Offline State API, see About the Offline State API.
After you set up an offline state add-in, you must implement functions to monitor and modify connection state changes. For more information, see Monitoring Connection State Changes Using an Offline State Add-in.
On Connection Routine
The IDTExtensibility2.OnConnection Method is called every time an add-in is loaded. It is the entry point for the add-in, so the code you put in the OnConnection function will be called when the add-in starts. In the following example, the OnConnection function calls the HrInitAddin function.
CMyAddin::OnConnection() Example
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;
}
Initialize Add-in Routine
The HrInitAddin function calls the LoadLibraries, HrCacheProfileName, and HrAddMenuItems functions to finish setting up the offline state add-in.
CMyAddin::HrInitAddin() Example
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;
}
Load Libraries Routine
The LoadLibraries function loads the dynamic-link library (DLL) files that the add-in requires.
LoadLibraries() Example
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");
}
}
}
}
Cache Profile Name Routine
The HrCacheProfileName function calls the IMAPISupport::OpenProfileSection function to open a profile section for the current session, and then sets the profile for the button handlers.
CMyAddin::HrCacheProfileName() Example
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;
}
Add Menu Items Routine
The HrAddMenuItems function defines the menu options that appear under the Offline State menu that is created when the add-in is loaded in Outlook, and then calls DispEventAdvise for each menu item.
CMyAddin::HrAddMenuItems() Example
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;
}
See Also
Concepts
Installing the Sample Offline State Add-in
About the Sample Offline State Add-in
Monitoring Connection State Changes Using an Offline State Add-in