使用C#進行Outlook 2003程式設計的簡介

iteye_20683發表於2009-12-17

出處:5DMail.Net收集整理 作者:請作者聯絡 時間:2007-3-12 12:35:31

摘要: 本文介紹了 Microsoft Outlook 2003 物件模型介,並探討了如何使用 C# 程式語言生成 Outlook 識別的應用程式和 Outlook 外接程式。

作為物件模型的 Outlook 2003

在將應用程式的功能公開給外部程式方面,Microsoft 有很長的歷史。例如,如果專案需要拼寫檢查功能,您可以利用從 Microsoft_ Word 公開的物件模型。以同樣的方式,如果正在生成的應用程式需要 Microsoft_ Outlook_ 2003 提供的功能,則可以利用關聯的物件模型。簡單地說,Outlook 2003 物件模型允許您與下列各項互動:

· 電子郵件項。

· Outlook 聯絡人資料庫。

· Outlook 日曆。

· Outlook 註釋和任務。

· Outlook 本身的UI(資源管理器、檢查器、命令欄等)。

這顯然是所包含功能的子集,但我肯定您有了大概的瞭解:可以通過關聯的物件模型來訪問 Outlook 2003 的功能。

Outlook 主互操作程式集 (PIA)

到目前為止,Outlook 的功能是通過一個基於 COM 的程式內伺服器 (msoutl.olb) 來公開的。。NET 開發人員希望與這些 COM 型別互動,因此,您需要通過互操作層來這樣做。Microsoft Corporation 已經提供了一個 Outlook 2003 附帶的"正式的"互操作程式集(即主互操作程式集)。

該程式集已經強命名,並駐留在名稱 Microsoft.Office.Interop.Outlook.dll 下面的全域性程式集快取中。要從 Microsoft_ Visual Studio_ .NET 2003 引用該程式集,請從"Add References"對話方塊訪問"COM"選項卡,並選擇"Microsoft Outlook 11.0 Object Library"(圖 1)。

圖 1. 引用 Outlook PIA

如果利用 Outlook PIA 的以前版本(或多個版本)生成自定義應用程式,一定要閱讀 http://go.microsoft.com/fwlink/?LinkId=30833,該文討論了某些可能的版本衝突。


有關互操作程式集的簡介

任何互操作程式集的最終目標都是要提供外觀與體驗與原始 COM 型別相似的 .NET 型別。互操作層(結合執行庫生成的代理,該代理的術語名稱是"執行庫可呼叫包裝",即 RCW)處理各種關於封送處理資料型別的詳細資訊。例如,如果介面方法定義為接受一個基於 COM 的 BSTR 引數,則 .NET 開發人員可以自由傳遞基於 CLR 的 System.String.

對於每個 COM 類,互操作程式集包含總是帶有"–Class"字尾的具體型別,以及名稱相同的託管等價項。例如,以下 COM IDL 定義:

coclass MyComObject
{
// Assume this interface defines three methods named
// One(), Two(), Three().
[default] interface IMyComObject;
// Assume this interface defines two methods named
// Four(), Five().
interface ISomeOtherInterface;
}

結果是兩個名為 MyComObject 和 MyComObjectClass 的 .NET 類型別。MyComObject 型別只公開 [default] 介面的成員。希望訪問其他介面的功能時,需要執行顯式轉換(這將在後臺觸發對 IUnknown::QueryInterface() 的呼叫):

// Create a new MyComObject.
MyComObject c = new MyComObject();
c.One();
// To call Four() or Five(), we need to obtain the
// ISomeOtherInterface explicity.
ISomeOtherInterface itfOther = (ISomeOtherInterface)c;
itfOther.Five();

另一方面,如果利用 MyComObjectClass 型別,您就能夠使用單個物件引用來訪問每個介面中的每個成員:

// Create a new MyComObjectClass.
MyComObjectClass c = new MyComObjectClass();
c.One();
c.Five();

實際上,帶 –Class 字尾的型別是原始 COM 型別的所有介面方法的聯合。假定 Outlook 2003 coclass 最初旨在僅支援單個 [default] COM 介面,則通常可以忽略以 –Class 為字尾的型別,並利用名稱相同的 .NET 代理。

如果希望更深入討論 COM 到 .NET 的轉換過程,訪問 http://blogs.msdn.com/eric_carter/archive/2004/05/06/127698.aspx 將很有幫助。

關於從託管語言與 COM 型別的互動,最後一點與 CLR 垃圾收集器的角色有關。。NET 記憶體管理模型在本質上是不確定的,因為我們作為開發人員不會準確知道物件將在什麼時候被銷燬,而只知道它最終會被銷燬。另一方面,COM 記憶體模型在本質上具有很麻煩的確定性,因為我們被迫使用各種 IUnknown::AddRef() 和 IUnknown::Release() 呼叫來手動調整對 COM 型別的物件內部引用計數(儘管 Visual Basic_ 6.0 試圖隱藏這一點)。

針對互操作程式集中的型別進行程式設計時,將像任何 CLR 引用型別一樣對代理型別進行垃圾收集。一旦代理已經被垃圾收集,RCW 將把所有需要的 IUnknown::Release() 呼叫轉發給關聯的 COM 物件,並在這時銷燬代理。使用該技術,可以確信只要代理在記憶體中是活動的,則關聯的 COM 物件在記憶體中也是活動的。

如果希望確保 COM 型別以更及時和更可預言的方式被銷燬,則可以利用 System.Runtime.InteropServices.Marshal 型別。該類定義了一個靜態方法,名為 ReleaseComObject()。只是傳遞物件引用,關聯的 COM 型別將被當場銷燬:

using System.Runtime.InteropServices;
class MyClass
{
public void SomeMethod()
{
MyComObjectClass c = new MyComObjectClass();
...
// Explicitly destroy COM type after use.
Marshal.ReleaseComObject(c);
}
}

雖然銷燬 COM 型別的想法聽起來可能很吸引人,但必須知道在 AppDomain 中的其他 CLR 物件現在無法使用基本 COM 型別。有了這種(危險的)可能性,本文中的示例程式碼將避免使用 Marshal.ReleaseComObject()。

在即將釋出的 .NET 平臺(Microsoft_ Visual Studio.NET_ 2005,即 Whidbey)的版本中,這個問題已經得到解決。有關進一步的詳細資訊,請參閱 http://blogs.msdn.com/yvesdolc/archive/2004/04/17/115379.aspx.

Outlook 2003 物件模型

一旦引用了 Outlook PIA,下一個任務就是調查 Microsoft.Office.Interop.Outlook 名稱空間中的很多型別(圖 2)。

圖 2. Microsoft.Office.Interop.Outlook 名稱空間

不管型別的大小是多少,好訊息是物件模型本身組織得非常好,並利用了常見設計模式。因此,一旦瞭解如何遍歷聯絡人列表,則遍歷收件箱項就會很簡單。

其他的好訊息是,整個物件模型在幫助檔案 (vbaol11.chm) 中有完整的介紹,預設情況下該幫助檔案位於 :/Program Files/Microsoft Office/OFFICE11/1033 下(圖 3)。

圖 3. Outlook 2003 文件

現在,壞訊息(取決於您的視點)是幫助系統使用 VBScript 程式碼示例和成員原型。假定本文沒有試圖詳細介紹 Outlook 2003 物件模型中的每個型別,請您參考該幫助系統來獲得完整的資訊。下面,讓我們來研究某些核心類型別。


Application 型別

第一個要知道的型別被適當地稱為"Application",它是層次結構中其他所有物件的根。一旦獲得該型別的物件,就能以程式設計方式控制 Outlook 本身的所有方面。表 1 列出了某些需要注意的(但決不是所有)成員。

表 1.選擇 Application 型別的成員

Application 型別的成員
基本含義

ActiveExplorer()

ActiveInspector()

這些方法分別從當前 Outlook 例項檢索 Explorer / Inspector 型別。本文隨後描述資源管理器/檢查器模型。

CreateItem()
允許通過程式設計建立新的 Outlook 項。

GetNamespace()
提供對資料儲存項的訪問。到 Outlook 2003 為止,MAPI 是唯一可以使用的名稱空間,它用於訪問 Outlook 資料夾組(收件箱、註釋等)。

Quit()
終止當前 Outlook 會話。

COMAddIns
該屬性允許您在執行時發現插入到當前 Outlook 例項中的外接程式集合。

Explorers

Inspectors

這些屬性允許獲得強型別的 Explorers/Inspectors 集合。

獲得 Application 型別的確切方式將根據所開發軟體的種類而有略微的不同。如果要生成一個合併 Outlook 2003 的自定義應用程式,則要做的所有事情是使用 C# new 關鍵字建立該型別:

// Create an Outlook Application object.
Application outLookApp = new Application();

另一方面,生成 Outlook 2003 外接程式時(本文隨後介紹),將通過名為 OnConnection() 的方法傳遞 Application 例項:

public void OnConnection(object application,
Extensibility.ext_ConnectMode connectMode,
object addInInst, ref System.Array custom)
{
// Assume 'applicationObject' is a member variable of
// type Microsoft.Office.Interop.Outlook.Application.
applicationObject = (Microsoft.Office.Interop.Outlook.Application)
application;
}

除了各種屬性和方法以外,Application 型別還定義了在各種環境中觸發的很多事件(StartUp、Quit、ItemSend、NewMailEx)。請考慮以下程式碼片段:

public class MyApp
{
public static void Main()
{
// Create an Outlook Application object.
Application outLookApp = new Application();
// Rig up the NewMailEx event.
outLookApp.NewMailEx += new
ApplicationEvents_11_NewMailExEventHandler(outLookApp_NewMailEx);
...
}
private static void outLookApp_NewMailEx(string EntryIDCollection)
{
// Do something interesting when a new e-mail arrives.
}
}

再次,在給定互操作層的角色後,處理基於 COM 的事件的過程看起來與處理 CLR 事件的過程相同。暫時不要理會細節,只需注意 NewMailEx 事件與一個具體的委託(ApplicationEvents_11_NewMailExEventHandler) 一起工作,這個委託可以呼叫任何接受 System.String 作為其唯一引數,並且不返回任何內容的方法。


Outlook"Item"類型別

一旦有了 Application 型別,就能建立新的 Outlook"項".通過 Microsoft.Office.Interop.Outlook.OlItemType 列舉可以列出可能的項:

public enum OlItemType
{
olAppointmentItem = 1;
olContactItem = 2;
olDistributionListItem = 7;
olJournalItem = 4;
olMailItem = 0;
olNoteItem = 5;
olPostItem = 6;
olTaskItem = 3;
}

假設您希望通過程式設計來建立新的 Outlook Task 項。要這樣做,請指定 OlItemType.olTaskItem 作為 Application.CreateItem() 的引數:

public static void Main()
{
// Create an Outlook Application object.
Application outLookApp = new Application();
// Create a new TaskItem.
TaskItem newTask =
(TaskItem)outLookApp.CreateItem(OlItemType.olTaskItem);
// Configure the task at hand and save it.
newTask.Body = "Don't forget to send DOM the links...";
newTask.DueDate = DateTime.Now;
newTask.Importance = OlImportance.olImportanceHigh;
newTask.Subject = "Get DOM to stop bugging me.";
newTask.Save();
}

注意,CreateItem() 的返回值是一般的 OlItemType;因此需要顯式地將結果轉換為正確的型別(在這裡是 TaskItem)。這時,只需要使用型別的公共介面來配置項。一旦執行,將能夠在 Outlook 任務檢查器中查詢任務(圖 4)。

圖 4. 通過程式設計生成的任務

儘管 OlItemType 列舉的名稱很簡單,但表 2 詳細列出了 OlItemType 列舉的成員與 Application.CreateItem() 產生的返回型別之間的關係。

表 2.OlItemType enum/Outlook 類型別關係

OlItemType 列舉值
所產生的型別
基本含義

olAppointmentItem
AppointmentItem
表示單個約會。

olContactItem
ContactItem
表示單個聯絡人。

olDistributionListItem
DistributionListItem
表示一個通訊組列表。

olJournalItem
JournalItem
表示單個日記項。

olMailItem
MailItem
表示單個電子郵件項。

olNoteItem
NoteItem
表示單個註釋。

olPostItem
PostItem
表示其他人可能瀏覽的公用資料夾中的公告。

olTaskItem
TaskItem
表示單個任務。

獲得現有 Outlook 項

除了建立新項以外,Outlook 2003 模型還允許獲得(並且可能修改)現有項。不管對列舉哪個 Outlook 項感興趣,基本過程都是:

* 從 Application.GetNamespace() 獲得 NameSpace 型別。

* 從 NameSpace.GetDefaultFolder() 獲得 MAPIFolder 型別。

* 使用 MAPIFolder.Items 索引器列舉子項。

指定字串"MAPI"作為 GetNamespace() 的引數時,將收到一個 NameSpace 型別,該型別表示具體的 Outlook 資料儲存的抽象級別(目前,"MAPI"是唯一有效的名稱空間)。MAPIFolder 型別可以表示給定使用者的郵件儲存中的任何資料夾(已刪除項、收件箱、日記項等)。資料夾選項的完整範圍由 OlDefaultFolders 列舉來表示:

public enum OlDefaultFolders
{
olFolderCalendar = 9;
olFolderConflicts = 19;
olFolderContacts = 10;
olFolderDeletedItems = 3;
olFolderDrafts = 16;
olFolderInbox = 6;
olFolderJournal = 11;
olFolderJunk = 23;
olFolderLocalFailures = 21;
olFolderNotes = 12;
olFolderOutbox = 4;
olFolderSentMail = 5;
olFolderServerFailures = 22;
olFolderSyncIssues = 20;
olFolderTasks = 13;
olPublicFoldersAllPublicFolders = 18;
}

要請求具體的資料夾,請將 OlDefaultFolders 列舉中的值指定為 NameSpace.GetDefaultFolder() 的引數。請考慮以下程式碼,這些程式碼列舉了當前使用者的任務集合:

static void Main(string[] args)
{
// Create an Outlook Application object.
Application outLookApp = new Application();
// Print all tasks.
NameSpace outlookNS = outLookApp.GetNamespace("MAPI");
MAPIFolder theTasks =
outlookNS.GetDefaultFolder(OlDefaultFolders.olFolderTasks);
foreach(TaskItem task in theTasks.Items)
{
Console.WriteLine("-> Time Created: {0}", task.CreationTime);
Console.WriteLine("-> Body: {0}", task.Body);
}
}

Inspectors 和 Explorers

Outlook 物件模型不僅使您能夠訪問各種項,還定義了用來對使用者介面進行操作的型別。Explorer 型別表示用於顯示資料夾內容的視窗。另一方面,Inspectors 表示開啟後可檢視的單個項。Application 類維護一個由所有 Explorers 和 Inspectors 組成的集合,通過使用適當命名的 Explorers / Inspectors 屬性可以獲得這些型別:

Application app = new Application();
Explorers theExplorers = app.Explorers;
foreach(Explorer e in theExplorers)
{
// Do something with each Explorer...
}

Application 類的 GetActiveExplorer() 和 GetActiveInspector() 方法可以用來獲得當前活動的 UI 元素:

Application app = new Application();
Explorer activeExp = app.ActiveExplorer();
Console.WriteLine("Explorer caption: {0}", activeExp.Caption);

當您生成自定義的 Outlook 外接程式時,Explorers 和 Inspectors 是很有用的,因為它們讓您能夠將 UI 小部件附加到現有的 CommandBars 集合中。本文稍後將進一步介紹這方面的情況。

生成 Outlook 識別的應用程式

要重點操作 Outlook 的物件模型(而不是生成奇特的使用者介面),第一個示例將利用簡單的命令列使用者介面。如果希望跟著做,請建立一個新的 C# 控制檯應用程式,並命名為 OPine.Unix 使用者可能知道,"Pine"是一個很流行的命令列電子郵件實用工具的名稱。OPine 將模仿 Pine 的功能子集。具體來說,OPine 將響應以下命令:

* dib:顯示收件箱項

* snm:傳送新郵件項

* cn:建立新註釋

* dn:顯示現有註釋

* q:退出 OPine

通過響應 NewMailEx 事件,OPine 還能在新郵件到達時通知使用者。

注OPine 將利用 ApplicationClass 型別(而不是 Application)來解決一個在隨後引用 System.Windows.Forms.dll 程式集時引入的名稱衝突。也可以使用如下所示的 C# 別名解決名稱衝突:

using OutLookApp = Microsoft.Office.Interop.Outlook.Application;

但在這種情況下,使用 –Class 型別將不會損害 OPine 示例。


處理"dib"命令

假定已經引用了 Outlook 2003 PIA,下一步是建立一個幫助器類 (OPineHelper),用該類定義一組執行批量處理的靜態方法。首先,我們有一個名為 DisplayInbox() 的方法,該方法接受 ApplicationClass 型別作為其唯一引數。DisplayInbox() 的實現將獲得當前的 MAPI 名稱空間,以便檢索收件箱資料夾中的每個 MailItem.在這裡,我們將使用 MailItem 型別的各種屬性,將接收時間、發件人名稱和主題列印到控制檯:

public static void DisplayInbox(ApplicationClass o)
{
// Get items in my inbox.
NameSpace outlookNS = o.GetNamespace("MAPI");
MAPIFolder inboxFolder
= outlookNS.GetDefaultFolder(OlDefaultFolders.olFolderInbox);
// Print out some basic info.
Console.WriteLine("You have {0} e-mails.",
inboxFolder.Items.Count);
Console.WriteLine();
foreach(object obj in inboxFolder.Items)
{
MailItem item = obj as MailItem;
if(item != null)
{
Console.WriteLine("-> Received: {0}",
item.ReceivedTime.ToString());
Console.WriteLine("-> Sender: {0}", item.SenderName);
Console.WriteLine("-> Subject: {0}", item.Subject);
Console.WriteLine();
}
}
}

注意,我們將通過 Items 屬性所獲得的項當作一般 System.Objects,而不是所期望的 MailItem 型別。此外還要注意,我們執行了一個動態檢查,以確定當前項是否可以被視為 MailItem(通過 C# 的 as 關鍵字),以及如果這樣我們將與型別的各種屬性互動。我們執行該動態檢查的理由是 Outlook 收件箱的確可以包含超過 MailItem 型別的項(例如,滿足請求)。如果將 foreach 邏輯設定為:

foreach(MailItem item in inboxFolder.Items)
{
...
}

那麼,如果遇到 MailItem 以外的任何內容,就可以收到執行庫異常。

在任何情況下,除了 ReceivedTime、SenderName 和 Subject 屬性,MailItem 型別還能夠訪問附件和重要性級別,以及內容的 HTML 表現形式(通過 HTMLBody 屬性)。有關這方面的完整細節,請參閱 Outlook 2003 文件。

處理"snm"命令

OPineHelper 的下一個靜態方法是 SendNewMail(),該方法負責代表使用者建立和傳送新的電子郵件。和前面看到的一樣,我們將通過 ApplicationClass.CreateItem() 建立新的 MailItem 型別。閱讀到這裡,以下程式碼應當很容易理解:

public static void SendNewMail(ApplicationClass o)
{
// Create a new MailItem.
MailItem myMail =
(MailItem)o.CreateItem(OlItemType.olMailItem);
// Now gather input from user.
Console.Write("Receiver Name: ");
myMail.Recipients.Add(Console.ReadLine());
Console.Write("Subject: ");
myMail.Subject = Console.ReadLine();
Console.Write("Message Body: ");
myMail.Body = Console.ReadLine();
// Send it!
myMail.Send();
}

建立 (cn) 和顯示 (dn) 註釋

假如我們實際需要做的只是重複用來建立新電子郵件和遍歷現有電子郵件項的過程,那麼隨後兩個靜態方法是很簡單的。在以下程式碼中,請注意由 OlItemType 和 OlDefaultFolders 列舉所指定值:

public static void CreateNote(ApplicationClass o)
{
// Get access to notes.
NoteItem myNote =
(NoteItem)o.CreateItem(OlItemType.olNoteItem);
Console.Write("Enter your note: ");
myNote.Body = Console.ReadLine();
// Now save the note.
myNote.Save();
}
public static void DisplayNotes(ApplicationClass o)
{
// Get items in my inbox.
NameSpace outlookNS = o.GetNamespace("MAPI");
MAPIFolder notesFolder
= outlookNS.GetDefaultFolder(OlDefaultFolders.olFolderNotes);
// Print out some basic info.
Console.WriteLine("You have {0} notes.",
notesFolder.Items.Count);
Console.WriteLine();
foreach(NoteItem item in notesFolder.Items)
{
Console.WriteLine("-> Time Created: {0}", item.CreationTime);
Console.WriteLine("-> Body: {0}", item.Body);
Console.WriteLine();
}
}

最後接觸

這裡關心的最後的靜態方法只是向終端使用者顯示一組選項:

public static void DisplayOPineOptions()
{
Console.WriteLine("***** Welcome To OPine *****");
Console.WriteLine("dib : Display Inbox");
Console.WriteLine("snm : Send New Mail");
Console.WriteLine("cn : Create Note");
Console.WriteLine("dn : Display Notes");
Console.WriteLine("q : Quit");
Console.WriteLine("****************************");
}

這將包裝 OPine 幫助器類的建立過程;現在可以使用它。


實現 Main() 方法

到這裡,我們準備實現 Main() 方法,該方法負責執行以下任務:

* 建立 ApplicationClass 型別的例項

* 通過 Console.ReadLine() 獲得使用者的命令選項

* 接受使用者提供的字串,並執行合適的方法 OPineHelper

給出這些要點後,下面是一個可能的實現:

static void Main(string[] args)
{
// String to hold the user request.
string userOption;
// Create an Outlook application object.
ApplicationClass outLookApp = new ApplicationClass();
// Display info.
OPineHelper.DisplayOPineOptions();
do
{
Console.Write("/nPlease enter your command: ");
userOption = Console.ReadLine();
switch(userOption)
{
// Display Inbox (dib)
case "dib":
OPineHelper.DisplayInbox(outLookApp);
break;
// Create Note (cn)
case "cn":
OPineHelper.CreateNote(outLookApp);
break;
// Send New Mail (snm)
case "snm":
OPineHelper.SendNewMail(outLookApp);
break;
// Display Notes (dn)
case "dn":
OPineHelper.DisplayNotes(outLookApp);
break;
// Quit (q)
case "q":
userOption = "q";
break;
default: // Anything else? Just display options.
OPineHelper.DisplayOPineOptions();
break;
}
}while(userOption != "q");
}

處理 NewMailEx 事件

我們將新增到 OPine 中的最後一項功能是處理傳入新電子郵件的能力。首先,在分配 ApplicationClass 型別之後處理 NewMailEx 事件:

// Create an Outlook application object.
ApplicationClass outLookApp = new ApplicationClass();
// Rig up the new message event.
outLookApp.NewMailEx += new
ApplicationEvents_11_NewMailExEventHandler(outLookApp_NewMailEx);

ApplicationEvents_11_NewMailExEventHandler 委託的目標需要一個型別為 System.String 的引數。該字串的值表示新的 MailItem 本身的 ID(可以通過 NameSpace.GetItemFromID() 方法來獲得 MailItem)。

在後面的事件處理程式中,注意我們使用 System.Windows.Forms.MessageBox 型別來通知使用者有新的郵件,所以一定要新增對 System.Windows.Forms.dll 的引用(並使用指令集更新您的檔案):

private static void outLookApp_NewMailEx(string EntryIDCollection)
{
if(DialogResult.Yes ==
MessageBox.Show("Do you want to see your message?",
"You've got mail!", MessageBoxButtons.YesNo))
{
// Get the incoming MailItem based on ID.
ApplicationClass o = new ApplicationClass();
NameSpace outlookNS = o.GetNamespace("MAPI");
MAPIFolder mFolder =
o.Session.GetDefaultFolder(OlDefaultFolders.olFolderInbox);
MailItem newMail = (MailItem)
outlookNS.GetItemFromID(EntryIDCollection, mFolder.StoreID);
// Now print out.
Console.WriteLine("/n/n***** New Message *****");
Console.WriteLine("-> Sender: {0}", newMail.SenderName);
Console.WriteLine("-> Subject: {0}", newMail.Subject);
Console.WriteLine("-> Body: {0}", newMail.Body);
Console.WriteLine("***********************/n/n");
}
}

這就是最後的步驟。現在我們可以執行編譯,並對 OPine 進行測試(圖 5)。

圖 5. 執行中的 Opine

我敢肯定,您可以找到很多方式來擴充套件和改進 OPine,包括從基於控制檯的 UI 移動到圖形 UI(通過 Windows 窗體)。儘管我顯然知道你們很少生成命令列電子郵件程式,但我希望該示例已經闡明瞭通過自定義應用程式與 Outlook 互動的過程。


與 Outlook 安全更新的衝突

執行 OPine 時,您肯定知道由 Outlook 啟動的以下對話方塊(圖 6)

圖 6. Outlook 2003 安全警告

儘管這會干擾終端使用者,但該行為是設計造成的。在 Outlook 2003 下面,(選擇物件的)選擇成員被認為是可能有安全風險的。因而,系統會提示使用者輸入許可權才能繼續操作,防止電子郵件蠕蟲和病毒使用物件模型幹壞事。

如果希望閱讀關於哪些 Outlook 型別和成員導致該安全提示的文件,請參閱文章 What's New in Microsoft Office Outlook 2003 for Developers?

假如終端使用者總是可以通過對安全提示作出"No"的響應來拒絕對 Outlook 的訪問,您就能夠在自定義應用程式中通過程式設計使用 Outlook 時自由地使用 try/catch 邏輯。例如,為了避免發生執行庫故障,應當對 OPineHelper.DisplayNotes()(以及其餘方法)進行如下更改:

public static void DisplayNotes(ApplicationClass o)
{
// Same as before...
try
{
foreach(NoteItem item in notesFolder.Items)
{
// Same as before...
}
}
catch{Console.WriteLine("Can't access Outlook");}
}

注 值得注意的是,生成 Outlook 外接程式時,OnConnection() 方法的傳入 Microsoft.Office.Interop.Outlook.Application 引數被假設為可信任的,在大多數 情況下,這將阻止安全警報的出現。

使用 Visual Studio .NET 2003 建立 Outlook 外接程式

下一個示例研究如何使用自定義功能來擴充套件 Outlook 2003.應用程式可擴充套件性的整個想法是 Microsoft 產品的另一個基石。基本上,諸如Outlook、Word 或 Visual Studio .NET 這樣的應用程式都旨在能夠讓外部廠商或個人通過插入新的物件(假設上述物件實現了正確的介面)來擴充套件上述功能。

雖然大多數時候您肯定只使用 C# 命令列編譯器 (csc.exe) 和 notepad.exe 來生成外接程式,但如果利用 Visual Studio .NET 共享外接程式專案模板,將節省一些鍵入時間。為了清楚地加以說明,我們將建立一個名為 EMailStatsAddIn 的外接程式。該外接程式將插到 Outlook 2003 的現有 UI 中,並提供以下功能:

* 顯示使用者在該天/月接收了多少封郵件。

* 顯示使用者在該天/月傳送了多少封郵件。

首先從 New Project 對話方塊的 Other Projects | Extensibility Projects 資料夾中選擇該模板(圖 7)。

圖 7. 共享的外接程式專案模板

一旦單擊 OK 按鈕,系統將指引您執行一個五步的嚮導,以便配置初始的共享外接程式專案。第一個步驟是選擇要使用的語言(Microsoft_ Visual C#_ 或 Microsoft_ Visual Basic_ .NET C++)和基本框架(。NET 或基於 COM 的 ATL)。對於我們的示例,我們顯然希望 Visual C#.

第二個步驟是選擇外接程式的宿主。假定我們只對 Outlook 2003 感興趣,請取消選中其他所有選項(圖 8)。

圖 8. 選擇所需宿主

步驟三允許您提供當前外接程式的"友好"名稱和說明。這些字串值用於控制外接程式將被宿主外接程式對話方塊如何註冊和顯示。請隨便輸入您認為適合的值。

步驟 4 中顯示的兩個選項用於指定外接程式是否應當在啟動時自動載入到宿主中,以及允許目標機器上的哪些使用者訪問外接程式。對於 EMailStatsAddIn,我們將同時選中這兩個選項(圖 9)。

圖 9. 載入共享外接程式的選項。

步驟五隻用來確認所選項。一旦完成共享外接程式嚮導,就會發現您已經得到一個包含兩個專案的解決方案:

*外接程式本身 (EMailStatsAddIn)

*安裝專案 (EMailStatsAddInSetup)

本文稍後討論安裝專案的角色。

引用的程式集

除了標準的 System.dll、System.Data.dll 和 System.XML.dll 程式集以外,共享外接程式還自動引用了一個名為 Extensibility.dll 的程式集。該程式集包含單個名稱空間 (Extensibility),該名稱空間確切定義了三個型別(參閱表 3)。

表 3.可擴充套件性名稱空間的型別

可擴充套件性名稱空間的型別
基本含義

IDTExtensibiltity2

所有外接程式都必須實現的關鍵介面。

ext_ConnectMode

列舉,表示將宿主連線到給定外接程式的各種方式。

ext_DisconnectMode

列舉,表示可以將給定的外接程式與宿主斷開的各種方式。

需要注意的被引用的其他程式集是 Office.dll.雖然該程式集的確定義很多型別(可以通過 Visual Studio.NET 2003 物件瀏覽器來確認),但最重要的型別必須與用自定義小部件來擴充套件宿主的 GUI 以便與正在開發的外接程式進行互動有關。在這裡,我不會對 Office 物件模型深入討論太多,這方面的內容請參閱 MSDN 網站上的 online reference.

注意,共享外接程式專案模板不會自動引用 Microsoft.Office.Interop.Outlook.dll 程式集,所以一定要現在通過 Add References 對話方塊進行該引用。這樣做時,請新增對 System.Windows.Forms.dll 的引用,在訪問 MessageBox 型別時將需要它。

相關文章