Hello,
I don't have any experience in C++ and I need to create a console application to create one Outlook profile with two message service for Exchange
Why C++? Since Outlook 2016 PRF files are no more supported and Extended MAPI needs to be used
Found the following code on Microsoft Website
https://docs.microsoft.com/en-us/office/client-developer/outlook/mapi/how-to-programmatically-create-a-profile-in-outlook
I changed the code to include tow emails instead of one but having an issue with CreateMsgService
Basically the second message service is created but empty
Copied the code at the end of this message
Thank you for your help
Goksel
// CreateProfile.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <Windows.h>
#include <MAPIX.h>
#include <MAPIUtil.h>
#include <EdkMdb.h>
#include <iostream>
#include <vector>
#include <map>
using namespace std;
#define PR_PROFILE_USER_SMTP_EMAIL_ADDRESS1
PROP_TAG(PT_TSTRING, pidProfileMin+0x41)
#define PR_PROFILE_USER_SMTP_EMAIL_ADDRESS1_W
PROP_TAG(PT_UNICODE, pidProfileMin+0x41)
#define PR_PROFILE_USER_SMTP_EMAIL_ADDRESS2
PROP_TAG(PT_TSTRING, pidProfileMin+0x41)
#define PR_PROFILE_USER_SMTP_EMAIL_ADDRESS2_W
PROP_TAG(PT_UNICODE, pidProfileMin+0x41)
#define PR_EMSMDB_SECTION_UID
PROP_TAG(PT_BINARY, 0x3D15)
#define MAPI_FORCE_ACCESS
0x80000
STDMETHODIMP GetGlobalProfileSection(LPSERVICEADMIN lpSvcAdmin, LPMAPIUID lpMapiUid, ULONG ulFlags, LPPROFSECT * lppProfSect);
STDMETHODIMP GetEMSMDBVarProfileSection(LPSERVICEADMIN lpSvcAdmin, LPPROFSECT lpGlobalProfSection, LPPROFSECT * lppProfSect);
std::map<ULONG, LPWSTR> PropValueMap1
{
{
PR_DISPLAY_NAME_W,
L"MAILBOX1"
},
{
PR_PROFILE_USER_SMTP_EMAIL_ADDRESS1_W,
L"=SMTP:mailbox1@contoso.com"
}
};
std::map<ULONG, LPWSTR> PropValueMap2
{
{
PR_DISPLAY_NAME_W,
L"MAILBOX2"
},
{
PR_PROFILE_USER_SMTP_EMAIL_ADDRESS2_W,
L"=SMTP:mailbox2@contoso.com"
}
};
int _tmain(int argc, _TCHAR* argv[])
{
HRESULT
hRes = S_OK; // Result from MAPI calls.
LPPROFADMIN
lpProfAdmin = NULL; // Profile Admin object.
LPSERVICEADMIN
lpSvcAdmin = NULL; // Service Admin object.
LPMAPITABLE
lpMsgSvcTable = NULL; // Table to hold services.
LPSRowSet
lpSvcRows = NULL; // Rowset to hold results of table query.
vector<SPropValue>
rgvals;
SRestriction
sres; // Restriction structure.
SPropValue
SvcProps; // Property structure for restriction.
LPPROFSECT
lpGlobalProfSection = nullptr;
LPPROFSECT
lpEmsMdbVarProfSect = nullptr;
SPropValue
spvSmtpAddressW;
SPropValue
spvDisplayName;
// This indicates columns we want returned from HrQueryAllRows.
enum { iSvcName, iSvcUID, cptaSvc };
SizedSPropTagArray(cptaSvc, sptCols) = { cptaSvc, PR_SERVICE_NAME, PR_SERVICE_UID };
string ProfileName = "SMS";
// Initialize MAPI.
if (FAILED(hRes = MAPIInitialize(NULL)))
{
cout << "Error initializing MAPI.";
goto error;
}
// Get an IProfAdmin interface.
if (FAILED(hRes = MAPIAdminProfiles(0, // Flags.
&lpProfAdmin))) // Pointer to new IProfAdmin.
{
cout << "Error getting IProfAdmin interface.";
goto error;
}
// Create a new profile.
if (FAILED(hRes = lpProfAdmin->CreateProfile((LPTSTR)ProfileName.c_str(), // Name of new profile.
nullptr, // Password for profile.
0, // Handle to parent window.
0))) // Flags.
{
cout << "Error creating profile.";
goto error;
}
// Get an IMsgServiceAdmin interface off of the IProfAdmin interface.
if (FAILED(hRes = lpProfAdmin->AdminServices((LPTSTR)ProfileName.c_str(), // Profile that we want to modify.
nullptr, // Password for that profile.
0, // Handle to parent window.
0, // Flags.
&lpSvcAdmin))) // Pointer to new IMsgServiceAdmin.
{
cout << "Error getting IMsgServiceAdmin interface.";
goto error;
}
// Create the new message service for Exchange.
if (FAILED(hRes = lpSvcAdmin->CreateMsgService("MSEMS", // Name of service from MAPISVC.INF.
NULL, // Display name of service.
NULL, // Handle to parent window.
NULL))) // Flags.
{
cout << "Error creating Exchange message service.";
goto error;
}
// You now have to obtain the entry id for the new service.
// You can do this by getting the message service table
// and getting the entry that corresponds to the new service.
if (FAILED(hRes = lpSvcAdmin->GetMsgServiceTable(0, // Flags.
&lpMsgSvcTable))) // Pointer to table.
{
cout << "Error getting Message Service Table.";
goto error;
}
// Set up restriction to query table.
sres.rt = RES_CONTENT;
sres.res.resContent.ulFuzzyLevel = FL_FULLSTRING;
sres.res.resContent.ulPropTag = PR_SERVICE_NAME;
sres.res.resContent.lpProp = &SvcProps;
SvcProps.ulPropTag = PR_SERVICE_NAME;
SvcProps.Value.lpszA = "MSEMS";
// Query the table to obtain the entry for the newly created message service.
if (FAILED(hRes = HrQueryAllRows(lpMsgSvcTable,
(LPSPropTagArray)&sptCols,
&sres,
NULL,
0,
&lpSvcRows)))
{
cout << "Error querying table for new message service.";
goto error;
}
ZeroMemory(&spvSmtpAddressW, sizeof(spvSmtpAddressW));
spvSmtpAddressW.ulPropTag = PR_PROFILE_USER_SMTP_EMAIL_ADDRESS1_W;
spvSmtpAddressW.Value.lpszW = PropValueMap1[PR_PROFILE_USER_SMTP_EMAIL_ADDRESS1_W];
rgvals.push_back(spvSmtpAddressW);
if (FAILED(hRes = GetGlobalProfileSection(
lpSvcAdmin,
(LPMAPIUID)lpSvcRows->aRow->lpProps[iSvcUID].Value.bin.lpb,
MAPI_MODIFY,
&lpGlobalProfSection)))
{
cout << "Error attempting to get the Global Profile Section.";
goto error;
}
if (FAILED(hRes = lpGlobalProfSection->SetProps(
rgvals.size(),
rgvals.data(),
nullptr)))
{
cout << "Error attempting to set the smtp address.";
goto error;
}
if (FAILED(hRes = lpGlobalProfSection->SaveChanges(
KEEP_OPEN_READWRITE)))
{
cout << "Error attempting to save after setting the smtp address";
goto error;
}
if (FAILED(hRes = GetEMSMDBVarProfileSection(lpSvcAdmin, lpGlobalProfSection, &lpEmsMdbVarProfSect)))
{
goto error;
}
ZeroMemory(&spvDisplayName, sizeof(spvDisplayName));
spvDisplayName.ulPropTag = PR_DISPLAY_NAME_W;
spvDisplayName.Value.lpszW = PropValueMap1[PR_DISPLAY_NAME_W];
rgvals.push_back(spvDisplayName);
if (FAILED(hRes = lpEmsMdbVarProfSect->SetProps(
rgvals.size(),
rgvals.data(),
nullptr)))
{
cout << "Error call set props on the ems mdb var prof sect using the smtp address";
goto error;
}
if (FAILED(hRes = lpEmsMdbVarProfSect->SaveChanges(
KEEP_OPEN_READWRITE)))
{
cout << "Error attempting to save after setting the smtp address on the ems mdb var prof sect";
goto error;
}
// Create the new message service for Exchange.
if (FAILED(hRes = lpSvcAdmin->CreateMsgService("MSEMS", // Name of service from MAPISVC.INF.
NULL, // Display name of service.
NULL, // Handle to parent window.
NULL))) // Flags.
{
cout << "Error creating Exchange message service.";
goto error;
}
ZeroMemory(&spvSmtpAddressW, sizeof(spvSmtpAddressW));
spvSmtpAddressW.ulPropTag = PR_PROFILE_USER_SMTP_EMAIL_ADDRESS2_W;
spvSmtpAddressW.Value.lpszW = PropValueMap2[PR_PROFILE_USER_SMTP_EMAIL_ADDRESS2_W];
rgvals.push_back(spvSmtpAddressW);
if (FAILED(hRes = GetGlobalProfileSection(
lpSvcAdmin,
(LPMAPIUID)lpSvcRows->aRow->lpProps[iSvcUID].Value.bin.lpb,
MAPI_MODIFY,
&lpGlobalProfSection)))
{
cout << "Error attempting to get the Global Profile Section.";
goto error;
}
if (FAILED(hRes = lpGlobalProfSection->SetProps(
rgvals.size(),
rgvals.data(),
nullptr)))
{
cout << "Error attempting to set the smtp address.";
goto error;
}
if (FAILED(hRes = lpGlobalProfSection->SaveChanges(
KEEP_OPEN_READWRITE)))
{
cout << "Error attempting to save after setting the smtp address";
goto error;
}
if (FAILED(hRes = GetEMSMDBVarProfileSection(lpSvcAdmin, lpGlobalProfSection, &lpEmsMdbVarProfSect)))
{
goto error;
}
ZeroMemory(&spvDisplayName, sizeof(spvDisplayName));
spvDisplayName.ulPropTag = PR_DISPLAY_NAME_W;
spvDisplayName.Value.lpszW = PropValueMap2[PR_DISPLAY_NAME_W];
rgvals.push_back(spvDisplayName);
if (FAILED(hRes = lpEmsMdbVarProfSect->SetProps(
rgvals.size(),
rgvals.data(),
nullptr)))
{
cout << "Error call set props on the ems mdb var prof sect using the smtp address";
goto error;
}
if (FAILED(hRes = lpEmsMdbVarProfSect->SaveChanges(
KEEP_OPEN_READWRITE)))
{
cout << "Error attempting to save after setting the smtp address on the ems mdb var prof sect";
goto error;
}
cleanup:
// Clean up
if (lpEmsMdbVarProfSect) lpEmsMdbVarProfSect->Release();
if (lpGlobalProfSection) lpGlobalProfSection->Release();
if (lpSvcRows) FreeProws(lpSvcRows);
if (lpMsgSvcTable) lpMsgSvcTable->Release();
if (lpSvcAdmin) lpSvcAdmin->Release();
if (lpProfAdmin) lpProfAdmin->Release();
MAPIUninitialize();
return 0;
error:
cout << " hRes = 0x" << hex << hRes << dec << endl;
goto cleanup;
}
STDMETHODIMP GetGlobalProfileSection(LPSERVICEADMIN lpSvcAdmin, LPMAPIUID lpMapiUid, ULONG ulFlags, LPPROFSECT * lppProfSect)
{
HRESULT
hRes = MAPI_E_CALL_FAILED;
LPPROFSECT
lpProfSect = nullptr;
LPPROFSECT
lpEmsMdbVarProfSect = nullptr;
ULONG
cValues = 0;
LPSPropValue
lpProps = nullptr;
SizedSPropTagArray(1, spta) = { 1,{ PR_EMSMDB_SECTION_UID } };
*lppProfSect = nullptr;
hRes = lpSvcAdmin->OpenProfileSection(lpMapiUid,
0,
MAPI_FORCE_ACCESS,
&lpProfSect);
if (FAILED(hRes) || lpProfSect == nullptr)
{
return hRes;
}
hRes = lpProfSect->GetProps((LPSPropTagArray)&spta, 0, &cValues, &lpProps);
if (FAILED(hRes) || lpProps == nullptr || cValues == 0)
{
return hRes;
}
if (lpProps[0].ulPropTag != PR_EMSMDB_SECTION_UID)
{
hRes = lpProps[0].Value.err;
goto Cleanup;
}
hRes = lpSvcAdmin->OpenProfileSection((LPMAPIUID)lpProps->Value.bin.lpb, 0, ulFlags, &lpEmsMdbVarProfSect);
if (FAILED(hRes) || lpEmsMdbVarProfSect == nullptr)
{
goto Cleanup;
}
*lppProfSect = lpEmsMdbVarProfSect;
Cleanup:
if (lpProps)
{
MAPIFreeBuffer(lpProps);
}
if (lpProfSect)
{
lpProfSect->Release();
}
return hRes;
}
STDMETHODIMP GetEMSMDBVarProfileSection(LPSERVICEADMIN lpSvcAdmin, LPPROFSECT lpGlobalProfSection, LPPROFSECT * lppProfSect)
{
HRESULT hRes = MAPI_E_CALL_FAILED;
SizedSPropTagArray(1, sptaStoreProviders) = { 1,{ PR_STORE_PROVIDERS } };
ULONG
cValues = 0;
LPSPropValue
lpProps = nullptr;
LPPROFSECT
lpProfSect = nullptr;
if (!lpSvcAdmin || !lpGlobalProfSection || !lppProfSect)
return E_INVALIDARG;
*lppProfSect = nullptr;
if (FAILED(hRes = lpGlobalProfSection->GetProps(
(LPSPropTagArray)&sptaStoreProviders,
0,
&cValues,
&lpProps)) || cValues == 0 || lpProps == nullptr)
{
cout << "Error attempting to get the PR_STORE_PROVIDERS property " << endl;
goto Cleanup;
}
if (lpProps->ulPropTag != sptaStoreProviders.aulPropTag[0])
{
hRes = lpProps->Value.err;
goto Cleanup;
}
if (FAILED(hRes = lpSvcAdmin->OpenProfileSection(
(LPMAPIUID)lpProps->Value.bin.lpb,
0,
MAPI_FORCE_ACCESS | MAPI_MODIFY,
&lpProfSect)) || lpProfSect == nullptr)
{
cout << "Could not open the profile section using the PR_STORE_PROVIDERS property " << endl;
goto Cleanup;
}
*lppProfSect = lpProfSect;
Cleanup:
if (lpProps)
{
MAPIFreeBuffer(lpProps);
lpProps = nullptr;
}
return hRes;
}