Setting Up an Offline State Add-in

Setting Up an Offline State Add-in

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

About the Offline State API

About the Sample Offline State Add-in

Installing the Sample Offline State Add-in

Monitoring Connection State Changes Using an Offline State Add-in

Disconnecting an Offline State Add-in