sept. 15

CITCON (Continuous Integration & Testing Conference) comes to Amsterdam in October 3rd & 4th (friday evening and saturday).

After Brussels last year (see my previous post about the 2007 edition here and here), I will be present in Amsterdam this year. Interested in 1-day of great conference about CI and testing ? Join me there !

Be careful, this year it's limited to the first 150 subscribee so hurry up.

Need more information about CITCON ? Visit their website dedicated to Amsterdam !

sept. 06

Some time ago, I have published a serie of article speaking about VSTO, .NET 3.5 and Excel. A few time ago, I wanted to merge a word document with a CSV file.

Let's see step by step how to achieve this:

Let's create a .csv file

  • Create a simple text file on which you will put
    • Some key names on the first line
    • Some values in the second line
  • Save it (let's say c:\temp\merge\datafile.txt)

This file will be the one that will be merged with your word template.

Let's create your template word document

  • Open Word (I will give the instructions following Word 2007)
  • Click on "Mailings"
  • Click on "Start Mail Merge" and "Letter"
  • Click on "Select Recipients"
  • Click on "Use an existing Data Source File" and select the file you have just created in the previous step
  • Just write down your document and when you want to insert one of the fields that is present in the document just do the following :
    • Click on "Mailings"
    • Click on "Insert a merge field" and select the field you want to add
  • Save the document (let's say c:\temp\merge\doc to merge.docx)

Let's now do the merge programmatically

  • Create a new Console Application
  • Add a reference to the following DLLs:
    • Microsoft.Office.Interop.Word.dll
    • Microsoft.Office.Tools.Word.v9.0.dll 

The code is quite clear but here are some additional comments to help understanding some parts:

using System;
using Microsoft.Office.Interop.Word;
 
class Program
{
   static object missing = Type.Missing;
 
   static void Main(string[] args)
   {
      //1. Get the winword application
      _Application application = (_Application)new Application();
 
      //2. Open the template document
      object fileName = @"C:\Temp\Merge\doc to merge.docx";
      _Document document = application.Documents.Open(ref fileName, 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, ref missing);
 
      //3. Prepare the Mail Merge
      document.MailMerge.MainDocumentType = WdMailMergeMainDocType.wdFormLetters;
      document.MailMerge.Destination = WdMailMergeDestination.wdSendToNewDocument;
 
      //4. Open the data source (recipents)
      string dataSource = @"C:\Temp\Merge\datafile.txt";
      object subType = WdMergeSubType.wdMergeSubTypeOther;
      document.MailMerge.OpenDataSource(dataSource, 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, ref subType);
 
      //5. Execute the MailMerge
      document.MailMerge.Execute(ref missing);
 
      //6. Close the template without saving
      object saveChanges = WdSaveOptions.wdDoNotSaveChanges;
      document.Close(ref saveChanges, ref missing, ref missing);
 
      //7. Get a reference to the newly created document 
      //   (it will be the only opened document, ie, index = 1)
      object index = 1;
      document = application.Documents.get_Item(ref index);
 
      //8. Save the newly created document
      object newFileName = @"C:\Temp\Merge\doc merged.docx";
      document.SaveAs(ref newFileName, 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, ref missing);
      document.Close(ref missing, ref missing, ref missing);
 
      //9. Close Winword
      object saveOptions = WdSaveOptions.wdDoNotSaveChanges;
      application.Quit(ref saveOptions, ref missing, ref missing);
   }
}
  • I use the _Application and _Document class instead of Application and Document to avoid having some warning due to ambiguous calls.
  • Yes, Application is an interface. So why do we do a new on an interface ? Simply because we are dealing with COM objects
  • The WORD object model uses only by reference parameters. However there is no problelm declaring a static variable as a shortcut to Type.Missing
  • All collection in the office object model are 1-based (contrary to the .NET collections that are all 0-based)
  • You should of course be a lot more cautious when using this code in production mode : be sure that the Close and Quit methods get called, otherwise, you will get many processes running in background !
  • If you want to see the application running, just do application.visible = true

What does it give ?

Tags: