Monday, October 13, 2008

Creating and Opening Microsoft Word Document from .NET Using C#

Creating and Opening Microsoft Word Document from .NET Using C#

This article is being written in response to a couple inquiries on the question, "How do I open a word document from .NET?"

Figure 1 - Word Launched from .NET Form

This article is being written in response to a couple inquiries on the question, "How do I open a word document from .NET?". I guess after people read my excel article, they were under the impression that I knew how to do this in Word. Luckily, after some hunting around on the forums and feedback from other C# Corner members I got the gist of it.

The First Step in manipulating Word in .NET is that you'll need to add a COM reference to your project by right clicking in the solution explorer on References->Add Reference. Click on the COM tab and look for the Microsoft Word 9.0 Object Library. Click Select and OK.

This will automatically place an assembly in your application directory that wraps COM access to Word. Now we are ready to create a word object in our code. To instantiate an instance of a Word application, you just declare the line below in your class:

private Word.ApplicationClass WordApp = new Word.ApplicationClass();

Now you can call the interesting methods and properties that Microsoft Word provides to you to manipulate documents in Word. Personally, I never want to figure the Microsoft Word code out myself, because the Word hierarchy and properties, although rich in features, has a bit of a learning curve. So in order to jump straight over the learning curve, I simple turn the Macro Recorder on in Word and let Word write the code for me. (Of course this is VBA code, but...close enough). To start the macro recorder in Word, go to Tools->Macro->Record New Macro inside Microsoft Word. Now anything you type, open, delete, or format, will get recorded in VBA, so you have a clue how to write your Word Interoperability code.

The application in this particular article is divided into two methods based on the button that is pressed in the form. The first button opens an existing Word Document and adds a copyright line to the document. The second button creates a new document, and brings up a dialog to allow you to enter a title to the document.

Below is the code for the first button event handler:

private void button1_Click(object sender, System.EventArgs e)
// Use the open file dialog to choose a word document
if (this.openFileDialog1.ShowDialog() == DialogResult.OK)
// set the file name from the open file dialog
object fileName = openFileDialog1.FileName;
object readOnly = false;
object isVisible = true;
// Here is the way to handle parameters you don't care about in .NET
object missing = System.Reflection.Missing.Value;
// Make word visible, so you can see what's happening
WordApp.Visible = true;
// Open the document that was chosen by the dialog
Word.Document aDoc = WordApp.Documents.Open(ref fileName, ref missing, ref readOnly, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref isVisible);
// Activate the document so it shows up in front
// Add the copyright text and a line break
WordApp.Selection.TypeText("Copyright C# Corner");

The code above opens a document based on the file chosen in the OpenFileDialog. Notice the parameters passed to the Document.Open method are all references. Don't ask me why it was done this way, but it seems like when Microsoft goes through a call with optional parameters, they had no choice but to make everything a variant so on the C# side of the parameter list looks like a bunch of references to objects. If you want to skip over a parameter in the call to Open, use the System.Reflection.Missing.Value and assign it to an object. Once you know this trick, the rest of the interoperability used with Word is pretty straightforward.

Below is the code for creating a document from scratch:

private void button2_Click(object sender, System.EventArgs e)
// Use the custom dialog to get the title of the document from the user
TitleQuery theQueryDialog = new TitleQuery();
if (theQueryDialog.ShowDialog() == DialogResult.OK)
// vba code generated from recorded macro to "remind me" how to do it.
// Selection.ParagraphFormat.Alignment = wdAlignParagraphCenter
// Selection.Font.Bold = wdToggle
// Selection.TypeText Text:="Creating a Title"
// Documents.Add Template:="C:\My Documents\CSharp Book Project\",
// NewTemplate:=False, DocumentType:=0
// **********************************************************
// Set up all the parameters as generic objects so we can pass them in Documents.Add
object missing = System.Reflection.Missing.Value;
object fileName = ""; // template file name
object newTemplate = false;
object docType = 0;
object isVisible = true;
// Create a new Document, by calling the Add function in the Documents collection
Word.Document aDoc = WordApp.Documents.Add(ref fileName, ref newTemplate, ref docType, ref isVisible);
// need to see the created document, so make it visible
WordApp.Visible = true;
// Global Constant enumerations are members of Word and can be assigned to Properties
// Set alignment to the center of the document
WordApp.Selection.ParagraphFormat.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter;
// Toggle the title to a Bold Font
WordApp.Selection.Font.Bold = (int)Word.WdConstants.wdToggle;
// Type the Text of the Title that was inputted by the user in the Custom Dialog

The code above is a little less intuitive, so I used the Macro Recorder in VBA to spit out the VBA code for creating a document. Creating a document is done through the Documents Collection. The Add method of the Documents Collection creates a new document and brings it up in Word. The Add method allows you to specify the template to use and the document type. Note that the Add method also takes optional parameters, so as a result, you need to pass it a series of references to objects that box the types you would normally pass.

The title being placed in the document is formatted using some of the existing Word global enumeration constants. These constants tend to be constants nested in constants for organizational purposes. Although VBA gives you a clue to the relative name of the constants, you need to hunt for them a little bit using intellisense to find the parent enumeration. The code above uses the global enumerations to first center the title and then make it bold. The final line is similar to the previous listing in that it types the title into the Document.