2

Inside of a Java process, is possible to do the following:

  • Invoke Microsoft Word to open a document
  • Sleep the Java process until the user finishes editing the document
  • When the user "closes" the document in Microsoft Word, restore the Java process and continue executing

I can open Microsoft Word from Java, using the Desktop or Process class, but i am not able to wait until Microsoft Words closes. My Java process always continues processing when Microsoft Word is started.

Is it possible to do this without any COM library?

Attempts that i have done:

1) Invoke winword.exe directly

Process p = Runtime.getRuntime().exec("C:\\Program Files (x86)\\Microsoft Office\\Office14\\WINWORD.EXE \""+FILEPATH+"\"");
    p.waitFor();    

But if i open another Word document while i am editing the opened document, then winword.exe does not close, so, Java Process does not continue executing and keep waiting. In addition, i must know where is Microsoft Word installed - it is bad idea -

2) Invoke rundll32 and fileprotocolhandler

Process p = Runtime.getRuntime().exec("rundll32 url.dll,FileProtocolHandler "+FILEPATH);
    p.waitFor();
    File file = new File(FILEPATH);
    while(true){
        try{
            FileChannel channel = new RandomAccessFile(file, "rw").getChannel();
            FileLock lock = channel.lock();
            break;
        }catch(Exception e){
            Thread.sleep(3*1000);
        }
    }

When opened, i try to lock the file. If i can lock the file i suppose Microsoft Word is closed. The problem is sometimes this code locks the file before Microsoft Word is opened, p.waitFor() does not work properly.

3) Create a visual basic .exe that opens Word document and when it is closed, then the .exe finish

Process p = Runtime.getRuntime().exec("C:/openWordAndWaitClose.exe "+FILEPATH);
    p.waitFor();

This works fine, but... i do not like it very much because there are several technologies for the purpose. In future updates, i do not know if it will work well.

Raiko1982
  • 21
  • 4
  • 1
    [`Process.waitFor()`](http://docs.oracle.com/javase/8/docs/api/java/lang/Process.html#waitFor--) maybe? – Seelenvirtuose Oct 28 '16 at 12:48
  • 1
    Hi and welcome to the site! Thanks for clearly stating what you're trying to do but could you edit your question to show some examples of what you have tried and what went wrong/right while trying it? Also, see http://stackoverflow.com/help/how-to-ask for some more tips on how to improve upon your question. A better question gets better and more answers so it is in everyone's interest to make questions and answers as good as possible :). – Buurman Oct 28 '16 at 12:52
  • 1
    Try to check if document file is lockable. [http://stackoverflow.com/a/5078121/3710490](http://stackoverflow.com/a/5078121/3710490) – Valijon Oct 28 '16 at 12:55
  • Thanks all, i will improve my question as son as i can. Thanks! very interesting the file lock, i will try. Thanks! – Raiko1982 Oct 30 '16 at 11:07

3 Answers3

3

You can use Process.waitFor() method

With process correspondind of the process who launch Microsoft Word

L. Carbonne
  • 471
  • 5
  • 10
  • This does not work, because when Microsoft Word is opened then Process.waitFor() is unlocked. It does not wait until Microsoft Word is closed(). Thanks! – Raiko1982 Oct 30 '16 at 11:03
  • It's a bad news, Microsoft Word probably create another process during his running. Another way is to create a VBA macro which is executed on close of microsoft word. This macro could communicate with your Java program and signal the closing. This should work but this is more long to set in place... Good luck – L. Carbonne Oct 30 '16 at 22:01
2

As others (L. Carbonne and Seelenvirtuose) have mentioned, you could use the Process.waitFor() method. Here is a working example that will invoke Word and wait for to exit before printing "Done".

public static void main(String[] args) throws IOException, InterruptedException {
    String cmd = "c:\\Program Files (x86)\\Microsoft Office\\Office15\\WINWORD.exe C:\\a.docx";
    Process p = Runtime.getRuntime().exec(cmd);
    p.waitFor();
    System.out.println("Done");
}
Justin L
  • 375
  • 2
  • 10
  • As i said to L. Carbonne, this does not work because when Microsoft Word is opened, then is printed "Done". I need to print "Done" when Microsoft Word is closed. Thanks for helping! – Raiko1982 Oct 30 '16 at 11:05
  • It seems to be happy on my end but you have a different configuration. You could always try and change the `cmd` string in my example to "cmd /c start /wait c:\a.docx" – Justin L Nov 01 '16 at 13:14
1

For word specifically, you can use the /w flag (https://support.microsoft.com/en-us/office/command-line-switches-for-microsoft-office-products-079164cd-4ef5-4178-b235-441737deb3a6#Category=Word) to stop word from merging the new process, but for that, you will likely need the path to the word executable. You can execute a PowerShell process that invokes AssocQueryString to get the path as described here: https://stackoverflow.com/a/68985904/4489577, or another method if your users might have another file association.

This method works if the user had a word document open before you executed the process because any new word documents will merge with that original process and not your process.

The downside (and the case you mention explicitly) is if the user opens up another word document themselves while your process is running. If yours is the only word process running, it'll merge with your process meaning they'll have to close both word documents before the p.waitFor() returns. I found by adding the /x parameter in addition to the /w that's no longer the case and that process won't be merged with. I haven't tested many other parameters.

import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;

/**
 *
 * @author Dean
 */
public class ProcessTest {

    public static void main(String args[]) throws IOException, InterruptedException {
        ArrayList<String> commands = new ArrayList<>();
        commands.add("cmd.exe");
        commands.add("/c");
        commands.add("C:\\Program Files (x86)\\Microsoft Office\\root\\Office16\\WINWORD.EXE");
        commands.add("Test.docx");
        commands.add("/w");
        commands.add("/x");
        ProcessBuilder builder = new ProcessBuilder(commands);
        Process p = builder.start();
        System.out.println(p.pid());
        boolean terminated = p.waitFor(3, TimeUnit.SECONDS);
        System.out.println("Terminated " + terminated);
        System.out.println(p.isAlive());
        Thread.sleep(15000);
    }
}
Dean Wookey
  • 181
  • 2
  • 4