C# - Office Automation : Outlook Security Message



If you've ever worked with office automation/integration (e.g. COM objects) and outlook, chances are that you've had a run in with its "object model guard".

This is a feature that Microsoft introduced (via Patch) since Office 98/2000 in order to secure Outlook (against exploitation etc), observe the following snippet:
 
static void Appointments()
{
    Outlook.ApplicationClass application = new Outlook.ApplicationClass();
    Outlook.MAPIFolder folder = application.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderCalendar);
 
    foreach (Outlook.AppointmentItem item in folder.Items)
    {
        Console.WriteLine(item.Subject);
        Console.WriteLine(item.Body);
    }
}
 

As soon as the snippet executes, the following allow/deny popup appears:



This obviously defeats the whole concept of "automation", we don't want users to allow/deny actions, but how do we get around this issue though?

We need to write code that is "trusted" by Outlook.

If you look at the preceding code snippet (which is from a console app), the code won't be trusted since first of all our code needs to run in context of outlook and secondly since we're outside the host process we can't access its trusted application object, which forces us to instantiate a new "untrusted" application object.

In the following snippet we alter the preceding snippet to run in context of outlook (via Add-In) and access the main application object (which is trusted), in theory the popup won't be displayed anymore. (i've seen in quite a number of forums people complaining that it still brings up the popup. Works for me though)
 
public void OnConnection(object application, Extensibility.ext_ConnectMode connectMode, object addInInst, ref System.Array custom)
{
	applicationObject = application;
	addInInstance = addInInst;
 
	Outlook.ApplicationClass outlook = (Outlook.ApplicationClass)application;
	Outlook.MAPIFolder folder = outlook.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderCalendar);
 
	foreach (Outlook.AppointmentItem item in folder.Items)
	{
		MessageBox.Show(item.Subject);
		MessageBox.Show(item.Body);
	}
}
 

But what about scenarios where we need to be out of process - which translates to untrusted?

There are two solutions I am going to explain in this post, one requires some minor alterations to code, the other one requires no changes in code.

In the following snippet I make use of the Redemption class written by the guys at dimastr.com:
 
static void Appointments()
{
    Outlook.ApplicationClass application = new Outlook.ApplicationClass();
    Outlook.MAPIFolder folder = application.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderCalendar);
 
    foreach (Outlook.AppointmentItem item in folder.Items)
    {
        Redemption.SafeAppointmentItemClass safe = new Redemption.SafeAppointmentItemClass();
        safe.Item = item;
        Console.WriteLine(item.Subject);
        Console.WriteLine(safe.Body);
    }
}
 

Basically instead of using the properties from the object model, the properties are extracted via Extended MAPI - bypassing the object model guard - which means no popup.

Another solution comes in the form of an Add-In written by the guys at mapilab.com. When we run our "untrusted" code, instead of an allow/deny popup, you will notice the following popup (for example) jumping up instead.



Which gives us a lot more control over external applications trying to access properties via COM.

Additional reading
http://www.mapilab.com/outlook/security/
http://www.dimastr.com/redemption/
http://support.microsoft.com/kb/327657





Post/View comments
 

C# Threading: Windows Forms and WPF InvokeRequired / CheckAccess



When interacting with UI via threads (using Windows Forms) you might have seen the following exception:
Cross-thread operation not valid: Control 'x' accessed from a thread other than the thread it was created on.

A Simple way to reproduce this exception, is to simply create a Windows Forms app, drop a button on the form, attach an event handler on the click event (of the button) and create a thread that attempts to access the button, for example:
 
private void action()
{
    button1.Text = "Clicked";
}
 
private void button1_Click(object sender, EventArgs e)
{
    Thread t = new Thread(action);
    t.Start();
}
 

The reason behind this exception is because Windows Form controls aren't thread safe, so in order to achieve some kind of thread safety, the UI controls are bound to the thread it was created on and in order to access them, one needs to reside in the same thread.

How does one achieve this (reside in the same thread) exactly?

One way, is to check the InvokeRequired property on the control and use the Invoke (synchronous) or BeginInvoke (asynchronous) method on the control in order to send some code (via delegate) to the thread that owns it, observe:

 
private void action()
{
    if (button1.InvokeRequired)
    {
        button1.Invoke(new Action(action));
        return;
    }
    button1.Text = "Clicked";
}
 

If we try to do the same thing (access controls that reside in the UI thread) in a WPF Application, we are confronted with the same issues,
 
private void action()
{
    button1.Content = "Clicked";
}
 
private void button1_Click(object sender, RoutedEventArgs e)
{
    Thread t = new Thread(action);
    t.Start();
}
 

The exception message looks a little bit different though:
The calling thread cannot access this object because a different thread owns it.

And unlike the Windows Forms solution, you won't find the InvokeRequired property on the WPF controls, instead one can use the Dispatcher property, observe:

 
private void action()
{
    if (button1.Dispatcher.CheckAccess())
    {
        button1.Content = "Clicked";
        return;
    }
    button1.Dispatcher.Invoke(
        System.Windows.Threading.DispatcherPriority.Normal,
        new Action(action));
}
 

Something interesting to note, is that CheckAccess method (and a few overloads within the invoke method) is hidden to intellisense, which is achieved by the following attribute:
 
[EditorBrowsable(EditorBrowsableState.Never)]
 

Looking at other solutions, you might want to have a look at the AsyncOperationManager & SynchronizationContext classes - perhaps a future post.




Post/View comments
 
First 11 12 13 14 15 16 17 18 19 20 Last / 62 Pages (124 Entries)

Latest Posts

Be the best stalker you can be


2011-12-13 22:33:54

Syntactic sugar (C#): Enum


2011-08-04 16:50:18

Top 5 posts

Simple WYSIWYG Editor


Creating a WYSIWYG textbox for your website is actually quite simple.
2007-02-01 12:00:00

Moving items between listboxes in ASP.net/PHP example


Move items between two listboxes in ASP.net(C#, VB.NET) and PHP
2008-06-12 17:07:43

Cross Browser Issues: Firefox Word Wrapping


Firefox word wrapping issues
2008-06-09 09:51:21

Populate a TreeView Control C#


Populate a TreeView control in a windows application.
2009-08-27 16:01:03

C# YouTube : Google API


Post on how to integrate with YouTube using the Google Data API
2011-03-12 08:37:51