How to: Get the Path of a Specific Version of MAPI for the Default Mail Client

Applies to: Office 2010 | Outlook 2010 | Visual Studio

This topic includes a code sample in C++ that shows how to obtain the path of a specific version of MAPI that is used by the default mail client on a computer. MAPI mail clients have an option to specify in the registry a custom DLL that the MAPI stub library should load and dispatch MAPI calls to. The registry key to set for this custom DLL for a default mail client is MSIComponentID, under the HKLM\Software\Clients\Mail key of the default mail client. The FGetComponentPath function, exported by the MAPI stub library, mapistub.dll, can return the path to the custom version of MAPI specified by the MSIComponentID registry key.

This code sample includes two functions: HrGetRegMultiSZValueA and GetMAPISVCPath. The GetMAPISVCPath function uses FGetComponentPath to obtain the path to the custom version of MAPI. It assumes that the default mail client is Microsoft Office Outlook 2007, and passes to FGetComponentPath the value, {FF1D0740-D227-11D1-A4B0-006008AF820E}, that Outlook 2007 sets as the component ID of MAPI for the MSIComponentID registry key.

Note

In practice, you should not assume the value, {FF1D0740-D227-11D1-A4B0-006008AF820E}, is always the component ID of MAPI and directly pass it to FGetComponentPath. To reliably find out which version of MAPI Outlook uses on a computer, you must read from the registry the value of MSIComponentID and pass it to FGetComponentPath.

The following steps describe how GetMAPISVCPath does this.

  1. Loads the MAPI stub library, mapistub.dll, from the system directory.

  2. Assumes that mapistub.dll exports the FGetComponentPath function, it tries to get the address of this function from mapistub.dll.

  3. If getting the address from mapistub.dll fails, it tries to get the address from mapi32.dll.

  4. If getting the address of FGetComponentPath succeeds, it opens the registry and uses the HrGetRegMultiSZValueA function to read the registry values under HKLM\Software\Clients\Mail\Microsoft Outlook.

  5. Calls FGetComponentPath, specifying the value, {FF1D0740-D227-11D1-A4B0-006008AF820E}, to obtain the path to the version of MAPI that Outlook 2007 uses.

Note that to support localized copies of MAPI for English and non-English locales, the code sample reads the values for the MSIApplicationLCID and MSIOfficeLCID subkeys and calls FGetComponentPath, first specifying MSIApplicationLCID as szQualifier, and then again specifying MSIOfficeLCID as szQualifier. For more information about registry keys for mail clients that support non-English languages, see Setting Up the MSI Keys for Your MAPI DLL.

// HrGetRegMultiSZValueA 
// Get a REG_MULTI_SZ registry value - allocating memory using new to hold it. 
void HrGetRegMultiSZValueA( 
    IN HKEY hKey, // the key. 
    IN LPCSTR lpszValue, // value name in key. 
    OUT LPVOID* lppData) // where to put the data. 
{ 
    *lppData = NULL; 
    DWORD dwKeyType = NULL;       
    DWORD cb = NULL; 
    LONG lRet = 0; 
    
    // Get its size 
    lRet = RegQueryValueExA( 
        hKey, 
        lpszValue, 
        NULL, 
        &dwKeyType, 
        NULL, 
        &cb); 
 
    if (ERROR_SUCCESS == lRet && cb && REG_MULTI_SZ == dwKeyType) 
    { 
        *lppData = new BYTE[cb]; 
       
        if (*lppData) 
        { 
            // Get the current value 
            lRet = RegQueryValueExA( 
                hKey,  
                lpszValue,  
                NULL,  
                &dwKeyType,  
                (unsigned char*)*lppData,  
                &cb); 
          
            if (ERROR_SUCCESS != lRet) 
            { 
                delete[] *lppData; 
                *lppData = NULL; 
            } 
        } 
    } 
} 
 
typedef BOOL (STDAPICALLTYPE FGETCOMPONENTPATH) ( 
    LPSTR szComponent, 
    LPSTR szQualifier, 
    LPSTR szDllPath, 
    DWORD cchBufferSize, 
    BOOL fInstall); 
typedef FGETCOMPONENTPATH FAR * LPFGETCOMPONENTPATH;  
 
/////////////////////////////////////////////////////////////////////////////// 
// Function name   : GetMAPISVCPath 
// Description       : This will get the correct path to the MAPISVC.INF file. 
// Return type      : void  
// Argument         : LPSTR szMAPIDir - Buffer to hold the path to the MAPISVC file. 
//                    ULONG cchMAPIDir - size of the buffer 
void GetMAPISVCPath(LPSTR szMAPIDir, ULONG cchMAPIDir) 
{ 
    HRESULT hRes = S_OK; 
    UINT uiRet = 0; 
    LONG lRet = 0; 
    BOOL bRet = true; 
    
    szMAPIDir[0] = '\0'; // Terminate string at position 0, safer if fail below 
    
    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; 
          
            HMODULE hmodStub = 0; 
            HMODULE hmodMapi32 = 0; 
          
            // Load mapistub.dll 
            hmodStub = LoadLibraryA(szDLLPath); 
            if (hmodStub) 
            {    
                // Get the address of FGetComponentPath from the mapistub 
                pfnFGetComponentPath = (LPFGETCOMPONENTPATH)GetProcAddress( 
                    hmodStub, "FGetComponentPath"); 
            } 
          
            // If failed to get the address of FGetComponentPath, 
            // try mapi32.dll 
            if (!pfnFGetComponentPath) 
            { 
                hRes = StringCchPrintfA(szDLLPath, MAX_PATH+1, "%s\\%s", 
                    szSystemDir, "mapi32.dll"); 
                if (SUCCEEDED(hRes)) 
                { 
                    // Load mapi32.dll 
                    hmodMapi32 = LoadLibraryA(szDLLPath); 
                    if (hmodMapi32) 
                    { 
                        // Get the address of FGetComponentPath from mapi32 
                        pfnFGetComponentPath = (LPFGETCOMPONENTPATH)GetProcAddress( 
                            hmodMapi32, "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); 
                } 
             
                // Only passing a fixed value as the component ID for MAPI in this example 
                // In practice, must read from the registry the value of MSIComponentID 
                if (szAppLCID) 
                { 
                    bRet = pfnFGetComponentPath( 
                        "{FF1D0740-D227-11D1-A4B0-006008AF820E}", szAppLCID, szMAPIDir, cchMAPIDir, true); 
                } 
                if ((!bRet || szMAPIDir[0] == _T('\0')) && szOfficeLCID) 
                { 
                    bRet = pfnFGetComponentPath( 
                    "{FF1D0740-D227-11D1-A4B0-006008AF820E}", szOfficeLCID, szMAPIDir, cchMAPIDir, true); 
                } 
                if (!bRet || szMAPIDir[0] == _T('\0')) 
                { 
                    bRet = pfnFGetComponentPath( 
                        "{FF1D0740-D227-11D1-A4B0-006008AF820E}", NULL, szMAPIDir, cchMAPIDir, true); 
                } 
             
                // Got the path to msmapi32.dll - need to strip it 
                if (bRet && szMAPIDir[0] != _T('\0')) 
                { 
                    LPSTR lpszSlash = NULL; 
                    LPSTR lpszCur = szMAPIDir; 
                
                    for (lpszSlash = lpszCur; *lpszCur; lpszCur = lpszCur++) 
                    { 
                        if (*lpszCur == _T('\\')) lpszSlash = lpszCur; 
                    } 
                   *lpszSlash = _T('\0'); 
                } 
 
                delete[] szOfficeLCID; 
                delete[] szAppLCID; 
                if (hMicrosoftOutlook) RegCloseKey(hMicrosoftOutlook);       
            } 
             
            // If FGetComponentPath returns FALSE or if 
            // it returned nothing, or if failed to find an 
            // address of FGetComponentPath, then 
            // just default to the system directory 
            if (!bRet || szMAPIDir[0] == '\0') 
            { 
                hRes = StringCchPrintfA( 
                    szMAPIDir, cchMAPIDir,"%s", szSystemDir); 
            } 
          
            if (szMAPIDir[0] != _T('\0')) 
            { 
                hRes = StringCchPrintfA( 
                    szMAPIDir, cchMAPIDir, "%s\\%s", szMAPIDir, "MAPISVC.INF"); 
            } 
          
            if (hmodMapi32) FreeLibrary(hmodMapi32); 
            if (hmodStub) FreeLibrary(hmodStub); 
        } 
    }    
}