Found what I was looking for but it is a bit long and ONLY demo code so you will need to change it a little/lot. This code has not been run for a long time - so treat it with some caution please - and it was desingned to take a Word document template file and perform a simple mail merge. You can test it bu changing the code in the constructor and have it open a file then print or re-save that file under a different name for a quick test. You will need to provide the full path and file name to the constructor because Word will be opening the file for you and knows nothing about the folder the application may already be in.
First thing to note is that you will be using Java to execute VBA commands. You can use the Macro Recorder feature of Word to discover the syntax of the commands for search and replace which I have just done;
Sub Macro1()
'
' Macro1 Macro
' Macro recorded 22/02/2007 by XXX XXXXXXXX
'
Selection.Find.ClearFormatting
Selection.Find.Replacement.ClearFormatting
With Selection.Find
.Text = "replace"
.Replacement.Text = "test"
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
Selection.Find.Execute
Selection.Find.Execute
End Sub
You will basically be using code to dynamically substitute the words replace and test that I used in the example above.
Well, here is the Java code. There are lots (too many!) of comments and it only opens, prints and then saves a file but I hope it does demonstarte the sort of approach you can use using SWT. Furthermore, it shows that you do not need to use a GUI as the link provided in a previous post suggests.
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.internal.ole.win32.TYPEATTR;
import org.eclipse.swt.ole.win32.OLE;
import org.eclipse.swt.ole.win32.OleAutomation;
import org.eclipse.swt.ole.win32.OleClientSite;
import org.eclipse.swt.ole.win32.OleFrame;
import org.eclipse.swt.ole.win32.OleFunctionDescription;
import org.eclipse.swt.ole.win32.OlePropertyDescription;
import org.eclipse.swt.ole.win32.OleParameterDescription;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.ole.win32.Variant;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.BufferedWriter;
import java.io.IOException;
public class WordDocumentHandler {
private String progID= "Word.Application";
private Shell shell= null;
private OleFrame frame= null;
private OleClientSite wordSite= null;
private OleAutomation wordAutomation = null;
private boolean cleaned = false;
public WordDocumentHandler() {
this.shell = new Shell();
this.frame = new OleFrame(this.shell, SWT.NONE);
this.wordSite= new OleClientSite(this.frame, SWT.NONE, this.progID);
this.wordAutomation = new OleAutomation(this.wordSite);
}
public void openFile(String fileName) throws SWTException,
NullPointerException,
FileNotFoundException {
OleAutomation documentsAutomation= null;
int[] id= null;
Variant[] arguments= null;
Variant invokeResult= null;
try {
// Check the the file name is not null
if(fileName == null) {
throw new NullPointerException("Null value passed to " +
"fileName parameters of the printFile() method.");
}
// Check the the file names ends with '.dot' or '.doc'.
// Remember to include templates and docuemnts
if(!(fileName.endsWith(".doc")) && !(fileName.endsWith(".dot"))) {
throw new IllegalArgumentException(
"The filename must end with the extensions \'.doc\' or \'.dot\'");
}
// Check that the file exists
File fileToPrint = new File(fileName);
if(!(fileToPrint.exists())) {
throw new FileNotFoundException("The file " +
fileName +
"cannot be found.");
}
// From the application, get an automation for the Documents property
documentsAutomation = this.getChildAutomation(this.wordAutomation,
"Documents");
// Get the ID of the Open method
id = documentsAutomation.getIDsOfNames(new String[]{"Open"});
if(id == null) {
throw new SWTException("It was not possible to recover an " +
"identifer for the Open method in WordDocumentHandler.openFile().");
}
// Build an array of parameters - holds just the file name
arguments= new Variant[1];
arguments[0] = new Variant(fileName);
// Invoke the Open method on the Documents property
invokeResult = documentsAutomation.invoke(id[0], arguments);
if(invokeResult == null) {
throw new SWTException("An error occurred whilst invoking the " +
"Open method for the following file: " +
fileName +
" in WordDocumentHandler.closeCurrentFile().");
}
}
finally {
// If the automation was instantiated then dispose of it to
// release resources.
if(documentsAutomation != null) {
documentsAutomation.dispose();
}
}
}
public void saveAs(String fileName) throws NullPointerException,
SWTException,
IllegalArgumentException {
OleAutomation activeDocumentAutomation = null;
int[] id= null;
Variant[] arguments= null;
Variant invokeResult= null;
try {
// If the fileName parameter is passed a null
// value, throw an exception.
if(fileName == null) {
throw new NullPointerException("A null value was passed to " +
"the fileName parameter of WordDocumentHandler.saveAs().");
}
// If the fileName parameter has been passed an empty String
// then again throw an excpetion.
if(fileName.length() == 0) {
throw new NullPointerException("An empty string was passed " +
"to the fileName parameter of WordDocumentHandler.saveAs().");
}
// Finally, make sure the file name ends in either
// .doc or .dot.
if((!fileName.endsWith(".dot")) && (!fileName.endsWith(".doc"))) {
throw new IllegalArgumentException("An illegal file name was " +
"passed to the fileName parameter of " +
"WordDocumentHandler.saveAs(). The file name must " +
"end in \'.dot\' or \'.doc\'.");
}
// If the fileName parameter passes all of the tests, the first
// step is to recover an automation for the ActiveDocument object
activeDocumentAutomation = this.getChildAutomation(
this.wordAutomation, "ActiveDocument");
// If it was possible to recover the automation for the
// ActiveDocument object, get an id for the PrintOut method
id = activeDocumentAutomation.getIDsOfNames(new String[]{"SaveAs"});
// If it was not possible to recover the id of the PrintOut
// method, throw an exception to notify the user and terminate
// processing.
if(id == null) {
throw new SWTException("Unable to obtain an automation for " +
"the SaveAs method in WordDocumentHandler.saveAs().");
}
// Build the array of argumnets that will be passed to the invoke
// method when the PrintOut method is invoked. In this case, this
// array will contain a single member - a String object encapsulating
// the path to and name of the output file.
arguments= new Variant[1];
arguments[0] = new Variant(fileName);
// Invoke the PrintOut method and catch the value returned
invokeResult = activeDocumentAutomation.invoke(id[0], arguments);
// If a null value was returned then the invocation of the
// PrintOut method failed. Throw an exception to notify the
// user and terminate processing.
if(invokeResult == null) {
throw new SWTException("A problem occurred invoking the " +
"SaveAs method in WordDocumentHandler.saveAs().");
}
}
finally {
// If the automation was instantiated, dispose of that object
if(activeDocumentAutomation != null) {
activeDocumentAutomation.dispose();
}
}
}
public void closeCurrentFile() throws SWTException {
OleAutomation activeDocumentAutomation = null;
int[] id= null;
Variant[] arguments= null;
Variant invokeResult= null;
try {
// Recover an automation for the ActiveDocument
activeDocumentAutomation = this.getChildAutomation(
this.wordAutomation, "ActiveDocument");
// If that was successful, recover the id of the Close
// method form this automation
id = activeDocumentAutomation.getIDsOfNames(new String[]{"Close"});
// If it was not possible to recover the id of the Close
// method then throw an exception to notify the user and
// terminate processing.
if(id == null) {
throw new SWTException("It was not possible to recover an " +
"identifier for the Close method in " +
"WordDocumentHandler.closeCurrentFile().");
}
// Invoke the Close method on the ActiveDocument automation
invokeResult = activeDocumentAutomation.invoke(id[0]);
// If the invocation of the Close method failed, throw an
// exception to notify the user and terminate processing.
if(invokeResult == null) {
throw new SWTException(
"An error occurred invoking the Close method in " +
"WordDocumentHandler.closeCurrentFile().");
}
}
finally {
// Dispose of any automation object created whilst this
// method was executing.
if(activeDocumentAutomation != null) {
activeDocumentAutomation.dispose();
}
}
}
public void printCurrentFile() throws SWTException {
OleAutomation activeDocumentAutomation = null;
int[] id= null;
Variant[] arguments= null;
Variant invokeResult= null;
try {
// From the application automation get the automation for the
// ActiveDocument property.
activeDocumentAutomation = this.getChildAutomation(
this.wordAutomation, "ActiveDocument");
// From the ActiveDocument automation, get the id of the
// PrintOut method.
id = activeDocumentAutomation.getIDsOfNames(new String[]{"PrintOut"});
// If it was not possible to recover the id of the PrintOut method
// throw an excpetion to notify the user and terminate processing
if(id == null) {
throw new SWTException("It was not possible to recover an " +
"identifier for the PrintOut method in " +
"WordDocumentHandler.printCurrentFile().");
}
// Invoke the PrintOut method
invokeResult = activeDocumentAutomation.invoke(id[0]);
// If the invocation of the PrintOut method failed, throw an
// exception to notify the user and terminate processing.
if(invokeResult == null) {
throw new SWTException(
"An error occurred invoking the PrintOut method in " +
"WordDocumentHandler.printCurrentFile().");
}
}
finally {
// Free resources by disposing of any automation objects here
if(activeDocumentAutomation != null) {
activeDocumentAutomation.dispose();
}
}
}
/**
Called to insert a piece of text at a bookmark. Bookmarks are named
places within a Word document where it is possible to insert an item
of text. The value passed to the bookmarkName parameter MUST be the
name of a bookmark that exists in the document as no checking is
performed by this method - an exception will be seen if the bookmark
cannot be found.
The method may be called to write a single character, one or more
words placed onto a single line or a number of lines. If the latter
then the lines should be separated from one another using carriage
return characters thus;
<code>
"41 Valmont Road\nBramcote\nNottingham\nNG9 3JB"
</code>
which could encapsulate an address for example.
Unfortunately, Word OLE Automation must be addressed in a slightly
different manner to that of Excel. The VBA command used to perform
the above would be;
<code>
Range range = ActiveDocument.Bookmarks.Item(bookmarkName).Range
range.InsertAfter(textToInsert)
</code>
Using the same technique applied to Excel and automation would be
recovered for ActiveDocument. From this, an automation would be
recovered for the Bookmarks collection and from this would be
recovered an automation for the Item object passing over the
name of the book mark as an element in an array of Variant(s).
Finally, an automation would be recovered from this for the Range.
From the Range automation, the id of the InsertAfter method would
be recovered, an array would be built containing the text that should be
inserted and the InsertAfter method would then be invoked on the
Range automation.
However, this method does not follow that pattern entirely owing to
differences in the way Word and Excel OLE Automation appear to work.
The first two stages are the same - automations are recovered for the
ActiveDocument and Bookmarks properties. Next though the id of the Item
property is recovered and an array of parameters built - the only
element in the array is the name of the bookmark. Next, the invoke
method is called on the Bookmarks automation, the id of the Item method
is passed along with the argumnets. A Variant is returned from this
method call and an automation object is recovered from it. This technique
seems to be required when working to obtain automations for properties
that require parameters.
@param bookmarkName A String encapsulating the name of the bookmark
@param textToInsert A String encapsulating the text to be inserted
after the bookmark.
@throw NullPointerException A NullPointerException will be thrown if
either of the methods parameters is passed
a null value.
@throw SWTException An SWTException will be thrown if any problems are
encountered either obtaining ids or invoking methods.
*/
public void insertAtBookmark(String bookmarkName, String textToInsert)
throws SWTException, NullPointerException{
OleAutomation childAutomation = null;
int[] id = null;
Variant[] arguments= null;
Variant invokeResult = null;
try {
// Ensure that a null value HAS NOT been passed to the
// bookmarkName parameter
if(bookmarkName == null) {
throw new NullPointerException("A null value was passed to " +
"the bookmarkName parameter of " +
"WordDocumentHandler.insertAtBookmark().");
}
// Ensure that a null value HAS NOT been passed to the
// textToInsert parameter
if(textToInsert == null) {
throw new NullPointerException("A null value was passed to " +
"the textToInsert parameter of " +
"WordDocumentHandler.insertAtBookmark().");
}
// Recover from the application automation an automation
// for the ActiveDocument object.
childAutomation = this.getChildAutomation(this.wordAutomation,
"ActiveDocument");
// From the ActiveDocument automation, recover an automation
// for the Bookmarks collection
childAutomation = this.getChildAutomation(childAutomation,
"Bookmarks");
// Try to get the id for the Item property
id = childAutomation.getIDsOfNames(new String[]{"Item"});
// If it was not possible to get the id for the Item property
// then throw an exception
if(id == null) {
throw new SWTException("It was not possible to recover an " +
"identifier for the Item property from the Bookmarks " +
"automation in WordDocumentHandler.insertAtBookmark().");
}
// Build an array to hold the arguments that will be passed
// when invoking the Item method. It will contain a single
// object - a String encapsulating the name of the bookmark
arguments= new Variant[1];
arguments[0] = new Variant(bookmarkName);
// Invoke the Item method
invokeResult = childAutomation.invoke(id[0], arguments);
if(invokeResult == null) {
throw new SWTException("A problem occurred trying to invoke " +
"the Item method in WordDocumentHandler.insertAtBookmark().");
}
// To progress any futher, it is necessary to recover an automation
// object that allows us to directly address the selected bookmark
childAutomation = invokeResult.getAutomation();
// That automation must be tested here and if any erros occurred
// an exception should be thrown
if(childAutomation == null) {
throw new SWTException("A problem occurred trying to recover " +
"an automation from the value returned following the " +
"invocation of the Item method in " +
"WordDocumentHandler.insertAtBookmark().");
}
// To address the bookmark directly, a Range object is required
childAutomation = this.getChildAutomation(childAutomation, "Range");
// From the Range automation, get the id of the InsertAfter
// method.
id = childAutomation.getIDsOfNames(new String[]{"InsertAfter"});
// If a problem occurred whilst recovering the id, throw an exception
if(id == null) {
throw new SWTException("It was not possible to recover the " +
"id for the InsertAfter method in " +
"WordDocumentHandler.insertAtBookmark().");
}
// Build an array of arguments. Again, the array will hold a single
// element - a String object encapsulating the text that will be
// inserted into the document at the bookmarks position
arguments = new Variant[1];
arguments[0] = new Variant(textToInsert);
// Invoke the InsertAfter method and pass the arguments. This method
// does not return a value so the invokeNoReply method is called
// Furthermore, it is not possible to tell whether the insertion
// was successful - oh dear!!
childAutomation.invokeNoReply(id[0], arguments);
}
finally {
// Dispose of any automation to release resources.
if(childAutomation != null) {
childAutomation.dispose();
}
}
}
public void dispose() throws SWTException {
// Set the cleaned flag to true. This prevents the method from
// running again if it is called from the finalize() method
this.cleaned = true;
// From the word automation, recover the id of the Quit method
int[] id = this.wordAutomation.getIDsOfNames(new String[]{"Quit"});
// If the id of the Quit method cannot be recovered
// throw an exception - not much good really though.
if(id == null) {
throw new SWTException("Unable to obtain an id for the Quit " +
"property in WordDocumentHandler.dispose().");
}
// Invoke Quit
Variant result = this.wordAutomation.invoke(id[0]);
// If an error occurs during the invocation, throw an exception.
// Again though that exception is of limited value.
if(result == null) {
throw new SWTException("A problem occurred trying to invoke the " +
"Quit method in WordDocumentHandler.dispose().");
}
// Finally, dispose of the word application automation.
this.wordAutomation.dispose();
}
private OleAutomation getChildAutomation(OleAutomation automation,
String childName) throws SWTException {
int[] id = automation.getIDsOfNames(new String[]{childName});
if (id == null) {
throw new SWTException("Could not get id for: " + childName);
}
Variant pVarResult = automation.getProperty(id[0]);
if (pVarResult == null) {
throw new SWTException("Could not get automation for property: " +
id[0]);
}
return(pVarResult.getAutomation());
}
public static void main(String[] args) {
WordDocumentHandler handler = null;
try {
handler = new WordDocumentHandler();
handler.openFile("C:\\Documents and Settings\\win user\\Desktop\\Excel Model\\REPAIR - No Parts Letter.dot");
handler.insertAtBookmark("Address_Block", "J + M Gotrel\n47 High Street\n");
handler.insertAtBookmark("Product_Code", "510-90");
handler.printCurrentFile();
handler.saveAs("C:\\Documents and Settings\\win user\\Desktop\\Excel Model\\REPAIR - New No Parts Letter.doc");
handler.closeCurrentFile();
}
catch(Exception e) {
System.out.println("Caught: " + e.getClass().getName());
System.out.println(e.getMessage());
e.printStackTrace(System.out);
}
finally {
if(handler != null) {
try {
handler.dispose();
}
catch(Exception innerE) {
}
}
}
}
}
To answer your question first, I honestly do not know. There are a few predefined operations that can be called but they tend to be limited to operations like printing.
Anyway, I reckon that I have sorted the code now and have attached it to this message. If you look down into the main method, you can see how to use the code, put simply, you create an instance of the class, call the openFile() method to open a file, call the replace() method to search for and replace text in the file and then either the save() method to re-save the file under it's current name or the saveAs() method to save a copy of the file under a different name. In fact, I think that it should be possible to set it up to loop through a listing of files if you;
Create an instance of the class;
Loop through the file listing calling the openFile(), replace(), save() and closeFile() methods for each one.
Call the dispose() method once all of the files have been processed.
Furthermore, though I have not tested this, I reckon that you could call the replace() method any number of times on the same file if you need to search for and replace different items of text.
I will not pretend to have fully tested the code, so you should do this before using it. Furthermore, I have not run it through the latest version of Word at all but reckon that the document model should be the same. Finally, you could experiment with the MatchCase and other similar settings in the replace() method; all they take is a simple boolean value. If you have any problems, let me know.
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.internal.ole.win32.TYPEATTR;
import org.eclipse.swt.ole.win32.OLE;
import org.eclipse.swt.ole.win32.OleAutomation;
import org.eclipse.swt.ole.win32.OleClientSite;
import org.eclipse.swt.ole.win32.OleFrame;
import org.eclipse.swt.ole.win32.OleFunctionDescription;
import org.eclipse.swt.ole.win32.OlePropertyDescription;
import org.eclipse.swt.ole.win32.OleParameterDescription;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.ole.win32.Variant;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.BufferedWriter;
import java.io.IOException;
public class WordSearchReplace {
private static final String PROG_ID= "Word.Application";
private static final int WD_REPLACE_ALL= 2;
private static final int WD_FIND_CONTINUE= 1;
private Shell shell= null;
private OleFrame frame = null;
private OleClientSite wordSite= null;
private OleAutomation wordAutomation= null;
private OleAutomation activeDocumentAutomation = null;
private boolean cleaned= false;
/**
* Create a new instance of the WordSearchReplace class.
*/
public WordSearchReplace() {
this.shell = new Shell();
this.frame = new OleFrame(this.shell, SWT.NONE);
this.wordSite= new OleClientSite(this.frame, SWT.NONE, WordSearchReplace.PROG_ID);
this.wordAutomation = new OleAutomation(this.wordSite);
}
/**
* Open an MS Word file. This is a file whose name ends with the extension
* .doc or .doc and which conforms to the correct format.
*
* Note; if it is possible to open the named file, an attempt is made
* to cache an OleAutomation object referencing that file which will be
* referred to in future as the active document. Most other methods
* need to capture references to further OleAutomation(s) that have the
* active document as their root.
*
* @param fileName An instance of the String class that encapsulates the
*path to and name of the file that is to be opened.
*Note; the full path name must be supplied as Word
*will be opening the file and no assumptions can
*safely be made concerning the applications 'home'
*folder.
*
* @throws NullPointerException if a null value is passed to the fileName
* parameter.
* @throws FileNotFoundException if it is not possible to locate the
* file.
* @throws IllegalArgumentException if the name of the file does not end
* with either the .dot or .doc extensions.
* @throws SWTException if a problem occurs whilst invoking any of the OLE
* methods.
*/
public void openFile(String fileName) throws SWTException,
NullPointerException,
FileNotFoundException,
IllegalArgumentException {
OleAutomation documentsAutomation = null;
int[] id = null;
Variant[] arguments= null;
Variant invokeResult = null;
try {
// Check the the file name is not null
if(fileName == null) {
throw new NullPointerException("Null value passed to " +
"fileName parameters of the openFile() method.");
}
// Check the the file names ends with '.dot' or '.doc'.
// Remember to include templates and docuemnts
if(!(fileName.endsWith(".doc")) && !(fileName.endsWith(".dot"))) {
throw new IllegalArgumentException(
"The filename must end with the extensions \'.doc\' or \'.dot\'");
}
// Check that the file exists
File fileToPrint = new File(fileName);
if(!(fileToPrint.exists())) {
throw new FileNotFoundException("The file " +
fileName +
"cannot be found.");
}
// From the application, get an automation for the Documents property
documentsAutomation = this.getChildAutomation(this.wordAutomation,
"Documents");
// Get the ID of the Open method
id = documentsAutomation.getIDsOfNames(new String[]{"Open"});
if(id == null) {
throw new SWTException("It was not possible to recover an " +
"identifer for the Open method in WordSearchReplace.openFile().");
}
// Build an array of parameters - holds just the file name
arguments= new Variant[1];
arguments[0] = new Variant(fileName);
// Invoke the Open method on the Documents property
invokeResult = documentsAutomation.invoke(id[0], arguments);
// If the call to invoke the open method failed, throw an SWTException
// to terminate processing.
if(invokeResult == null) {
throw new SWTException("An error occurred whilst invoking the " +
"Open method for the following file: " +
fileName +
" in WordSearchReplace.openFile().");
}
// If it was possible to open the document successfully, grab an
// automation object referencing the active document here.
else {
this.activeDocumentAutomation = this.getChildAutomation(
this.wordAutomation, "ActiveDocument");
}
}
finally {
// If the automation was instantiated then dispose of it to
// release resources. This OleAutomation was only required
// to open the file and can safely be released here.
if(documentsAutomation != null) {
documentsAutomation.dispose();
}
}
}
/**
* Save the currently open file - the active document.
*
* @throws SWTException if a problem occurs whilst invoking any of the OLE
* methods.
*/
public void save() throws SWTException {
int[] id = null;
Variant invokeResult = null;
// From the automation for the ActiveDocument object, get an id for
// the Save method
id = this.activeDocumentAutomation.getIDsOfNames(new String[]{"Save"});
// If it was not possible to recover the id of the Save
// method, throw an exception to notify the user and terminate
// processing.
if(id == null) {
throw new SWTException("Unable to obtain an automation for " +
"the Save method in WordSearchReplace.save().");
}
// Invoke the Save method and catch the value returned
invokeResult = this.activeDocumentAutomation.invoke(id[0]);
// If a null value was returned then the invocation of the
// Save method failed. Throw an exception to notify the
// user and terminate processing.
if(invokeResult == null) {
throw new SWTException("A problem occurred invoking the " +
"Save method in WordSearchReplace.save().");
}
}
/**
* Save the active document using the name provided.
*
* @param fileName Am instance of the String class encapsulating the name
*for the file. Again, the path to and name of the file should
*be supplied.
*
* @throws NullPointerException if a null value is passed to the fileName
* parameter.
* @throws IllegalArgumentException if either an empty String is passed
* to the fileName parameter or if the files name does not end
* with one of the two permissible extensions - .dot and .doc
*/
public void saveAs(String fileName) throws SWTException,
NullPointerException,
IllegalArgumentException {
int[] id = null;
Variant[] arguments = null;
Variant invokeResult = null;
// If the fileName parameter is passed a null
// value, throw an exception.
if(fileName == null) {
throw new NullPointerException("A null value was passed to " +
"the fileName parameter of WordSearchReplace.saveAs().");
}
// If the fileName parameter has been passed an empty String
// then again throw an exception.
if(fileName.length() == 0) {
throw new NullPointerException("An empty string was passed " +
"to the fileName parameter of WordSearchReplace.saveAs().");
}
// Finally, make sure the file name ends in either
// .doc or .dot.
if((!fileName.endsWith(".dot")) && (!fileName.endsWith(".doc"))) {
throw new IllegalArgumentException("An illegal file name was " +
"passed to the fileName parameter of " +
"WordSearchReplace.saveAs(). The file name must " +
"end in \'.dot\' or \'.doc\'.");
}
// From the automation for the ActiveDocument object, get an id for
// the SaveAs method
id = this.activeDocumentAutomation.getIDsOfNames(new String[]{"SaveAs"});
// If it was not possible to recover the id of the SaveAs
// method, throw an exception to notify the user and terminate
// processing.
if(id == null) {
throw new SWTException("Unable to obtain an automation for " +
"the SaveAs method in WordSearchReplace.saveAs().");
}
// Build the array of arguments that will be passed to the invoke
// method when the SaveAs method is invoked. In this case, this
// array will contain a single member - a String object encapsulating
// the path to and name of the output file.
arguments= new Variant[1];
arguments[0] = new Variant(fileName);
// Invoke the SaveAs method and catch the value returned
invokeResult = this.activeDocumentAutomation.invoke(id[0], arguments);
// If a null value was returned then the invocation of the
// PrintOut method failed. Throw an exception to notify the
// user and terminate processing.
if(invokeResult == null) {
throw new SWTException("A problem occurred invoking the " +
"SaveAs method in WordSearchReplace.saveAs().");
}
}
/**
* Mimics Words 'replace' functionality by searching the active
* document for evey string of characters that matches the value passed to
* the searchTerm parameter and replacing them with the string of
* characters passed to the replacementTerm method.
*
* It is possible to code a VBA macro within Word that will perfrom a serach
* and replace. That code would look like the following;
*
* <pre>
* Selection.Find.ClearFormatting
*Selection.Find.Replacement.ClearFormatting
*With Selection.Find
*.Text = "serach"
*.Replacement.Text = "search"
*.Forward = True
*.Wrap = wdFindContinue
*.Format = False
*.MatchCase = False
*.MatchWholeWord = False
*.MatchWildcards = False
*.MatchSoundsLike = False
*.MatchAllWordForms = False
*End With
*Selection.Find.Execute Replace:=wdReplaceAll
* <pre>
*
* and this method will 'automate' it.
*
* @param searchTerm An instance of the String class that will encapsulate
*the series of characters that should be replaced.
* @param replacementTerm An instance of the String class that will
*encapsulate the series of characters that should replace the
*searchTerm.
*
* @throws NullPointerException if a null value is passed to either the
* searchTerm or replacementTerm methods.
* @throws SWTException if a problem occurs when invoking any of the
* OLE methods.
*/
public void replace(String searchTerm,
String replacementTerm) throws SWTException,
NullPointerException {
OleAutomation selectionFindAutomation = null;
OleAutomation childAutomation = null;
Variant[] arguments= null;
Variant invokeResult= null;
int[] id= null;
int[] namedArguments= null;
boolean success= true;
// Validate the searchTerm parameter and throw exception if
// null value passed.
if(searchTerm == null) {
throw new NullPointerException("Null value passed to " +
"searchTerm parameter of the replace() method.");
}
// Validate the replacementTerm parameter and throw exception if
// null value passed.
if(replacementTerm == null) {
throw new NullPointerException("Null value passed to " +
"replacementTerm parameter of the replace() method.");
}
// Most of the VBA instructions used to perform the search and
// replace functionality and child automations of Selection.Find,
// therefore, it is wise to cache that automation first.
// From the application, get an automation for the Selection property
childAutomation = this.getChildAutomation(this.wordAutomation,
"Selection");
selectionFindAutomation = this.getChildAutomation(childAutomation,
"Find");
// Next, using the cached automation, invoke the 'ClearFormatting'
// method, validate the returned value and invoke the method.
//
// Selection.Find.ClearFormatting
//
id = selectionFindAutomation.getIDsOfNames(new String[]{"ClearFormatting"});
if(id == null) {
throw new SWTException("It is not possible to recover an identifier " +
"for the ClearFormatting method in WordSearchReplace.replace() " +
"when clearing the formatting for the search string.");
}
invokeResult = selectionFindAutomation.invoke(id[0]);
if(invokeResult == null) {
throw new SWTException("A problem occurred invoking the " +
"ClearFormatting method in WordSearchReplace.repace() " +
"when clearing formatting for the search string.");
}
// Now, perform the same function but for the replacement string.
//
// Selection.Find.Replacement.ClearFormatting
//
childAutomation = this.getChildAutomation(selectionFindAutomation,
"Replacement");
id = childAutomation.getIDsOfNames(new String[]{"ClearFormatting"});
if(id == null) {
throw new SWTException("It is not possible to recover an identifier " +
"for the ClearFormatting method in WordSearchReplace.replace() " +
"when clearing the formatting for the replacement string.");
}
invokeResult = childAutomation.invoke(id[0]);
if(invokeResult == null) {
throw new SWTException("A problem occurred invoking the " +
"ClearFormatting method in WordSearchReplace.repace() " +
"when clearing formatting for the replacement string.");
}
// Firstly, set the search text.
//
// .Text = "search term"
//
arguments= new Variant[1];
arguments[0] = new Variant(searchTerm);
success = this.setPropertyValue(selectionFindAutomation, "Text", arguments);
if(!success) {
throw new SWTException("A problem occurred setting the Text " +
"property for the search string in WordSearchReplace.replace().");
}
// Next, the replacement text
//
// .Replacement.Text = "replacement term"
//
childAutomation = this.getChildAutomation(selectionFindAutomation,
"Replacement");
arguments[0] = new Variant(replacementTerm);
success = this.setPropertyValue(childAutomation, "Text", arguments);
if(!success) {
throw new SWTException("A problem occurred setting the Text property" +
" for the replacement string in WordSearchReplace.replace().");
}
// Set the direction of the search - forward in this case.
//
// .Forward = True
//
arguments[0] = new Variant(true);
success = this.setPropertyValue(selectionFindAutomation, "Forward", arguments);
if(!success) {
throw new SWTException("A problem occurred setting the Forward " +
"property in WordSearchReplace.replace().");
}
// Tell the search to wrap. Note the literal wdFindContinue relates to
// a constant that is defined within Word. I have provided a static
// final to replace it called WD_FIND_CONTINUE
//
// .Wrap = wdFindContinue
//
arguments[0] = new Variant(WordSearchReplace.WD_FIND_CONTINUE);
success = this.setPropertyValue(selectionFindAutomation, "Wrap", arguments);
if(!success) {
throw new SWTException("A problem occurred setting the Wrap " +
"property in WordSearchReplace.replace().");
}
// Set the Format property to False.
//
// .Format = False
//
arguments[0] = new Variant(false);
success = this.setPropertyValue(selectionFindAutomation, "Format", arguments);
if(!success) {
throw new SWTException("A problem occurred setting the Format " +
"property in WordSearchReplace.replace().");
}
// Set the MatchCase property to false.
//
// .MatchCase = False
//
arguments[0] = new Variant(false);
success = this.setPropertyValue(selectionFindAutomation, "MatchCase", arguments);
if(!success) {
throw new SWTException("A problem occurred setting the MatchCase " +
"property in WordSearchReplace.replace().");
}
// Set the MatchWholeWord property to false.
//
// .MatchWholeWord = False
//
arguments[0] = new Variant(false);
success = this.setPropertyValue(selectionFindAutomation, "MatchWholeWord", arguments);
if(!success) {
throw new SWTException("A problem occurred setting the " +
"MatchWholeWord property in WordSearchReplace.replace().");
}
// Set the MatchWildCards property to false.
//
// .MatchWildcards = False
//
arguments[0] = new Variant(false);
success = this.setPropertyValue(selectionFindAutomation, "MatchWildCards", arguments);
if(!success) {
throw new SWTException("A problem occurred setting the " +
"MatchWildCards property in WordSearchReplace.replace().");
}
// Set the MatchSoundsLike property to false.
//
// .MatchSoundsLike = False
//
arguments[0] = new Variant(false);
success = this.setPropertyValue(selectionFindAutomation, "MatchSoundsLike", arguments);
if(!success) {
throw new SWTException("A problem occurred setting the " +
"MatchSoundsLike property in WordSearchReplace.replace().");
}
// Set the MatchAllWordForms property to false.
//
// .MatchAllWordForms = False
//
arguments[0] = new Variant(false);
success = this.setPropertyValue(selectionFindAutomation, "MatchAllWordForms", arguments);
if(!success) {
throw new SWTException("A problem occurred setting the " +
"MatchAllWordForms property in WordSearchReplace.replace().");
}
// Invoke the Execute command passing the correct value to the Replace
// parameter. Again, wdReplaceAll is a constant that I have provided
// a ststic final for called WD_REPLACE_ALL
//
// Selection.Find.Execute Replace:=wdReplaceAll
//
id = selectionFindAutomation.getIDsOfNames(new String[]{"Execute", "Replace"});
if(id == null) {
throw new SWTException("It was not possible to recover an identifier " +
"for the Execute method in WordSearchReplace.replace().");
}
arguments = new Variant[1];
arguments[0]= new Variant(WordSearchReplace.WD_REPLACE_ALL);
namedArguments= new int[1];
namedArguments[0] = id[1];
// There was some indication that the invokeNoReply method should
// be used when making this call but no, invoke SEEMS to work well
//selectionFindAutomation.invokeNoReply(id[0], arguments, namedArguments);
invokeResult = selectionFindAutomation.invoke(id[0], arguments, namedArguments);
if(invokeResult == null) {
throw new SWTException("A problem occurred trying to invoke the " +
"Execute method in WordSearchReplace.replace().");
}
}
/**
* Close the active document.
*
* @throws SWTException if a problem is encountered invoking any of the
* OLE methods.
*/
public void closeFile() throws SWTException {
int[] id = null;
Variant[] arguments = null;
Variant invokeResult = null;
try {
// From the OleAutomation referencing the active document, recover
// the id of the Close method.
id = this.activeDocumentAutomation.getIDsOfNames(new String[]{"Close"});
// If it was not possible to recover the id of the Close
// method then throw an exception to notify the user and
// terminate processing.
if(id == null) {
throw new SWTException("It was not possible to recover an " +
"identifier for the Close method in " +
"WordSearchReplace.closeFile().");
}
// Invoke the Close method on the ActiveDocument automation
invokeResult = this.activeDocumentAutomation.invoke(id[0]);
// If the invocation of the Close method failed, throw an
// exception to notify the user and terminate processing.
if(invokeResult == null) {
throw new SWTException(
"An error occurred invoking the Close method in " +
"WordSearchReplace.closeFile().");
}
}
finally {
if(this.activeDocumentAutomation != null) {
this.activeDocumentAutomation.dispose();
}
}
}
/**
* Release resources.
*/
public void dispose() throws SWTException {
try {
// Set the cleaned flag to true. This prevents the method from
// running again if it is called from the finalize() method
this.cleaned = true;
// From the word automation, recover the id of the Quit method
int[] id = this.wordAutomation.getIDsOfNames(new String[]{"Quit"});
// If the id of the Quit method cannot be recovered
// throw an exception - not much good really though.
if(id == null) {
throw new SWTException("Unable to obtain an id for the Quit " +
"property in WordSearchReplace.dispose().");
}
// Invoke Quit
Variant result = this.wordAutomation.invoke(id[0]);
// If an error occurs during the invocation, throw an exception.
// Again though that exception is of limited value.
if(result == null) {
throw new SWTException("A problem occurred trying to invoke the " +
"Quit method in WordSearchReplace.dispose().");
}
}
finally {
// Finally, dispose of the word application automation.
this.wordAutomation.dispose();
}
}
/**
* The finalize() method has been over-ridden to ensure that resources
* are correctly released if a WordSearchReplace object is created but
* not disposed of properly before it becomes eligible for garbage
* collection. The cleaned flag is used as acheck to ensure that the
* dispose() method cannot be called more than once.
*/
public void finalize() throws Throwable {
if(!this.cleaned) {
this.dispose();
}
}
/**
* Creates and returns a 'child' OleAutomation object. The object model
* employed by Word, Excel and the like, arrange objects, methods and
* properties hierarchically. To invoke a method, it is often necessary
* to iterate through this hierarchy from parent to child and this method
* supports that process.
*
* @param automation An OleAutomation object that references the parent
*automation.
* @param childName An instance of the String class that encapsulates the
*name of the child automation.
*
* @throws SWTException if a problem is encountered invoking one or
* other of the OLE methods.
*/
private OleAutomation getChildAutomation(OleAutomation automation,
String childName) throws SWTException {
// Try to recove the unique identifier for the child automation
int[] id = automation.getIDsOfNames(new String[]{childName});
// If the identifier cannot be found then throw an exception to
// terminate processing.
if (id == null) {
throw new SWTException(
"A problem occurred trying to obtain and id for: " +
childName +
"in the getChildAutomation() method.");
}
// SWT's implementation of OLE referes to all of Words objects, methods
// and properties using the single term 'property'. The next stage
// therefore is to recover a refence to the 'property' that relates
// to the child automation.
Variant pVarResult = automation.getProperty(id[0]);
// If it is not possible to recover a 'property' for the child
// automation, then throw an SWTException.
if (pVarResult == null) {
throw new SWTException(
"A problem occurred trying to obtain an automation for property: " +
id[0] +
" in the getChildAutomation() method.");
}
// As we are after a child automation in this instance, call the
// getAutomation() method on the 'property'.
return(pVarResult.getAutomation());
}
/**
* Sets the value of a property.
*
* @param automation An instance of the OleAutomation class that will
*hold a reference to the properties parent automation object
* @param propertyName An instance of the String class that encapsulates the
*name of the property whose value is to be set.
* @param arguments An array of type Variant whose elements contain the
*values that will be set for the named property.
*
* @return A primitive boolean value that indicates whether or not the
* properties value was successfully set.
*
* @throws NullPointerException will be thrown if a null value is passed to
* any of the methods three arguments.
* @throws IllegalArgumentException will be thrown if an empty String
* is passed to the propertyName parameter or if an empty array
* is passed to the arguments parameter. Note, no check is made
* on the vallues of the elements in the arguments array.
* @throws SWTException will be thrown if a problem is encountered
* imvoking any of the OLE methods.
*/
private boolean setPropertyValue(OleAutomation automation,
String propertyName,
Variant[] arguments) throws SWTException,
NullPointerException,
IllegalArgumentException {
// Validate the various parameters
if(automation == null) {
throw new NullPointerException(
"A null value was passed to the automation parameter of " +
"WordSearchReplace.setPropertyValue().");
}
if(propertyName == null) {
throw new NullPointerException(
"A null value was passed to the propertyName parameter of " +
"WordSearchReplace.setPropertyValue().");
}
if(propertyName.length() == 0) {
throw new IllegalArgumentException(
"An empty - zero length - String was passed to the propertyName " +
"parameter of WordSearchReplace.setPropertyValue().");
}
if(arguments == null) {
throw new NullPointerException(
"A null value was passed to the arguments parameter of " +
"WordSearchReplace.setPropertyValue().");
}
if(arguments.length == 0) {
throw new IllegalArgumentException(
"An empty - zero length - array was passed to the arguments " +
"parameter of WordSearchReplace.setPropertyValue().");
}
// Recover the identifier for the property
int[] id = automation.getIDsOfNames(new String[]{propertyName});
if(id == null) {
throw new SWTException("Unable to obtain an identifier for the " +
propertyName +
" property in WordSearchReplace.setPropertyValue().");
}
// Try to set the properties value. If this fails, the boolean value
// false will be returned to the calling code.
return(automation.setProperty(id[0], arguments));
}
/**
* The main entry point for the program. Currently contains code to open
* a named file, replace certain terms and then save the file again.
*/
public static void main(String[] args) {
WordSearchReplace wordSR = null;
try {
wordSR = new WordSearchReplace();
wordSR.openFile(PATH TO AND NAME OF DOCUMENT);
wordSR.replace("SEARCH TERM", "REPLACEMENT TERM");
// If you want to save the modified document under a different name
// simply uncomment saveAs() and comment out save()
//wordSR.saveAs(PATH TO AND NAME OF DOCUMENT);
// This method will save the modified document under it's
// existing name/location.
wordSR.save();
wordSR.closeFile();
}
catch(Exception e) {
System.out.println("Caught: " + e.getClass().getName());
System.out.println(e.getMessage());
e.printStackTrace(System.out);
}
finally {
if(wordSR != null) {
try {
wordSR.dispose();
}
catch(Exception innerE) {
System.out.println("Caught: " + innerE.getClass().getName());
System.out.println(innerE.getMessage());
innerE.printStackTrace(System.out);
}
}
}
}
}