A big part of development against Exchange 2007 will be understanding where to put your code or which Exchange roles affect your code. Exchange 2007 can be broken out to run these different roles on different machines or all roles (except the Edge server role on one server). The Exchange team blog has a new post providing information on each of these roles.
Here is an excerpt of article introducing each of the roles...
"- Mailbox (MB): The Mailbox server role is responsible for hosting mailbox and public folder data. This role also provides MAPI access for Outlook clients. Note that there is also a variation of this role called Clustered Mailbox role, for use with high-availability MSCS clustering of mailbox data. When Clustered Mailbox role is selected, other server roles cannot be combined on the same physical server.
- Client Access (CA): The Client Access server role provides the other mailbox server protocol access apart from MAPI. Similar to Exchange 2003 FrontEnd server, it enables user to use an Internet browser (OWA), 3rd party mail client (POP3/IMAP4) and mobile device (ActiveSync) to access their mailbox.
- Unified Message (UM): This role enables end users to access their mailbox, address book, and calendar using telephone and voice. IP-PBX or VoIP gateway needs to be installed and configured to facilitate much of the functionality of this server role.
- Hub Transport (HT): The Hub Transport role handles mails by routing them to next hop: another Hub Transport server, Edge server or mailbox server. Unlike Exchange 2003 Bridgehead that needs Exchange admin defined routing groups, Exchange 2007 Hub Transport role uses AD site info to determine the mail flow.
- Edge Transport (ET): The last hop of outgoing mail and first hop of incoming mail, acting as a "smart host" and usually deployed in a perimeter network, Edge Transport provides mail quarantine and SMTP service to enhance security. One advantage of this role is that is does not require Active Directory access, so it can function with limited access to the corporate network for increased security."
Ryan actually published this post last week but I had yet to link to it. I have been asked many of these questions regarding Outlook 2007 in my support role at Microsoft. Here are some of the questions he addresses...
"Is there a future for the Outlook view control (OVC)?
Have the form controls been improved?
Is the IDE for form script any better?
How do you envision people debugging code on forms?
Do you see people continuing to use Public folders?
Was work put into improving custom forms management/deployment?
OWA/Mobile. Design once, run everywhere is a definite necessity, will this story be improved?
Is WYSIWYG forms printing supported in Outlook 2007?
Progress and Excitement. Do you think there is a REAL commitment within the Outlook team for extensibility?"
If you have COM AddIns written in Outlook 2003 and earlier that you want to know what we are doing to have them run in Outlook 2007 as well or you are going to write an AddIn for Outlook 2007 then you should read this post by Ryan Gregg who is an Outlook PM. Ryan talks about the backward compatability effort in Outlook 2007 and his work with ISVs to support AddIns in Outlook 2007...
Ryan also talks about some changes to exception handling in Outlook AddIns for the technical refresh. If you are an AddIn developer be sure to read this section which details changes in how we let AddIns crash Outlook 2007 and the reasons behind that. There is a new dialog which will prompt after a crash to disable the AddIn or not instead of automatically disabling or not disabling the AddIn without your input.
We put a lot of effort into backward compatability in all our products and part of my job in support is helping costumer and filing bugs for that very purpose...
The Outlook 2003 Object Model does not have much support for shared folders outside the GetSharedDefaultFolder function. One common question we get asked is, "Given an OOM MAPIFolder object that represents a shared folder, how can I determine who's the owner of that folder?". This is a common question from Outlook COM AddIn developers who are working with Inspectors and need to know what calendar a user is making changes in.
Like I said before, OOM doesn't have much support for shared folders so we came up with a hack to answer the question. The StoreID of the folder actually will contain the owner's information if you decode the binary string. The following code sample will pull the owner name out of the StoreID of a MAPIFolder object...
public string GetFolderOwner(Outlook.MAPIFolder oFolder)
{
if (oFolder == null) return "";
string storeID = oFolder.StoreID;
return ParseEntryID(storeID);
}
// Convert the EntryID to characters and parse out the
// owner name
private string ParseEntryID(string storeID)
string s = HexReader.GetString(storeID);
//TODO: These values might be different depending on
what you have named your groups in ESM
const string REG_EX = @"/o=First Organization/ou=First
Administrative Group/cn=Recipients/cn=(\w+)";
Match m = Regex.Match(s, REG_EX);
return m.Value;
Here is the code for the HexReader class…
/// <summary>
/// Simple class for reading a string containing Hex numbers
/// </summary>
public class HexReader
private HexReader()
// this class cannot be directly instantiated
// Given a string containing hex characters
// this function will return the actual string
// representation of that hex string
public static string GetString(string hexString)
System.Text.StringBuilder sb = new StringBuilder();
System.Text.StringBuilder sb2 = new StringBuilder();
for (int i = 0; i < hexString.Length; i = i + 2)
string s = hexString.Substring(i, 2);
try
int j = int.Parse(s, System.Globalization.NumberStyles.HexNumber);
char c = ConvertToCharacter(j);
sb.Append(c);
catch (System.Exception e)
System.Diagnostics.Debug.WriteLine(e.Message);
return sb.ToString();
private static char ConvertToCharacter(int CharCode)
char ch1;
if ((CharCode < -32768) || (CharCode > 0xffff))
// throw error
if ((CharCode >= 0) && (CharCode <= 0x7f))
return Convert.ToChar(CharCode);
int num1;
// get the current encoding
Encoding encoding1 = Encoding.GetEncoding(
Thread.CurrentThread.CurrentCulture.TextInfo.ANSICodePage);
if ((encoding1.GetMaxByteCount(1) == 1) &&
((CharCode < 0) || (CharCode > 0xff)))
char[] chArray1 = new char[2];
byte[] buffer1 = new byte[2];
Decoder decoder1 = encoding1.GetDecoder();
if ((CharCode >= 0) && (CharCode <= 0xff))
buffer1[0] = (byte)(CharCode & 0xff);
num1 = decoder1.GetChars(buffer1, 0, 1, chArray1, 0);
else
buffer1[0] = (byte)((CharCode & 0xff00) / 0x100);
buffer1[1] = (byte)(CharCode & 0xff);
num1 = decoder1.GetChars(buffer1, 0, 2, chArray1, 0);
ch1 = chArray1[0];
catch (Exception exception1)
throw exception1;
return ch1;