Converting Word 2010 Documents from the DOCM to DOCX File Format by Using the Open XML SDK 2.0

Office Visual How To

Summary:  Use the strongly typed classes in the Open XML SDK 2.0 to convert a Word document including VBA code (with a DOCM extension) to a standard document (with a DOCX extension), without loading the document into Microsoft Word.

Applies to: Excel 2010 | Office 2010 | Open XML | PowerPoint 2010 | VBA | Word 2010

Published:  September 2010

Provided by:  Ken Getz, MCW Technologies, LLC

Overview

The Open XML file formats make it possible to programmatically modify the structure of Microsoft Word documents, but doing this requires some effort. The Open XML SDK 2.0 adds strongly typed classes that simplify access to the Open XML file formats: The SDK simplifies the tasks of modifying the parts of a document. The code sample that is included with this Visual How To shows how to the use the SDK to do this.

Code It

The sample provided with this Visual How To includes the code that is required to convert a Word 2007 or Word 2010 document that contains VBA code (and has a DOCM extension) to a standard document (with a DOCX extension). The following sections describe the code in detail.

Set Up References

To use the code from the Open XML SDK 2.0, you must add references to your project. The sample project includes these references, but in your own code, you must explicitly reference the following assemblies:

  • WindowsBase─This reference may be set, depending on the kind of project that you create.

  • DocumentFormat.OpenXml─Installed by the Open XML SDK 2.0.

You should also add the following using/Imports statements to the top of your code file.

Imports DocumentFormat.OpenXml
Imports DocumentFormat.OpenXml.Packaging
Imports System.IO
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using System.IO;

Examine the Procedure

The WDConvertDOCMtoDOCX procedure accepts a single parameter that indicates the name of the document to modify (string).

Public Sub WDConvertDOCMtoDOCX(ByVal fileName As String)
public static void WDConvertDOCMtoDOCX(string fileName)

The procedure modifies the document that you specify, verifying that the document contains a VBA part, and if so, deleting the part. After the code deletes the part, it changes the document type internally and renames the document by using the DOCX extension. To call the procedure, pass the parameter value, as shown in the code example. Ensure that you provide a document named C:\temp\WithMacros.docm, which contains at least a single VBA procedure, before you run this sample code.

WDConvertDOCMtoDOCX("C:\Temp\WithMacros.docm")
WDConvertDOCMtoDOCX("C:\\Temp\\WithMacros.docm");

Access the Document

The code starts by opening the document by using the WordprocessingDocument.Open method and indicating that the document should be open for read/write access (the final true parameter). The code then retrieves a reference to the Document part by using the Document property of the MainDocumentPart property of the word processing document.

Using document = WordprocessingDocument.Open(fileName, True)
  Dim docPart = document.MainDocumentPart.Document
  ' Code removed here…
End Using
using (var document = WordprocessingDocument.Open(fileName, true))
{
  var docPart = document.MainDocumentPart.Document;
  // Code removed here…
}

Locate and Delete the VBA Part

If the passed-in document contains VBA code, the document stores that code in a discrete VBA part. The sample code next verifies that the VBA part exists, and if so, deletes the part and saves the document. To find the VBA part, the sample code retrieves the VbaProjectPart property of the document. It calls the DeletePart method to delete the VBA part, and then calls the Save method of the document to save the changes.

' Look for the VBA part. If it is there, delete it.
Dim vbaPart = docPart.VbaProjectPart
If vbaPart IsNot Nothing Then
  docPart.DeletePart(vbaPart)
  docPart.Document.Save()
  ' Code removed here…
End If
var vbaPart = docPart.VbaProjectPart;
if (vbaPart != null)
{
  docPart.DeletePart(vbaPart);
  docPart.Document.Save();
  // Code removed here.
}

Converting the Document Type

It is not enough to delete the VBA part from the document. You must also convert the document type, internally. The Open XML SDK 2.0 provides a simple means of performing this task: You can call the document ChangeDocumentType method and indicate the new document type (in this case, supply the WordProcessingDocumentType.Document enumerated value).

You must also rename the file. However, you cannot do that while the file is open. The using block closes the file at the end of the block. Therefore, you need some way to indicate to code after the block that you have modified the file: The fileChanged Boolean variable tracks this information for you.

' Change the document type so that it no 
' longer thinks it is macro-enabled.
document.ChangeDocumentType(WordprocessingDocumentType.Document)

' Track that the document has been changed.
fileChanged = True
// Change the document type so that it no 
// longer thinks it is macro-enabled.
document.ChangeDocumentType(
  WordprocessingDocumentType.Document);

// Track that the document has been changed.
fileChanged = true;

Renaming the File

The code then renames the newly modified document. To do this, the code calculates a new file name by changing the extension; verifies that the output file exists and deletes it, if so; and finally moves the file from the old file name to the new file name.

If fileChanged Then
  Dim newFileName = Path.ChangeExtension(fileName, ".docx")
  If File.Exists(newFileName) Then
    File.Delete(newFileName)
  End If
  File.Move(fileName, newFileName)
End If
if (fileChanged)
{
  var newFileName = Path.ChangeExtension(fileName, ".docx");
  if (File.Exists(newFileName))
  {
    File.Delete(newFileName);
  }
  File.Move(fileName, newFileName);
}

The Sample Procedure

The following code example contains the complete sample procedure.

Public Sub WDConvertDOCMtoDOCX(ByVal fileName As String)
  Dim fileChanged As Boolean = False

  Using document As WordprocessingDocument =
    WordprocessingDocument.Open(fileName, True)

    Dim docPart = document.MainDocumentPart

    ' Look for the VBA part. If it is there, delete it.
    Dim vbaPart = docPart.VbaProjectPart
    If vbaPart IsNot Nothing Then
      docPart.DeletePart(vbaPart)

      docPart.Document.Save()

      ' Change the document type so that it no 
      ' longer thinks it is macro-enabled.
      document.ChangeDocumentType(WordprocessingDocumentType.Document)

      ' Track that the document has been changed.
      fileChanged = True
    End If
  End Using

  ' If anything goes wrong in this file handling,
  ' the code will raise an exception back to the caller.
  If fileChanged Then
    Dim newFileName = Path.ChangeExtension(fileName, ".docx")
    If File.Exists(newFileName) Then
      File.Delete(newFileName)
    End If
    File.Move(fileName, newFileName)
  End If
End Sub
public static void WDConvertDOCMtoDOCX(string fileName)
{
  bool fileChanged = false;

  using (WordprocessingDocument document = WordprocessingDocument.Open(fileName, true))
  {
    var docPart = document.MainDocumentPart;
      // Look for the VBA part. If it is there, delete it.
    var vbaPart = docPart.VbaProjectPart;
    if (vbaPart != null)
    {
      docPart.DeletePart(vbaPart);
      docPart.Document.Save();

      // Change the document type so that it no 
      // longer thinks it is macro-enabled.
      document.ChangeDocumentType(
        WordprocessingDocumentType.Document);

      // Track that the document has been changed.
      fileChanged = true;
    }
  }

  // If anything goes wrong in this file handling,
  // the code will raise an exception back to the caller.
  if (fileChanged)
  {
    var newFileName = Path.ChangeExtension(fileName, ".docx");
    if (File.Exists(newFileName))
    {
      File.Delete(newFileName);
    }
    File.Move(fileName, newFileName);
  }
}
Read It

The sample that is included with this Visual How To shows code that converts a document by using VBA code (and a DOCM extension) to a standard document (with a DOCX extension). To use the sample, install the Open XML SDK 2.0, available from the link listed in the Explore It section. The sample also uses a modified version of code included as part of a set of code examples for the Open XML SDK 2.0. The Explore It section also includes a link to the full set of code examples. Be aware that you can use the sample without downloading and installing the code examples.

The sample application shows only some available properties and methods that are provided by the Open XML SDK 2.0 that you can interact with when modifying document structure. For more information, investigate the documentation that is included with the Open XML SDK 2.0 Productivity Tool: Click the Open XML SDK Documentation tab in the lower-left corner of the application window, and search for the class that you have to study. Although the documentation does currently not include code examples, given the sample shown here and the documentation, you should be able to successfully modify the sample application.

See It

Watch the video

> [!VIDEO https://www.microsoft.com/en-us/videoplayer/embed/7ec201ef-fb89-4add-a666-d06ce3dbd3b9]

Length: 00:06:43

Click to grab code

Grab the Code

Explore It

About the Author
Ken Getz is a senior consultant with MCW Technologies. He is coauthor of ASP.NET Developers Jumpstart (Addison-Wesley, 2002), Access Developer's Handbook (Sybex, 2001), and VBA Developer's Handbook, 2nd Edition (Sybex, 2001).