sklett

It's been 5 days now and I'm still at square one. I must being doing something very wrong in my add-in. The problem I'm having is that my add-in seems to crash (or the events are being 'disconnected' somehow)

I have a simple add-in that inserts a CommandBarButton in the context menu of the MailItem list. The code inserts the button fine, but when I start to use outlook a little my code eventually stops running and doesn't add the button to the context menu any longer.

I've narrowed down one reproducible scenario:
Start outlook in debug
Right click first MailItem to confirm the CommandBarButton is there (it is)
Right click second mail item to confirm the CommandBarButton is there (it is)
Choose "Open" from the context menu and then close the email after it opens.
Right click first MailItem and the CommandBarButton is gone.

It would seem that when Outlook loses focus the add-in fails. I can also cause the add-in to fail by changing to a different mail folder and right clicking an item.

I'm not getting any exceptions, it just dies. I've started my project over twice now, carefully adding each piece of code and trying to follow the various VSTO sample I have. In the end I always seem to end up with a crashing add-in.

Here is the code, it's a bit big:
Code Snippet


namespace PMDOutAddin
{
public partial class ThisApplication
{
private Outlook.Explorer _activeExplorer = null;
private IncomingMailTracker _incomingMailTracker = null;
private Office.CommandBar _contextMenu = null;
private bool _someFlag = false;
private Office.CommandBarButton _contextButton = null;

private void ThisApplication_Startup(object sender, System.EventArgs e)
{
try
{
_activeExplorer = this.ActiveExplorer();
_activeExplorer.SelectionChange += new Microsoft.Office.Interop.Outlook.ExplorerEvents_10_SelectionChangeEventHandler(ThisApplication_SelectionChange);
_activeExplorer.CommandBars.OnUpdate += new Microsoft.Office.Core._CommandBarsEvents_OnUpdateEventHandler(CommandBars_OnUpdate);

Trace.Listeners.Add(new ConsoleTraceListener());
}
catch (COMException comException)
{
Trace.TraceError(comException.ToString());
MessageBox.Show(comException.Message);
}
catch(Exception exception)
{
Trace.TraceError(exception.ToString());
MessageBox.Show(exception.Message);
}
}

void ThisApplication_SelectionChange()
{
//MessageBox.Show("Selection Changed");
}

private void ThisApplication_Shutdown(object sender, System.EventArgs e)
{
}

void CommandBars_OnUpdate()
{
if(_someFlag)
{
return;
}

try
{
// Try to get the context menu
try
{
_contextMenu = _activeExplorer.CommandBars["Context Menu"];
}
catch(System.Reflection.TargetInvocationException itemNotFoundException){}

if (_contextMenu != null)
{
AddContextMenuButton();
}
}
catch (COMException e)
{
Trace.TraceError(e.Message);
MessageBox.Show(e.Message);
}
catch(Exception exception)
{
Trace.TraceError(exception.Message);
MessageBox.Show(exception.Message);
}
}

private void AddContextMenuButton()
{
const string buttonTagAndCaption = "Send Something to NetSuite";
Office.CommandBarButton button;

try
{
button = (Office.CommandBarButton)_contextMenu.FindControl(
Office.MsoControlType.msoControlButton,
Type.Missing,
buttonTagAndCaption,
Type.Missing,
Type.Missing);

if(button == null)
{
if (_contextButton != null)
{
// remove the event handler
_contextButton.Click -= button_Click;
}


ChangingBar(_contextMenu, false);

_contextButton = (Office.CommandBarButton)_contextMenu.Controls.Add(Office.MsoControlType.msoControlButton,
Type.Missing,
string.Empty,
1,
true);

_contextButton.Tag = buttonTagAndCaption;
_contextButton.Caption = buttonTagAndCaption;
_contextButton.Priority = 1;
_contextButton.Visible = true;
_contextButton.Enabled = true;
_contextButton.Click += new Microsoft.Office.Core._CommandBarButtonEvents_ClickEventHandler(button_Click);
_contextButton.Style = Microsoft.Office.Core.MsoButtonStyle.msoButtonIconAndCaption;

ChangingBar(_contextMenu, true);

Trace.WriteLine("Context Menu Button Created", "Information");
}
}
catch (COMException e)
{
MessageBox.Show(e.Message);
}
catch (Exception exception)
{
MessageBox.Show(exception.Message);
}
}

void button_Click(Microsoft.Office.Core.CommandBarButton Ctrl, ref bool CancelDefault)
{
try
{
MessageBox.Show("Context menu option clicked");
}
catch (Exception e)
{
Trace.TraceError(e.Message);
MessageBox.Show(e.Message);
}
}

// Called once to prepare for changes to the command bar, then again with
// Restore = true once changes are complete.
private void ChangingBar(Office.CommandBar bar, bool restore)
{
bool oldProtectFromCustomize = false;
bool oldIgnore = false;

if(restore)
{
// Restore the Ignore Changes flag
_someFlag = oldIgnore;

// Restore the protect-against-customization bit
if(oldProtectFromCustomize)
{
bar.Protection = bar.Protection & Office.MsoBarProtection.msoBarNoCustomize;
}
}
else
{

// Store the old Ignore Changes flag
oldIgnore = _someFlag;
_someFlag = true;

// Store old protect-against-customization bit setting then clear
// CAUTION: Be careful not to alter the property if there is no need,
// as changing the Protection will cause any visible CommandBarPopup
// to disappear unless it is the popup we are altering.
oldProtectFromCustomize = (bar.Protection & Office.MsoBarProtection.msoBarNoCustomize) == Office.MsoBarProtection.msoBarNoCustomize;
if(oldProtectFromCustomize)
{
bar.Protection = bar.Protection &~ Office.MsoBarProtection.msoBarNoCustomize;
}
}
}

#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(ThisApplication_Startup);
this.Shutdown += new System.EventHandler(ThisApplication_Shutdown);
}

#endregion
}
}




If the problem isn't obvious, I would like to move to plan B: If anyone has a working and reliable example of adding a button to a context menu using C# and Outlook 2003 I will pay you for it. I'm desperate at this point and just need to get caught up on this project. Of course I would rather learn what I'm doing wrong, but without any errors I'm pretty stuck.

Thanks for reading and for any help you might be able to offer.
-Steve


Re: Visual Studio Tools for Office Need help with OL2003 and context menu

sklett

I think I found the problem. I wasn't storing a reference to the CommandBars collection of the active Explorer, after changing that problem my OnUpdate events seems to be firing very consistently.




Re: Visual Studio Tools for Office Need help with OL2003 and context menu

unr8d

What do you mean by adding the reference to the CommandBars collection

I had very similar code in C# and getting kind of the same error as you'd mentioned before.

I wonder if you could post the updated version of your code here. Would surely appreciate it alot!





Re: Visual Studio Tools for Office Need help with OL2003 and context menu

Sue Mosher - Outlook MVP

unr8d, generally, you need to have a maintain reference at the class level to avoid having the object firing the event go out of scope. This article explains why -- Handling Complex COM Objects with Interop Assemblies or "Why Has My Menu Button Stopped Working in Office "



Re: Visual Studio Tools for Office Need help with OL2003 and context menu

Hiren

Hi

I am facing the same problem as unr8d, can anyone please specify clearly, what needs to be done to be able to retrieve the "Context Menu" CommandBar from the collection.

I have iterated through the CommandBars collection of the ActiveExplorer and am not able to find the Context Menu item.

Any help would be appreciated.

Thanks





Re: Visual Studio Tools for Office Need help with OL2003 and context menu

sklett

This code is FAR from optimized or pretty, but it does work.

Code Snippet

private FaxReceiver _faxReceiver = null;


private Outlook.ExplorerClass _activeExplorer = null;
private IncomingMailTracker _incomingMailTracker = null;
private NetSuiteService _nsService = null;
private bool _someFlag = false;

private Office.CommandBar _contextMenu = null;
private Office.CommandBarButton _contextButtonReceiveFax = null;
private Office.CommandBarButton _contextButtonReceiveLead = null;
private Office.CommandBars _commandBars = null;

// UI Elements
Office.CommandBarPopup _topLevelMenuItem = null;
Office.CommandBarButton _settingMenuItem = null;

private Stream _logFile = null;
private TextWriterTraceListener _logTextListener = null;

private Outlook.ExplorerClass Explorer
{
get
{
return this._activeExplorer;
}
set
{
if (this._activeExplorer != null)
{
this._activeExplorer.ExplorerEvents_Event_BeforeFolderSwitch -= new Microsoft.Office.Interop.Outlook.ExplorerEvents_BeforeFolderSwitchEventHandler(_activeExplorer_ExplorerEvents_Event_BeforeFolderSwitch);
this._activeExplorer.ExplorerEvents_Event_Activate -= new Microsoft.Office.Interop.Outlook.ExplorerEvents_ActivateEventHandler(_activeExplorer_ExplorerEvents_Event_Activate);
this._activeExplorer.ExplorerEvents_Event_Close -= new Microsoft.Office.Interop.Outlook.ExplorerEvents_CloseEventHandler(_activeExplorer_ExplorerEvents_Event_Close);
}
this._activeExplorer = value;
if (this._activeExplorer != null)
{
this._activeExplorer.ExplorerEvents_Event_BeforeFolderSwitch += new Microsoft.Office.Interop.Outlook.ExplorerEvents_BeforeFolderSwitchEventHandler(_activeExplorer_ExplorerEvents_Event_BeforeFolderSwitch);
this._activeExplorer.ExplorerEvents_Event_Activate += new Microsoft.Office.Interop.Outlook.ExplorerEvents_ActivateEventHandler(_activeExplorer_ExplorerEvents_Event_Activate);
this._activeExplorer.ExplorerEvents_Event_Close += new Microsoft.Office.Interop.Outlook.ExplorerEvents_CloseEventHandler(_activeExplorer_ExplorerEvents_Event_Close);
}
}
}

private Office.CommandBars ExplorerBars
{
get
{
return this._commandBars;
}
set
{
if (this._commandBars != null)
{
this._commandBars.OnUpdate -= new Microsoft.Office.Core._CommandBarsEvents_OnUpdateEventHandler(_commandBars_OnUpdate);
}
this._commandBars = value;
if (this._commandBars != null)
{
this._commandBars.OnUpdate += new Microsoft.Office.Core._CommandBarsEvents_OnUpdateEventHandler(_commandBars_OnUpdate);
}
}
}

public Office.CommandBarButton ContextButtonReceiveFax
{
get { return _contextButtonReceiveFax; }
set
{
if (_contextButtonReceiveFax != null)
{
// remove the existing Click handlers
_contextButtonReceiveFax.Click -= _contextButtonReceiveFax_Click;
}

// Store the new value
_contextButtonReceiveFax = value;

// Add the Click handler
if (_contextButtonReceiveFax != null)
{
_contextButtonReceiveFax.Click += new Microsoft.Office.Core._CommandBarButtonEvents_ClickEventHandler(_contextButtonReceiveFax_Click);
}
}
}

public Office.CommandBarButton ContextButtonReceiveLead
{
get { return _contextButtonReceiveLead; }
set
{
if (_contextButtonReceiveLead != null)
{
// Remove the existing Click handler
_contextButtonReceiveLead.Click -= _contextButtonReceiveLead_Click;
}

// Store the new value
_contextButtonReceiveLead = value;

// Setup the new Click Handler
if(_contextButtonReceiveLead != null)
{
_contextButtonReceiveLead.Click += new Microsoft.Office.Core._CommandBarButtonEvents_ClickEventHandler(_contextButtonReceiveLead_Click);
}
}
}



private void ThisApplication_Startup(object sender, System.EventArgs e)
{
try
{
// other code snipped!

Explorer = this.ActiveExplorer() as Outlook.ExplorerClass;
ExplorerBars = this.ActiveExplorer().CommandBars;
}
catch (COMException comException)
{
Trace.TraceError(comException.ToString());
MessageBox.Show(comException.Message);
}
catch(Exception exception)
{
Trace.TraceError(exception.ToString());
MessageBox.Show(exception.Message);
}
}

void _commandBars_OnUpdate()
{
if (_someFlag)
{
return;
}

try
{
// Try to get the context menu
try
{
_contextMenu = _activeExplorer.CommandBars["Context Menu"];
}
catch (System.Reflection.TargetInvocationException itemNotFoundException) { }

if (_contextMenu != null)
{
AddContextMenuButtons();
}
}
catch (COMException e)
{
Trace.TraceError(e.Message);
MessageBox.Show(e.Message);
}
catch(ArgumentException)
{
// swallow the exception, it's being thrown by trying to
// access the above CommandBar by key and it doesn't exist.
}
catch (Exception exception)
{
Trace.TraceError(exception.Message);
MessageBox.Show(exception.Message);
}
}

void _activeExplorer_ExplorerEvents_Event_Activate()
{
try
{
if (this.ExplorerBars == null)
{
this.ExplorerBars = this.Explorer.CommandBars;
}
}
catch (Exception exception1)
{
Trace.TraceError(exception1.Message);
MessageBox.Show(exception1.Message);
}

}

void _activeExplorer_ExplorerEvents_Event_Close()
{
this.Explorer = this.ActiveExplorer() as Outlook.ExplorerClass;
}

private void AddContextMenuButtons()
{
const string receiveFaxCaption = "SOLO - Receive Fax Response";
const string receiveLeadCaption = "SOLO - Receive New Lead";

Office.CommandBarButton tmpButton;

try
{
// Receive Fax Button
tmpButton = ContextButtonReceiveFax;
CreateContextMenuButton(ref tmpButton, receiveFaxCaption, string.Empty, Properties.Resources.FaxHS, Properties.Resources.FaxHS_Mask);
ContextButtonReceiveFax = tmpButton;

// Receive New Lead Button
tmpButton = ContextButtonReceiveLead;
CreateContextMenuButton(ref tmpButton, receiveLeadCaption, string.Empty, Properties.Resources.NewLead, Properties.Resources.NewLead_Mask);
ContextButtonReceiveLead = tmpButton;
}
catch (COMException e)
{
MessageBox.Show(e.Message);
}
catch (Exception exception)
{
MessageBox.Show(exception.Message);
}
}

private void CreateContextMenuButton(ref Office.CommandBarButton button,
string caption,
string tag,
Image icon,
Image iconMask)
{
// Search for the control, it could already exist
Office.CommandBarButton tmpButton = _contextMenu.FindControl(
Office.MsoControlType.msoControlButton,
Type.Missing,
caption,
Type.Missing,
Type.Missing) as Office.CommandBarButton;

// If the button wasn't located, we need to create it.
if (tmpButton == null)
{
// Unprotect the CommandBar
ChangingBar(_contextMenu, false);

// Create the new control
button = _contextMenu.Controls.Add(
Office.MsoControlType.msoControlButton,
Type.Missing,
Type.Missing,
1,
true) as Office.CommandBarButton;
Guard.ReferenceNotNull(button, "Failed creating the new context menu control");

// Setup the controls properties
button.Caption = caption;
button.Tag = tag;
button.Picture = ImageToPictureConverter.Convert(icon);
button.Mask = ImageToPictureConverter.Convert(iconMask);
button.Style = Microsoft.Office.Core.MsoButtonStyle.msoButtonIconAndCaption;

// Protect the context menu CommandBar
ChangingBar(_contextMenu, true);
}
}

// Called once to prepare for changes to the command bar, then again with
// Restore = true once changes are complete.
private void ChangingBar(Office.CommandBar bar, bool restore)
{
bool oldProtectFromCustomize = false;
bool oldIgnore = false;

if(restore)
{
// Restore the Ignore Changes flag
_someFlag = oldIgnore;

// Restore the protect-against-customization bit
if(oldProtectFromCustomize)
{
bar.Protection = bar.Protection & Office.MsoBarProtection.msoBarNoCustomize;
}
}
else
{

// Store the old Ignore Changes flag
oldIgnore = _someFlag;
_someFlag = true;

// Store old protect-against-customization bit setting then clear
// CAUTION: Be careful not to alter the property if there is no need,
// as changing the Protection will cause any visible CommandBarPopup
// to disappear unless it is the popup we are altering.
oldProtectFromCustomize = (bar.Protection & Office.MsoBarProtection.msoBarNoCustomize) == Office.MsoBarProtection.msoBarNoCustomize;
if(oldProtectFromCustomize)
{
bar.Protection = bar.Protection &~ Office.MsoBarProtection.msoBarNoCustomize;
}
}
}






Re: Visual Studio Tools for Office Need help with OL2003 and context menu

Malleswar

Hi Sklett,

I got the following errors when I have copied the code as it is and tried to run.

The type or namespace name 'FaxReceiver' could not be found (are you missing a using directive or an assembly reference )

The type or namespace name 'IncomingMailTracker' could not be found (are you missing a using directive or an assembly reference )

The type or namespace name 'NetSuiteService' could not be found (are you missing a using directive or an assembly reference )

are they ur classes If I comment and try it gives full of errors.

I am doing it in VS2005. can you please guide me

Thanks in Advance







Re: Visual Studio Tools for Office Need help with OL2003 and context menu

srinin

i am able to successfully run the project but it's not showing anything on the context menu.

I am running on VS2005 with Outlook 2003. Will it work only on Outlook 2007

-SN