错误: 为 Office 事件取消参数将在 Visual Studio.net 2003年中被忽略

文章翻译 文章翻译
文章编号: 830519 - 查看本文应用于的产品
本文已归档。它按“原样”提供,并且不再更新。
展开全部 | 关闭全部

本文内容

概要

当您处理 Microsoft Visual Studio.net 2003年时, 您可能会遇到问题,Microsoft Word,Microsoft Excel 或 Microsoft Outlook 将引发一个 COM 事件中使用该 取消 参数时。虽然代码接收 COM 事件并在代码可以相应地,设置参数,但 COM 不取消事件。当您从托管客户端 (如 Microsoft Visual C# 或 Microsoft Visual Basic.net),使用 COM 互操作,并且您还使用 1.1 版的 Microsoft.net 框架时,会出现此问题。

原因

.NET Framework 1.1 引入了对与 COM 组件进行交互时增强类型安全的安全更改。.NET Framework 1.1 使用组件的类型库中的封送处理信息,从而增强了类型安全。当您从托管客户端自动 Word、 Excel,或 Outlook 时,COM 互操作程序集 (IA) 或 Microsoft Office XP,主 Interop 程序集 (PIA) 将使用存储在 Microsoft Office 类型库来处理事件的类型信息。在 Word 的现有版本为 [输入] 参数键入库、 Excel 类型库中,和 Outlook 类型库标记在 取消 参数。在 取消 参数标记为 [输入] 参数中,以使公共语言运行库强制实施此限制,并防止通过托管代码中被返回给调用方所做的任何更改。因此,从托管的代码 IA (或 PIA),不能取消该事件。

解决方案

Microsoft Office 2003 中,此缺陷已得到纠正。

替代方法

如果您使用早期版本的 Word、 Excel 的早期版本或较早版本的 Outlook,您必须在托管代码中建立您自己的连接点接收器。类型库依赖项和强制实施类型保护通常适用的可以避免自定义处理程序。因此,可以将参数传递到调用方。

Microsoft 提供的编程示例只,用于说明不附带任何明示或暗示保证。这包括,但不限于对适销性或针对特定用途的适用性的暗示的担保。本文假定您熟悉演示了正在使用的编程语言以及用于创建和调试过程的工具。Microsoft 支持工程师可以帮助解释某个特定过程的功能,但他们不会修改这些示例以提供额外的功能或构建过程来满足您的具体要求。

正在生成帮助器类

若要直接接收事件向上从 Visual C#,您必须创建您自己的调度接口定义,您还必须创建帮助器类实现事件代码。全局唯一标识符 (GUID) 和调度标识符 (dispid) 以便由您要接收事件的 Office 对象的事件接收器,调度接口定义必须匹配。若要了解这些值是什么,您可以使用下列方法之一:
  • 您可以使用 Visual Studio.net 2003年专业版中包含 OLE/COM 对象查看器
  • 您可以使用平台 SDK。有关平台 SDK 的其他信息,请访问下面的 Microsoft 网站:

    http://www.microsoft.com/msdownload/platformsdk/sdkupdate
您知道 GUID 和该 dispid 后,您可以构建您自己的调度接口定义在 Visual Basic.net 中或在 Visual C# 中的定义。

本文提供了您向您展示如何使用自定义连接的两个示例指向变通解决此问题。第一个示例演示如何接收 应用程序 对象事件,对于 Word 2000,然后取消 DocumentBeforeClose 事件,以使用户不能关闭该文档。 第二个示例接收器 ItemSend 事件的 Outlook 2002,以便您可以在您的应用程序中取消发送操作。

示例 1: 取消 DocumentBeforeClose 事件

  1. 启动 Visual Studio.net 2003年。启动新项目。选择 Visual C# 项目类型。选择 Windows 应用程序 为模板。命名该项目 MyWordEventTest,然后单击 确定

    默认状态下,创建 Form1。
  2. 项目 菜单上单击 添加引用。在对话框框中选择 Microsoft Word 9.0 对象库 在 COM 选项卡上单击 $ 选择 以添加一个引用,然后单击 确定 以关闭该对话框。

    自动为您生成一个自定义 IA。
  3. 项目 菜单上单击 添加类。选择 代码文件,然后命名类 Word9EventHelper.cs。单击 确定 以生成文件。
  4. 添加以下代码以 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();}
    	}
    }
  5. 切换回 Form1,然后添加一个命令按钮。 双击命令按钮,以使显示 Form1.cs 代码窗口。 或在 视图 菜单上单击 代码 以使显示 Form1.cs 代码窗口。将下面的代码添加到按钮处理程序中,单击 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;
    
  6. 下面的代码添加到按钮处理程序之前 Form1 类:
    Word.Application m_oApp;
    WordAppEvents9.WordAppEventHelper m_oAppEvents;
    
  7. 生成 菜单上单击 生成解决方案 若要使该项目。单击 调试,然后单击 $ 开始 以运行该应用程序。

    将启动该应用程序时您可以单击该命令按钮,则 Word 会显示。您不能关闭 Word 窗口,直到您关闭您的应用程序。

    您可以使用类似的代码用于 Excel 处理事件。

示例 2: 取消 ItemSend 事件

  1. 启动 Visual Studio.net 2003年。启动新项目。选择 Visual C# 项目类型。选择 Windows 应用程序 为模板。命名该项目 MyOutlookEventTest,然后单击 确定

    默认状态下,创建 Form1。
  2. 项目 菜单上单击 添加引用。在对话框框中选择 Microsoft Outlook 10.0 对象库 在 COM 选项卡上单击 $ 选择 以添加一个引用,然后单击 确定 以关闭该对话框。

    自动为您生成一个自定义 IA。
  3. 项目 菜单上单击 添加类。选择 代码文件,然后命名类 Outlook10EventHelper.cs。单击 确定 以生成文件。
  4. 将下面的代码添加到代码窗口中,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. 否则,不能取消该事件。
  5. 切换回 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);
    邮件。
  6. 下面的代码添加到按钮处理程序之前 Form1 类:
    Outlook.Application m_oApp;
    OutlookAppEvents10.OutlookAppEventHelper m_oAppEvents;
    
  7. 生成 菜单上单击 生成解决方案 若要使该项目。单击 调试,然后单击 $ 开始 以运行该应用程序。

    将启动该应用程序时您可以单击该命令按钮,则 Outlook 会显示。 自动创建一个新的电子邮件草稿。输入 收件人 行中的收件人,然后单击 发送。您将获得一个弹出对话框询问您是否要取消 ItemSend 事件。单击 以取消它。

    您可以使用类似的代码用于 Excel 处理事件。

状态

Microsoft 已经确认这是本文"适用于"一节中列出的 Microsoft 产品中的问题。

参考

有关 Office 从 Visual Studio 自动化的其他信息.net,单击下面的文章编号,以查看 Microsoft 知识库中相应的文章:
311452与 Visual Studio.net 开发 Microsoft Office 解决方案
317109office 应用程序不会退出后从 Visual Studio.net 客户端的自动化

属性

文章编号: 830519 - 最后修改: 2014年2月27日 - 修订: 3.5
这篇文章中的信息适用于:
  • Microsoft Excel 2002 标准版
  • Microsoft Word 2002 标准版
  • Microsoft Outlook 2002 标准版
  • Microsoft Excel 2000 标准版
  • Microsoft Word 2000 标准版
  • Microsoft Outlook 2000
  • Microsoft .NET Framework 1.1
  • Microsoft Visual Studio .NET 2003 Professional Edition
  • Microsoft Visual Studio .NET 2003 Enterprise Architect
  • Microsoft Visual Studio .NET 2003 Academic Edition
关键字:?
kbnosurvey kbarchive kbmt kbnofix kbbug KB830519 KbMtzh
机器翻译
注意:这篇文章是由无人工介入的微软自动的机器翻译软件翻译完成。微软很高兴能同时提供给您由人工翻译的和由机器翻译的文章, 以使您能使用您的语言访问所有的知识库文章。然而由机器翻译的文章并不总是完美的。它可能存在词汇,语法或文法的问题,就像是一个外国人在说中文时总是可能犯这样的错误。虽然我们经常升级机器翻译软件以提高翻译质量,但是我们不保证机器翻译的正确度,也不对由于内容的误译或者客户对它的错误使用所引起的任何直接的, 或间接的可能的问题负责。
点击这里察看该文章的英文版: 830519
Microsoft和/或其各供应商对于为任何目的而在本服务器上发布的文件及有关图形所含信息的适用性,不作任何声明。 所有该等文件及有关图形均"依样"提供,而不带任何性质的保证。Microsoft和/或其各供应商特此声明,对所有与该等信息有关的保证和条件不负任何责任,该等保证和条件包括关于适销性、符合特定用途、所有权和非侵权的所有默示保证和条件。在任何情况下,在由于使用或运行本服务器上的信息所引起的或与该等使用或运行有关的诉讼中,Microsoft和/或其各供应商就因丧失使用、数据或利润所导致的任何特别的、间接的、衍生性的损害或任何因使用而丧失所导致的之损害、数据或利润不负任何责任。

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com