|
| Accessing common properties of Outlook Items in .NET |
|
|
|
|
| Messages |
|
Related Types |
This message was discovered on microsoft.public.dotnet.framework.interop.
Responses highlighted in red are from those people who are likely to be able to contribute good, authoratitive information to this discussion. They include Microsoft employees, MVP's and others who IMHO contribute well to these kinds of discussions.
| Mike Timms |
| GOOD ANSWER |
I'm trying to find a clean approach to accessing the common properties of Outlook items using the Outlook object model under .NET.
The Outlook Items collection can contain heterogeneous object types such as MailItem, PostItem, ContactItem etc. In VB6 it was possible to declare an item as variant and then you could access properties common to any of item types without having to cast to a specific object type. See: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnout2k/htm l/olcollections.asp.
However, the equivalent technique doesn't work under .NET, since there is no base item class to inherit from. It's therefore necessary to determine the actual item type and then cast to a variable of the specific type. Following is a partial implementation of the code required to get the MessageClass of an item:
Public void OnNewInspector(Outlook.Inspector inspector) { string messageClass;
if (inspector.CurrentItem is Outlook.MailItem) { Outlook.MailItem mitem = inspector.CurrentItem as Outlook.MailItem; messageClass = mitem.MessageClass; } else if (inspector.CurrentItem is Outlook.PostItem) { Outlook.PostItem pitem = inspector.CurrentItem as Outlook.PostItem; messageClass = pitem.MessageClass; } else if ......
The only mechanism I found to simplify this was to create a pseudo item class that wraps the ugliness of testing the object type and gives the client code at least the illusion of a base item object. A partial implementation is:
public class OutlookItem : IDisposable { private Outlook.OlItemType m_itemType; private Outlook.PostItem m_pItem; private Outlook.MailItem m_mItem; ....
// constructor public OutlookItem(object item) {
if (item is Outlook.PostItem) { m_itemType = Outlook.OlItemType.olMailItem; m_mItem = item as Outlook.MailItem; } else if (item is Outlook.PostItem) { m_itemType = Outlook.OlItemType.olPostItem; m_pItem = item as Outlook.PostItem; } else if (item is ............) ......... else { // raise invalid object exception } }
public Outlook.OlItemType ItemType { get { return m_itemType; } }
public string MessageClass { get { switch (m_itemType) { case Outlook.OlItemType.olPostItem: return m_pItem.MessageClass; case Outlook.OlItemType.olMailItem: return m_mItem.MessageClass; case Outlook.OlItemType...... ............ } return ""; } set { switch (m_itemType) { case Outlook.OlItemType.olPostItem: m_pItem.MessageClass = value; break; case Outlook.OlItemType.olMailItem: m_mItem.MessageClass = value; break; case Outlook.OlItemType......
} } }
public void Dispose () { switch (m_itemType) { case Outlook.OlItemType.olPostItem: Marshal.ReleaseComObject(m_pItem); break; case Outlook.OlItemType.olMailItem: Marshal.ReleaseComObject(m_mItem); break; case Outlook.OlItemType...... } }
This class can then be used as follows:
private void OnNewInspector(Outlook.Inspector inspector) { string messageClass;
OutlookItem item = new OutlookItem(inspector.CurrentItem); messageClass = item.MessageClass; if (messageClass = "IPM.Note.MyMessageClass") { .......... } item.Dispose(); }
This doesn't reduce the amount of code but at least hides the ugliness in the helper class. However, since VB6 can access these items polymorphically, I'm hoping there's a more elegant solution using interop library functions. Has anybody got an ideas?
- Mike
|
|
|
| |
|
|
| |
| |
| Jay B. Harlow [MVP - Outlook] (VIP) |
| GOOD ANSWER |
Mike, In VB.NET this is easy. You turn Option Strict Off, place the Outlook Item in an Object variable, then call the methods.
VB.NET is using interop methods to call IDispatch methods of the Outlook item behind the scenes for you. Unfortunately I cannot find what those methods are, nor the reference I had to them...
FWIW: In your code example, I would use polymorphism rather then ifs & switches...
Forgive my C# ;-)
private void OnNewInspector(Outlook.Inspector inspector) { string messageClass;
OutlookItem item = OutlookItem.CreateItem(inspector.CurrentItem);
messageClass = item.MessageClass; if (messageClass = "IPM.Note.MyMessageClass") { .......... } item.Dispose(); }
class OutlookItem { public abstract string MessageClass { get; set }
// Only this method needs if statements! static OutlookItem CreateItem(object item) { if (item is Outlook.MailItem) { return new MailItem(item) } else if (item is Outlook.PostItem) { return new PostItem(item) } ... else { // raise invalid object exception } }
}
class MailItem : OutlookItem { Outlook.MailItem m_item;
MailItem(object item) { m_item = item as Outlook.MailItem; }
public string MessageClass { get { return m_item.MessageClass; } set { m_item.MessageClass = value; } } }
Of course you could use VB.NET to write the wrapper, which is then used by your C# code...
Hope this helps Jay
"Mike Timms" <Click here to reveal e-mail address> wrote in message news:O8G8sB#jBHA.5836@tkmsftngp04... [Original message clipped]
|
|
|
| |
|
|
| |
| |
| Mike Timms |
| GOOD ANSWER |
Jay,
Thanks for your response.
"Jay B. Harlow [MVP - Outlook]" <Click here to reveal e-mail address> wrote in message news:<u6KUcBVkBHA.2448@tkmsftngp02>... [Original message clipped]
I did some more digging on accessing properties through IDispatch and found that I can use the System.Type.InvokeMember method to access a named property at run time regardless of the actual object type. This was just what I was looking for!
The following C# code works:
object item = inspector.CurrentItem; Type t = item.GetType(); string messageClass = t.InvokeMember("MessageClass", BindingFlags.Public | BindingFlags.GetField | BindingFlags.GetProperty, null, item, new object[]{}).ToString(); if (messageClass = "IPM.Note.MyMessageClass") { .......... }
I'm still intending to use the OutlookItem helper class since it makes the client code easier to understand. But now I can greatly simplify it and just wrap the InvokeMember method call for each property access. A partial implementation of the helper class now looks like the following:
public class OutlookItem : IDisposable { private object m_item; private Type m_type;
// constructor public OutlookItem(object item) { m_item = item; m_type = item.GetType(); }
public string MessageClass { get { return (m_type.InvokeMember("MessageClass", BindingFlags.Public | BindingFlags.GetField | BindingFlags.GetProperty, null, m_item, new object[]{} ).ToString()); } set { ............ } }
public string EntryID { get { return (m_type.InvokeMember("EntryID", BindingFlags.Public | BindingFlags.GetField | BindingFlags.GetProperty, null, m_item, new object[]{} ).ToString()); } } public ..... other common properties
public void Dispose () { Marshal.ReleaseComObject(m_item); } }
thanks again,
- Mike
[Original message clipped]
|
|
|
| |
|
|
| |
| |
| Jay B. Harlow [MVP - Outlook] (VIP) |
| GOOD ANSWER |
Mike, Glad you found it. I knew it was there, I just did not remember where, I was thinking it was under the Interop namespace itself...
Yes, the single helper class in this case will be very beneficial!
Thanks for the info Jay
"Mike Timms" <Click here to reveal e-mail address> wrote in message news:Click here to reveal e-mail address... [Original message clipped]
|
|
|
| |
|
|
| |
| |
| Mike Timms |
| GOOD ANSWER |
Here's the updated OutlookItem helper class with a representative selection of property value types implemented.
- Mike
------------------------------------ using System; using System.Reflection; using System.Runtime.InteropServices; using Outlook;
namespace OutlookLibrary { /// <summary> /// Helper class to access common properties of Outlook Items. /// </summary> /// /// Uses the IDispatch interface of the Outlook object model to access the common properties of /// Outlook items regardless of the actual item type. This prevents having to test for and cast to /// a specific object in order to access common properties. /// /// Usage example: /// /// OutlookItem item = new Outlook.Item(inspector.CurrentItem); /// string message = item.CreateTime.ToString("f") + " - " + item.Subject); /// MessageBox.Show(message, "New Inspector"); /// item.Dispose(); /// // // TODO: Add remaining common properties // TODO: Handle 'no such property name' exceptions //
public class OutlookItem : IDisposable { private object m_item; // the wrappped Outlook item private Type m_type; // type for the Outlook item private object[] m_args; // dummy argument array private Outlook.OlItemType m_itemType; // item type of Outlook item private bool m_isItemTypeInitialized; private System.Type m_typeOlObjectClass;
// constants for property names private const string OlMessageClass = "MessageClass"; private const string OlClass = "Class"; private const string OlCreationTime = "CreationTime"; private const string OlSubject = "Subject"; private const string OlParent = "Parent"; private const string OlFormDescription = "FormDescription"; private const string OlEntryID = "EntryID";
// Constructor public OutlookItem(object item) { m_item = item; m_type = m_item.GetType(); m_args = new Object[]{}; m_isItemTypeInitialized = false; }
public void Dispose() { Marshal.ReleaseComObject(m_item); }
// Public Properties public Outlook.OlItemType ItemType { get { // item type is evaluated in 'lazy' fashion the first time required if (m_isItemTypeInitialized) return m_itemType; else if (m_item is Outlook.PostItem) m_itemType = Outlook.OlItemType.olPostItem; else if (m_item is Outlook.MailItem) m_itemType = Outlook.OlItemType.olMailItem; else if (m_item is Outlook.ContactItem) m_itemType = Outlook.OlItemType.olContactItem; else if (m_item is Outlook.AppointmentItem) m_itemType = Outlook.OlItemType.olAppointmentItem; else if (m_item is Outlook.TaskItem) m_itemType = Outlook.OlItemType.olTaskItem; else if (m_item is Outlook.JournalItem) m_itemType = Outlook.OlItemType.olJournalItem; else if (m_item is Outlook.DistListItem) m_itemType = Outlook.OlItemType.olDistributionListItem; else if (m_item is Outlook.NoteItem) m_itemType = Outlook.OlItemType.olNoteItem; m_isItemTypeInitialized = true; return m_itemType; } }
public string EntryID { get { return this.GetPropValue(OlEntryID).ToString(); } }
public string Subject { get { return this.GetPropValue(OlSubject).ToString(); } }
public string MessageClass { get { return this.GetPropValue(OlMessageClass).ToString(); } }
public Outlook.OlObjectClass Class { get { if (m_typeOlObjectClass == null) { // Note: instantiate dummy ObjectClass enumeration to get type. // type = System.Type.GetType("Outlook.OlObjectClass") doesn't seem to work Outlook.OlObjectClass objClass = Outlook.OlObjectClass.olAction; m_typeOlObjectClass = objClass.GetType(); } return (Outlook.OlObjectClass)System.Enum.ToObject(m_typeOlObjectClass, his.GetPropValue(OlClass)); } }
public System.DateTime CreationTime { get { return (System.DateTime)this.GetPropValue(OlCreationTime); } }
public object Parent { get { return this.GetPropValue(OlParent); } }
public Outlook.FormDescription FormDescription { get { return this.GetPropValue(OlFormDescription) as Outlook.FormDescription; } }
// Private methods
// Get a propery value by name private object GetPropValue(string propertyName) { // An invalid property name exception is propagated to client return m_type.InvokeMember( propertyName, BindingFlags.Public | BindingFlags.GetField | BindingFlags.GetProperty, null, m_item, m_args); }
}
}
|
|
|
| |
|
|
| |
|
|
|
|
|
|
|
|
|
|
|
BootFX
Reliable and powerful .NET application framework. |
|
|
|
|
|
|