Edit OOXML with VBA – Cool Code

For Office users, the closest thing to a “programming language of the people” is VBA. It’s not too hard to get started, there are gobs of help information from a good search, and the results are immediate. But VBA’s abilities haven’t expanded as its environment has changed. This has become abundantly clear with current versions of Office, where task panes and the Windows-version Backstage haven’t been included in the VBA object model. Many want to edit OOXML with VBA, but Microsoft prefers to shuffle you off to the Open XML SDK programmed with C# to do that job.

Fortunately, we’re on the case at Brandwares. We collaborated with programmer Jan Karel Pieterse to develop a PowerPoint version of his macro set that edits Excel OOXML. We’re making this freely available as a download so you can get the benefit of this.

Let me apologize to my macOS readers. I really try to provide solutions that work cross-platform, but this macro set relies on Windows system calls.

I’ll be honest, this isn’t the most elegant OOXML editing solution. The macro set unzips the OOXML to its component files, gives you the opportunity to edit the XML using VBA string manipulation, then rezips the OOXML to a usable PowerPoint file. The unzip/rezip operations are fairly slow, especially with large files. It’s not something you can use in a real-time editing situation.

One of Brandwares’s specialties is converting legacy presentations to new themes/templates. Often, there are OOXML mismatches that make reused slides retain artifacts or formatting from the old decks. We solve these issues with macro convertors that take a folder full of old decks and transform them into new presentations with new branding. This macro set is great for that.

Edit OOXML with VBA: a Peek Under the Hood

THe file contains 3 VBA modules and 1 class module. Module modConvert is the only one you need to modify. In it, Sub MainVBAOperations does the actual work of opening files, saving as a work file, calling the XML process, saving the modified file and deleting the work file. This is also where you would do any additional VBA processing. As one example, after you modify the XML of a slide master or layout, you have to reset the slide based on it to display the changes. MainVBAOperations is where you would do this.

The other Sub is ProcessXML. Here’s where you unzip the file being modified, open different XML parts for find and replace processes, followed by a rezip of all files back to a working file. The sample code in this module shows a typical revision to the idx numbers of placeholders, a common requirement of legacy presentation conversions and one that can’t be done with the PowerPoint interface.

The module modDisplay, by Shyam Pillai, provides the PowerPoint equivalent of the Application.Screenupdating command that exists in Word VBA. Useful to prevent the screen flashing and jumping as files are processed, it also helps speed code execution. modUNC by Randy Birch, assists with file management.

Jan Karel Pieterse wrote the class module clsEditOpenXML that does the heavy lifting of unzipping and rezipping the document to be modified and reading and writing the XML.

As noted in the code, You are free to use this code within your own applications, add-ins, documents etc but you are expressly forbidden from selling or otherwise distributing this source code without prior consent. This includes both posting free demo projects made from this code as well as reproducing the code in text or html format.

Converting Legacy Presentations

We use often use this macro set to update old (legacy) presentations with a new design. Successful updating requires meeting 5 criteria, please read this article for more details: Legacy Slides – Best Practices. As noted on that page, the 5th requirement is that placeholder idx numbers in the OOXML must match on the old and new layouts. There’s nothing in PowerPoint’s interface that allows you to set idx number, but this macro set allows you to do just that. The pre- and post-processing sections of the macros allow you to set the the other 4 parameters for each slide layout. Click here to download it.

The following advice is particular to presentation conversion. It’s routine that slide masters and layouts will be changed in that process. Then, to apply those changes to the actual slides in a presentation, the slides must be reset, as if you pressed the Home>Reset button in a presentation. Resetting slides wipes out character-based formatting. If a user has applied bold or italic or an underline to particular text, that all will disappear. It’s important to notify your client of this. To make an exact update would require a painstaking construction of a multi-dimensional array for each placeholder on each slide that would record all character-based formatting, then restore it after the update, for which you would have to charge many times as much as for the basic conversion work.

Brandwares is a world leader in presentation updating and conversion. We’re available for presentation assessments, to identify potential problems. We have multiple techniques for seamless re-use of legacy presentations. Contact us when you’re redesigning to ensure your new template will reuse your old slides without a hiccup.

Office AppleScript Reference – Cool Code

For Office for Mac users, AppleScript remains a useful tool in scripting Office documents. VBA for Mac has poor links to the operating suystem. In Windows, a programmer can easily make system calls to the OS. In macOS, the analogous system calls are not documented by either Apple or Microsoft. A few intrepid programmers have posted about macOS equivalents, but the information is sporadic and very hard to find. macOS’s built-in AppleScript can solve many of these issues, so I’m posting the best available Office AppleScript Reference.

This is old Microsoft documentation from 2008 that they’ve removed from their site. I don’t guarantee this, or offer support, I’m just posting it to make it available to interested programmers.

Office AppleScript Reference: MacScript vs AppleScriptTask

Ron de Bruin is a European programmer and MVP (Microsoft Valued Professional) who has written lots of good information about programming Office on a Mac. While he writes mostly about Excel, VBA is so similar across Office that most of the information also applies to Word and PowerPoint. Here’s his page on using the AppleScriptTask command in Office 2016 and later to call AppleScripts from a VBA macro: AppleScriptTask in Mac Office 2016 or higher.

Office AppleScript Reference: Conditional Compilation

To create a macro that can run on different versions of Office for Mac, or on both Windows and Mac, you’ll need to use conditional compilation. This uses #If – #Else – #End if statements to run a set of commands only in certain conditions. Here is Microsoft’s page on conditional statements for different Mac versions: Differentiate between Office for Mac versions at compile time. This MS reference page shows all available conditional compiler constants: Compiler constants.

Click here to download: Office AppleScript Reference.

Every AutoShape – Cool Code

There are more AutoShapes in Office than appear in the user interface. Over time, Microsoft has quietly added to the collection stored in Office. Many of the more recent shapes are used in SmartArt files, while others have no current use that I can detect. But for anyone who hacks XML or codes VBA will find this week’s download or every autoshape a useful reference.

I’m preparing to start a series on custom SmartArt files. This is a deep topic: SmartArt XML is a programming language with a Frankenstein syntax. But the starting point for any language is to get the names right. SmartArt and VBA both reference the AutoShapes collection in Office, but they use different names for the same objects. Many of the same shapes are seen in the Shapes dropdown of Office programs, but those names are also different. The main source of the VBA names are from this page: MsoAutoShapeType enumeration (Office), while the XML names come from this out-of-date listing: SmartArt AutoShapes.

So, for my own sanity, I created a Word document showing an example of each shape, along with it’s name in XML, in VBA and in the user interface. This has smoothed out my workflow, and it may help you as well.

Listing of every AutoShape

For any non-interface shapes, you can insert them into a document with code analogous to this. For PowerPoint:

Sub MakeShape()
  ActivePresentation.Slides(1).Shapes.AddShape msoShapeTrapezoid, 24, 24, 144, 144
End Sub

Change the bolded word to the shape name in the VBA MsoShapeType Name column.

Some shapes have specialized VBA commands, like callouts:

Sub MakeShape()
  ActivePresentation.Slides(1).Shapes.AddCallout msoCalloutTwo, 24, 24, 144, 144
End Sub

Callouts led me to a discovery about legacy versions. msoCalloutOne gives exactly the same result as msoCalloutTwo in current versions of Office.That seemed odd, so I ran the same macro in PowerPoint 2003 (I still have it installed for its macro recorder). In that version, msoCalloutOne creates a callout with a vertical leading line that can be moved up and down, but not at an angle. Presumably, MS found that useless and deprecated it.

Download the Word document showing every autoshape here.

Uniform Rounded Corners – Cool Code

A client sent a design for a Word template that had lots of boxes and photos with uniform rounded corners. Not an unreasonable request, but Office doesn’t do that well. In PowerPoint, Word and Excel, rounded corners are proportional to the size of the shape. Making them uniform manually is picky and time-consuming. But with a dash of VBA, we can make the job easy.

The Math

As a round-cornered shape gets larger, the corner radius increases as well, in proportion to the shape size. Since we want to keep the radius the same size, we need to create a formula that makes a smaller number as the height and width increase. We need an inverse number! The simplest way to create an inverse is to divide 1 by the measurements. Then, we need a number to set the radius size: a constant. The formula looks like this: (1 / (Shape.Height + Shape.Width)) * RadiusFactor. And you thought you’d never need that high school math!

Here’s VBA code that will work in Excel, Word and PowerPoint on a selection of round-cornered boxes:

Sub RoundedCorners()
  Dim oShape As Shape, RadiusFactor!
  RadiusFactor! = 50
  For Each oShape In ActiveWindow.Selection.ShapeRange
    With oShape
      If .AutoShapeType = msoShapeRoundedRectangle Then
        .Adjustments(1) = (1 / (oShape.Height + oShape.Width)) * RadiusFactor!
      End If
    End With
  Next oShape
End Sub

Uniform Rounded Corners for the Whole Document

To run this on a whole presentation, document or workbook, we need to customize the routine for each Office program. Here’s the Excel version:

Sub RoundAllXLCorners()
  Dim oWorksheet As Worksheet, oShape As Shape, RadiusFactor!
  RadiusFactor! = 50
  For Each oWorksheet In ActiveWorkbook.Worksheets
    For Each oShape In oWorksheet.Shapes
      With oShape
        If .AutoShapeType = msoShapeRoundedRectangle Then
          .Adjustments(1) = (1 / (oShape.Height + oShape.Width)) * RadiusFactor!
        End If
      End With
    Next oShape
  Next oWorksheet
End Sub

To do the same in PowerPoint

Sub RoundAllPPCorners()
  Dim oSlide As Slide, oShape As Shape, RadiusFactor!
  RadiusFactor! = 50
  For Each oSlide In ActivePresentation.Slides
    For Each oShape In oSlide.Shapes
      With oShape
        If .AutoShapeType = msoShapeRoundedRectangle Then
          .Adjustments(1) = (1 / (oShape.Height + oShape.Width)) * RadiusFactor!
        End If
      End With
    Next oShape
  Next oSlide
End Sub

And finally, for Word

Sub RoundAllWDCorners()
  Dim oShape As Shape, RadiusFactor!
  RadiusFactor! = 50
  For Each oShape In ActiveDocument.Shapes
    With oShape
      If .AutoShapeType = msoShapeRoundedRectangle Then
        .Adjustments(1) = (1 / (oShape.Height + oShape.Width)) * RadiusFactor!
      End If
    End With
  Next oShape
End Sub
Before: Rounded Corners, but not Uniform
Rounded Corners, but not Uniform

The Word version is a little simpler because a Word document is one big object, while Excel and PowerPoint both have multiple objects for each worksheet and slide, respectively. But the similarites point out that when you’re searching online for VBA code, finding something for a different program and modifying it can be a huge time-saver. By far, Excel has way more code written for it, so Excel VBA sites can be a fruitful source for Word and PowerPoint code ideas.

After: Uniform Rounded Corners
Uniform Rounded Corners

These macros have been tested under both Windows and macOS and work well under both.

To use these macros with other shapes, please see my article Every AutoShape – Cool Code for a downloadable reference file showing all AutoShapes along with their XML and VBA names. Then replace msoShapeRoundedRectangle with the mso shape name you need.

Content Controls for macOS – Cool Code

Content Controls are an improved form of fillable form field, but the Word for Mac user interface doesn’t include Content Controls for macOS. I show you how to sidestep this limitation to be able to create superior fillable forms.

Microsoft Word for Windows has three different types of fields to use for fillable forms. The oldest of these are Legacy Form Fields, which exist in every version of Word, Windows and Mac, but not DOS, back to the dawn of time. Legacy form fields require the document to be protected for forms, which closes down many formatting options even on unprotected sections. These are the only form fields available in the Mac program interface. Windows version also have ActiveX controls. These generally have a crude appearance. They don’t work at all on Mac versions of Word.

Finally, we have the newest type of form fields, Content Controls. These were introduced on Windows in Word 2007. The collection of controls was expanded a little in 2010 and a little more in 2013. Word 2008 and 2011 can’t use or create them, but in Word 2016 for Mac, the program started honoring Content Controls created in Windows, so they work as expected on both platforms. Unfortunately, the tools to add and modify them are still not in the program.

Content Controls for macOS: What Are They?

While Legacy Form Fields have only 3 types (Text field, Checkbox and Dropdown), there are 9 (or 10, depending on how you count) types of Content Controls. Here’s a look at each type:

Plain Text and Rich Text
Plain Text and Rich Text Appearance

These look identical on the screen. The screen shot shows what they look like unselected (top) and selected (bottom). The Plain Text control is most similar to the Legacy Text form field. All the text has the same formatting and you can’t include other types of content other than text. By comparision, the Rich Text control allows selected text to be bold or italic or a different font. You can insert tables and pictures and even other Content Controls into Rich Text controls.

Picture Control Appearance

Finally! A true picture placeholder for Word! The picture can be set when the control is created. There are options to allow the user to replace it or not. Or it can be left blank (as shown) for the user to add a picture later. You can change the shape from a square using Picture Format>Picture Styles. This choice can also add a soft edge or other visual effects to a photo that the user inserts later.

It’s worth noting that Picture Content Controls only work as inline pictures. To float them and wrap text around them, you need to place the CC in a table cell or frame or some other object that allows text wrapping. These controls come in at 2″ square, but you can set numeric dimensions on the Picture Format tab. (Thanks to Timothy Rylatt for the tips!)

Building Block
Building Block Control Appearance

This is the only Content Control that doesn’t work yet on a Mac. While Building Blocks in the Windows version of Word is the same technology as AutoText on the Mac, Microsoft hasn’t gone the extra mile to make it work on a Mac. The macro further down the page sets the control to work with AutoText (as you almost always should if your template is being distributed to others). But when you click on the control’s AutoText tab, a dropdown list of AutoText entries doesn’t appear like it does in the Windows version.

At least if your Windows client needs it in their template, you can create it on a Mac. AutoText works by grabbing content from the active document’s attached template. If you’re sending a template with AutoText content, the Content Control will find that. If you’re sending a document instead of a template, the Content Control will grab AutoText from the user’s Normal.dotm file.

Check Box
Checkbox Appearance

Similar to the Legacy Check Box form field, but with the added advantage that the filled symbol can be set to other symbols than an X. This control was added in Word 2010, so don’t include one for a client using 2007.

But still no radio buttons? Give me a break, Microsoft! Using elaborate VBA kludges, it’s possible to make a set of checkboxes operate like radio buttons with both Legacy and Content Control versions. But it shouldn’t be so hard!

Combo Box and Drop-Down
ComboBox and Dropdown Appearance

Another similar pair of controls. The Drop-Down is most similar to the Legacy Drop-Down (which MS often refers to as a Combo Box, just to confuse everyone). The Drop-Down restricts users to choosing an item on the list, while a Combo Box allows a user to enter a value that is not on the list.

Date Picker
Date Picker Appearance

While Legacy Text fields have a date option, it’s only to enforce date formatting after a user tries to enter a date. The Date Picker Content Control is way cooler, it’s pops a little calendar for the user to choose a date visually. Handy!

Repeating Section
Repeating Section Appearance

…And the prize for longest prompt text goes to this control. Added to Word 2013, so it won’t work for 2007 and 2010 clients. Clicking on the plus sign in the bottom right corner duplicates the content. There are already a couple of ways to do this, so I think this is strictly for user convenience. Unlike the others, this control spans the page by default, probably because of the long prompt.


No screen capture for this one, because it’s more of an operation than a control. Applying this to a selected set of Content Controls will group them together, so they can be copied as a unit. You can’t include a Rich Text control, which can also be used as a group. If you select controls, then get an error when grouping that a control is “partially covered”, it will usually be about the topmost control. Add a carriage return before, include it when you select, then run the Group macro.

Simple Controls from Keyboard shortcuts

Fortunately, the VBA object model for Word 2016 and 2019 for Mac includes Content Controls. If you’re creating forms for your own use, there is a simple way to create basic Content Controls on your Mac:

  1. In Word, choose Tools>Customize Keyboard
  2. Scroll Categories and pick All Commands
  3. Scroll Commands and pick ContentControlCheckBox
  4. Click inside the Press new keyboard shortcut field and type a key combination. Word will inform you if that combination is already in use. If there is no conflict, or an insignificant conflict, click on the Assign button. Finally, click on OK. The Control key is a good modifier, because all existing keyboard shortcuts with Control are duplicates of ones that also use the Command key.
  5. Click on your document where you would like to see a checkbox, then use the keyboard shortcut. Viola! Instant checkbox!

Repeat the steps for the other Content Control commands. It’s not a bad idea to make a sample document with Content Controls and their shortcuts, for later reference. BTW, keyboard shortcuts are the only customization that can access Content Controls. Equivalent commands for the QAT and Ribbon haven’t been added as of this writing.

Content Controls for macOS: Complex Controls for Clients

The keyboard shortcuts are fine for plain vanilla controls. But they’re so basic, some are useless. Sure you can insert a Drop-Down or Combo Box, but they don’t have any items in the list and there’s no easy way to add them. What we need is more fine-grained control so we can set all the same options that a Windows user can. This is possible by inserting them using VBA.

If you never used macros in Word, start by making the Developer tab visible on the Ribbon. Choose Word>Preferences>View and check Show developer tab. The tab becomes visible when you close the Prefs panel.

On the Developer tab, click on the Visual Basic button (Word doesn’t run Visual Basic, but a very similar language called Visual Basic for Applications. This is VBA, not VB, but why would MS care about an accurate button title?). The VBA Editor opens. In the top left corner is a windows called Projects. If you have a fresh installation, you’ll only see Normal here. If you have Add-ins installed, there will be other project names. Select Normal.

From the macOS menu, choose Insert>Module. Call it ContentControls. A new module page is opened where you can insert macro code. Copy and paste the following code onto that page:

Sub AddRichTextCC()
  Dim oCC As ContentControl
  Set oCC = ActiveDocument.ContentControls.Add(wdContentControlRichText, Selection.Range)
  Set oCC = Nothing
End Sub
Sub AddPlainTextCC()   Dim oCC As ContentControl   Set oCC = ActiveDocument.ContentControls.Add(wdContentControlText, Selection.Range)   With oCC     .MultiLine = True   End With   Set oCC = Nothing End Sub
Sub AddPictureCC()   Dim oCC As ContentControl   Set oCC = ActiveDocument.ContentControls.Add(wdContentControlPicture, Selection.Range)   Set oCC = Nothing End Sub
Sub AddBuildingBlockCC()   Dim oCC As ContentControl   Set oCC = ActiveDocument.ContentControls.Add(wdContentControlBuildingBlockGallery, Selection.Range)   With oCC     .BuildingBlockType = wdTypeAutoText     .BuildingBlockCategory = "General"   End With   Set oCC = Nothing End Sub
Sub AddCheckBoxCC()
  Dim oCC As ContentControl
  Set oCC = ActiveDocument.ContentControls.Add(wdContentControlCheckBox, Selection.Range)
  With oCC
    .Checked = False
    .SetCheckedSymbol CharacterNumber:=&HFE, Font:="Wingdings"
    .SetUncheckedSymbol CharacterNumber:=&HA8, Font:="Wingdings"
  End With
  Set oCC = Nothing
End Sub
Sub AddComboBoxCC()   Dim oCC As ContentControl   Set oCC = ActiveDocument.ContentControls.Add(wdContentControlComboBox, Selection.Range)   With oCC     .DropdownListEntries.Add "Choose an item.", value:=""     .DropdownListEntries.Add "Item 1"     .DropdownListEntries.Add "Item 2"   End With   Set oCC = Nothing End Sub
Sub AddDropDownCC()   Dim oCC As ContentControl   Set oCC = ActiveDocument.ContentControls.Add(wdContentControlDropdownList, Selection.Range)   With oCC     .DropdownListEntries.Add "Choose an item.", value:=""     .DropdownListEntries.Add "Item 1"     .DropdownListEntries.Add "Item 2"   End With   Set oCC = Nothing End Sub
Sub AddDatePickerCC()
  Dim oCC As ContentControl
  Set oCC = ActiveDocument.ContentControls.Add(wdContentControlDate, Selection.Range)
  With oCC
    .DateCalendarType = wdCalendarWestern
    .DateDisplayFormat = "MMMM d, yyyy"
    .DateDisplayLocale = wdEnglishUS
  End With
  Set oCC = Nothing
End Sub
Sub AddRepeatingSectionCC()   Dim oCC As ContentControl   Set oCC = ActiveDocument.ContentControls.Add(wdContentControlRepeatingSection, Selection.Range)   With oCC     .AllowInsertDeleteSection = True     .RepeatingSectionItemTitle = "Repeating Section Item"   End With   Set oCC = Nothing End Sub
Sub AddGroupCC()   Dim oCC As ContentControl   Set oCC = ActiveDocument.ContentControls.Add(wdContentControlGroup, Selection.Range)   Set oCC = Nothing End Sub

Use the Tools>Customize Keyboard command to assign these macros keyboard shortcuts. You can also add them to the Quick Access Toolbar. If you subscribe to Office 365 or have Office 2019, you can also add them to the Ribbon.

If you take a close look at the code, you’ll see there are additional lines on some that allow you to set options for that type of control. As one example, the Date Picker includes options for the calendar type, date format and date language. In use, you would alter these options to suit the client, then run the macro to add a control with those options set.

Content Controls for macOS: Setting the Options

Here’s where you can really customize the Content Controls. These are generic options that can be set for all Content Controls. Rather than bulk up each individual macro, here’s one macro to set the extra options. Set the options in code, select a Content Control that you’ve already inserted, then run the macro. If you’re inserting many controls that have a common setting, like .LockControl = True, add that line to the code for inserting the control to avoid extra steps.

Sub SetOptions()
  If Selection.Information(wdInContentControl) Then
    With Selection.ParentContentControl
      'Sets the appearance to the original bounding box look. For the newer tags look, use wdContentControlTags
      'If you don't need to change a setting, comment it out before running the macro
      .Appearance = wdContentControlBoundingBox
      'Sets the color of the control to a preset color       .Color = wdColorWhite
      'Sets whether the Content Control can be deleted or not. If the control has had .Temporary = True applied, you must reverse that property to True before applying this.       .LockContentControl = True
      'Sets whether the contents of the Content Control can be deleted or not.       .LockContents = False
      'Sets the placeholder text or prompt for the control       .SetPlaceholderText , , "Default Text"
      'Sets the Content Control tag property       .Tag = "Tag"
      'If this is set to true, the Content Control will be removed when the contents are edited.       .Temporary = False
      'Sets the title of the Content Control. This appears on a tab above the control when it is activated.       .Title = "Title"     End With   Else     MsgBox "Please select a Content Control to change its options."   End If End Sub

Utility Macros

The following macros perform essential functions that may only be occasionally required. First, a pair to toggle all Content Controls between the older Bounding Box appearance and the newer Tags look. The only control that currently displays as a tag in macOS is the Group Content Control. All others appear as plain text in a mysterious field. As a consequence, don’t use this setting for forms to be used on a Mac. Save it for Windows clients:

Sub BoundingBoxAppearance() 'Sets all Content Controls in the document to a bounding box appearance
  Dim oCC As ContentControl
  For Each oCC In ActiveDocument.ContentControls
    oCC.Appearance = wdContentControlBoundingBox
  Next oCC
  Set oCC = Nothing
End Sub
Sub TagAppearance() 'Sets all Content Controls in the document to the tag appearance.   Dim oCC As ContentControl   For Each oCC In ActiveDocument.ContentControls     oCC.Appearance = wdContentControlTags   Next oCC   Set oCC = Nothing End Sub

This macro deletes the existing list of a Combo Box or Drop-Down and replaces it with a new list.

Sub ReviseComboBoxOrDropDownList()
  If Selection.Information(wdInContentControl) Then
    If Selection.ParentContentControl.Type = wdContentControlComboBox Or Selection.ParentContentControl.Type = wdContentControlDropdownList Then
      With Selection.ParentContentControl
        .DropdownListEntries.Add "Choose an item.", value:=""
        .DropdownListEntries.Add Text:="List Item 1", value:="1"
        .DropdownListEntries.Add Text:="List Item 2", value:="2"
      End With
    End If
    MsgBox "Please select a Combo Box or Drop-Down Content Control to change its list."
  End If
End Sub

Finally, one to ungroup a Group Content Control. Switch to Tag view to see Groups, they’re invisble in Bounding Box view. Don’t try to select all group items before ungrouping, it will generate an error. Instead, single-click anywhere inside the group:

Sub UnGroupCC() 'Ungroups a group control
  If Selection.Information(wdInContentControl) Then
  End If
End Sub

For more in-depth reference on these macros, please see Microsoft’s documentation.

Now you’re equipped to send your client top-quality fillable forms with the latest technology. So when your client asks if you can create Content Controls, instead of saying “Huh?”, you can reply confidently “No problem!”