Monday, November 28

Word automation - replace a placeholder with a file

There appears to be surprisingly little in the way of tutorials on the web on the subject of controlling Word from a Windows application.

I was trying to get Word to load a document and replace the string "<>" with another document. The first document was a standard template, and the second document was generated by my application. I followed a 4 step process for this:

1) Generate a word macro
2) Look up any constants
3) Copy this to C# code, and add a reference to your word application.
4) Create reference objects for any function parameters.
5) Encapsulate this in a C# function.

1) Generating a word macro

The best way I found to get started with this was to record a macro and view the source of the macro. This gives you a clue as to the names of the required functions. These didn't prove easy to find out any other way.


With Selection.Find
.Text = "searchtext"
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindAsk
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
Selection.Find.Execute
Selection.InsertFile
FileName:="myfile.doc", _
Range:="", ConfirmConversions:=False,
Link:=False, Attachment:=False


2) Looking up constants

It was then necessary to convert this into C# code. The first thing was to find out what the value of wdFindAsk was - entering this into a search engine gave a page that listed its value as zero.

I'd already set up a Word Automation class and opened the document using the following code:


wordApp = new Word.Application();
object o = filename;
oDoc = wordApp.Documents.Open(ref o,
ref missing,ref missing,ref missing,
ref missing,ref missing,ref missing,
ref missing,ref missing,ref missing,
ref missing,ref missing,ref missing,
ref missing,ref missing);
wordApp.Visible = true;


3) Converting the macro to C#

To change the macro into C#, I noted the macro first set up the Selection.Find object, and then called the Execute function.

Setting up the selection.Find object meant adding wordApp before the word selection. This became


wordApp.Selection.Find.Text = placeholder;
wordApp.Selection.Find.Replacement.Text = "";


To call the Execute function, I typed "wordApp.Selection.Find.Execute" into Visual Studio, and noted all the parameters it required. The only one that seemed to matter was the first one. Word functions seem to take all their arguments in the form ref object, so missing objects for the other arguments needed to be set up:

4) Creating reference objects


missing = System.Reflection.Missing.Value;


I then had to insert the file. Again, I took the macro as a start point, and typed wordApp.Selection.InsertFile into Visual Studio to see what arguments were needed. I set up objects for an empty string and the Boolean false, and called the function in the form


wordApp.Selection.InsertFile(filename,
ref emptystring, ref falseobject,
ref falseobject, ref falseobject);


5) Encapsulating this in a C# function

The code for the complete replace placeholder function was as follows:


// Replace the placeholder on a file
// that we have launched with a new file

public void ReplacePlaceholder(String filename,
String placeholder)
{
object o = filename;
object falseobject = false;
object zeroobject = 0;
object normal = "Normal";
object emptystring = "";

// Insert the new document into the original

object osearchtext = placeholder;

wordApp.Selection.Find.ClearFormatting();
wordApp.Selection.Find.Text = placeholder;
wordApp.Selection.Find.Replacement.Text = "";

bool found = wordApp.Selection.Find.Execute(
ref osearchtext,
ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing,
ref missing, ref missing);

// Does the search text exist?

if(found)
{
wordApp.Selection.InsertFile(filename,
ref emptystring,
ref falseobject, ref falseobject, ref falseobject);
}
}

No comments: