How to clear the Clipboard when exiting Microsoft Word

This week a colleague approached me to consult about a problem he had encountered, where it was necessary to ensure that the Clipboard was empty when Microsoft Word exits. It was part of a legacy Word automation solution that he wasn’t in a position to change just yet, and it would crash if there was anything left on the clipboard.

Two approaches came to mind, one using a Word VBA Macro, the other using a VSTO add-in. Here is an attempt at a solution for the first approach – let’s hope it fixes the problem.

You can hook into events using Word VBA quite easily, either by creating a macro with a special name (reference: http://msdn.microsoft.com/en-us/library/bb208800.aspx), or by setting up event handlers. In this case, we will use a macro called AutoExit which is invoked “when you exit Word or unload a global template”. We’ll save the macro in a template file and have it loaded as a global template, so this event should be ideal for our purposes.

The first step is to load Word and get to the Visual Basic editor (press Alt-F11). Here, double-click on the ThisDocument entry in the project explorer to open up a code window:

Then, copy and paste the following code (which I will explain soon) into the code window you just opened:

'Events: http://msdn.microsoft.com/en-us/library/bb208800.aspx
Sub AutoExit()
    ClearClipboard
End Sub

Sub ClearClipboard()
    Dim MyData As Object
    ' source: http://akihitoyamashiro.com/en/VBA/LateBindingDataObject.htm
    Set MyData = CreateObject("new:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")
    MyData.SetText ""
    MyData.PutInClipboard
    Set MyData = Nothing
End Sub

Now save the document as a Word Macro-Enabled Document Template (.dotm) with a name such as ClearClipboardOnWordExit.dotm:

Place this document in the Word Startup folder. By default, it should be %appdata%\Microsoft\Word\Startup, but you can find out where it really is by going to Word Options, Advanced, scrolling to the bottom and clicking on File Locations:

Word will load any templates in this folder as global templates when it starts.

That’s about it! Now to test it, open Word afresh, type something and copy it to the clipboard. Then exit Word and check to confirm that the clipboard no longer has the text you just copied.

Explanation of the code

  • The name of the macro, AutoExit, makes it get called when Word is closing:
    Sub AutoExit()
        ClearClipboard
    End Sub
    
  • Then we create a DataObject, which is part of the Microsoft Forms 2.0 Object Library. However, instead of adding a reference to it, I prefer using late binding so I found this page that describes how to do it using the clsid: http://akihitoyamashiro.com/en/VBA/LateBindingDataObject.htm

        Dim MyData As Object
        Set MyData = CreateObject("new:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")
    
  • Using this object, we set a blank string to the clipboard, effectively clearing it:
        MyData.SetText ""
        MyData.PutInClipboard
    

Get email Headers from an Outlook MailItem

While working on a VSTO add-in for Microsoft Outlook, I came across the need to access the headers of an email, to parse out X-CustomProperty tags that were put in by an application that sent the emails. However, I couldn’t find a Headers property in the Outlook object model, so below is an attempt to create one.

The Regex used is courtesy of John Gietzen’s answer on this stackoverflow question.

using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.Office.Interop.Outlook;

public static class MailItemExtensions
{
    private const string HeaderRegex =
        @"^(?<header_key>[-A-Za-z0-9]+)(?<seperator>:[ \t]*)" +
            "(?<header_value>([^\r\n]|\r\n[ \t]+)*)(?<terminator>\r\n)";
    private const string TransportMessageHeadersSchema =
        "http://schemas.microsoft.com/mapi/proptag/0x007D001E";

    public static string[] Headers(this MailItem mailItem, string name)
    {
        var headers = mailItem.HeaderLookup();
        if (headers.Contains(name))
            return headers[name].ToArray();
        return new string[0];
    }

    public static ILookup<string, string> HeaderLookup(this MailItem mailItem)
    {
        var headerString = mailItem.HeaderString();
        var headerMatches = Regex.Matches
            (headerString, HeaderRegex, RegexOptions.Multiline).Cast<Match>();
        return headerMatches.ToLookup(
            h => h.Groups["header_key"].Value,
            h => h.Groups["header_value"].Value);
    }

    public static string HeaderString(this MailItem mailItem)
    {
        return (string)mailItem.PropertyAccessor
            .GetProperty(TransportMessageHeadersSchema);
    }
}

Sample usage:

string[] preparedByArray = mailItem.Headers("X-PreparedBy");
string preparedBy;
if (preparedByArray.Length == 1)
    preparedBy = preparedByArray[0];
else 
    preparedBy = "";

string allHeaders = mailItem.HeaderString();

Edit 2011/08/05:
Thanks to Rob for the heads-up. I updated the code to return a Lookup instead of a Dictionary – this handles the case of multiple headers with the same name.

How to filter select list options

Here’s a jQuery extension method to filter the elements of a select list (option tags). It binds to a textbox, and as you type in the textbox the select list gets filtered to match what you are typing.

jQuery.fn.filterByText = function(textbox, selectSingleMatch) {
  return this.each(function() {
    var select = this;
    var options = [];
    $(select).find('option').each(function() {
      options.push({value: $(this).val(), text: $(this).text()});
    });
    $(select).data('options', options);
    $(textbox).bind('change keyup', function() {
      var options = $(select).empty().scrollTop(0).data('options');
      var search = $.trim($(this).val());
      var regex = new RegExp(search,'gi');

      $.each(options, function(i) {
        var option = options[i];
        if(option.text.match(regex) !== null) {
          $(select).append(
             $('<option>').text(option.text).val(option.value)
          );
        }
      });
      if (selectSingleMatch === true && 
          $(select).children().length === 1) {
        $(select).children().get(0).selected = true;
      }
    });
  });
};

Parameters:

  • textbox
    This could be a jQuery selector, a jQuery object, or a DOM object.
  • selectSingleMatch
    This is optional, if you set it to true, when the filtered list includes only one item, that item will be automatically selected.

For example:

$(function() {
  $('#select').filterByText($('#textbox'), true);
});  

Live example (or in a new window):

You can play around with it on jsbin: http://jsbin.com/egogeh/edit

What it does:

When you invoke the function on a select object, it finds all child option tags and saves their text and values into an array. This array is saved to the select object itself as a HTML5 custom data attribute, called data-options. Then, when a change or keyup event fires on the associated textbox, the select list is emptied, and for any entries in the array that match the search text a new option element is created.

Edit 2012-10-15: Added ScrollTop(0) to improve the way it works with long lists, thanks to a comment by xarel below.

Using Open XML SDK to get Custom Properties from a Word document

I stumbled across a library that I didn’t realize was out there, for working with Microsoft Office documents. It only works with the newer Office 2007 and 2010 files (and 2003 with a compatibility pack), i.e. those using the Open XML standard.

Download and install the Open XML SDK 2.0 for Microsoft Office: http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=5124.

I got the second, smaller file:

Open XML SDK 2.0 for Microsoft Office

Add a reference to DocumentFormat.OpenXml and WindowsBase to your project:

You can now programmatically access Office documents, without the need to have Microsoft Office installed or any Interop DLLs. This works with Word, Excel and PowerPoint (using the OpenXML WordprocessingML, SpreadsheetML and PresentationML).

For example, to get the custom properties of a Word document:

public static Dictionary<string, string> GetCustomPropertiesOfWordDocument
                                                  (string filename)
{
    using (var package = WordprocessingDocument.Open(filename, false))
    {
        var properties = new Dictionary<string, string>();
        foreach (var property in package.CustomFilePropertiesPart
            .Properties.Elements<CustomDocumentProperty>())
        {
            properties.Add(property.Name, property.VTLPWSTR.Text);
        }
        return properties;
    }
}

In this example, you would need to add some error handling around line 9 (property.VTLPWSTR.Text) as your property may be a different type or null.

When deploying your solution, you need to include DocumentFormat.OpenXml.dll with your application. You can set Copy Local to True in the properties for the reference, and it will be copied to your output folder when you compile the project:

Download a sample project here.

How to hide the dotted border outline on focused elements in HTML, using CSS

While working on a web application for data entry, I had to scour the net for a way to hide the dotted border that appears when an element is focused on a web page. Here are my findings.

First, the obligatory disclaimer – I do understand that the dotted border is for accessibility purposes and should be left in place under normal circumstances. However, in this case we already had a replacement in place – when an element receives focus it is styled differently, using a very distinct background color. And this applies to all elements, regardless of whether they were selected by mouse or keyboard. So the dotted border is redundant, and somewhat distracting.

To further clarify the question, these are the dotted borders I refer to:
save-outline and cancel-outline

While the solution needed to be usable across browsers, the target browsers where well defined – modern versions of Firefox and Chrome, and IE 7 or newer. I first came across this question on stackoverflow.com which pointed me to using outline:none. Then this one helped with Firefox compatibility. And then I saw this post which provides a number of different techniques.

I ended up using the following CSS, which seems to cover most bases. As I didn’t see this combination on other sites I thought I would post it myself. It doesn’t apply to the select element in Firefox and IE7. Testing was done on Windows XP.

/* hide the dotted lines around an element when it receives focus */
* { _noFocusLine: expression(this.hideFocus=true); } /* ie7 */
::-moz-focus-inner {border:0;}	                     /* firefox */
:focus {outline:none;}                               /* ie8, chrome, etc */