Code Snippet
using
System;
using
System.Windows.Forms;
using
Microsoft.VisualStudio.Tools.Applications.Runtime;
using
Outlook = Microsoft.Office.Interop.Outlook;
using
Office = Microsoft.Office.Core;
using
System.Collections;
using
System.Diagnostics;
using
System.Reflection;
namespace
ExplorerTest
{
public partial class ThisAddIn
{
/// <summary>
/// This generic collection holds a reference to our open explorers.
/// </summary>
Hashtable _WrappedExplorers;
/// <summary>
/// This variable must be used to keep a reference to the Application Explorers collection.
/// Required to get informed about new Explorers.
/// </summary>
Outlook.
Explorers _Explorers;
Hashtable _WrappedInspectors;
Outlook.
Inspectors _Inspectors;
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
// initialize the List that will keep an eye on our active Outlook Explorers.
_WrappedExplorers =
new Hashtable(10);
// Do we have already some explorers after startup
_Explorers = Application.Explorers;
for (int i = _Explorers.Count; i >= 1; i--)
{
// Wrap the Explorer and do some usefull with it
WrapExplorer(_Explorers[i]);
}
// remember the Outlook.Explorers (GC)
_Explorers =
this.Application.Explorers;
// register for new Explorer event.
_Explorers.NewExplorer +=
new Outlook.ExplorersEvents_NewExplorerEventHandler(Explorers_NewExplorer);
// remember the Outlook.Inspectors object (GC)
_Inspectors =
this.Application.Inspectors;
// Create a Hashtable that holds a reference to the wrapped Inspectors
_WrappedInspectors =
new Hashtable();
// register for the new inspector event
_Inspectors.NewInspector +=
new Outlook.InspectorsEvents_NewInspectorEventHandler(_Inspectors_NewInspector);
}
private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
{
// remove all references to the wrapped Inspectors.
_WrappedInspectors.Clear();
_Inspectors =
null;
// remove all references to the wrapped Explorers.
_WrappedExplorers.Clear();
_Explorers =
null;
}
/// <summary>
/// The new Inspector event occures whenever an outlook inspector was opened.
/// </summary>
/// <param name="Inspector">The outlook inspector object.</param>
void _Inspectors_NewInspector(Outlook.Inspector Inspector)
{
try
{
Outlook.
Inspector inspector = Inspector;
WrapInspector(inspector);
}
catch (System.Exception ex)
{
// log the error always
Trace.TraceError("{0}: [class]:{1} [method]:{2}\n[message]:{3}\n[Stack]:\n{4}",
DateTime.Now, // when was the error happened
MethodInfo.GetCurrentMethod().DeclaringType.Name, // the class name
MethodInfo.GetCurrentMethod().Name, // the method name
ex.Message,
// the error message
ex.StackTrace
// the stack trace information
);
}
}
/// <summary>
/// This method wraps an Outlook Inspector object and registers for the InspectorClosed event.
/// </summary>
/// <param name="Inspector">The Outlook Inspector Object.</param>
void WrapInspector(Outlook.Inspector Inspector)
{
// Wrap the Explorer and do some usefull with it
InspectorWrapper wrappedInspector = new InspectorWrapper(Inspector);
// register for the closed event, so we can releas it from memory
wrappedInspector.InspectorClosed +=
new InspectorClosedDelegate(UnwrapInspector);
_WrappedInspectors.Add(wrappedInspector.ID, wrappedInspector);
}
/// <summary>
/// This method should be called when a wrapped Outlook Inspector has been closed.
/// </summary>
/// <param name="explorerId">The unique ID of the closed explorer.</param>
void UnwrapInspector(Guid explorerId)
{
// if we have a reference to this explorer we can release it now
if (_WrappedInspectors.ContainsKey(explorerId))
{
_WrappedInspectors.Remove(explorerId);
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
/// <summary>
/// This event occures en a new outlook explorer has been opened.
/// </summary>
/// <param name="Explorer">The opened Outlook Explorer object.</param>
void Explorers_NewExplorer(Outlook.Explorer Explorer)
{
// Wrap the Explorer and do some usefull with it
Outlook.
Explorer activeExplorer = Application.ActiveExplorer();
WrapExplorer(activeExplorer);
}
/// <summary>
/// This method wraps an Outlook Explorer object and registers for the ExplorerClosed event.
/// </summary>
/// <param name="Explorer">The Outlook Explorer Object.</param>
void WrapExplorer(Outlook.Explorer Explorer)
{
// Wrap the Explorer and do some usefull with it
ExplorerWrapper wrappedExplorer = new ExplorerWrapper(Explorer);
// register for the closed event, so we can releas it from memory
wrappedExplorer.ExplorerClosed +=
new ExplorerClosedDelegate(UnwrapExplorer);
_WrappedExplorers.Add(wrappedExplorer.ID, wrappedExplorer);
}
/// <summary>
/// This method should be called when a wrapped Outlook Explorer has been closed.
/// </summary>
/// <param name="explorerId">The unique ID of the closed explorer.</param>
void UnwrapExplorer(Guid explorerId)
{
// if we have a reference to this explorer we can release it now
if (_WrappedExplorers.ContainsKey(explorerId))
{
_WrappedExplorers.Remove(explorerId);
}
}
#region
VSTO generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InternalStartup()
{
this.Startup += new System.EventHandler(ThisAddIn_Startup);
this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
}
#endregion
}
#region
delegates used handling explorers
/// <summary>
/// A delegate used to inform the application that an explorer has been closed.
/// </summary>
/// <param name="explorerId">The unique ID of the Explorer that has been closed.</param>
internal delegate void ExplorerClosedDelegate(Guid explorerId);
#endregion
#region
ExplorerWrapper
/// <summary>
/// The ExplorerWrapper is used to wrap around an Outlook Explorer.
/// It keeps a reference to the Explorer in memory and registers for the Explorer events.
/// </summary>
internal class ExplorerWrapper
{
#region
explorer wrapper events
/// <summary>
/// This event is fired from out wrapper when the wrapped Outlook Explorer has been closed.
/// </summary>
public event ExplorerClosedDelegate ExplorerClosed;
#endregion
#region
explorer wrapper variables & properties
/// <summary>
/// An unique ID that can used to identify this explorer (commandbars, buttons, etc...)
/// </summary>
Guid _Id;
/// <summary>
/// An unique ID that can used to identify this explorer (commandbars, buttons, etc...)
/// </summary>
public Guid ID
{
get { return _Id; }
}
/// <summary>
/// The Outlook Explorer object used to keep a reference in memory and register for the explorer events.
/// </summary>
Outlook.
ExplorerClass _Explorer;
/// <summary>
/// The Outlook Explorer object used to keep a reference in memory and register for the explorer events.
/// </summary>
public Outlook.Explorer Explorer
{
get { return _Explorer; }
}
/// <summary>
/// A Missing.Value used for COM interoperability.
/// </summary>
object _Missing = System.Reflection.Missing.Value;
#endregion
#region
explorer wrapper construction and cleanup
/// <summary>
/// The construction code.
/// </summary>
/// <param name="explorer">The outlook explorer that should be wrapped.</param>
public ExplorerWrapper(Outlook.Explorer explorer)
{
try
{
_Id =
Guid.NewGuid();
_Explorer = explorer
as Outlook.ExplorerClass;
if (_Explorer != null)
{
_Explorer.FolderSwitch +=
new Microsoft.Office.Interop.Outlook.ExplorerEvents_10_FolderSwitchEventHandler(_Explorer_FolderSwitch);
_Explorer.ExplorerEvents_Event_Close +=
new Microsoft.Office.Interop.Outlook.ExplorerEvents_CloseEventHandler(_Explorer_ExplorerEvents_Event_Close);
}
}
catch (System.Exception ex)
{
// log the error always
Trace.TraceError("{0}: [class]:{1} [method]:{2}\n[message]:{3}\n[Stack]:\n{4}",
DateTime.Now, // when was the error happened
MethodInfo.GetCurrentMethod().DeclaringType.Name, // the class name
MethodInfo.GetCurrentMethod().Name, // the method name
ex.Message,
// the error message
ex.StackTrace
// the stack trace information
);
// throw the Exception to the calling class
throw ex;
}
}
#endregion
/// <summary>
/// This event occures when this explorer has been closed.
/// </summary>
void _Explorer_ExplorerEvents_Event_Close()
{
// here we release all references to the explorer from memory.
_Explorer.FolderSwitch -=
new Microsoft.Office.Interop.Outlook.ExplorerEvents_10_FolderSwitchEventHandler(_Explorer_FolderSwitch);
_Explorer.ExplorerEvents_Event_Close -=
new Microsoft.Office.Interop.Outlook.ExplorerEvents_CloseEventHandler(_Explorer_ExplorerEvents_Event_Close);
_Explorer =
null;
// fire an event to inform the application that this explorer has been closed.
if (ExplorerClosed != null)
{
ExplorerClosed(
this._Id);
}
}
/// <summary>
/// This event occures when another folder has been selected in this explorer.
/// </summary>
void _Explorer_FolderSwitch()
{
try
{
// We change the application menu depending on what folder we have selected
// ModifyMenu();
}
catch (System.Exception ex)
{
// log the error always
Trace.TraceError("{0}: [class]:{1} [method]:{2}\n[message]:{3}\n[Stack]:\n{4}",
DateTime.Now, // when was the error happened
MethodInfo.GetCurrentMethod().DeclaringType.Name, // the class name
MethodInfo.GetCurrentMethod().Name, // the method name
ex.Message,
// the error message
ex.StackTrace
// the stack trace information
);
// now display a friendly error to the user
MessageBox.Show(null, "There was an application error, you should save your work and restart Outlook.",
"OutlookAdminTools",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
#endregion
}
#region
delegates used handling inspectors
/// <summary>
/// A delegate used to inform the application that an inspector has been closed.
/// </summary>
/// <param name="inspectorId">The unique ID of the Explorer that has been closed.</param>
internal delegate void InspectorClosedDelegate(Guid inspectorId);
#endregion
/// <summary>
/// The <b>InspectorWrapper</b> class is used to handle multiple open document windows within outlook.
/// </summary>
internal class InspectorWrapper
{
/// <summary>
/// This event informs our application that an "wrapped" inspector has been closed and should be released from memory.
/// </summary>
public event InspectorClosedDelegate InspectorClosed;
#region
explorer wrapper variables & properties
/// <summary>
/// An unique ID that can used to identify this explorer (commandbars, buttons, etc...)
/// </summary>
Guid _Id;
/// <summary>
/// An unique ID that can used to identify this explorer (commandbars, buttons, etc...)
/// </summary>
public Guid ID
{
get { return _Id; }
}
/// <summary>
/// This variable holds a reference to the outlook iitem behind the inspector.
/// Used to handle to item.open event.
/// Only when the item has been displayed, it's save to manipulate the inspector - or close the inspector.
/// </summary>
object _Item;
/// <summary>
/// The outlook inspector object that is wrapped by this class.
/// </summary>
Outlook.
InspectorClass _Inspector;
#endregion
/// <summary>
/// Initialisation code.
/// Remembers the inspector in memory and registers for the close event and the item.open event
/// </summary>
/// <param name="inspector">The outlook inspector object that should be handled.</param>
public InspectorWrapper(Outlook.Inspector inspector)
{
try
{
// each inspector gets a unique id.
_Id =
Guid.NewGuid();
// remember the inspector object in memory
_Inspector = inspector
as Outlook.InspectorClass;
// register for the close event - used to release ourself from memory
_Inspector.InspectorEvents_Event_Close +=
new Outlook.InspectorEvents_CloseEventHandler(_Inspector_InspectorEvents_Event_Close);
// remember the item behind the inspector in memory
_Item = _Inspector.CurrentItem;
// register for the item_open event
if (_Item is Outlook.ContactItem)
{
// we have no latebinding - so we have to cast explicitly to get events
Outlook.
ContactItem item = _Item as Outlook.ContactItem;
item.Open +=
new Outlook.ItemEvents_10_OpenEventHandler(item_Open);
// remember the object in memory
_Item = item;
}
else if (_Item is Outlook.TaskItem)
{
Outlook.
TaskItem item = _Item as Outlook.TaskItem;
item.Open +=
new Outlook.ItemEvents_10_OpenEventHandler(item_Open);
_Item = item;
}
else if (_Item is Outlook.JournalItem)
{
Outlook.
JournalItem item = _Item as Outlook.JournalItem;
item.Open +=
new Outlook.ItemEvents_10_OpenEventHandler(item_Open);
_Item = item;
}
else if (_Item is Outlook.MailItem)
{
Outlook.
MailItem item = _Item as Outlook.MailItem;
item.Open +=
new Outlook.ItemEvents_10_OpenEventHandler(item_Open);
_Item = item;
}
else
{
// we don't handle this inspector and release it from memory
_Item =
null;
}
}
catch (System.Exception ex)
{
// log the error always
Trace.TraceError("{0}: [class]:{1} [method]:{2}\n[message]:{3}\n[Stack]:\n{4}",
DateTime.Now, // when was the error happened
MethodInfo.GetCurrentMethod().DeclaringType.Name, // the class name
MethodInfo.GetCurrentMethod().Name, // the method name
ex.Message,
// the error message
ex.StackTrace
// the stack trace information
);
// the wrapper is called only from application - throw the message to it.
throw new Exception("There was an application error, the new Window could not be handled.\nyou should save your work and restart Outlook.", ex);
}
}
/// <summary>
/// Handles the item open event and checks if this item a OutlooAdminTools item.
/// When we have a new item - and we are in an OAT folder - we close this item and create a new OAT item.
/// </summary>
/// <param name="Cancel"></param>
void item_Open(ref bool Cancel)
{
try
{
Type itemType = _Item.GetType();
// check the messageclass of the new opened inspector.
string messageclass = (string)itemType.InvokeMember("MessageClass", BindingFlags.GetProperty, null, _Item, null);
// access the entryId - so we can get the parent folder object
string entryId = (string)itemType.InvokeMember("EntryID", BindingFlags.GetProperty, null, _Item, null);
// after we have accessed the entryID - we can access the parentfolder property
Outlook.
MAPIFolder parent = itemType.InvokeMember("Parent", BindingFlags.GetProperty, null, _Item, null) as Outlook.MAPIFolder;
string folderName = parent.Description;
int itemSize = (int)itemType.InvokeMember("Size", BindingFlags.GetProperty, null, _Item, null);
}
catch (System.Exception ex)
{
// log the error always
Trace.TraceError("{0}: [class]:{1} [method]:{2}\n[message]:{3}\n[Stack]:\n{4}",
DateTime.Now, // when was the error happened
MethodInfo.GetCurrentMethod().DeclaringType.Name, // the class name
MethodInfo.GetCurrentMethod().Name, // the method name
ex.Message,
// the error message
ex.StackTrace
// the stack trace information
);
// the wrapper is called anytime from application.
// display a messagebox directly to the user
MessageBox.Show("There was an application error, a new Window could not be handled,\nyou should save your work and restart Outlook.",
"OutlookAdminTools",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
/// <summary>
/// This event occures when the user has closed the open inspector.
/// Used to release ourself from memory and avoid memory leaks.
/// </summary>
void _Inspector_InspectorEvents_Event_Close()
{
try
{
_Item =
null;
_Inspector.InspectorEvents_Event_Close -=
new Outlook.InspectorEvents_CloseEventHandler(_Inspector_InspectorEvents_Event_Close);
_Inspector =
null;
GC.Collect();
GC.WaitForPendingFinalizers();
if (InspectorClosed != null)
{
InspectorClosed(_Id);
}
}
catch (System.Exception ex)
{
// log the error always
Trace.TraceError("{0}: [class]:{1} [method]:{2}\n[message]:{3}\n[Stack]:\n{4}",
DateTime.Now, // when was the error happened
MethodInfo.GetCurrentMethod().DeclaringType.Name, // the class name
MethodInfo.GetCurrentMethod().Name, // the method name
ex.Message,
// the error message
ex.StackTrace
// the stack trace information
);
// the wrapper is called anytime from application.
// display a messagebox directly to the user
MessageBox.Show("There was an application error, a Window close could not be handled,\nyou should save your work and restart Outlook.",
"OutlookAdminTools",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
}