I do a lot of work from my workstation using Remote Desktop (or RDP). Because I only have one monitor, I usually view the remote screen in full screen mode, and so I have to switch back to my workstation screen where Outlook runs to see any new email or meeting/appointment alerts. And, like most developers, I can get absorbed in my work and forget what time it is! So I needed a solution that would alert me whenever a meeting reminder popped up on my workstation desktop or if I had new emails. I found this article at the Channel 9 site from a couple of years ago that seemed to do what I needed with an Outlook Add In, but so much has changed in the Office Object Model, that it would not even compile. However there was some good logic that I could borrow for an updated version of the Add In.
So, I fired up Visual Studio 2010 and began a new Outlook Add In project called RemoteOutlookAlerts. It set up the base project structure and files for me.
 | 1) The generated Add In class 2) The class used to invoke the command-line MSG command 3) The configuration form |
The important parts as shown above are: 1) the generated class file, ThisAddIn.cs; 2) the NetMessage class I modified from the original article (it used NetSend) to send the alerts across the wire using the Msg utility; and, 3) the SettingsForm I created to allow me to configure where to send the alerts, how many emails to ‘log’ before sending an alert, and whether or not to enable alerts to be sent (I’m not always working in RDP).
The Add In class generated by the project template wizard has two important methods: thisAddInStartup and thisAddInShutdown. This is where you build your Add In menu, set up any event handlers you will need, and in my case, set up a polling timer to check whether or not enough new emails have arrived to send an alert to the remote desktop. For the Add In menu, I followed the example from the original article:
private void buildMenu()
{
_menuBar = this.Application.ActiveExplorer().CommandBars.ActiveMenuBar;
_helpMenuIndex = _menuBar.Controls[MenuBefore].Index;
_topMenu = (Office.CommandBarPopup)(
_menuBar.Controls.Add(Office.MsoControlType.msoControlPopup,
Type.Missing, Type.Missing, _helpMenuIndex, true));
_topMenu.Caption = "Remote Alerts";
_topMenu.Visible = true;
_settingsMenu = (Office.CommandBarButton)(
_topMenu.Controls.Add(Office.MsoControlType.msoControlButton,
Type.Missing, Type.Missing, Type.Missing, true));
_settingsMenu.Caption = "Remote Alert Notification Settings...";
_settingsMenu.Visible = true;
_settingsMenu.Enabled = true;
}
My modified startup code looks like this:
private void thisAddInStartup(object sender, System.EventArgs e)
{
buildMenu();
Application.Reminder += thisAddInReminder;
Application.NewMail += thisAddInNewMail;
_settingsMenu.Click += _settingsMenu_Click;
// 1 minute default for polling timer
emailBucketTimer = new System.Timers.Timer { Interval = 60000 };
emailBucketTimer.Elapsed += emailCollectionTimerElapsed;
emailBucketTimer.Enabled = true;
}
I set up separate event handlers for new Reminders and for new Emails, since email notifications occur with each email that arrives, and I didn’t want to have one message box appear on my remote desktop for each new email. I took the approach of having the NewMail event handler increment a count, using a polling timer to check the current count, and if the count becomes equal to or exceeds the configured count, send out the alert.
I also turned off the timer in the Shutdown event handler.
The new Reminder event handler is almost identical to the one used in the original article, so I won’t spend any time on it. The NewMail event handler simply increments a private variable, and when the timer fires, that count is compared to the configured count like so:
void thisAddInNewMail()
{
_emailBucketCount += 1;
}
private void emailCollectionTimerElapsed(object sender, ElapsedEventArgs e)
{
if (Settings.Default["RemoteRemindersEnabled"].ToString() == "True")
{
if (_emailBucketCount >
Convert.ToInt32(Settings.Default["RemoteRemindersNumber"]))
{
string emailMsg = String.Format("You've Got Mail!");
NetMessage.Send(Settings.Default["RemoteRemindersAddress"].ToString(),
Settings.Default["RemoteRemindersUser"].ToString(),
emailMsg);
_emailBucketCount = 0;
}
}
}
The Send method of the NetMessage class is based on invoking the Msg command just like you would from a command prompt. There was one interesting twist I had to solve, and that is that Msg is not always located in the Windows\System32 directory. In 64-bit Windows, it is located elsewhere. So I used some hand waving and trickeration to establish the path to the Msg utility on any system. My solution is included in the source code you can grab at the end of the article. The rest of the logic is fairly straightforward.
var myArguments = String.Format("/Server:{0} {1} {2}", address, user, message);
var systemDir = Is64BitOperatingSystem ? "\\Sysnative\\" : "\\System32\\";
var p = new Process
{
StartInfo =
{
FileName = Environment.GetEnvironmentVariable("WINDIR") + systemDir + "MSG",
Arguments = myArguments,
CreateNoWindow = true,
UseShellExecute = false
}
};
p.Start();
I also created and used the built-in Settings facility that generates app.config entries for the configurable settings. These are read and saved when the form is opened and closed from the Outlook Add In menu. It has four app settings entries:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="userSettings"
type="System.Configuration.UserSettingsGroup, System,
Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089" >
<section name="RemoteOutlookAlerts.Properties.Settings"
type="System.Configuration.ClientSettingsSection,
System, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089"
allowExeDefinition="MachineToLocalUser"
requirePermission="false" />
</sectionGroup>
</configSections>
<userSettings>
<RemoteOutlookAlerts.Properties.Settings>
<setting name="RemoteRemindersAddress" serializeAs="String">
<value />
</setting>
<setting name="RemoteRemindersUser" serializeAs="String">
<value />
</setting>
<setting name="RemoteRemindersNumber" serializeAs="String">
<value>5</value>
</setting>
<setting name="RemoteRemindersEnabled" serializeAs="String">
<value>False</value>
</setting>
</RemoteOutlookAlerts.Properties.Settings>
</userSettings>
</configuration>
I strong-named the assembly using sn –k RemoteOutlookAlerts.snk from the project directory, and signed the assembly with my Authenticode Certificate.
I created a setup project to install the Add In and grabbed a messages icon for the Programs and Features Control Panel applet. Here is a link to an MSDN article covering the current best practices for deploying Office Add Ins. I signed the msi as well.
Finally, there is a small security tweak you’re most likely going to have to set up on the target computer to avoid getting Error 5 (Unable to Create Session) messages.
On the target machine, open up the Registry Editor and navigate to
HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server
Then change the following value:
Name : AllowRemoteRPC
Type : REG_DWORD
Value : 1
Reboot the target machine.
After you’ve installed the Add In, open up Outlook, select the Add Ins menu and then the Remote Alerts item. This is the configuration menu (with a nice Watermarked TextBox extension method to boot):

Since the remote machine I’m using is on my own network and it’s DHCP-enabled, I enter the IP address of the machine, my username, and then adjust the number of emails and check the checkbox if I’m going to start a session. This is what it looks like on the Remote Desktop when a Reminder alert appears:

And this is what it looks like after x number of new emails have arrived in my Inbox:

If you grab the source, and have any suggestions for improvement, please don’t hesitate to contact me. Enjoy, and I hope this helps!
UPDATE: There is one bug I am still working to solve. I followed the best practices from the MSDN article above, but if you delete the bin folder of the main project after building the setup project, the installation does not seem to know about the installed location of the .vsto and .manifest files. Instead, when you start up Outlook, it complains about the RemoteOutlookAlerts.vsto it cannot find. So for now, you can right-click the Setup project and select Install right from Visual Studio 2010, and, as long as you do not delete the Release build binaries, the Add In will work just fine. I will update this post again when I find a solution that allows posting the installer here.
Source Code in a zip archive
Bob Baker
Technorati Tags:
Outlook Add-in,
.Net