Outlook VSTO NewMailEx is not firing for new storage - events

I am developing an Outlook plugin and faced with the problem when my callback NewMailEx is not called for a newly added storage.
My code looks like the next:
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
Application.ItemSend += Application_ItemSend;
Application.NewMailEx += Application_NewMailEx;
}
private void Application_NewMailEx(string EntryIDCollection)
{
logger.Debug("Received e-mail with ID: {0}", EntryIDCollection);
var outlook_namespace = Application.GetNamespace("MAPI");
dynamic item = outlook_namespace.GetItemFromID(EntryIDCollection);
if (!(item is Outlook.MailItem))
return;
// do some stuff with mail
}
I also tried to subscribe for a new storage:
{
Application.Session.Stores.StoreAdd += Stores_StoreAdd;
}
private void Stores_StoreAdd(Outlook.Store store)
{
logger.Info("New store is added: " + store.DisplayName);
Outlook.MAPIFolder rootFolder = store.GetRootFolder();
Outlook.MAPIFolder inbox = store.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
inbox.Items.ItemAdd += items_ItemAdd;
}
private void items_ItemAdd(object item)
{
if (item is Outlook.MailItem)
{
Outlook.MailItem mail = item as Outlook.MailItem;
// do some stuff with mail
}
}
But ItemAdd is called only for items during the synchronization. For a new mails neither NewMailEx nor ItemAdd are called.
But after the restart everything works and NewMailEx works as usual.
Do you have any ideas how to fix it or some workaround?

Your items_ItemAdd event handler will never fire because you set up the event handler on an implicit variable created by the compiler on the line inbox.Items.ItemAdd += items_ItemAdd. You need to save Items object in a dedicated variabler (or event better a List<Items>) to make sure it stays alive and GC never releases it.

Related

VSTO How to hide FormRegion in Reply email [in InlineResponse also]?

So, as the subject says...what is the easiest way to hide FormRegion if email is in Reply mode whether its in a new window or with InlineResponse?
Just set the FormRegion.Visible property which returns a Boolean value that indicates whether the form region is visible or hidden.
Went back to test the approach in my answer after the question from #EugeneAstafiev and -- of course -- this was more complicated than I first thought... but I did get it working with some additional code.
The issue is that when the user clicks "Reply", it opens a new inspector window with a new instance of the FormRegion. So setting the Visible property to false in the event handler sets it only on the current "Read" mode inspector window -- rather than the new "Compose" mode inspector window that gets opened. So, instead the code samples below set up a bool flag property in ThisAddIn called LoadFormRegion that can be toggled to "false" when the Reply or ReplyAll event is fired.
Also, I noticed that setting Visible to false on the FormRegion still draws the area of the FormRegion on the inspector window, just with nothing in it. To completely prevent the FormRegion from loading, you can test for "Compose" mode and then the ThisAddin.LoadFormRegion flag in the FormRegionInitializing event handler located inside of the "Form Region Factory" at the top of the code page -- which is usually folded away from view. In that code block, setting "e.Cancel = true" will prevent the FormRegion from loading at all.
Here is the revised code for the FormRegion, which now subscribes to all three email button click events (Reply, ReplyAll, Forward), and sets the ThisAddIn.LoadFormRegion flag accordingly:
namespace TESTINGOutlookAddInVSTO
{
partial class FormRegion1
{
#region Form Region Factory
[Microsoft.Office.Tools.Outlook.FormRegionMessageClass(Microsoft.Office.Tools.Outlook.FormRegionMessageClassAttribute.Note)]
[Microsoft.Office.Tools.Outlook.FormRegionName("TESTINGOutlookAddInVSTO.FormRegion1")]
public partial class FormRegion1Factory
{
// Occurs before the form region is initialized.
// To prevent the form region from appearing, set e.Cancel to true.
// Use e.OutlookItem to get a reference to the current Outlook item.
private void FormRegion1Factory_FormRegionInitializing(object sender, Microsoft.Office.Tools.Outlook.FormRegionInitializingEventArgs e)
{
if (e.FormRegionMode == Outlook.OlFormRegionMode.olFormRegionCompose)
{
var myAddIn = Globals.ThisAddIn;
if (myAddIn.LoadFormRegion == false)
{
e.Cancel = true;
}
}
}
}
#endregion
// Occurs before the form region is displayed.
// Use this.OutlookItem to get a reference to the current Outlook item.
// Use this.OutlookFormRegion to get a reference to the form region.
private void FormRegion1_FormRegionShowing(object sender, System.EventArgs e)
{
// Reset ThisAddIn.LoadFormRegion flag to true (in case user starts
// composing email from scratch without clicking Reply, ReplyAll or Forward)
var myAddin = Globals.ThisAddIn;
myAddin.LoadFormRegion = true;
var myMailItem = this.OutlookItem as Outlook.MailItem;
// Track these events to set the ThisAddIn.FormRegionShowing flag
((Outlook.ItemEvents_10_Event)myMailItem).Reply += myMailItem_Reply;
((Outlook.ItemEvents_10_Event)myMailItem).ReplyAll += myMailItem_ReplyAll;
((Outlook.ItemEvents_10_Event)myMailItem).Forward += myMailItem_Forward;
}
// Sets FormRegionShowing flag on ThisAddin
private void SetFormRegionShowing(bool show)
{
var myAddIn = Globals.ThisAddIn;
myAddIn.LoadFormRegion = show;
}
private void myMailItem_Forward(object Forward, ref bool Cancel)
{
SetFormRegionShowing(true);
}
private void myMailItem_ReplyAll(object Response, ref bool Cancel)
{
SetFormRegionShowing(false);
}
private void myMailItem_Reply(object Response, ref bool Cancel)
{
SetFormRegionShowing(false);
}
// Occurs when the form region is closed.
// Use this.OutlookItem to get a reference to the current Outlook item.
// Use this.OutlookFormRegion to get a reference to the form region.
private void FormRegion1_FormRegionClosed(object sender, System.EventArgs e)
{
}
}
}
And here's the new code for ThisAddIn to setup the LoadFormRegion property flag:
namespace TESTINGOutlookAddInVSTO
{
public partial class ThisAddIn
{
private bool loadFormRegion;
public bool LoadFormRegion { get => loadFormRegion; set => loadFormRegion = value; }
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
LoadFormRegion = true;
}
private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
{
// Note: Outlook no longer raises this event. If you have code that
// must run when Outlook shuts down, see https://go.microsoft.com/fwlink/?LinkId=506785
}
#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
}
}
Tested the above and works nearly perfectly... I noticed that if there is a "Draft" reply in the user's Inbox created before the add-in was loaded, clicking on that email to continue editing in the Preview window or a new inspector window will cause some wonky display issues with the FormRegion. However, once I closed out that draft, then everything seemed to return to normal.

Outlook vsto - Folder restrictions

I have a little Outlook 2010 AddIn and need to restrict some actions on a custom folder:
Can I somehow prevent the user from renaming a folder?
Is it possible to prevent the user from moving any item to the folder? I know the ItemAdd Event, but this is only fired after the item was already moved. This is too late for me.
Would it be possible to disable the context menu (right click) of a folder?
Thanks a lot!
// edit: I think I found a solution for the context menu problem. Is that ok or is there a flaw in doing this?
outlook.FolderContextMenuDisplay += DisableArchiveFolderContextMenu;
private void DisableArchiveFolderContextMenu(Office.CommandBar commandBar, MAPIFolder folder)
{
if (folder.Name.Equals(Settings.Default.ArchiveFolderName))
{
// Disable the context menu
commandBar.Enabled = false;
}
else
{
commandBar.Enabled = true;
}
}
Take a look at BeforeItemMove for preventing users from moving items into your folder. This event would need to be attached to every folder you are interested in watching - there is no global BeforeItemMove that I am aware of. You will have to recursively iterate each mailbox folder or latch onto Explorer.FolderSwitch and attach your item listener. The FolderSwitch has limitations though since you can still move items without switching folders via Inspector Ribbon, OWA, or EWS.
To keep users from renaming your folder, you can use the StorageItem to persist the Folder name implemented via FolderChange of the folders' context parent.
public partial class ThisAddIn
{
Outlook.Folder folder;
Outlook.Folder customFolder;
Outlook.Folders mailbox;
Outlook.Explorer explorer;
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
explorer = Globals.ThisAddIn.Application.ActiveExplorer();
explorer.FolderSwitch += new Outlook.ExplorerEvents_10_FolderSwitchEventHandler(explorer_FolderSwitch);
mailbox = Globals.ThisAddIn.Application.Session.DefaultStore.GetRootFolder().Folders;
if (mailbox.Cast<Outlook.Folder>().Where(c => c.Name == "Custom Folder").Count() == 0)
{
customFolder = mailbox.Add("Custom Folder") as Outlook.Folder;
Outlook.StorageItem si = customFolder.GetStorage("Custom Folder Storage", Outlook.OlStorageIdentifierType.olIdentifyBySubject);
si.UserProperties.Add("PermanentFolderName", Outlook.OlUserPropertyType.olText).Value = customFolder.Name; // store persistent name
si.Save();
}
else
customFolder = mailbox["Custom Folder"] as Outlook.Folder;
mailbox.FolderChange += new Outlook.FoldersEvents_FolderChangeEventHandler(mailbox_FolderChange);
}
void explorer_FolderSwitch()
{
folder = explorer.CurrentFolder as Outlook.Folder; // grab new handle
folder.BeforeItemMove += new Outlook.MAPIFolderEvents_12_BeforeItemMoveEventHandler(folder_BeforeItemMove);
}
void mailbox_FolderChange(Outlook.MAPIFolder Folder)
{
Outlook.Folder folder = Folder as Outlook.Folder;
Outlook.StorageItem si = folder.GetStorage("Custom Folder Storage", Outlook.OlStorageIdentifierType.olIdentifyBySubject);
if (si.Size > 0 && si.UserProperties.Count > 0 && si.UserProperties["PermanentFolderName"].Value != folder.Name)
folder.Name = si.UserProperties["PermanentFolderName"].Value; // override users name change
}
void folder_BeforeItemMove(object Item, Outlook.MAPIFolder MoveTo, ref bool Cancel)
{
if (MoveTo.Name == "Custom Folder")
Cancel = true; // disallow moving items here
}
}

Outlook Event is not getting fired on click of custom button

I am developing a Microsoft Outlook Add-in, where I have added one button in Add-In tab name OPENISMS. I could see the button, however on click the event is not getting fired. I have no clue why it is behaving in this manner. Please find below are code for adding button and attaching event to it. Any help will be highly appreciated.
private void AddButtonToNewDropdown()
{
Office.CommandBar commandBar = this.Application.ActiveExplorer().CommandBars["Standard"];
Office.CommandBarControl ctl = commandBar.Controls["&New"];
if (ctl is Office.CommandBarPopup)
{
Office.CommandBarButton commandBarButton;
Office.CommandBarPopup newpopup = (Office.CommandBarPopup)ctl;
commandBarButton = (Office.CommandBarButton)newpopup.Controls.Add(1, missing, missing, missing, true);
commandBarButton.Caption = "OpenISMS";
commandBarButton.Tag = "OpenISMS";
commandBarButton.FaceId = 6000;
//commandBarButton.Enabled = false;
commandBarButton.OnAction = "OpenISMSThruMail.ThisAddIn.ContextMenuItemClicked";
commandBarButton.Click += new Office._CommandBarButtonEvents_ClickEventHandler(ContextMenuItemClicked);
}
}
private void ContextMenuItemClicked(CommandBarButton Ctrl, ref bool CancelDefault)
{
if (currentExplorer.Selection.Count > 0)
{
object selObject = currentExplorer.Selection[1];
if (selObject is MailItem)
{
// do your stuff with the selected message here
MailItem mail = selObject as MailItem;
MessageBox.Show("Message Subject: " + mail.Subject);
}
}
}
I am calling AddButtonToNewDropdown() method from ThisAddIn_Startup event.
You need to make the CommandBarButton a class-member variable in scope - otherwise it will be garbage collected and the event will not fire as you've observed.
public class ThisAddIn
{
Office.CommandBarButton commandBarButton;
private void AddButtonToNewDropdown()
{
// ...
}
}
See related SO post regarding similar issue.

Alarm feature in Windows Phone 7

I am trying to controll the snooze and dismiss button when the alarm sound in windows phone 7.
But i couldnt find any source code example on it.
Can anyone help me with it?
What i want is like when i clicked on the snooze or dimiss button it will do something such as the dismiss button will naviagte to another page.
And one more thing is that when the alarm is triggered can i set it to play some music??
Because the one that i have tried out does not play any music.
private static void CreateAlarm(string title, string time)
{
var alarm = new Alarm(title)
{
Content = "You have a meeting with your team now.",
BeginTime = Convert.ToDateTime(time),
};
ScheduledActionService.Add(alarm);
}
private static void ResetAlarm()
{
ScheduledActionService.Remove("MyAlarm");
}
private void SetAlarm_Click(object sender, RoutedEventArgs e)
{
string time = Convert.ToString(timePicker1.ValueString);
CreateAlarm(txtTitle.Text, time);
}
private void ResetAlarm_Click(object sender, RoutedEventArgs e)
{
ResetAlarm();
}
}
The Alarm class has a .Sound property to controls the sound file that is played.
To use it, say you have Alarm.mp3 in your project under the Sounds folder with it's build action set to Content.
var alarm = new Alarm() {
Sound = new Uri('Sounds/Alarm.mp3', UriKind.Relative)
}
There is no way to respond to snooze or dismiss that I have seen.

How to access MailItem from UserControl?

hey guys, i have a usercontrol within the default email compose form, I want to get the mailitem of that window.
Is there an easy way to do this?
Since you are composing an email, you must be in an Outlook Inspector. So you would have code like this:
Inspector inspector = window as Inspector;
MailItem mailItem = inspector.CurrentItem as MailItem;
Assuming you have some type of CheckBox or RadioButton control on your user UserControl you could utilize the ActiveInspector to get a hold of the mailItem:
using Outlook = Microsoft.Office.Interop.Outlook;
namespace My_Outlook_Plugin
{
public partial class UserControl_Classification : UserControl
{
public UserControl_Classification()
{
InitializeComponent();
}
private void UserControl_Classification_Load(object sender, EventArgs e)
{
}
private void radioButton1_CheckedChanged(object sender, EventArgs e)
{
try
{
Inspector inspector = Globals.ThisAddIn.Application.ActiveInspector();
if (inspector.CurrentItem is Outlook.MailItem)
{
MailItem mailItem = inspector.CurrentItem as MailItem;
//Do something with mailItem
Marshal.ReleaseComObject(mailItem);
}
}
catch (System.Exception ex)
{ }
}
}
Also, this is a really good explanation on setting up a wrapper which you need to to to track each potential mailItem window the the user might open and dispose of it properly - enter link description here

Resources