In my last project I had to do A LOT of Word Interop.  Everything from data-heavy reports to quick documents exist in this system.  Let me start by saying if you can find a way for to do what you want WITHOUT using Word Interop....do it.  It's such a pain in the ass if you want to do anything non-trivial.

Some things word interop really shines for is allowing you to preformat a document and just "fill in the blanks" with some data.  This is great if you're doing something like Packing Slips, cover sheets, and other simple documents.

Basic Word Interop

Let's start with some basics.  This will get you up and running, and you will find that you can do a lot of stuff with just a handful of code stuffed away in a library.

This is a basic skeleton class you can use to interact with any word document in a simple way:

You will need to add a reference to the Word 11.0 library to your project.

public class WordDocumentGenerator : IDisposable
{
private ApplicationClass wordApplication;
private Document wordDocument;
private object save = false;
private object boolTrue = true;
private object boolFalse = false;
private object oMissing = System.Reflection.Missing.Value;
private object reportPath;

public WordDocumentGenerator(string documentPath)
{
reportPath = documentPath;
}

public void ShowDocument()
{
wordApplication.Visible = true;
}

public void SaveDocument(string filePath)
{
object oFilePath = (object)filePath;
wordDocument.SaveAs(ref oFilePath, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing,
ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing,
ref oMissing, ref oMissing, ref oMissing, ref oMissing);
}

public void LoadDocument()
{
if (reportPath != null)
{
wordApplication = new ApplicationClass();
wordApplication.Visible = false;
wordDocument = wordApplication.Documents.Open(ref reportPath, ref oMissing, ref oMissing, ref oMissing,
ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing,
ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing);
}
}

public void SetBookmark(string bookmarkName, string bookmarkText)
{
try
{
object bookmark = bookmarkName;
Range bookmarkRange = wordDocument.Bookmarks.get_Item(ref bookmark).Range;
bookmarkRange.Text = bookmarkText;
}
catch
{}
}

#region IDisposable Members

public void Dispose()
{
wordApplication.Quit(ref save, ref oMissing, ref oMissing);
System.Runtime.InteropServices.Marshal.ReleaseComObject(wordApplication);
}

#endregion
}

Given the annoyance just with all the ref oMissing params in every stupid function call, I recommend always encapsulating this stuff into some utility class so you don't get the carpal tunnel typing it out.

So basic usage on this:  Let's say you have a Fax Cover Sheet you want to generate from data on screen.  In the word document, you would set Bookmarks (Insert->Bookmark) on the range (selection) you want to replace.  Let's say you set bookmarks for CustomerName and CustomerFax.

WordDocumentGenerator word = new WordDocumentGenerator(m_TemplatePath);
word.LoadDocument(); //This loads the document into memory so you can interact wit hit
//Replace the bookmark fields with our variables
SetBookmark("CustomerName", m_CustomerName);
SetBookmark("CustomerFax", m_CustomerFax);

//Show the document so the user can print it
word.ShowDocument();

//Alternatively, save it somewhere
word.SaveDocument(m_SavePath);

//and when you are all done, kill it
word.Dispose();

Okay so very easy stuff here.  This is quick and painless (fairly) providing you can do everything you want by setting bookmarks in the document and filling them with data after.  You can handle formatting by formatting the bookmark text the way you want, and when you call SetBookmark it will inherit that formatting.

A caveat about bookmarks:  They are damn flaky.  They are based on a "Range", so you should Select the text where you want the bookmark from beginning to end, make sure you don't include the trailing space or paragraph mark, and don't just double-click a word to select it.  I actually had an issue with this because I would sometimes select from back to front depending on where my cursor was, and those bookmarks didn't work! (That was with .net 1.1, but I wasn't willing to risk it in 2.0)

 So there you have it - A simple way to do some Word interop to make very straightforward data driven word documents.  This is becoming a wall of text already, so I will do a part 2 post for more advanced stuff like formatting and interacting with the document (prepare to be frustrated) on a deeper level.  Hope this helps someone.


Tags: