Click here to Skip to main content
15,867,835 members
Articles / Desktop Programming / Windows Forms

Add-in Programming

Rate me:
Please Sign up or sign in to vote.
3.00/5 (3 votes)
12 Jul 2010GPL34 min read 45.6K   21   12
Add-in - add-on programming and an example for Outlook add-in regions, views, rules, and reports.

Introduction

I have recognized there is no enough information about OutlookAddIn programming in the internet therefore I decided to write this article. I have searched many website and I have read some books interesting AddIn Programming. After some of my professional works I have find out some critical solutions for new AddIn Programmers and I am here.

This article identifying some critical details interesting with:

Contents

  1. Regions
  2. EventHandlers
  3. Reports
  4. Task, Mail, and Appointment Management
  5. Operational System and Version Detection
  6. Views
  7. Rules

Startup

An add-in starts with some event handler because if programmer wants to do some things according some conditions in an office program it gives up an event to the programmer and he can handle this event and he can use according his aims. An event handler begins like below at the startup:

C#
private void InternalStartup()
{
    this.Startup += new System.EventHandler(ThisAddIn_Startup);
    this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
}

After this progress Programmer may use next steps:

C#
public static Outlook.Inspectors inspectors;

private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
    inspectors.NewInspector += 
      new Microsoft.Office.Interop.Outlook.
      InspectorsEvents_NewInspectorEventHandler(inspectors_NewInspector);
    _instance = this;
}

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

Logic

Inserting a Button to the Tool Bar or Context Menu, catching some screens for changing their algorithms according the necessities and releasing full requirements is the main factors in an AddIn program. So, we can write all this phases starting from the inspector which we have handled in the Start Up event before. Current Item gives us the substantial element when the event fired. I have handled Appointment Item in this case like below. I will use timer object to draw a graphic to the current window that user has entered. After this operation I am calling the ReportInspector function for an inspection if any report is exist than I am sending this report to the current user as a mail.

C#
void inspectors_NewInspector(Microsoft.Office.Interop.Outlook.Inspector Inspector)
{
    _manuelCancel = false;

    Object anitem = (Outlook.AppointmentItem)Inspector.CurrentItem;

    if (anitem != null)
    {
        _aitm = (Outlook.AppointmentItem)anitem;

        if (_aitm.Body == null)
        {
            _tm.Interval = 10;
            _tm.Tick += new EventHandler(tm_Tick);
            _timerSwitch = true;
            _tm.Start();
        }
    }

    _isLiiveMessageShowing = IsLiveMeetingShowing(DateTime.Now, Inspector);

    ReportInspector(DateTime.Now, Inspector);
}

When we have handled the new appointment window than we can capture its content over to make a new special design by using some tables and graphical COM Objects. The content is a Document Class in here.

C#
void tm_Tick(object sender, EventArgs e)
{
    if (_timerSwitch)
    {
        try
        {
            _timerSwitch = false;
            _tm.Stop();

            if (((inspectors[1].WordEditor as 
                  Microsoft.Office.Interop.Word.DocumentClass)
                  ).InlineShapes.Count < 1)
            {

                object ranger = (inspectors[1].WordEditor as 
                  Microsoft.Office.Interop.Word.DocumentClass
                  ).Application.Selection.Range;

                if (((inspectors[1].WordEditor as 
                      Microsoft.Office.Interop.Word.DocumentClass)).Tables.Count == 0)

                    ((inspectors[1].WordEditor as 
                      Microsoft.Office.Interop.Word.DocumentClass)).Tables.Add(
                      range, 2, 2, ref defaultBehavior, ref autoFitBehavior);

                Microsoft.Office.Interop.Word.Cell vertical1 = 
                  ((inspectors[1].WordEditor as 
                    Microsoft.Office.Interop.Word.DocumentClass)
                    ).Tables[1].Columns[1].Cells[1];
                Microsoft.Office.Interop.Word.Column clm1 = 
                  ((inspectors[1].WordEditor as 
                    Microsoft.Office.Interop.Word.DocumentClass)).Tables[1].Columns[1];
                clm1.Width = 40;
                area1.Range.Font.Name = "Calibri";
                merger3.Merge(vertical1);

                vertical1.Range.Font.Size = 22;
                vertical1.Range.Font.Name = "Calibri";
                vertical1.Height = 200;
                vertical1.Range.Bold = 12;
                vertical1.Range.Text = "";
                vertical1.Range.Orientation = 
                  Microsoft.Office.Interop.Word.WdTextOrientation.wdTextOrientationUpward;
                vertical1.VerticalAlignment = 
                  Microsoft.Office.Interop.Word.WdCellVerticalAlignment.wdCellAlignVerticalCenter;
                vertical1.Range.Shading.BackgroundPatternColor = 
                  Microsoft.Office.Interop.Word.WdColor.wdColorBrightGreen;
                vertical1.Range.FitTextWidth = 0;
                vertical1.Range.Font.Color = Microsoft.Office.Interop.Word.WdColor.wdColorWhite;

                area1.Range.Borders.OutsideLineStyle = 
                       Microsoft.Office.Interop.Word.WdLineStyle.wdLineStyleThinThickLargeGap;
                cellHorizontal1.Range.Borders.OutsideLineStyle = 
                       Microsoft.Office.Interop.Word.WdLineStyle.wdLineStyleThinThickLargeGap;
                cellHorizontal1.Range.Borders[
                       Microsoft.Office.Interop.Word.WdBorderType.wdBorderTop].Color = 
                       Microsoft.Office.Interop.Word.WdColor.wdColorGray05;

                //...

                vertical1.Borders[Microsoft.Office.Interop.Word.WdBorderType.wdBorderBottom].Color = 
                        Microsoft.Office.Interop.Word.WdColor.wdColorGray05;
                Outlook.AppointmentItem app = inspectors[1].CurrentItem as Outlook.AppointmentItem;
                ((Outlook.ItemEvents_10_Event)app).Close += 
                     new ItemEvents_10_CloseEventHandler(ThisAddIn_Close);
                ((Outlook.ItemEvents_10_Event)app).Send += 
                     new ItemEvents_10_SendEventHandler(ThisAddIn_Send);
            }
        }
        catch (System.Exception ex)
        {
            Outlook.AppointmentItem outlookAppointmentItem = 
                    (Outlook.AppointmentItem)inspectors[2].CurrentItem;
            outlookAppointmentItem.Close(OlInspectorClose.olDiscard);
            outlookAppointmentItem.Delete();
        }
    }
}

Close and Send Event handlers are providing some kind of special behaviors when this item has been sending or closing by the user interaction. I have used many control code when this item has been closed and sending. I have recognized which button user has entered from the algorithms in the Close event because Close event is working in every scenario which user has altered in the user interface.

C#
public void ThisAddIn_Send(ref bool Cancel)
{
    if (!Cancel && IsLiveMeeting((inspectors[1].CurrentItem as 
         Outlook.AppointmentItem).RequiredAttendees, 
         (inspectors[1].CurrentItem as Outlook.AppointmentItem).Location))
    {

        WarningLiveMeeting wlm = new WarningLiveMeeting();
        wlm.StartPosition = FormStartPosition.CenterScreen;

        if (wlm.ShowDialog() == DialogResult.OK)
        {
            if (wlm._sellection)
            {
                Cancel = true;
                return;
            }
        }
    }

    (((inspectors[1].WordEditor as Microsoft.Office.Interop.Word.DocumentClass)
      ).Content as Outlook.MailItem).BodyFormat = OlBodyFormat.olFormatUnspecified;
}

Reports and Functionality

We can get periodical statistics as a report in some way. Also we can take some reports from Exchange Server. I will show you some personal reports taking by this scenario. The GetMonthlyReport function is getting the default MAPI folder to identifying how many meeting user has released how much time he spent in last month.

C#
public List<Outlook.AppointmentItem> GetMonthlyReport()
{

    counter = 0;
    Outlook.MAPIFolder mpiFolder = 
       Application.GetNamespace("MAPI").GetDefaultFolder(
       OlDefaultFolders.olFolderCalendar);

    var appItems = new List<Outlook.AppointmentItem>();

           

    foreach (object obj in mpiFolder.Items)
    {
        counter++;
        AppointmentItem appointment = obj as AppointmentItem;

        if (appointment != null)
        {
            if (appointment.Start.Month == DateTime.Now.Month -1)
            {
                if (appointment.RequiredAttendees == null || 
                    appointment.RequiredAttendees.Equals(string.Empty))
                {
                    _meetingCountOwner++;
                }

                if (appointment.MeetingStatus == OlMeetingStatus.olMeeting ||
                    appointment.MeetingStatus == OlMeetingStatus.olMeetingReceived ||
                    appointment.RequiredAttendees == null ||
                    appointment.RequiredAttendees.Equals(string.Empty))
                {
                    _meetingCount++;
                    _totalMeetingTime += appointment.End - appointment.Start;
                }

                if (appointment.Subject.Contains("Live Meeting") ||
                    appointment.Subject.Contains("LiveMeeting") ||
                    appointment.Subject.Contains("livemeeting") ||
                    appointment.Subject.Contains("live meeting"))
                      _livmeetingCount++;
            }
        }
    }
    return appItems;
}

This case is also looking for his live meetings and accepted meetings. Also we can use this routine in other folders too checking their periodical background. For example, getting featured Appointments, Tasks and Mails like below.

C#
public List<Outlook.AppointmentItem> GetFeaturedAppointments()
{
    Outlook.MAPIFolder mpiFolder = 
      Application.GetNamespace("MAPI").GetDefaultFolder(OlDefaultFolders.olFolderCalendar);

    var appItems = new List<Outlook.AppointmentItem>();

    foreach (object obj in mpiFolder.Items)
    {
        AppointmentItem appointment = obj as AppointmentItem;

        if (appointment != null)
        {
            if (appointment.Start > DateTime.Now - new TimeSpan(0, 30, 0))
                appItems.Add(appointment);
        }
    }
    return appItems;
}

public List<Outlook.TaskItem> GetFeaturedTasks()
{
    Outlook.MAPIFolder mpiFolder = 
       Application.GetNamespace("MAPI").GetDefaultFolder(
       OlDefaultFolders.olFolderTasks);

    var taskItems = new List<Outlook.TaskItem>();

    foreach (object obj in mpiFolder.Items)
    {
        TaskItem task = obj as TaskItem; 
        if (task != null)
        {
            taskItems.Add(task);
        }
    }
    return taskItems;
}

public List<Outlook.MailItem> GetFeaturedMails()
{

    Outlook.MAPIFolder mpiFolder = 
      Application.GetNamespace("MAPI").GetDefaultFolder(
      OlDefaultFolders.olFolderSentMail);

    var mailItems = new List<Outlook.MailItem>();

    foreach (object obj in mpiFolder.Items)
    {
        MailItem mail = obj as MailItem;
        if (mail != null)
        {
            mailItems.Add(mail);
        }
    }
    return mailItems;
}

Version Detection

The Detection of the Op. System is out from this article’s target but I want to show you how you can detect this AddIn’s version and how we can write an AddIn according other Op. Systems and according other versions of the office. I will show Op. System detection routine before as below.

C#
private string FindVersion()
{
    System.OperatingSystem osInfo = System.Environment.OSVersion;
    string operatingSystem = "Unknown";

    switch (osInfo.Platform)
    {
        case System.PlatformID.Win32Windows:
            // Current OS is Windows - can be Windows95, 98 or ME
            switch (osInfo.Version.Minor)
            {
                case 0:
                    operatingSystem = "Windows 95";
                    break;
                case 10:
                    operatingSystem = "Windows 98";
                    break;
                case 90:
                    operatingSystem = "Windows Me";
                    break;
            }
            break;

         case System.PlatformID.Win32NT:
            // Current OS is Windows NT, 2000 or XP
            switch (osInfo.Version.Major)
            {
                case 3:
                    operatingSystem = "Windows NT 3.51";
                    break;
                case 4:
                    operatingSystem = "Windows NT 4.0";
                    break;
                case 5:
                    if (osInfo.Version.Minor == 0)
                        operatingSystem = "Windows 2000";
                    else
                        operatingSystem = "XP";
                    break;
                case 6:
                    operatingSystem = "Win7";
                    break;
            }
            break;
    }
    return operatingSystem;
}

When we have got the system knowledge then we can write any opportunities according it’s properties. Anyway, the real important point here is the Version detection which I have prepared like below.

C#
string version = ((Microsoft.Office.Interop.Outlook.ApplicationClass)(
  ((Microsoft.Office.Interop.Outlook.InspectorClass)(_inspector)).Application)).Version;

int preVer = Convert.ToInt32(version.Substring(0, 2));

While preVer indicates 12 than office version is 2007 and when preVer indicates 14 than office version is 2007.

I was teach from this work Microsoft office 2007 Sp1 has a hot fix for office 2007 object model’s Close and Save events supporting. Even office 2010 does not have this opportunity yet.

Views

Views are providing customized screen and action management in outlook. User can make settings from tool menu but I want to prepare this feature by programmatically in C#.

C#
private void CreateCustomAksiyonViewIfNotExist()
{
    Application.ActiveExplorer().CurrentFolder.CustomViewsOnly = true;
    Outlook.View lastView = Application.ActiveExplorer().CurrentFolder.CurrentView;
    Outlook.View newView = null;

    try
    {
        bool isthere = false;
        Application.ActiveExplorer().NavigationPane.CurrentModule = 
             Application.ActiveExplorer().NavigationPane.Modules[4];
        foreach (Outlook.View view in Application.ActiveExplorer().CurrentFolder.Views)
        {
            if (view.Name.Equals("Actions"))
                isthere = true;
        }

        if (!isthere)
        {
            newView = Application.ActiveExplorer().CurrentFolder.Views.Add("Actions",
            Outlook.OlViewType.olTableView,
            Outlook.OlViewSaveOption.olViewSaveOptionThisFolderEveryone);
            newView.Filter = "\"urn:schemas:httpmail:subject\" LIKE '% Actions %'";
            newView.Save();
            newView.Apply();
        }
    }

    catch (System.ArgumentException ex)
    { 
        MessageBox.Show(ex.Message);
        return;
    }

    Application.ActiveExplorer().NavigationPane.CurrentModule = 
                Application.ActiveExplorer().NavigationPane.Modules[1];
}

Rules

Rules look likes Views as a user customization but the Rules are relying on just actions and special contents when actions are releasing.

C#
void CreateActionRule()
{
    Rules ruless = this.Application.Session.DefaultStore.GetRules();

    for (int k = 1; k < ruless.Count; k++)
    {
        if (ruless[k].Name.Equals("ActionAndDecissionRule"))
            return;
    }

    Outlook.MAPIFolder inbox = this.Application.Session.GetDefaultFolder(
            Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderInbox);
    inbox.Folders.Add("Aksiyon&Kararlar", 
       Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderInbox);
    Outlook.MAPIFolder targetfolder = inbox.Folders["Aksiyon&Kararlar"];
    Rules rules = this.Application.Session.DefaultStore.GetRules();
    Outlook.Rule rule = rules.Create("ActionAndDecissionRule",
    Microsoft.Office.Interop.Outlook.OlRuleType.olRuleReceive);
    Outlook.TextRuleCondition sub = rule.Conditions.Body;
    sub.Enabled = true;
    sub.Text = new string[] { "ToplantisiKararlari-iyitoplantiKontrol" };
    Outlook.MoveOrCopyRuleAction movecopy = rule.Actions.MoveToFolder;
    movecopy.Enabled = true; 
    movecopy.Folder = targetfolder; 
    rule.Execute(true, inbox, false,
    Outlook.OlRuleExecuteOption.olRuleExecuteUnreadMessages);
    rules.Save(false);
}

Conclusion

In conclusion, I have researched many documents and I have not found enough information on this subject and there is no way to get a free book in this field. I am Suring this information will be useful when someone wants to write an AddIn.

Annexes

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
Turkey Turkey
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.
This is a Organisation (No members)


Comments and Discussions

 
QuestionHow to handle the mailitem save event? Pin
amit_832-Jan-14 5:45
professionalamit_832-Jan-14 5:45 
AnswerRe: How to handle the mailitem save event? Pin
hamityildirim10-Dec-14 1:46
hamityildirim10-Dec-14 1:46 
GeneralMy vote of 3 Pin
YuriKu9-Sep-10 20:43
YuriKu9-Sep-10 20:43 
GeneralRe: My vote of 3 Pin
hamityildirim8-Feb-11 10:48
hamityildirim8-Feb-11 10:48 
GeneralTruested Publisher for Silent Installment Pin
hamityildirim21-Aug-10 14:38
hamityildirim21-Aug-10 14:38 
GeneralCreate Outlook Add-Ins that run under 2003/2007/2010 Pin
C Is Sharp10-Aug-10 19:34
C Is Sharp10-Aug-10 19:34 
GeneralRe: Create Outlook Add-Ins that run under 2003/2007/2010 Pin
hamityildirim11-Aug-10 5:12
hamityildirim11-Aug-10 5:12 
GeneralMy vote of 2 Pin
pagal12314-Jul-10 1:14
pagal12314-Jul-10 1:14 
GeneralRe: My vote of 2 Pin
AORD23-Aug-10 12:13
AORD23-Aug-10 12:13 
GeneralFormat suggestion Pin
Emilio Garavaglia11-Jul-10 23:50
Emilio Garavaglia11-Jul-10 23:50 
GeneralPretty good stuff but you need to fix the formation issues first Pin
Md. Marufuzzaman11-Jul-10 18:31
professionalMd. Marufuzzaman11-Jul-10 18:31 
GeneralFormating Pin
Not Active11-Jul-10 16:57
mentorNot Active11-Jul-10 16:57 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.