2

我正在编写一个使用Jacob 库(桥接 COM 和 Java)与 Microsoft Outlook 交互的 Java 程序。这个程序创建了一个新的MailItem,向用户显示它的Inspector窗口。我希望订阅检查员的Close 事件,以了解用户何时完成对其邮件项目的编辑。

要订阅该活动,我按照Jacob 文档中的说明进行操作(大约在页面下方23处):

当前的 [event] 模型在概念上类似于 Visual BasicWithEvents 构造。基本上,我提供了一个名为的类 com.jacob.com.DispatchEvents,它有一个构造函数,它接受一个源对象(类型 com.jacob.com.Dispatch)和一个目标对象(任何类型)。查询源对象的 IConnectionPointContainer接口,我尝试 IConnectionPoint为其默认源接口(我从 获取 IProvideClassInfo)获取一个。同时,我还创建了默认源接口的 DISPID 到实际方法名称的映射。jmethodID 然后,我使用方法名称从目标 Java 对象 获取句柄。当前所有事件方法都必须具有相同的签名:一个参数是一个 Java 变量数组,以及一个 void 返回类型。

这是我的InspectorEventHandler课程,符合 Jacob 的文档:

public class InspectorEventHandler {

    public void Activate(Variant[] arguments) {

    }

    public void BeforeMaximize(Variant[] arguments) {

    }

    public void BeforeMinimize(Variant[] arguments) {

    }

    public void BeforeMove(Variant[] arguments) {

    }

    public void BeforeSize(Variant[] arguments) {

    }

    public void Close(Variant[] arguments) {
        System.out.println("Closing");
    }

    public void Deactivate(Variant[] arguments) {

    }

    public void PageChange(Variant[] arguments) {

    }

}

以下是我使用此类订阅事件的方式InspectorEventHandler

Object outlook = new ActiveXComponent("Outlook.Application");
Object mailItem = Dispatch.call(outlook, "CreateItem", 0).getDispatch();
Object inspector = Dispatch.get(mailItem, "GetInspector").getDispatch();

InspectorEventHandler eventHandler = new InspectorEventHandler();

// This supposedly registers eventHandler with the inspector
new DispatchEvents((Dispatch) inspector, eventHandler);

但是,最后一行失败,但出现以下异常:

线程“主”com.jacob.com.ComFailException 中的异常:找不到事件 iid
    在 com.jacob.com.DispatchEvents.init(本机方法)
    在 com.jacob.com.DispatchEvents.(DispatchEvents.java)
    在 cake.CakeApplication.run(CakeApplication.java:30)
    在 cake.CakeApplication.main(CakeApplication.java:15)
无法获得 IProvideClassInfo

据谷歌称,其他一些人也收到了这个错误。不幸的是,他们都没有收到答复。

我正在使用 Jacob 库的 1.7 版,它声称可以防止这个问题:

1.7 版还包括直接从 progid 读取类型库的代码。这使得处理所有 Microsoft Office 应用程序事件以及 IE5 事件成为可能。有关示例,请参见 samples/test/IETest.java 示例。

我注意到上述IETest.java文件订阅了这样的事件:

new DispatchEvents((Dispatch) ieo, ieE,"InternetExplorer.Application.1");

因此,我尝试以类似的方式订阅我的活动:

new DispatchEvents((Dispatch) inspector, eventHandler, "Outlook.Application");
new DispatchEvents((Dispatch) inspector, eventHandler, "Outlook.Application.1");
new DispatchEvents((Dispatch) inspector, eventHandler, "Outlook.Application.12");

所有这些尝试都因相同的错误而失败。

4

3 回答 3

2

经过一些实验,我确定我可以通过订阅MailItem'Close事件而不是Inspector'Close事件来达到预期的结果。我现在有一个MailItemEventHandler处理所有MailItem事件的类:

public class MailItemEventHandler {

    public void AttachmentAdd(Variant[] arguments) {
        System.out.println("AttachmentAdd");
    }

    public void AttachmentRead(Variant[] arguments) {
        System.out.println("AttachmentRead");
    }

    public void AttachmentRemove(Variant[] arguments) {
        System.out.println("AttachmentRemove");
    }

    public void BeforeAttachmentAdd(Variant[] arguments) {
        System.out.println("BeforeAttachmentAdd");
    }

    public void BeforeAttachmentPreview(Variant[] arguments) {
        System.out.println("BeforeAttachmentPreview");
    }

    public void BeforeAttachmentRead(Variant[] arguments) {
        System.out.println("BeforeAttachmentRead");
    }

    public void BeforeAttachmentSave(Variant[] arguments) {
        System.out.println("BeforeAttachmentSave");
    }

    public void BeforeAttachmentWriteToTempFile(Variant[] arguments) {
        System.out.println("BeforeAttachmentWriteToTempFile");
    }

    public void BeforeAutoSave(Variant[] arguments) {
        System.out.println("BeforeAutoSave");
    }

    public void BeforeCheckNames(Variant[] arguments) {
        System.out.println("BeforeCheckNames");
    }

    public void BeforeDelete(Variant[] arguments) {
        System.out.println("BeforeDelete");
    }

    public void Close(Variant[] arguments) {
        System.out.println("Close");
    }

    public void CustomAction(Variant[] arguments) {
        System.out.println("CustomAction");
    }

    public void CustomPropertyChange(Variant[] arguments) {
        System.out.println("CustomPropertyChange");
    }

    public void Forward(Variant[] arguments) {
        System.out.println("Forward");
    }

    public void Open(Variant[] arguments) {
        System.out.println("Open");
    }

    public void PropertyChange(Variant[] arguments) {
        System.out.println("PropertyChange");
    }

    public void Read(Variant[] arguments) {
        System.out.println("Read");
    }

    public void Reply(Variant[] arguments) {
        System.out.println("Reply");
    }

    public void ReplyAll(Variant[] arguments) {
        System.out.println("ReplyAll");
    }

    public void Send(Variant[] arguments) {
        System.out.println("Send");
    }

    public void Unload(Variant[] arguments) {
        System.out.println("Unload");
    }

    public void Write(Variant[] arguments) {
        System.out.println("Write");
    }

}

我使用以下方式订阅事件:

Object outlook = new ActiveXComponent("Outlook.Application");
Object mailItem = Dispatch.call(outlook, "CreateItem", 0).getDispatch();

MailItemEventHandler eventHandler = new MailItemEventHandler();
new DispatchEvents((Dispatch) mailItem, eventHandler);

对COM了解不多,但是好像Inspector对象注册有问题……

于 2010-06-16T13:05:25.933 回答
1

自从你努力做好你的工作后,Jacob 可能已经改变了。今天,使用 Jacob 1.15-M3,我设法从 Excel 接收事件,但仅使用 4 个参数构造函数:

DispatchEvents de = new DispatchEvents(
  sh,
  new Sink(), 
  "Excel.Sheet",
  "C:\\Program Files (x86)\\Microsoft Office\\OFFICE11\\EXCEL.EXE"
);

提供可执行文件的路径是非常不可移植的,但我想有可能以某种方式解决它。我只是在做测试,所以硬编码的可执行文件对我来说没问题。

使用更少的参数,我收到了与您相同的错误:

Exception in thread "main" com.jacob.com.ComFailException: Can't find event iid
(...)
GetEventIID: couldn't get IProvideClassInfo
于 2012-10-13T08:49:41.807 回答
0

我想附加到 Word 实例的 Close 事件,如果没有将正确的 Dispatch 对象放在 DispatchEvents 的参数列表中,则会出现类似的错误,但现在这适用于我的情况。

ActiveXComponent oWord = new ActiveXComponent("Word.Application");
oWord.setProperty("Visible", new Variant(true));
Dispatch oDocuments = oWord.getProperty("Documents").toDispatch();
Dispatch oDocument = Dispatch.call(oDocuments, "Open", strInputDoc).toDispatch();
WordEventHandler w = new WordEventHandler();
new DispatchEvents(oDocument, w);

import com.jacob.com.*;

public class WordEventHandler {
    public void Close(Variant[] arguments) {
        System.out.println("closed word document");
    }
}
于 2012-09-08T16:21:47.440 回答