Friday, June 10, 2005
Redemption still needed with Outlook VSTO 2005
These things are exactly as before, Microsoft has not added any new functionality to the toolkit, just made it .NET managed code and more reliable. This is 'by design' according to Microsoft, this was the default reply to my wishes during the alpha programme: "VSTO-O does not add any additional functionality to the object model".
During the testing I wanted to set the mail sender without using Redemption. After a suggestion by Sue Mosher I tried by granting a user 'send as' permissions on department mailboxes and changing the sender using the standard SentOnBehalfOfName in the ItemSend event handler, but this never worked. Ken Laws [MSFT] has confirmed that using SentOnBehalfOfName in the ItemSend event is too late, thus you still need Redemption to set this through extended MAPI. This property only works e.g. when set on a Outlook.MailItem created by code.
Changing the sender of an Outlook.MailItem object in ItemSend:
Redemption.SafeMailItem safeMail = new Redemption.SafeMailItemClass();
//Select the item to be modified
safeMail.Item = mailItem;
//fill in the e-mail address in 'From'
int tag = safeMail.GetIDsFromNames("{00020386-0000-0000-C000-000000000046}", "From");
tag = tag 0x1E; //the type is PT_STRING8
safeMail.set_Fields(tag, address);
Getting the SMTP address of an Exchange user from an Outlook.AddressEntry object:
//check if Exchange address
if (mailAddress.StartsWith("/o="))
{
//get SMTP address from MAPI
Redemption.MAPIUtils mapiUtils = new Redemption.MAPIUtils();
int PR_EMAIL = 0x39FE001E;
mailAddress = mapiUtils.HrGetOneProp(entry.MAPIOBJECT, PR_EMAIL).ToString();
mapiUtils.Cleanup();
}
The Outlook toolkit should be reviewed before RTM to add more of the most needed MAPI fields to the list of properties exposed in the object model. Please Microsoft VSTO-O team!
Tuesday, June 07, 2005
Outlook 2003 .NET add-ins with VSTO 2005
Now that it is official that VSTO 2005 will provide support for writing .NET add-ins for Outlook 2003 (formerly known as 'Project Elixir'), I can blog some experiences about this new toolkit that is currently in beta.
I have participated in the alpha program for Outlook support in VSTO 2005, and I can tell you that this stuff makes developing add-ins with .NET easier than before. You do not need to bother with superfluous interface methods, COM shims, calling InvokeMember(), shaky event handlers, the Outlook shutdown bug, MSCorEE.DLL, etc. The Outlook add-in template for Visual Studio 2005 is also much better than the one available for VS.NET 2003. E.g. the template is preconfigured to start Outlook when debugging, and some other improvements.
Short intro article on MSDN
Long add-in architecture article on MSDN
Developing and debugging Office 2003 add-ins with VSTO 2005 is a breeze, there are several sample projects with the toolkit that will get you started. You just need to ensure that you keep a reference for all objects you add (menus, toolbars, buttons, etc) for the lifetime of the add-in. If you do not, your event handlers for these object will work for some time, until the garbage collector frees the object reference and thus your event handler. The toolkit samples contain some bugs of this kind.
What you will find out the hard way, is that testing your add-in on another PC is not straightforward as the setup project template still has a way to go until RTM. The generated .MSI package will install the .NET Framework 2.0, the detected dependencies and your component. But it will not install the VSTO 2005 runtime or the Office 2003 PIAs. Refer to these pre-release guidelines for what you need to install on a client/test PC.
This is what I had to do to get my add-in to load (i.e. to make the add-in visible and checked in the Outlook "COM Add-ins" dialog box):
- Copy the VSTAddin.DLL assembly to the .\VSTO\8.0\ folder (this assembly replaces the MSCorEE.DLL used in the COM shim era; referred to as AddinLoader.DLL on MSDN, but it is not named so in beta 2)
- Deploy the .manifest file of my add-in .DLL to the install directory of my add-in
- The setup project did not include any of the required registry settings for Outlook, so I had to export the Outlook add-in registry settings, plus the class ID and prog ID settings of the DLL; and then import them on the test PC
- Modify the "ManifestLocation" path to point to the install directory (note that the "CodeBase" stuff for COM shims have been replaced by the deployment manifest file)
Even after installing all of these components, my add-in would be listed in Outlook, but not loaded, with the standard error message "A runtime error occurred during the loading of the COM add-in". This was caused by another change for .NET add-ins, they are now treated as .NET components and code access security must be configured on the target PC:
- Run the .NET FW 2.0 CASPOL.EXE to grant full trust to the install directory of the add-in (see the end of this MSDN article)
Note that you might not find the "Microsoft .NET Framework 2.0 Configuration" tool in Control Panel-Administrative Tools after installing the .NET FW 2.0 beta 2. Neither will you find the MMC snap-in, which is installed with VS2005.
Wednesday, May 25, 2005
Quick Launch Bar in SharePoint areas
What has puzzled me for some time is that the quick launch bar is never shown in SharePoint Portal Server 2003 areas, even if I flag e.g. a document library in the SPS area with 'Display ... on the QLB'. So I opened a SPS area with FrontPage 2003 to check if the area contains any code for showing the flagged lists, and the area did not. I had used FP2003 several times before on WSS team-sites to change the QLB, e.g. to remove the 'Surveys' groups header and to add links to other web part pages in the same team-site. So I decided to try to copy code from a WSS team-site to a SPS area. This works fine and is actually quite simple to do.
Start by copying the applicable code for the QLB groups that you want in your area from an existing WSS site, e.g. the 'Documents' group for showing all applicable document libraries:
<table border="0" cellpadding="0" cellspacing="0" class="ms-navframe">
<TR>
<td id="onetidWatermark" class="ms-navwatermark" dir="ltr"> </td>
<TD class="ms-navheader" width="126" style="padding-right: 2px;"><A HREF="_layouts/1033/viewlsts.aspx?BaseType=1">Documents</A></TD></TR>
<TR>
<td id="onetidWatermark" class="ms-navwatermark" dir="ltr"></td>
<TD style="height: 6px">
<!--webbot bot="Navigation" S-Btn-Nobr="FALSE" S-Type="sequence" S-Rendering="html" S-Orientation="Vertical" B-Include-Home="FALSE" B-Include-Up="FALSE" U-Page="sid:1004" S-Bar-Pfx="<table border=0 cellpadding=4 cellspacing=0>" S-Bar-Sfx="</table>" S-Btn-Nml="<tr><td><table border=0 cellpadding=0 cellspacing=0><tr><td><img src='_layouts/images/blank.gif' ID='100' alt='Icon' border=0>&nbsp;</td><td valign=top><a ID=onetleftnavbar#LABEL_ID# href='#URL#'>#LABEL#</td></tr></table></td></tr>" S-Target TAG="BODY" --></TD></TR>
</table>
The code contains a small webbot that looks up the flagged listings and builds the links to those listings. In addition, I have added an extra <TD> element to get the same indent as the other content of the SPS area navigation panel.
Then you need to locate the slot in the SPS area navigation panel where you want the quick launch links to be added. A good location is below the 'Current location' and the 'Category navigation' SharePoint components. Locate this web control with FrontPage and add the copied code just below the CategoryNavigationWebPart component:
<SPSWC:CategoryNavigationWebPart runat="server" id="VerticalNavBar" DisplayStyle="VerticalOneLayer" />
<!-- ADD QUICK LAUNCH LINKS CODE HERE -->
<SPSWC:ToolBar runat="server" id="ActionBar" RenderIfEmpty="false" Orientation="Vertical" TitleLocId="CategoryManagement_ActionBar_Title_Text">
Save the SPS area after adding the code with FP2003, then do a hard refresh (ctrl-F5) of the page in MSIE to check that your changes are functioning as expected.
Note that you must change the location ID (1033) of the QLB code if your SharePoint installation is not using the US English version. Use e.g. 1044 on a Norwegian SharePoint version.
Monday, May 23, 2005
The Exchange RUS and external AD contacts
The problem is that even if you set only a SMTP mail address on the new AD contact as shown in the SDK, the RUS will apply all the other types of mail addresses defined in your Exchange policies during its processing. This will give the external contact an internal Exhcange address, an X.400 address, etc. Thus, Exhcange will not be able to resolve or deliver e-mails to these contacts as most of these addresses will be bogus.
To correctly mail enable an external AD contact you need to set a GUID in two specific Exchange properties on the AD contact:
DirectoryEntry adContact = adContainter.Children.Find("CN=" + contactId, CONST.AD_CONTACT);
//exlude from RUS
adContact.Properties["msExchPoliciesExcluded"].Value = "{26491CFC-9E50-4857-861B-0CB8DF22B5D7}";
adContact.Properties["msExchPoliciesIncluded"].Value = "{26491CFC-9E50-4857-861B-0CB8DF22B5D7}";
//set mail AD property to e-mail address
//must set again after exluding from RUS
adContact.Properties["mail"].Value = mailAddress;
// Write Exchange information to the directory.
adContact.CommitChanges();
The policy GUID must be set on both the Exchange RUS policies excluded list and the policies included list. The specified GUID is valid for Exchange Server 2003. Refer to my previous post for details about how to write code for Exchange Server 2003.
You should also ensure that you never add an internal user's mail address as an AD contact through code. If your code does not prevent this, it will prevent Exchange from delivering incoming e-mail to the user's mailbox as it cannot resolve the mailbox when both an AD user and an AD contact has the same address.
Note that you should not exclude mail enabled AD distribution group (mailing lists) from the RUS, as this will cause the mailing lists to stop working. They must be processed by the RUS to function properly.