Created
March 25, 2016 04:28
-
-
Save hinchley/ce2db8d1cec3fef87f61 to your computer and use it in GitHub Desktop.
Create an Outlook 2016 MAPI Profile
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "stdafx.h" | |
#include <windows.h> | |
#include <mapix.h> | |
#include <mapiutil.h> | |
#include <edkmdb.h> | |
#include <atlbase.h> | |
#include <iostream> | |
#include <vector> | |
#include <map> | |
#include <sstream> | |
using namespace std; | |
#define PR_PROFILE_USER_SMTP_EMAIL_ADDRESS PROP_TAG(PT_TSTRING, pidProfileMin+0x41) | |
#define PR_PROFILE_USER_SMTP_EMAIL_ADDRESS_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); | |
HRESULT CreateProfile(LPSTR szProfile, LPSTR szSmtpAddress, LPSTR szDisplayName, LPSTR szOstPath) | |
{ | |
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 sprops; // Property structure for restriction. | |
LPPROFSECT lpGlobalProfSection = nullptr; | |
LPPROFSECT lpEmsMdbVarProfSect = nullptr; | |
SPropValue spvSmtpAddressW; | |
SPropValue spvDisplayNameW; | |
SPropValue spvOfflineStore; | |
USES_CONVERSION; | |
std::map<ULONG, LPWSTR> PropValueMap | |
{ | |
{ | |
PR_DISPLAY_NAME_W, | |
A2W(szDisplayName) | |
}, | |
{ | |
PR_PROFILE_USER_SMTP_EMAIL_ADDRESS_W, | |
A2W(szSmtpAddress) | |
} | |
}; | |
// This indicates columns we want returned from HrQueryAllRows. | |
enum { iSvcName, iSvcUID, cptaSvc }; | |
SizedSPropTagArray(cptaSvc, sptCols) = { cptaSvc, PR_SERVICE_NAME, PR_SERVICE_UID }; | |
string MSEMS = "MSEMS"; | |
// 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)szProfile, // 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)szProfile, // 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( | |
(LPTSTR)"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 = &sprops; | |
sprops.ulPropTag = PR_SERVICE_NAME; | |
sprops.Value.lpszW = L"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_ADDRESS_W; | |
spvSmtpAddressW.Value.lpszW = PropValueMap[PR_PROFILE_USER_SMTP_EMAIL_ADDRESS_W]; | |
rgvals.push_back(spvSmtpAddressW); | |
ZeroMemory(&spvDisplayNameW, sizeof(spvDisplayNameW)); | |
spvDisplayNameW.ulPropTag = PR_DISPLAY_NAME_W; | |
spvDisplayNameW.Value.lpszW = PropValueMap[PR_DISPLAY_NAME_W]; | |
rgvals.push_back(spvDisplayNameW); | |
// Experimental. | |
ZeroMemory(&spvOfflineStore, sizeof(spvOfflineStore)); | |
spvOfflineStore.ulPropTag = PR_PROFILE_OFFLINE_STORE_PATH; | |
spvOfflineStore.Value.lpszA = szOstPath; | |
rgvals.push_back(spvOfflineStore); | |
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; | |
} | |
if (FAILED(hRes = lpEmsMdbVarProfSect->SetProps(rgvals.size(), rgvals.data(), nullptr))) | |
{ | |
cout << "Error setting properties on the EMS MDB variable profile section 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 variable profile section"; | |
goto error; | |
} | |
cleanup: | |
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; | |
} | |
int _tmain(int argc, _TCHAR* argv[]) | |
{ | |
if (argc < 4) { | |
cout << "Usage: CreateMapiProfile.exe <ProfileName> <[email protected]> <OST Path>" << endl; | |
return 0; | |
} | |
LPSTR arg1 = new CHAR[lstrlenW(argv[1]) + 1]; | |
LPSTR arg2 = new CHAR[lstrlenW(argv[2]) + 1]; | |
LPSTR arg3 = new CHAR[lstrlenW(argv[3]) + 1]; | |
WideCharToMultiByte(CP_ACP, 0, argv[1], -1, arg1, lstrlenW(argv[1]) + 1, 0, 0); | |
WideCharToMultiByte(CP_ACP, 0, argv[2], -1, arg2, lstrlenW(argv[2]) + 1, 0, 0); | |
WideCharToMultiByte(CP_ACP, 0, argv[3], -1, arg3, lstrlenW(argv[3]) + 1, 0, 0); | |
CreateProfile(arg1, arg2, arg2, arg3); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment