當您使用 Microsoft Visual Studio.NET 2003年時,您可能會遇到問題,當您在 COM 事件所引發的 Microsoft Word、 Microsoft Excel 或 Microsoft Outlook 中使用
Cancel 參數。雖然程式碼會接收 COM 事件,並將程式碼可以據此,設定參數,[COM 不取消事件。當您從 Managed 用戶端 (例如 Microsoft Visual C# 或 Microsoft Visual Basic.NET),使用 COM Interop 並且您也使用 Microsoft.NET Framework 1.1 版時,就會發生這個問題。
.NET Framework 1.1 已引入增強型別安全,與 COM 元件互動時的安全性變更。.NET Framework 1.1 增強型別安全利用元件的型別程式庫中的封送處理資訊。當您從 Managed 用戶端,自動化 Word、 Excel 或 Outlook 時,COM Interop 組件 (IA) 或 Microsoft Office XP,主要 Interop 組件 (PIA) 使用型別資訊,儲存在 Microsoft Office 型別程式庫來處理事件。現有版本的 [Word 鍵入程式庫]、 [Excel 型別程式庫] 及 [Outlook 類型程式庫
Cancel 參數標記為
[中] 參數。
Cancel 參數被標記為
[中] 參數,以便通用語言執行階段強制實施這項限制,並避免任何 Managed 程式碼從傳回給呼叫端所做的變更。因此,無法取消事件從 Managed 程式碼 IA (或 PIA)。
這個 Bug 已經在 Microsoft Office 2003 中獲得修正。
如果您使用 Word、 較早的 Excel 版本或較早版本的 Outlook 的較早版本時,您必須建立您自己的連接點接收在 Managed 程式碼中。自訂處理常式可以避免型別程式庫相依性與通常套用強制執行型別保護。因此,引數可以傳遞給呼叫者。
Microsoft 僅,為了說明提供程式設計範例,不提供任何明示或默示的保證。這包括,但不限於適售性或適合某特定用途之默示擔保責任。本文假設您已熟悉使用我們所示範的程式設計語言以及建立和偵錯程序所使用的工具。Microsoft 技術支援工程師可以協助解釋特定程序的功能,但它們不會修改這些範例以提供附加功能或建構程序,以符合您特定需求。
產生協助程式類別
若要直接接收事件從 Visual C#,您必須建立您自己的分配介面定義,並且您也必須建立實作事件程式碼的協助程式類別。分配介面定義必須符合全域唯一識別項 (GUID) 和分派識別項 (DISPID),為您想要接收事件的 Office 物件所預期的事件接收器。若要找出這些值是,您可以使用下列方法之一:
您知道 GUID 以及 [DISPID 之後您可以建置自己的分配介面定義在 Visual Basic.NET 或在 Visual C# 中定義。
本文提供您告訴您如何使用自訂連線的兩個範例指向解決這個問題。第一個範例示範如何接收 Word 2000 到
應用程式 物件事件,並使使用者不能關閉文件,然後取消
DocumentBeforeClose 事件。 第二個範例接收
ItemSend 事件的 Outlook 2002,讓您可以在您的應用程式中取消傳送作業。
範例 1: [取消] DocumentBeforeClose 事件
- 啟動 Visual Studio.NET 2003年。啟動新的專案。選取 Visual C# 做為專案類型。選取 Windows 應用程式 與範本。為專案的名稱 MyWordEventTest,然後按一下 [確定]。
依照預設值,會建立 Form1。 - 在 [專案] 功能表上按一下 新增參考。在對話方塊中,選取 Microsoft Word 9.0 物件程式庫 [COM] 索引標籤上按一下 [選取] 以加入一個參考,然後按一下 [確定] 關閉對話方塊。
自訂 IA 會自動為您產生。 - 按一下 [專案] 功能表 新增一個類別。選取 程式碼檔,],然後再命名類別 Word9EventHelper.cs。按一下 [確定] 以產生該檔案。
- 加入下列程式碼,以 Word9EventHelper.cs:
using System;
using System.Runtime.InteropServices;
using Word; // The default name for a custom Word IA.
// If you use Office XP and you have the PIAs
// referenced in your project, you must change the previous line to read:
// using Word = Microsoft.Office.Interop.Word;
namespace WordAppEvents9
{
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch),
GuidAttribute("000209FE-0000-0000-C000-000000000046")]
public interface DWordApplicationEvents9
{
[DispId(0x00000001)] void Startup();
[DispId(0x00000002)] void Quit();
[DispId(0x00000003)] void DocumentChange();
[DispId(0x00000004)] void DocumentOpen(Word.Document doc);
[DispId(0x00000006)] void DocumentBeforeClose(Word.Document doc, ref bool Cancel);
[DispId(0x00000007)] void DocumentBeforePrint(Word.Document doc, ref bool Cancel);
[DispId(0x00000008)] void DocumentBeforeSave(Word.Document doc, ref bool SaveAsUI, ref bool Cancel);
[DispId(0x00000009)] void NewDocument(Word.Document doc);
[DispId(0x0000000a)] void WindowActivate(Word.Document doc, Word.Window wn);
[DispId(0x0000000b)] void WindowDeactivate(Word.Document doc, Word.Window wn);
[DispId(0x0000000c)] void WindowSelectionChange(Word.Selection sel);
[DispId(0x0000000d)] void WindowBeforeRightClick(Word.Selection sel, ref bool Cancel);
[DispId(0x0000000e)] void WindowBeforeDoubleClick(Word.Selection sel, ref bool Cancel);
}
public class WordAppEventHelper : DWordApplicationEvents9, IDisposable
{
public WordAppEventHelper()
{
m_oConnectionPoint = null;
m_Cookie = 0;
}
public void Startup()
{System.Diagnostics.Debug.WriteLine("Startup");}
public void Quit()
{System.Diagnostics.Debug.WriteLine("Quit");}
public void DocumentChange()
{System.Diagnostics.Debug.WriteLine("DocumentChange");}
public void DocumentOpen(Word.Document doc)
{System.Diagnostics.Debug.WriteLine("DocumentOpen");}
public void DocumentBeforeClose(Word.Document doc, ref bool Cancel)
{
System.Diagnostics.Debug.WriteLine("DocumentBeforeClose");
Cancel = true; // Cancel the close!
}
public void DocumentBeforePrint(Word.Document doc, ref bool Cancel)
{System.Diagnostics.Debug.WriteLine("DocumentBeforePrint");}
public void DocumentBeforeSave(Word.Document doc, ref bool SaveAsUI, ref bool Cancel)
{System.Diagnostics.Debug.WriteLine("DocumentBeforeSave");}
public void NewDocument(Word.Document doc)
{System.Diagnostics.Debug.WriteLine("NewDocument");}
public void WindowActivate(Word.Document doc, Word.Window wn)
{System.Diagnostics.Debug.WriteLine("WindowActivate");}
public void WindowDeactivate(Word.Document doc, Word.Window wn)
{System.Diagnostics.Debug.WriteLine("WindowDeactivate");}
public void WindowSelectionChange(Word.Selection sel)
{System.Diagnostics.Debug.WriteLine("WindowSelectionChange");}
public void WindowBeforeRightClick(Word.Selection sel, ref bool Cancel)
{System.Diagnostics.Debug.WriteLine("WindowBeforeRightClick");}
public void WindowBeforeDoubleClick(Word.Selection sel, ref bool Cancel)
{System.Diagnostics.Debug.WriteLine("WindowBeforeDoubleClick");}
private UCOMIConnectionPoint m_oConnectionPoint;
private int m_Cookie;
public void SetupConnection(Word.Application app)
{
if (m_Cookie != 0) return;
// GUID of the DIID_ApplicationEvents dispinterface.
Guid guid = new Guid("{000209FE-0000-0000-C000-000000000046}");
// QI for IConnectionPointContainer.
UCOMIConnectionPointContainer oConnPointContainer = (UCOMIConnectionPointContainer)app;
// Find the connection point and then advise.
oConnPointContainer.FindConnectionPoint(ref guid, out m_oConnectionPoint);
m_oConnectionPoint.Advise(this, out m_Cookie);
}
public void RemoveConnection()
{
if (m_Cookie != 0)
{
m_oConnectionPoint.Unadvise(m_Cookie);
m_oConnectionPoint = null;
m_Cookie = 0;
}
}
public void Dispose(){RemoveConnection();}
}
} - 切換回 [Form1],然後再新增指令按鈕。 連按兩下指令按鈕,以使出現 Form1.cs 的程式碼視窗。 或在 [檢視] 功能表上按一下 [程式碼 進行 Form1.cs 的程式碼視窗會出現。按鈕處理常式中下列程式碼加入 Click event:
Word.Document doc;
Object missing = System.Reflection.Missing.Value;
// Create a new instance of Word and then set up the event handler.
m_oApp = new Word.ApplicationClass();
m_oAppEvents = new WordAppEvents9.WordAppEventHelper();
m_oAppEvents.SetupConnection(m_oApp);
// Make Word visible and then display a new document to test close.
m_oApp.Visible = true;
doc = m_oApp.Documents.Add(ref missing, ref missing, ref missing, ref missing);
doc.UserControl = true;
doc.Content.Text = "Try to close the document";
// You only have to do this one time in this sample.
button1.Enabled = false;
- 將下列程式碼加入至 Form1 類別按鈕處理常式之前:
Word.Application m_oApp;
WordAppEvents9.WordAppEventHelper m_oAppEvents;
- 在 [建置] 功能表上按一下 建置方案 使專案。按一下 [偵錯],然後再按一下 [[開始],以執行應用程式。
啟動應用程式時, 您可以按一下指令按鈕,然後再出現 Word。您無法關閉 Word 視窗,直到您關閉您的應用程式。
您可以使用類似的程式碼來處理事件,Excel。
範例 2: [取消] ItemSend 事件
- 啟動 Visual Studio.NET 2003年。啟動新的專案。選取 Visual C# 做為專案類型。選取 Windows 應用程式 與範本。為專案的名稱 MyOutlookEventTest,然後按一下 [確定]。
依照預設值,會建立 Form1。 - 在 [專案] 功能表上按一下 新增參考。在對話方塊中,選取 Microsoft Outlook 10.0 物件程式庫 [COM] 索引標籤上按一下 [選取] 以加入一個參考,然後按一下 [確定] 關閉對話方塊。
自訂 IA 會自動為您產生。 - 按一下 [專案] 功能表 新增一個類別。選取 程式碼檔,],然後再命名類別 Outlook10EventHelper.cs。按一下 [確定] 以產生該檔案。
- 將下列程式碼加入至程式碼視窗 Outlook10EventHelper.cs:
using System;
using System.Runtime.InteropServices;
//using Outlook; // The default name for a custom Word IA.
// If you use Office XP and you have the PIAs
// referenced in your project, you must change the previous line to read:
using Outlook = Microsoft.Office.Interop.Outlook;
using System.Windows.Forms;
namespace OutlookAppEvents10
{
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch),
GuidAttribute("0006300E-0000-0000-C000-000000000046")]
public interface DOutlookApplicationEvents_10
{
void ItemSend(object Item, ref bool Cancel);
void NewMail();
void Reminder(object Item);
void OptionsPagesAdd(Outlook.PropertyPages Pages);
void Startup();
void Quit();
void AdvancedSearchComplete(Outlook.Search SearchObject);
void AdvancedSearchStopped(Outlook.Search SearchObject);
void MAPILogonComplete();
}
public class OutlookAppEventHelper : IDisposable
{
public OutlookAppEventHelper()
{
m_oConnectionPoint = null;
m_Cookie = 0;
}
private UCOMIConnectionPoint m_oConnectionPoint;
private int m_Cookie;
public void SetupConnection(Outlook.Application app)
{
if (m_Cookie != 0) return;
// GUID of the DIID_ApplicationEvents dispinterface.
Guid guid = new Guid("{0006300E-0000-0000-C000-000000000046}");
// QI for IConnectionPointContainer.
UCOMIConnectionPointContainer oConnectionPointContainer = (UCOMIConnectionPointContainer)app;
// Find the connection point and then advise.
oConnectionPointContainer.FindConnectionPoint(ref guid, out m_oConnectionPoint);
m_oConnectionPoint.Advise(this, out m_Cookie);
}
public void RemoveConnection()
{
if (m_Cookie != 0)
{
m_oConnectionPoint.Unadvise(m_Cookie);
m_oConnectionPoint = null;
m_Cookie = 0;
}
}
#region IDisposable Members
public void Dispose()
{
RemoveConnection();
}
#endregion
//#region DOutlookApplicationEvents_10 Members
[DispId(0x0000F002)]
public void ItemSend(object Item, ref bool Cancel)
{
DialogResult result;
result = MessageBox.Show("Do you want to cancel the ItemSend event?","",MessageBoxButtons.YesNo);
if(result == DialogResult.Yes)
{
System.Diagnostics.Debug.WriteLine("Cancelling Message");
Cancel = true;
}
else
{
System.Diagnostics.Debug.WriteLine("Passing Message");
Cancel = false;
}
}
[DispId(0x0000F003)]
public void NewMail()
{
MessageBox.Show("NewMail");
}
[DispId(0x0000F004)]
public void Reminder(object Item)
{
MessageBox.Show("Reminder");
}
[DispId(0x0000F005)]
public void OptionsPagesAdd(Microsoft.Office.Interop.Outlook.PropertyPages Pages)
{
MessageBox.Show("OptionsPagesAdd");
}
[DispId(0x0000F006)]
public void Startup()
{
MessageBox.Show("Startup");
}
[DispId(0x0000F007)]
public void Quit()
{
MessageBox.Show("Quit");
}
[DispId(0x0000FA6A)]
public void AdvancedSearchComplete(Microsoft.Office.Interop.Outlook.Search SearchObject)
{
MessageBox.Show("AdvancedSearchComplete");
}
[DispId(0x0000FA6B)]
public void AdvancedSearchStopped(Microsoft.Office.Interop.Outlook.Search SearchObject)
{
MessageBox.Show("AdvancedSearchStopped");
}
[DispId(0x0000FA90)]
public void MAPILogonComplete()
{
MessageBox.Show("MAPILogonComplete");
}
//#endregion
}
} Note You need to place the [DispId(#)] attribute on the methods. 否則,無法取消事件。 - 切換回 [Form1],然後再新增指令按鈕。 連按兩下指令按鈕,以使出現 Form1.cs 的程式碼視窗。 或在 [檢視] 功能表上按一下 [程式碼 進行 Form1.cs 的程式碼視窗會出現。按一下 event:
Outlook.MailItem item;
if (m_oApp == null)
{
// Create a new instance of Outlook and then set up the event handler.
m_oApp = new Outlook.ApplicationClass();
m_oAppEvents = new OutlookAppEvents10.OutlookAppEventHelper();
m_oAppEvents.SetupConnection(m_oApp);
}
// Make Outlook visible and then display a new message to test send.
item = (Outlook.MailItem)m_oApp.CreateItem(Outlook.OlItemType.olMailItem);
item.Subject = "The Subject!";
item.Body = "Try sending the message.";
item.Display(m_oApp); 訊息。 - 將下列程式碼加入至 Form1 類別按鈕處理常式之前:
Outlook.Application m_oApp;
OutlookAppEvents10.OutlookAppEventHelper m_oAppEvents;
- 在 [建置] 功能表上按一下 建置方案 使專案。按一下 [偵錯],然後再按一下 [[開始],以執行應用程式。
啟動應用程式時, 您可以按一下指令按鈕,然後再 Outlook 會出現。 自動建立新的電子郵件草稿。輸入 到 列中的收件者,然後按一下 [傳送]。就會出現快顯對話方塊,詢問您是否要取消 ItemSend 事件。按一下 [是] 以取消它。
您可以使用類似的程式碼來處理事件,Excel。
Microsoft 已確認這是本文 < 適用於 > 一節中所列的 Microsoft 產品中的問題。
如需詳細資訊,有關自動化 Office 從 Visual Studio.NET,按一下下面的文件編號,檢視 「 Microsoft 知識庫 」 中的發行項:
311452
(http://support.microsoft.com/kb/311452/
)
使用 Visual Studio.NET 開發 Microsoft Office 解決方案
317109
(http://support.microsoft.com/kb/317109/
)
Office 應用程式不會結束之後從 Visual Studio.NET 用戶端的自動化
文章編號: 830519 - 上次校閱: 2006年9月27日 - 版次: 3.5
這篇文章中的資訊適用於:
- Microsoft Excel 2002 Standard Edition
- Microsoft Word 2002 Standard Edition
- Microsoft Outlook 2002 Standard Edition
- Microsoft Excel 2000 Standard Edition
- Microsoft Word 2000 Standard Edition
- Microsoft Outlook 2000
- Microsoft .NET Framework 1.1
- Microsoft Visual Studio .NET 2003 專業版
- Microsoft Visual Studio .NET 2003 Enterprise Architect
- Microsoft Visual Studio .NET 2003 Academic Edition
| kbmt kbnofix kbbug KB830519 KbMtzh |
機器翻譯重要:本文是以 Microsoft 機器翻譯軟體翻譯而成,而非使用人工翻譯而成。Microsoft 同時提供使用者人工翻譯及機器翻譯兩個版本的文章,讓使用者可以依其使用語言使用知識庫中的所有文章。但是,機器翻譯的文章可能不盡完美。這些文章中也可能出現拼字、語意或文法上的錯誤,就像外國人在使用本國語言時可能發生的錯誤。Microsoft 不為內容的翻譯錯誤或客戶對該內容的使用所產生的任何錯誤或損害負責。Microsoft也同時將不斷地就機器翻譯軟體進行更新。
按一下這裡查看此文章的英文版本:
830519
(http://support.microsoft.com/kb/830519/en-us/
)
Microsoft及(或)其供應商不就任何在本伺服器上發表的文字資料及其相關圖表資訊的恰當性作任何承諾。所有文字資料及其相關圖表均以「現狀」供應,不負任何擔保責任。Microsoft及(或)其供應商謹此聲明,不負任何對與此資訊有關之擔保責任,包括關於適售性、適用於某一特定用途、權利或不侵權的明示或默示擔保責任。Microsoft及(或)其供應商無論如何不對因或與使用本伺服器上資訊或與資訊的實行有關而引起的契約、過失或其他侵權行為之訴訟中的特別的、間接的、衍生性的損害或任何因使用而喪失所導致的之損害、資料或利潤負任何責任。