Embedding Office in Java
Asked Answered
L

3

10

I'm trying to get Office 2007/2010 application embedded inside a Java application using SWT using the following code:

import java.awt.Canvas;
import javax.swing.JFrame;

import org.eclipse.swt.SWT;
import org.eclipse.swt.awt.SWT_AWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.ole.win32.*;
import org.eclipse.swt.widgets.*;

public class EmbeddingTest extends Canvas {
    private void initOleViewer(String target) {
        Display display = new Display();
        Shell shell = SWT_AWT.new_Shell(display, this);
        shell.setLayout(new FillLayout());

        OleFrame oleFrame = new OleFrame(shell, SWT.NONE);

        OleControlSite oleControlSite = new OleControlSite(oleFrame, SWT.NONE, "Word.Document");
        oleControlSite.doVerb(OLE.OLEIVERB_INPLACEACTIVATE);

        OleAutomation word = new OleAutomation(oleControlSite);

        int[] applicationId = word.getIDsOfNames(new String[]{"Application"});
        Variant property = word.getProperty(applicationId[0]);
        OleAutomation application = property.getAutomation();

        int[] documentId = application.getIDsOfNames(new String[]{"Documents"});            
        property = application.getProperty(documentId[0]);
        OleAutomation documents = property.getAutomation();

        shell.open();
        Variant[] arguments = new Variant[] { new Variant(target) };
        int[] automationIDs = documents.getIDsOfNames(new String[]{"Open", "FileName"});
        documents.invokeNoReply(automationIDs[0], arguments, new int[]{automationIDs[1]});

        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
    }

    public static void main(String[] args) {
        JFrame jFrame = new JFrame("Embedding Test");
        jFrame.setVisible(true);

        EmbeddingTest viewer = new EmbeddingTest();
        jFrame.add(viewer);
        jFrame.setSize(600, 600);

        viewer.initOleViewer(args[0]);
    }
}

When I don't try to call 'Open' on the document object Word embeds successfully inside the application but the whole file menu is disabled. When I call 'Open' the application crashes with the following error (DISP_E_EXCEPTION):

Exception in thread "main" org.eclipse.swt.SWTException: Action can not be performed. result = -2147352567
 at org.eclipse.swt.ole.win32.OLE.error(Unknown Source)
 at org.eclipse.swt.ole.win32.OleAutomation.invokeNoReply(Unknown Source)
 at EmbeddingTest.initOleViewer(EmbeddingTest.java:68)
 at EmbeddingTest.main(EmbeddingTest.java:88)

Does anyone know how to fix this problem or an alternative solution to embed Office apps in Java? Thanks!



Update:

Querying the IDs for 'Open' and 'FileName' separately returns null for 'FileName' so its incorrect. I've also tried without the named parameter without any success:

documents.invokeNoReply(automationIDs[0], arguments);
Lateen answered 19/7, 2010 at 4:59 Comment(2)
Looks like the bounty is going to expire. Sorry I couldn't be of any help.Debus
@Debus Thanks anyway! At least you got three times as many people to have a look at it. :)Lateen
D
1

Why aren't you doing any error handling, result checking, or assertions? Remember that getIDsOfNames(..) will silently fail and return null values for unrecognized names.

Try printing the value ofdocuments.getLastError() after catching the offending exception.

Debus answered 19/7, 2010 at 7:37 Comment(4)
'FileName' seems to be a problem since it returns an ID of 0. But documents.getLastError() just returns null.Lateen
@Luke: The docs say it should be null in case of an error, so the filename ID could still be correct. Perhaps indicating that it's the 0th parameter? Speaking of docs, do you have a link for the Word.Document specification?Debus
Here's the documentation that I've been looking at: msdn.microsoft.com/en-us/library/bb216319(office.12).aspxLateen
I wonder why Format is listed as "Required" there when there are code examples where it isn't used? Anyway, @Luke, are you using absolute or relative paths? It could be as simple as file-not-found or even an unsupported file type or corrupted file.Debus
I
0

You need to use Word.Application, because Word.Document will not let you use automation features, this is my experience at least. When I implemented automation and Ole I did it in 2 steps.

  1. Opened word document in automation mode (Word.Application), didsome automation tasks and closed
  2. Opened word document as Word.Document. Automation tasks did not work, but it was an OLE object. User can edit document, but save options are disabled. You can however add extra menu and do something like Ole.Save. Then captured document can be processed furter.

Here you find example of how to open document in Word.Application. Then according to my experience you should save it and open in OLE as Word.Document. Showing Word.Application can be skipped.

import java.awt.Canvas;
import javax.swing.JFrame;

import org.eclipse.swt.SWT;
import org.eclipse.swt.ole.win32.*;
import org.eclipse.swt.widgets.*;

public class EmbeddingTest extends Canvas {

    private void initOleViewer(String target) {
        Display display = new Display();
        Shell shell = new Shell(display);
        OleFrame oleFrame = new OleFrame(shell, SWT.NONE);
        OleClientSite oleClientSite = new OleClientSite(oleFrame, SWT.NONE, "Word.Application");
        OleAutomation word = new OleAutomation(oleClientSite);



    Variant[] arguments;


    //open the file
    int[] id1 = word.getIDsOfNames(new String[]{"Documents"});
    Variant pVarResult = word.getProperty(id1[0]);
    OleAutomation resultDocuments = pVarResult.getAutomation();

    int[] id2 = resultDocuments.getIDsOfNames(new String[]{"Open"});

    arguments = new Variant[1];
    arguments[0] = new Variant(target);
    Variant invokeResult = resultDocuments.invoke(id2[0], arguments);

    resultDocuments.getIDsOfNames(new String[]{"ActiveDocument"});


     //show the word app, not necessary        
    arguments=new Variant[1];
    arguments[0] = new Variant(true);
    int[] id3 = word.getIDsOfNames(new String[]{"Visible"});
    word.setProperty(id3[0], arguments); 


        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
    }

    public static void main(String[] args) {
        JFrame jFrame = new JFrame("Embedding Test");
        jFrame.setVisible(true);

        EmbeddingTest viewer = new EmbeddingTest();
        jFrame.add(viewer);
        jFrame.setSize(600, 600);

        viewer.initOleViewer("d:\\aaa.doc");
    }
}
Idealist answered 10/6, 2013 at 10:15 Comment(0)
X
0

I have updated the code to use OleClientSite instead of OleControlSite and it works for me.

package com.test.swt;

import java.awt.Canvas;
import java.io.File;

import javax.swing.JFrame;

import org.eclipse.swt.SWT;
import org.eclipse.swt.awt.SWT_AWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.ole.win32.OLE;
import org.eclipse.swt.ole.win32.OleClientSite;
import org.eclipse.swt.ole.win32.OleFrame;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

public class EmbeddingTest extends Canvas {
private static final long serialVersionUID = 1L;

public void initOleViewer(String target) {
    Display display = new Display();
    Shell shell = SWT_AWT.new_Shell(display, this);
    shell.setLayout(new FillLayout());

    OleFrame oleFrame = new OleFrame(shell, SWT.NONE);

    OleClientSite oleControlSite = new OleClientSite(oleFrame, SWT.NONE, "Word.Document", new File(target));
    oleControlSite.doVerb(OLE.OLEIVERB_INPLACEACTIVATE);
    shell.setSize(800, 600);
    shell.open();
    while (!shell.isDisposed()) {
        if (!display.readAndDispatch()) {
            display.sleep();
        }
    }
}

public static void main(String[] args) {
    JFrame jFrame = new JFrame("Embedding Test");
    jFrame.setVisible(true);

    EmbeddingTest viewer = new EmbeddingTest();
    jFrame.add(viewer);
    jFrame.setSize(600, 600);

    viewer.initOleViewer("C:\\Users\\test.docx");
}
}
Xylograph answered 22/2, 2018 at 14:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.