Outlook Interop
Outlook 2007 object model incorporates the CDO 1.21 library
The Outlook Shutdown Issue
The Outlook shutdown problem occurs when there are unreleased references to the Outlook objects in a COM add-in (implementing IDTExtensibility2) when the application is closed
Because there are still references to Outlook objects, the OnDisconnection method never gets called and Outlook doesn't get closed properly
Even though the Outlook user interface might not be visible, Outlook is still running (task manager has outlook.exe)
VSTO helps address this issue by keeping track on the number of Inspectors and Explorers that are opened and closed
When no more windows are open in Outlook, it indicates that Outlook has closed and VSTO ensures that Outlook is shut down properly
It does this by unloading the application domain in which the add-ins were loaded and releasing the references to any COM objects
It is important to release though that you still might experience problems when Outlook closes if you are automating Outlook and you are create a running instance of Outlook without making it visible or opening any of its windows (if no Inspectors or Explorers are opened then VSTO cannot track them)
Events
The main difference between the NewMail and NewMailEx events is that with the NewMailEx you get information about each of the items based on its ID.
You should use the Shutdown event handlers rather than QuitEvent because the add-in is unloaded before this event is raised
Object Model
Outlook custom property pages
Application
Inspectors
Inspector
Outlook Item
Explorers
Explorer
Folder
Items
Folders
Namespace
ApplicationEvents_11_Events - contains all the events defined for Outlook 2007
Application.ActiveExplorer
Application.ActiveInspector
Application.ActiveWindow
Application.Session
Application.GetNamespace
Application.Explorers()
Application.Inspectors()
Application.Reminders()
Select Name dialog box - SelectNamesDialog.Display()
objNamespace.PickFolder()
Outlook Ribbon
Use the Context property of the Ribbon class to get the Outlook Inspector object for the window
The Context property returns an object that can be cast to an Outlook.Inspector object
Stores Collection
This represents all the stores in the current Outlook profile
objFolderRoot = Application.Session.DefaultStore.GetRootFolder
Store Object
This represents a file that stores email messages and other items.
If you are using an Exchange Server, this file might be:
1) on a server in a public folder
2) on a local computer in a pst file
3) on a local computer in an offline folder file (ost)
Declaring Events
Here is an example of how to declare an event handler for the Application Startup event
Application.Startup += new Outlook.ApplicationEvents_11_StartupEventHandler(Event_ApplicationStartup)
public void Event_ApplicationStartup()
{
}
Application.Quit
((Outlook.ApplicationEvents_11_Event)Application).Quit += new Outlook.ApplicationEvents_11_QuitEventHandler(Event_ApplicationQuit)
public void Event_ApplicationQuit()
{
}
Addhandler
Inspector.Close
Inspector.Activate
((Outlook.InspectorEvents_10_Event)inspector).Activate += new Outlook.InspectorEvents_10_ActivateEventHandler(Event_InspectorActivate)
public void Event_InspectorActivate()
{
}
Addhandler
Explorer.Activate
((Outlook.ExplorerEvents_10_Event)explorer).Activate += new Outlook.ExplorerEvents_10_ActivateEventHandler(Event_ExplorerActivate)
public void Event_ExplorerActivate()
{
}
Addhandler
Explorer.Close
MailItem.Send
Item.Close
((Outlook.ItemEvents_10_Event)mailitem).Close += new Outlook.ItemEvents_10_CloseEventHandler(Event_ItemClose)
public void Event_ItemClose()
{
}
Addhandler
// start of COM objects
private object applicationObject = null;
private Outlook.Application m_Outlook = null;
private Outlook.NameSpace m_NameSpace = null;
private Office.COMAddIn addInInstance = null;
// Event-aware references to Explorers collection & Explorer object
private Outlook.Explorers m_Explorers = null;
private Outlook.ExplorersClass m_ExplorersClass = null;
private Outlook.Explorer m_Explorer = null;
private Outlook.ExplorerClass m_ExplorerClass = null;
// Event-aware references to Inspectors collection & Inspector object
private Outlook.Inspectors m_Inspectors = null;
private Outlook.InspectorsClass m_InspectorClass = null;
private Outlook.Inspector m_Inspector = null;
private Outlook.InspectorClass m_InspectorClass = null;
// end of COM objects
// Explorer Wrapper Collection
private System.Collections.SortedList m_ExplWrap = null;
// Inspector Wrapper Collection
private System.Collections.SortedList m_InspWrap = null;
private string m_ProgID = "";
private int m_WrapperID = 0;
private int m_OutlookVersion = 0;
//Initialization flags
private bool m_Teardown = false;
private bool m_Init = false;
applicationObject = application;
try
{
m_Outlook = (Outlook.Application)application;
m_NameSpace = m_Outlook.GetNamespace("MAPI");
//event-aware reference to Explorers collection
//use NewExplorer event to watch for UI creation
m_Explorers = m_Outlook.Explorers;
try
{
m_Teardown = false;
//Are we starting with UI?
if (m_Explorers.Count > 0)
{
m_Explorer = m_Outlook.Explorers[1];
//we have UI - initialize base class
InitHandler();
if (m_Init == true)
{
// allot space initially for 10 open Explorers at a time
m_ExplWrap = new System.Collections.SortedList(10);
OutExpl adder = new OutExpl();
m_WrapperID = adder.AddExpl(m_Explorer,
m_WrapperID, ref m_ExplWrap);
adder = null;
}
m_Inspectors = m_Outlook.Inspectors;
//After the initializations are finished for the open Explorerto put it in a sorted list and the Inspectors collec-
//tion is initialized, the event handlers are added for the NewExplorer, ExplorerClose, and NewInspector
//events.
m_Explorers.NewExplorer += new
Outlook.ExplorersEvents_NewExplorerEventHandler(m_Explorers_NewExplorer);
m_ExplorerClass = (Outlook.ExplorerClass)m_Explorer;
m_ExplorerClass.ExplorerEvents_Event_Close += new
Outlook.ExplorerEvents_CloseEventHandler(m_Explorer_Close);
m_InspectorsClass = (Outlook.InspectorsClass)m_Inspectors
m_InspectorsClass.NewInspector += new
Outlook.InspectorsEvents_NewInspectorEventHandler(m_InspectorsClass_NewInspector);
}
else
{
//do nothing
//monitor Explorers collection (in this module)
//if NewExplorer event is raised then we have UI
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
TearDown();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
TearDown();
}
}
private void m_Explorers_NewExplorer(Microsoft.Office.Interop.Outlook.Explorer
Explorer)
{
//assign ActiveExplorer
m_Explorer = Explorer;
if (m_Init == false)
{
//we didn't have UI before - initialize addin objects
InitHandler();
}
if (m_Init == true)
{
OutExpl adder = new OutExpl();
m_WrapperID = adder.AddExpl(Explorer, m_WrapperID, ref m_ExplWrap);
adder = null;
}
}
The code in Listing6.15 shows the event handler for the Explorer.Closeevent. When Explorer.Close
fires, the module-level m_Exploreris assigned to ActiveExplorer. If that fails, and there are no open
Inspectors, the Teardown()procedure is called to release all Outlook objects. The code in Listings 6.15
and 6.16 is only needed if you aren't using Explorerwrappers and aren't using VSTO 2005 SE. Similar
code is used in the Explorerand Inspectorwrappers to handle the Closeevents.
Listing6.15
// Monitor Explorer_Close to see when UI "disappears"
private void m_Explorer_Close()
{
//release current reference
m_Explorer = null;
try
{
m_Explorer = m_Outlook.ActiveExplorer();
}
catch
{
if (m_Outlook.Inspectors.Count == 0)
{
//release addin objects
if (m_Teardown == false) TearDown();
}
}
}
#endregion
When a new Inspectoris opened, it's checked to make sure it's not a Note Inspector, and if not a
module level m_InspectorClassobject is instantiated as the new Inspectorfor event-handling pur-
poses as shown in Listing6.16.
Inspectorevents that are overloaded by Inspectormethods, such as Close, are handled not by
theInspectorobject but by the InspectorClassobject in C#. This also applies to other objects
where events are overloaded by methods with the same name.
An event handler for the Inspector.Closeevent is created to allow the code to handle the closing of
the new Inspector.
m_InspectorClass.InspectorEvents_Event_Close += new
Outlook.InspectorEvents_CloseEventHandler(molInspector_Close);
Then the new Inspectoris added to the Inspectorwrapper sorted list.
#region inspector_related_events
private void m_InspectorsClass_NewInspector(Outlook.Inspector Inspector)
{
//No handling of Inspectors for Notes, they are brain dead
// set up to get the Class property of the item in the Inspector
object item = Inspector.CurrentItem;
Type _type;
_type = item.GetType();
object[] _args = new Object[] { }; // dummy argument array
Outlook.OlObjectClass _class = Outlook.OlObjectClass.olNote;
try // try to get the Class using reflection
{
_class = (Outlook.OlObjectClass)_type.InvokeMember("Class",
BindingFlags.Public | BindingFlags.GetField | BindingFlags.GetProperty, null, item,
_args);
}
catch (Exception ex)
{
//MessageBox.Show(ex.Message);
_class = Outlook.OlObjectClass.olNote;
}
if (_class != Outlook.OlObjectClass.olNote) {
m_Inspector = Inspector;
a try
{
m_InspectorClass = (Outlook.InspectorClass)m_Inspector;
m_InspectorClass.InspectorEvents_Event_Close += new
Outlook.InspectorEvents_CloseEventHandler(molInspector_Close);
OutInsp adder = new OutInsp();
m_WrapperID = adder.AddInsp(Inspector, m_WrapperID, _class, ref
m_ExplWrap);
adder = null;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
When the Inspectorcloses, the Closeevent handler assigns ActiveInspectorto m_Inspector, and
if that fails and there are no open Explorers, the Teardown()procedure is called to release the Outlook
objects, as shown below. The code in Listing6.17 is used only if wrapper classes aren't being used.
private void molInspector_Close()
{
m_Inspector = null;
try
{
m_Inspector = m_Outlook.ActiveInspector();
}
catch
{
if (m_Inspector == null)
{
if (m_Outlook.Explorers.Count == 0)
{
if (m_Teardown == false)
{
TearDown();
}
}
}
}
}
private void TearDown()
{
if (m_Teardown == false)
{
try
{
if (m_ExplWrap != null)
{
m_ExplWrap.Clear();
m_ExplWrap = null;
}
if (m_InspWrap != null)
{
m_InspWrap.Clear();
m_InspWrap = null;
}
// remove the event handlers
if (m_Explorers != null)
{
m_Explorers.NewExplorer -= new
Outlook.ExplorersEvents_NewExplorerEventHandler(
m_Explorers_NewExplorer);
}
if (m_InspectorsClass != null)
{
m_InspectorsClass.NewInspector -= new
Outlook.InspectorsEvents_NewInspectorEventHandler(
m_InspectorsClass_NewInspector);
}
//release reference to Outlook objects
if (m_Explorer != null) m_Explorer = null;
if (m_Explorers != null) m_Explorers = null;
if (m_Inspectors != null) m_Inspectors = null;
if (m_Inspector != null) m_Inspector = null;
if (m_ExplorersClass != null) m_ExplorersClass = null;
if (m_ExplorerClass != null) m_ExplorerClass = null;
if (m_InspectorsClass != null) m_InspectorsClass = null;
if (m_InspectorClass != null) m_InspectorClass = null;
if (m_NameSpace != null) m_NameSpace = null;
if (m_Outlook != null) m_Outlook = null;
if (applicationObject != null) applicationObject = null;
if (addInInstance != null) addInInstance = null;
m_Teardown = true;
m_Init = false;
GC.Collect();
GC.WaitForPendingFinalizers();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
© 2024 Better Solutions Limited. All Rights Reserved. © 2024 Better Solutions Limited TopPrevNext