F# Scripting Zen – Word Interop
Edit: Added a ‘comarg’ function to dramatically clean up the syntax for doing COM-interop, since F# will pass ‘ref types’ as byrefs to COM calls.
In a previous post I talked about how to take advantage of .FSX (F# Script) files to automate tasks for you. In this post I would like to share a script which I’ve found useful.
Let’s say you are working with a lot of Word documents, for example writing a book for O’Reilly on an upcoming .NET language. If you find revising your writing by hand easier than sitting in front of a computer, it would be helpful to have a script which prints out the book’s contents in such a way that doesn’t kill too many trees.
Here’s a simple F# script to automate the task of printing every Word doc in the same folder as the script. Simply copy the .FSX file into the desired folder, and whenever you want to print out all the documents right click and select ‘Run in F# Interactive…’.
Note how this takes advantage of F#’s support for optional parameters for COM-components.
#light #I @"C:\Program Files\Microsoft Visual Studio 9.0\Visual Studio Tools for Office\PIA\Office12\" #r "Office.dll" #r "stdole.dll" #r "Microsoft.Office.Interop.Word.dll" open Microsoft.Office.Interop.Word let private m_word : ApplicationClass option ref = ref None let OpenWord() = m_word := Some(new ApplicationClass()) let GetWordInstance() = Option.get !m_word let CloseWord() = (GetWordInstance()).Quit() let comarg x = ref (box x) let OpenDocument filePath = printfn "Opening %s..." filePath word.Documents.Open(comarg filePath) let PrintDocument (doc : Document) = printfn "Printing %s..." doc.Name doc.PrintOut( Background = comarg true, Range = comarg WdPrintOutRange.wdPrintAllDocument, Copies = comarg 1, PageType = comarg WdPrintOutPages.wdPrintAllPages, PrintToFile = comarg false, Collate = comarg true, ManualDuplexPrint = comarg false, PrintZoomColumn = comarg 2, // Pages 'across' PrintZoomRow = comarg 2) // Pages 'up down' let CloseDocument (doc : Document) = printfn "Closing %s..." doc.Name doc.Close(SaveChanges = comarg false) // ------------------------------------------------------------- let currentFolder = __SOURCE_DIRECTORY__ open System open System.IO try OpenWord() printfn "Printing all files in [%s]..." currentFolder Directory.GetFiles(currentFolder, "*.docx") |> Array.iter (fun filePath -> let doc = OpenDocument filePath PrintDocument doc CloseDocument doc) finally CloseWord() printfn "Press any key..." Console.ReadKey(true) |> ignore
Disclaimer: Note that this post is provided ‘AS IS’ and offers no warranty and confers no rights. If this script file causes you bad mojo, seek a shaman for help and don’t blame me.