赵翔鹏的Blog Xiangpeng's Thinkpad

8九/082

用VSTO 2008写一个Outlook 2007插件

VSTO是微软的Office开发框架,基于.Net。跟以前的VBA宏相比,功能更强,优点很多,而且可以在Visual Studio里面用。我用VSTO做了一个Outlook插件(Addin),模拟了Gmail的“存档”按钮。

为什么做这个?

我喜欢Gmail的“存档(Archive)”按钮,它的功能很简单,就是把选中的邮件(一般是已经看过的邮件)移动到一个叫“Archive”的文件夹里。这样做的好处是可以保持收件箱(Inbox)里的邮件比较少(留下的都是要用的),看起来比较干净,而且载入的速度也快(以前我的Outlook收件箱里有5000封信,每次打开都很慢)。

虽然Outlook也很强大,虽然我也可以建一个“Archive”文件夹,把看过的email用鼠标拖拽过去,但这其实很麻烦,稍不留神就丢到错误的文件夹里了。所以我就花了些时间做了这个小程序。

实现

1. 首先在VS 2008里建一个Outlook 2007 Addin工程,在ThisAddIn类中加了几个成员变量:

        private Office.CommandBar archiveToolBar;
        private Office.CommandBarButton archiveEmailButton;
        private Outlook.Explorers selectExplorers;
        private Outlook.MAPIFolder inBox;
        private const string ARCHIVE_FOLDER_NAME = "Archived emails";

2. 加一个Toolbar,放一个"Archive"按钮进去。

        private void ThisAddIn_Startup(object sender, System.EventArgs e)
        {
            // Get inbox reference
            inBox = this.Application.ActiveExplorer().Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
            // Add toolbar
            selectExplorers = this.Application.Explorers;
            selectExplorers.NewExplorer += new Outlook
                .ExplorersEvents_NewExplorerEventHandler(newExplorer_Event);
            AddToolbar();
        }
        private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
        {
        }
        private void newExplorer_Event(Outlook.Explorer new_Explorer)
        {
            ((Outlook._Explorer)new_Explorer).Activate();
            archiveToolBar = null;
            AddToolbar();
        }
        private void AddToolbar()
        {
            if (archiveToolBar == null)
            {
                Office.CommandBars cmdBars =
                    this.Application.ActiveExplorer().CommandBars;
                archiveToolBar = cmdBars.Add("Archive Email",
                    Office.MsoBarPosition.msoBarTop, false, true);
            }
            try
            {
                Office.CommandBarButton button_1 =
                    (Office.CommandBarButton)archiveToolBar.Controls
                    .Add(1, missing, missing, missing, missing);
                button_1.Style = Office
                    .MsoButtonStyle.msoButtonCaption;
                button_1.Caption = "Arch&ive";
                button_1.Tag = "Archive selected email";
                if (this.archiveEmailButton == null)
                {
                    this.archiveEmailButton = button_1;
                    archiveEmailButton.Click += new Office.
                        _CommandBarButtonEvents_ClickEventHandler
                        (ArchiveButtonClick);
                }
                archiveToolBar.Visible = true;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

3. 响应Button click事件,代码如下:

        private void ArchiveButtonClick(Office.CommandBarButton ctrl, ref bool cancel)
        {
            // Make sure we are at "inBox"
            Outlook.Explorer activeExplorer = this.Application.Explorers.Application.ActiveExplorer();
            if (activeExplorer.CurrentFolder.FullFolderPath != inBox.FullFolderPath)
            {
                MessageBox.Show("Please do archive operation in " + inBox.Name);
                return;
            }
            // Get "archive" folder
            Outlook.MAPIFolder archiveFolder = null;
            try
            {
                archiveFolder = inBox.Folders[ARCHIVE_FOLDER_NAME]; // ARCHIVE_FOLDER_NAME is a const string I defined.
            }
            catch (Exception ex)
            {
                inBox.Folders.Add(ARCHIVE_FOLDER_NAME, missing);  // Create a new folder if not exist.
                archiveFolder = inBox.Folders[ARCHIVE_FOLDER_NAME];
            }
            // move selected items to "archive" folder
            Outlook.Explorer activeExplorer = this.Application.Explorers.Application.ActiveExplorer();
            foreach (object selectedItem in activeExplorer.Selection)
            {
                try
                {
                    Outlook.MailItem moveMail = selectedItem as Outlook.MailItem;
                    if (moveMail != null) // TODO: && movemail is in "inBox"
                    {
                        //string titleSubject = (string)moveMail.Subject;
                        //if (titleSubject.IndexOf("Test") > 0)
                        moveMail.Move(archiveFolder);
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
        }

在自己的机器上编译运行这个小程序后,Outlook就会自动加入这个插件,以后每次启动Outlook都会运行。不过,要想做个安装包在别人机器上运行,可就麻烦了。这里有个“简单”部署教程 Update: VSTO 2008里,部署超级简单!

部署

VSTO 2008新增了ClickOnce功能。 只要右键点项目,选“publish”就可以生成安装文件,超级简单!这篇文章里有几个截图。

总结

VSTO挺好用,什么时候给IE写插件也能用.Net就好了。MS Office在不断进步,Open Office,WPS Office貌似永远都赶不上啊……

资料

VSTO for Mere Mortals,讲VSTO的一本入门书,适合入门,不过不详细。

MSDN里有好多how to小例子,值得看看。