【问题标题】:Attaching an event handler to an Outlook.MailItem that was programmatically created将事件处理程序附加到以编程方式创建的 Outlook.MailItem
【发布时间】:2016-08-01 16:13:20
【问题描述】:

我正在用 VBA 编写一个 Outlook 2010 宏来回复电子邮件,但不会自动发送电子邮件。相反,宏只是显示电子邮件,以便我可以在单击“发送”按钮之前查看其内容。

但是,我希望第一个宏附加另一个宏,当我点击检查器中的“发送”按钮时运行该宏。虽然我能够轻松响应应用程序级发送事件(使用Application_ItemSend(),如this other question 中所述),但我更愿意将第二个宏仅附加到以编程方式生成的回复中,以便它仅适用于电子邮件我使用宏本身创建,而不是所有电子邮件。这可能吗?

更具体地说,我的项目中有一个常规模块可以执行以下操作(简化):

Public Sub replyToEmail()
    Dim responseMail As Outlook.MailItem, originalEmail As Outlook.MailItem
    Dim myHandler as New replyHandler
    Set responseMail = originalEmail.reply
    ' do something and set responseMail.Body intelligently, then
    Set myHandler.reply = responseMail ' <-- WHY DOESN'T THIS PERSIST?
    responseMail.Display ' Show me the email so I can review it
End Sub

我还有一个用于自动回复的类模块,replyHandler,如下所示:

Public WithEvents reply As Outlook.MailItem

Private Sub reply_Send(Cancel As Boolean)
    ' Do additional processing upon Send event
    ' but why doesn't this ever get called, despite "reply" being set in the subroutine above?
End Sub

这是我遇到问题的这个类模块,因为似乎无论我在第一个宏中尝试什么,reply_Send() Sub 都不会被执行。也就是说,我的问题是如何让 Sub 在 replyToEmail() 运行后运行?或者换一种说法,我如何在replyToEmail() 中保留对responseMail 的引用,以便在我单击replyToEmail() 创建的消息的“发送”按钮时实际调用我的类模块的reply_Send() 事件处理程序,并显示?

有没有办法在不附加全局应用程序级 ItemSend 处理程序的情况下做到这一点?

Microsoft Help 提供了一些指导,但它的示例要求在创建响应电子邮件之后和单击检查员的发送按钮之前运行第三个宏。 (上面写着:“示例代码必须放在类模块中,例如ThisOutlookSession,并且必须在Microsoft Outlook 调用事件过程之前调用SendMyMail 过程。”)我宁愿做这一步也自动。但是,同样,我怎样才能在两个Subroutines 中保留对以编程方式创建的 MailItem 的引用?

提前致谢。

编辑澄清解决方案:

这里的问题原来是变量范围。而不是子例程本身中的Dim myHandler as New replyHandler,这应该在模块级别声明为Public myHandler As New replyHandler。然后,稍后执行Set myHandler.reply = responseMail 的行将myHandler.reply 变量正确地持久化到第二个子例程。

【问题讨论】:

  • 您是否正在创建一个沉没类的实例,而不仅仅是使用邮件项目?
  • 如果我正确理解了您的问题,那么我尝试两者都做。我创建了类模块的一个实例,并将其.reply 成员设置为从originalEmail.reply 方法返回的MailItem,并尝试将MailItem 保存在常规模块的公共成员中。两者都不起作用,我不确定为什么。也许Outlook在宏到达End Sub时释放常规模块的对象引用?

标签: vba email outlook


【解决方案1】:

要正确处理所有 Outlook 项目或特定项目的事件,您需要管理 Inspector Wrappers 的集合。基本思想是捕获 Inspectors.NewInspector 事件,如果这是您要捕获的项目(例如,撰写模式下的电子邮件),则创建包装器。每个单独的包装器都有自己的事件容器。请参阅这篇文章以获得很好的解释:

https://msdn.microsoft.com/en-us/library/ff973716.aspx

否则,当您第一次创建回复项目时,您可以获得回复方法返回的新撰写电子邮件的句柄,并开始为该项目处理事件。因此,您可以捕获 MailItem.Send 并在需要时取消它,并且该事件只会在新的回复电子邮件有效时触发。没有其他项目会触发该特定事件。您只需要确保为要为其公开事件的项目声明一个具有公共范围(并使用 WithEvents)的模块级变量。

【讨论】:

  • 感谢对 Inspectors 的引用,但是这种方法仍然依赖于创建全局事件处理程序来“捕获 Inspectors.NewInspector 事件”对吗?这正是我想要避免的。此外,您在“否则”块中完美地描述我要做什么,但实际上您并没有解释如何执行此操作的任何细节。我知道我可以处理新的撰写电子邮件。我的问题是如何保持这个从一个子例程内部生成的句柄,以便它可以用来捕获与其关联的 MailItem.Send 事件。提前致谢。
  • Eric,我已经编辑了我的问题中的代码,试图澄清关于我尝试使用的代码的问题。
  • 我看到了问题:您的replyHandler 类可以工作,但是您正试图将一个对象设置为myHandler.reply;回复字段是私有的,实际上应该引发编译错误(我认为)。将其更改为该类中的公共属性/字段,它应该可以工作。
  • 对不起埃里克,我在复制和粘贴时出错了。 myHandler 成员是公共的。我尝试了一个带有 setter 的私有属性,比如Public Sub setHandledItem(item As Outlook.MailItem) Set reply = item End Sub,然后从第一个 Sub 调用这个处理程序类的 Sub,但这也失败了。所以,不,成员的可见性不是问题(我将更正上面的代码)。这是我首先尝试的,但我的问题仍然存在:如果这 应该 工作(这是我尝试的第一件事),是什么导致它不起作用?
  • 尝试在模块范围内声明myHandler
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-01
  • 2015-01-11
  • 1970-01-01
相关资源
最近更新 更多