Java, Jacob and Microsoft Outlook events: Receivin

2019-05-28 00:42发布

I am writing a Java program that interacts with Microsoft Outlook using the Jacob library (bridges COM and Java). This program creates a new MailItem, displaying its Inspector window to the user. I wish to subscribe to the inspector's Close event to know when the user is finished editing their mail item.

To subscribe to the event, I followed the instructions in Jacob's documentation (about 23 down the page):

The current [event] model is conceptually similar to the Visual Basic WithEvents construct. Basically, I provide a class called com.jacob.com.DispatchEvents which has a constructor that takes a source object (of type com.jacob.com.Dispatch) and a target object (of any type). The source object is queried for its IConnectionPointContainer interface and I attempt to obtain an IConnectionPoint for its default source interface (which I obtain from IProvideClassInfo). At the same time, I also create a mapping of DISPID's for the default source interface to the actual method names. I then use the method names to get jmethodID handles from the target Java object. All event methods currently must have the same signature: one argument which is a Java array of Variants, and a void return type.

Here is my InspectorEventHandler class, conforming to Jacob's documentation:

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) {

    }

}

And here is how I subscribe to the events using this InspectorEventHandler class:

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);

However, the last line fails with the following exception:

Exception in thread "main" com.jacob.com.ComFailException: Can't find event iid
    at com.jacob.com.DispatchEvents.init(Native Method)
    at com.jacob.com.DispatchEvents.(DispatchEvents.java)
    at cake.CakeApplication.run(CakeApplication.java:30)
    at cake.CakeApplication.main(CakeApplication.java:15)
couldn't get IProvideClassInfo

According to Google, a few others have also received this error. Unfortunately, none of them have received an answer.

I am using version 1.7 of the Jacob library, which claims to prevent this problem:

Version 1.7 also includes code to read the type library directly from the progid. This makes it possible to work with all the Microsoft Office application events, as well as IE5 events. For an example see the samples/test/IETest.java example.

I noticed that the aforementioned IETest.java file subscribes to events like this:

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

Therefore, I tried subscribing to my events in a similar manner:

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

All these attempts failed with the same error.

3条回答
爷、活的狠高调
2楼-- · 2019-05-28 01:17

I wanted to attach to the Close event of an Word instance and got similar error if didn't put the right Dispatch object in the parameter list of DispatchEvents, but this works in my case, now.

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);

and

import com.jacob.com.*;

public class WordEventHandler {
    public void Close(Variant[] arguments) {
        System.out.println("closed word document");
    }
}
查看更多
手持菜刀,她持情操
3楼-- · 2019-05-28 01:25

After some experimentation, I determined that I could achieve the desired result by subscribing to the MailItem's Close event rather than the Inspector's Close event. I now have a MailItemEventHandler class that handles all MailItem events:

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");
    }

}

I subscribe to the events using:

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

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

I don't know much about COM, but it appears that there is something wrong with the Inspector object registration...

查看更多
贼婆χ
4楼-- · 2019-05-28 01:28

Jacob may have changed since you were trying to do your job. Today, with Jacob 1.15-M3, I managed to receive events from Excel, but only using 4 argument constructor:

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

Giving the path to the executable is quite unportable, but I guess it's possible to workaround it somehow. I was only doing tests, so hardcoded executable was ok for me.

With fewer arguments I was receiving the same errors as you:

Exception in thread "main" com.jacob.com.ComFailException: Can't find event iid
(...)
GetEventIID: couldn't get IProvideClassInfo
查看更多
登录 后发表回答