My previous article covered how to figure out which account Outlook was operating under in circumstances where profiles with multiple Exchange accounts were active.

I ended with showing you how to get the profile section of the message service of the active Exchange account. However, if you actually want to read the juicy configuration options, like PR_PROFILE_CONFIG_FLAGS, you’ll need to dig a bit deeper. Although some configuration settings are available at the message service profile section level, that specific profile section isn’t actually the “new” global profile section in 2010.

So where’s my global profile section!?

In order to find the “new” global profile section in 2010, you need to look through that message service’s service providers. A single provider will have a profile section that will contain all of the configuration settings previously available from the global profile section.

I’m referring to this section as the “new” global profile section because I have yet to find a term from Microsoft that describes the profile section containing all of the configuration settings previously found in the global profile section.

Again, what you are using to access the profile system doesn’t really matter, for purposes of brevity I assume you’re using .NET and Profman.dll to do so.

So, if you look at where we left off, we ended with an IService object. This is the active message service. You can see that IService exposes a Providers property, which is the collection of all of the service providers found below the message service.

Resource Type Values

Each IProvider belonging to this collection will have a number of properties. The one of interest here is ResourceType, otherwise known as PR_RESOURCE_TYPE (0x3E030003), which is an indicator of the…you guessed it…service provider type! Its value can be one of the following:

  • MAPI_STORE_PROVIDER (0×00000021)
  • MAPI_AB (0×00000022)
  • MAPI_AB_PROVIDER (0×00000023)
  • MAPI_TRANSPORT_PROVIDER (0×00000024)
  • MAPI_SPOOLER (0×00000025)
  • MAPI_PROFILE_PROVIDER (0×00000026)
  • MAPI_SUBSYSTEM (0×00000027)
  • MAPI_HOOK_PROVIDER (0×00000028)

There’s a lot that can be said about any of those, however the one we care about is none of the above. We actually want the one provider that doesn’t have a resource type set.

If you’re hitting the provider up with straight-up MAPI then you want the provider that returns 0x8004010F (MAPI_E_NOT_FOUND). If you’re using Profman.dll or something else to make your life easier, than the value for the provider we care about will most like be 0.

Example (continuing from code in last article)

Please be aware the following code, for the sake of brevity, again does not follow the absolute best practices for COM interop object lifetime management. I have other articles on that, etc.

IProvider provider = null;

for (int k = 1; k <= service.Providers.Count; k++)
{
  //"service" is the active message service we found in the last article
  provider = service.Providers.Item[k];

  if (provider.ResourceType == 0)
    break;
}

//This provider should contain the section we want (the "new"
//global profile section).
if (null == provider)
  return;

IProfSect newGlobalSection = provider.ProfSect;

object configFlags = newGlobalSection.Item[0x66010003];
//This should give you PR_PROFILE_CONFIG_FLAGS.

That’s it.

 

One of the biggest new features included with Outlook 2010 is the ability to add multiple Exchange mail accounts to a single profile. Integrating multiple Exchange accounts in the past was simply not possible; in order to use a different Exchange mail account, you had to quit Outlook and log on using a different profile.

In this article I will briefly cover how multiple Exchange accounts may affect a user’s Outlook experience, and then touch on how to interface with profiles that feature multiple Exchange accounts from your code for profile management purposes.

Multiple Exchange Accounts? What does this actually do?!

Adding another Exchange account to your profile essentially creates a new profile section for a message service (MSEMS) as well as the required sections for the service providers underneath that.

Assuming you are Samuel Clemens, and you add Test User1′s Exchange account to your profile, you will see two Exchange mailboxes when running Outlook. Expanding these mailboxes will give you access to all the usual goods: Calendar, Inbox, etc.

We get access to their mailbox…is that it?

So far, this may seem similar to managing another user’s mailbox in previous versions of Outlook. If you are unfamiliar with the process, adding a user’s mailbox this way requires the completion of a ridiculous number of steps (one them even being restarting your computer! Hmm…).

So, the ability to directly add the account to your profile surely simplifies the process. You get much more than convenience, however. Account settings specific to a new account will be in effect while operating within that account’s boundaries. Leaving those boundaries results in a change of the active account, thus resulting in the application of a different set of settings.

For example, I might have Samuel Clemens’ account set to connect using Cached Exchange Mode. With Test User1, for whatever reason, I may have disabled Cached Exchange Mode in my profile. These settings were set the normal way one would set them via editing the accounts of the profile.

Previously, the only settings that mattered were whatever your default profile had set when managing other mailboxes. Surely, even with Outlook 2010, only one connection mode will be active (either online or cached) right?

Well, actually, if you load up your Outlook, you will be connected to Exchange in both online and cached modes. Yes, if your product has a close relationship with Outlook that is affected by the active connection mode, you may already be in a panic. Anyone who has had to do anything non-trivial with Outlook knows that the behavior of Outlook and Exchange differ in a great many ways depending on your connection mode. Time to suck it up.

If you click on the primary user mailbox, and go to their calendar, what you are seeing is the cached contents of your calendar. If you click on the new user’s mailbox, and go to their calendar, you are treated to the live contents of your calendar as it exists on Exchange.

Everything in one mailbox is in cached mode, everything in the other is in online mode.

I’m sure there are many other things to take note of in regards to the user experience of adding another mailbox, however those will be covered by someone else on the Internet, or perhaps in a future article from myself.

Now, onto how this will affect your development experience.

How to Manage Multiple Mailbox Profiles.

Whether or not your code base will requirement modification in light of this new feature is something I cannot answer for you. It all depends on what your product does, and how deeply it interfaces with Outlook and Exchange. Feel free to leave a comment detailing a specific interaction with Outlook/Exchange that you are unsure about in regards to whether or not it will require modification, and I will lend my thoughts.

Because I just started to look at this topic myself, I am not able to provide a simple bullet point list of specific “gotchas” produced by this change. Then again, we’re still encountering “gotchas” from Outlook and Exchange as a whole, so I’m not going to feel too bad about that.

An overview of all potential developmental problems brought about by this change is outside the scope of this article. We’re going to start at ground zero and discuss how you can read and act off of settings from a profile with multiple accounts.

Before we get into that, however, let’s briefly touch on how profile management has traditionally been done.

Traditional Profile Management.

By profile management, I am speaking of the act of reading relevant profile sections from the active MAPI profile itself and retrieving settings required for your product to function its best. The settings at interest here will typically be settings not available elsewhere.

One example is a service profile’s PR_PROFILE_CONFIG_FLAGS (0×66010003) property. This will return a bitmask that can contain a host of important settings; it will be comprised of one or more or none of the following flags:

  • CONFIG_SHOW_CONNECT_UI (0×00000004)
    • Flag that determines whether a user interface will be shown during the process of connecting a service provider
  • CONFIG_OST_CACHE_PRIVATE (0×00000180)
    • Flag indicating we wish to use cached Exchange mode. This flag directly corresponds to the “Use Cached Exchange Mode” check box in an account’s settings.
  • CONFIG_OST_CACHE_PUBLIC (0×00000400)
    • Flag indicating that we want to use cached Exchange mode when dealing with public folder favorites. This flag directly corresponds to the “Download Public Folder Favorites” check box in an account’s settings.
  • CONFIG_NO_AUTO_DETECT (0×00000010)
    • Flag indicating we want to manually control the connection state during start up. The presence of this flag directly corresponds to the selection of the “Manually control connection state” radio button present in the “When starting” section of the General tab of the properties dialog of the Exchange account.
  • CONFIG_SHOW_STARTUP_UI (0×00000002)
    • Flag indicating we want to choose the connection type when starting. This directly corresponds to the checkbox “Choose the connection type when starting” located underneath the “Manually control connection state” radio button. This can only be set if CONFIG_NO_AUTO_DETECT is present.
  • CONFIG_PROMPT_FOR_CREDENTIALS (0×00000008)
    • Flag indicating that we should be prompted for credentials during the initial connection phase. This corresponds to the “Always prompt for logon credentials” check box in the account settings.
  • CONFIG_SERVICE (0×00000001)
    • I am not aware offhand of what this one does.

So, as you can see from above, the PR_PROFILE_CONFIG_FLAGS tells us a great deal about our user. You may have noticed one important flag was missing, however. What about the “Download shared folders” setting? This is on by default (when cached mode is enabled), and indicates whether or not cached mode applies to shared folder environments.

Serious Outlook environments are rife with shared folder usage, so this is an important setting. Although we’re getting slightly off-topic here, I don’t believe this information is elsewhere on the Internet (at least I’ve never stumbled upon it). So I felt like I should share it with you.

The flag for “Download shared folders” has no name I am aware of — I’m fairly certain there is no name for it. Regardless, the flag for it is 0×00000800.

So, a typical cached mode set profile will have the following value for PR_PROFILE_CONFIG_FLAGS:

CONFIG_SHOW_CONNECT_UI|CONFIG_OST_CACHE_PRIVATE|0x00001000|0x0000800

Now, you may be scratching your head at the second last flag there, however let’s not worry about that now and get back to how we actually read this value.

I’m going to assume you are using ProfMan.dll, a profile management helper library made available with Redemption.

The code appearing in the rest of this article is purely demonstrative code. This code, as it is, is not code that would appear in any professional work I have control over. You will need to have the proper supplemental code checking for all possible conditions such as libraries not being registered, access issues, proper unmanaged resource disposal, etc. Copy/pasting this code will cause failure, as you need to have a head on your shoulders to tackle this stuff without causing problems down the line.

Unfortunately the people that the above disclaimer targets are probably the ones least likely to read it.

Here’s how we would get the PR_PROFILE_CONFIG_FLAGS traditionally:

//Load all of the profiles.
Type profilesType = Type.GetTypeFromProgID("ProfMan.Profiles");
IProfiles profiles = (IProfiles) Activator.CreateInstance(profilesType);

//Find the profile of interest.
//This will be the current Outlook session's profile, or whatever you fancy.
IProfile profile = null;

for (int i = 1; i <= profiles.Count; i++)
{ //The profiles are not enumerable.
  profile = profiles.Item[i];
  if (profile.Name == currentProfileName)
  break;
}

//Open the global profile section.
IProfSect globalSection = profile.GlobalProfSect;

//Get PR_PROFILE_CONFIG_FLAGS
int configFlags = (int) globalSection.Item[0x66010003];

And there you have it. The above code is missing a lot of COM interop maintenance and management code, so you’ve been warned.

Unless your eyes aren’t working very well, you may have noticed that we found the setting in the profile’s “Global Profile Section”. To make a long story short, this is where many of the profile’s settings are stored.

Now, how are multiple Exchange mailbox profiles different?

Multiple Mailbox Profile Management.

Recall that the config flags property was located in the Global Profile Section. There are many other settings located there are as well. When you say “Global Profile Section” to yourself, it just seems to drip with a timbre that sounds both unique and exclusive, no? How is this going to work with more than one Exchange mailbox?

Well, it won’t work. The Global Profile Section is now an obsolete concept, starting with Outlook 2010. This MSDN article contains all of the gory details.

To sum up the above article, because we have multiple Exchange accounts, each one will require its own special profile section to store the multitude of settings associated with it.

A unique identifier for the profile section is dynamically allocated per profile. This unique identifier is known as the PidTagExchangeProfileSectionId canonical property.

Microsoft, being whimsical and cute as always, refers to PidTagExchangeProfileSectionID as emsmdbUID when speaking of it as a unique identifier used to specify an Exchange account. If Microsoft uses that term, then, hell, so will I.

What if you don’t update your code, and you continue to retrieve the Global Profile Section? Well, again, Microsoft being Microsoft, your code will be somewhat compatible with Outlook 2010. Queries for the Global Profile Section will be redirected to a single Exchange account that handles legacy inquiries.

Here’s the best part though, the Exchange account designated as the one to handle queries for the Global Profile Section has absolutely nothing to do with the default store and default account settings you have in place!

So, this means that leaving your code as is may very well be unacceptable, and you need to be able to support finding the correct profile section based on its emsmdbUID.

OK, OK, well then where the hell do I get this emsmdbUID!?! Which account is active?

Hey. Glad you asked.

For the purpose of figuring out which account is active, looking at the folder you’re in more or less works. In fact, that’s the Microsoft recommended way (at least, according to the only MSDN article I could find on the subject).

It was suggested to look at the current folder’s store ID, and then match that to the store ID of one of the DeliveryStore properties in the session Accounts collection.

So if I’m in my second user’s calendar in Outlook (and by the way, if you have a user’s mailbox added to your profile, it is impossible to access the user’s calendar as a shared calendar as the primary user. I’d imagine this could interfere with some advanced delegation roles, so take note), the store ID of the current store will match the second user’s DeliveryStore’s ID.

Another way would be to simply look at the emsmdbUID property of the current store, and (assuming you’ve been keeping a dictionary or some other sort of collection) and then get an account by its PidTagExchangeProfileSectionID easily. More on that later.

One area where both of these fail is if you’re in a user’s shared folder, and that user doesn’t belong to your profile. No account will match the store ID of the delivery store, and you will fail if you try to get the PidTagExchangeProfileSectionID from the other user’s store.

The problem that leaves us with is, which account is active when neither of those properties are available? Does it default to the default mailbox account? Most likely. What if the default mailbox account is on another Exchange server? Hmm, well, it would have to use the other account then. You may need to keep track of these things, and it may involve a lot of care in doing so. This is an area of uncertainty, and will need to be ironed out through either trial by fire or further documentation releases from Microsoft.

Now, all of that is great for activation, but it doesn’t help us get the different profile-specific settings. So how do we do that?

You could iterate through each profile and profile section, and try to match up the Exchange mailbox account name to a known name, but that isn’t a very precise or safe way to do it. Names are names, and shouldn’t be used to identify things. Unique identifiers should be used to identify things, and the emsmdbUID is the unique identifier.

So, one important thing to always remember is that the active emsmdbUID can be found in any message store, folder, or address book container (as long as they belong to one of the accounts that belong to the profile). So let’s say you’re in a folder in Outlook and you want some profile-specific settings for the active account.

I’m going to go over how you would retrieve the unique identifier and find the relevant profile.

//session is an initialized RDOSession.
//explorer is the Active Explorer.
//I'm going to retrieve the RDOFolder of the current folder.
//Note that I can also get the RDOStore instead, and the rest of this sample
//works the same.
MAPIFolder outlookFolder = explorer.CurrentFolder;
RDOFolder currentFolder = session.GetFolderFromID(currentFolder.EntryID);

//Now I'm going to get the PidTagExchangeProfileSectionId.
//This is available as a field from the folder.
//I'm doing this with Redemption obviously. I can also do it using
//Outlook's PropertyAccessor.
IEnumerable<object> emsmdbUidField = currentFolder.Fields["0x3d150102"];

//This is an object array of decimals. We need to convert it to a
//string of base-16 values.
string emsmdbUid
  = emsmdbUidField
     .Select(t => String.Format(CultureInfo.InvariantCulture, "{0:X}", t))
     .Aggregate(String.Empty, (current, byteString)
       => String.Format(
              CultureInfo.InvariantCulture,
              byteString.Length < 2 ? "{0}0{1}" : "{0}{1}",
              current, byteString));    

Type profilesType = Type.GetTypeFromProgID("ProfMan.Profiles");
IProfiles profiles = (IProfiles) Activator.CreateInstance(profilesType);

IProfile profile = null;

for (int i = 1; i <= profiles.Count; i++)
{
  profile = profiles.Item[i];
  if (profile.Name == Application.Session.CurrentProfileName)
    break;
}

//I just broke two responsible COM interop management principles with the
//previous loop. Don't do the same.

Service service = null;
IProfSect profileSection = null;

for (int j = 1; j <= profile.Services.Count; j++)
{
  service = profile.Services.Item[j];
  profileSection = service.ProfSect;

  object sectionUid = profileSection.Item(0x3d150102);
  if (null == sectionUid)
    continue;

  if (emsmdbUid == sectionUid.ToString())
    //We have located the matching message service and profile section.
    break;
}
//Again, the previous for-loop breaks some good practices with
//managing COM objects. Don't be an idiot!
//(Not enough time to be complete here with the proper practices included)

Armed with the correct profile section, you should have no problems discerning which account is active, whether or not cached mode is in effect, etc. If the current store has no unique identifier for the profile section, then I would just use the account marked as the default (again, this may not be how it actually works under the hood, only time will tell).

Good day.

© 2012-2013 Matt Weber. All Rights Reserved. Terms of Use.