Export (0) Print
Expand All
Expand Minimize

How to: Programmatically Set the Resolution Order for Address Lists

Office 2007

This topic contains a code sample in C++ that programmatically sets the order of address lists by which recipients in e-mail messages and attendees in meeting requests are resolved.

In MAPI, each profile can support multiple address lists and each address list resides in its own container. MAPI supports the SetSearchPath method in the IAddrBook interface that allows you to set a new search path in the profile that is used for name resolution. To use the IAddrBook::SetSearchPath method, you have to define the desired resolution order in a SRowSet array that holds the containers of the relevant address books in the desired order, and then specify the array as the lpSearchPath parameter. The first property for each entry in the SRowSet array must be the PR_ENTRYID property of the corresponding address book.

The code sample sets the resolution order in the following steps:

  1. Initializes numANR to the number of containers to match, and specifies the names and resolution order of the desired address lists in an ANROrder array.
  2. Initializes MAPI by using the MAPIInitialize function.
  3. Logs on to MAPI and allows the user to choose a profile.
  4. Gets a pointer to the address book from the current session.
  5. Opens the Address Book.
  6. Opens the container for the root Address Book.
  7. Opens the hierarchy table of the root address book container.
  8. Gets the list of address book containers in the hierarchy.
  9. Looks for the entry IDs of the desired address lists by comparing the names of the desired address lists in ANROrder to the existing names in the address book hierarchy.
  10. Sets the appropriate entry IDs to the SRowSet array, pNewRows.
  11. Calls and passes pNewRows as the lpSearchPath parameter to IAddrBook::SetSearchPath to set the search path.
  12. Cleans up internal buffers and pointers.
  13. Logs off from MAPI.
  14. Uninitalizes MAPI.

This code sample uses address lists that are available in the default installation of Microsoft Office Outlook: All Contacts, All Groups, and Contacts. You must run the sample after Outlook is started and is running on an initialized profile. The sample works well with names that are in one language (for example, all names are in English). It is not designed to work in multi-lingual deployments, for example the Contacts folder localized for a user running a non-English Outlook build.

#include "stdafx.h"
#include <mapix.h>
#include <mapiguid.h>
#include <mapiutil.h>
#include <mapidefs.h>
#include <stdio.h>
#include <conio.h>

//Number of address lists to resolve against
const int numANR = 3;
WCHAR *ANROrder[numANR] = {_T("All Contacts"), _T("All Groups"), _T("Contacts")};
UINT  numContainersFound [numANR] = {0};

// Temporary structure to allocate buffer in MAPI. This will be used as a parent buffer to free space later.
LPVOID tempLink;

// Forward declaration of helper function to copy binary data
STDMETHODIMP CopySBinary(
    LPSBinary psbDest,
    const LPSBinary psbSrc,
    LPVOID pParent);

void main()
{
    // MAPI address book and session variables
    HRESULT       hRes = S_OK;            // Result code returned from MAPI calls.
    LPMAPISESSION lpSession = NULL;   // Pointer to MAPI session.
    LPADRBOOK     lpAddrBook = NULL;  // Pointer to Address Book.

    // Counters
    ULONG         i = 0;                  // Index counter
    ULONG         j = 0;                  // Index counter

    // Used for querying hierarchy
    ULONG                                   ulObjType = 0L;      // Object type returned by MAPI
    LPMAPICONTAINER     pIABRoot = NULL;     // Root address book container
    LPMAPITABLE              pHTable = NULL;      // Holds hierarchy table
    LPSRowSet        pRows = NULL;        // Pointer to row set. Stores AB Address Lists

    // Used for setting search path
    LPSRowSet     pNewRows = NULL;        // Pointer to new row set
    SizedSRowSet  (numANR, NewRows);      // New row set
    SPropValue    sProps[numANR] = {0};   // Property tag structure

    // Structures contaning MAPI Column Sets required for querying tables
    enum {
        abPR_ENTRYID,
        abPR_DISPLAY_NAME_W,
        abNUM_COLS};

    static SizedSPropTagArray(abNUM_COLS,abCols) = {
        abNUM_COLS,
        PR_ENTRYID,
        PR_DISPLAY_NAME_W,
    };

    // Initialize MAPI
    if (FAILED ( hRes = MAPIInitialize(NULL))) goto Exit;

    // Log on to MAPI and allow user to choose profile

    // Note: This uses the current MAPI session if there is one
    if (FAILED ( hRes = MAPILogonEx(NULL, NULL, NULL, MAPI_LOGON_UI, &lpSession))) goto Exit;

    // Open the Address Book
    if (FAILED (hRes = lpSession->OpenAddressBook(NULL, NULL, NULL, &lpAddrBook))) goto Cleanup;

    // Open the Address Book Root container
    if (FAILED (hRes = lpAddrBook -> OpenEntry (
        0L, 
        NULL,
        NULL, 
        0L,
        &ulObjType,
        (LPUNKNOWN *) &pIABRoot )))
    goto Cleanup;

    // Intentionally allocate 0 bytes. This is used for buffer management.
    MAPIAllocateBuffer(0L, &tempLink); 

    // Make sure there is a Container object
    // Query hierarchy for containers
    if ( MAPI_ABCONT == ulObjType ) {
        // - Call IMAPIContainer::GetHierarchyTable to open the Hierarchy
        //   table of the root address book container
        if ( FAILED ( hRes = pIABRoot -> GetHierarchyTable ( CONVENIENT_DEPTH | MAPI_UNICODE,
            &pHTable ) ) )
        goto Cleanup;

        // Get the list of address book containers first
        if ( FAILED ( hRes = HrQueryAllRows ( 
            pHTable,
            (LPSPropTagArray) &abCols,
            NULL,
            NULL,
            0L,
            &pRows ) ) )
        goto Cleanup;

        // Initialize the structures to set the search order
        ZeroMemory(&NewRows, numANR * sizeof(SRow));
        pNewRows = (LPSRowSet)&NewRows;

        // Set the number of rows you are going to set
        pNewRows->cRows = numANR;

        // Set the pointers to the structures
        for (i=0; i<numANR; i++)
            pNewRows->aRow[i].lpProps = &sProps[i];

        // Compare the list to the ones that of interest
        for (i=0; i<pRows->cRows; i++) {
            if (pRows->aRow[i].lpProps[abPR_DISPLAY_NAME_W].ulPropTag == PR_DISPLAY_NAME_W) {
                LPWSTR containerName =  pRows->aRow[i].lpProps[abPR_DISPLAY_NAME_W].Value.lpszW;
                for (j=0; j<numANR; j++)
                    if (!wcscmp (containerName, ANROrder[j])) {
                        // First check if a container with this name has been found already
                        if (numContainersFound[j] == 0) {
                            numContainersFound[j]++;
                            pNewRows->aRow[j].cValues = 1;

                            // The property being passing is PR_ENTRY_ID
                            pNewRows->aRow[j].lpProps[0].ulPropTag = PR_ENTRYID;

                            // Copy the binary data over
                            if (FAILED (hRes = CopySBinary(
                                &pNewRows->aRow[j].lpProps[0].Value.bin,
                                &pRows->aRow[i].lpProps[abPR_ENTRYID].Value.bin,
                                tempLink))) { 
                                    printf ("Fatal Error:Failed to copy entry IDs\n");
                                    goto Cleanup;
                            }
                         }
                         // More than 1 container matched the same name
                         else { 
                             printf ("Fatal Error: Duplicate container found, container name = %s\n", containerName);
                             goto Cleanup;
                         }
                    }
            }
        }

        // Only set the search path if all the rows have been found
        // Check the array for any entries that were blank
        for (i=0; i< numANR; i++)
            if (numContainersFound [i] == 0) {
                printf ("Fatal Error: all containers were not found\n");
                goto Cleanup;
            }

        // Everything is safe to set the search path now
        if (FAILED (hRes = lpAddrBook->SetSearchPath(0, pNewRows))) {                   
            printf ("Fatal Error: failed to set the search path\n");
            goto Cleanup;
        }
    }

 

    Cleanup:
        MAPIFreeBuffer(tempLink);
        UlRelease(pHTable);
        FreeProws(pRows);
        UlRelease (pIABRoot);
        UlRelease(lpAddrBook);

        // Log off from MAPI
        hRes = lpSession->Logoff(NULL, NULL, 0);
        UlRelease(lpSession);

    Exit:
        // Uninitialize MAPI
        MAPIUninitialize();
}

 

/////////////////////////////////////////////////////////////
//    CopySBinary()
//
//    Parameters
//
//    Purpose
//      Allocates a new SBinary and copies psbSrc into it
//

STDMETHODIMP CopySBinary(
    LPSBinary psbDest,
    const LPSBinary psbSrc,
    LPVOID pParent)
{
    HRESULT     hRes = S_OK;
    psbDest->cb = psbSrc->cb;

    if (psbSrc->cb) {
        if (pParent)
            hRes = MAPIAllocateMore(
                 psbSrc->cb,
                 pParent,
                 (LPVOID*) &psbDest->lpb);
        else
            hRes = MAPIAllocateBuffer(
                 psbSrc->cb,
                 (LPVOID*) &psbDest->lpb);

    if (!FAILED(hRes))
        CopyMemory(psbDest->lpb,psbSrc->lpb,psbSrc->cb);
    }

   return hRes;
}

See Also

About Setting the Search Path for Address Books in Outlook


Community Additions

ADD
Show:
© 2014 Microsoft