Click here to Skip to main content
14,775,690 members
Articles » Platforms, Frameworks & Libraries » COM / COM+ » ActiveX
Posted 18 May 2006


67 bookmarked

A Word add-in to syntax highlight selected text

Rate me:
Please Sign up or sign in to vote.
4.77/5 (12 votes)
2 Feb 2007CPOL
A Word addin to syntax highlight selected text. The toolbar is permanent, with a transparent button icon.

Sample Image - Addin_Shot.gif


The Syntax Highlight add-in is a COM add-in for Microsoft Word. Through a COM add-in, we can add a menu item or toolbar button onto Word, implementing special functions which we need.

The add-in on this page can change the color or background color of a selected text. How to do this is not fixed. Anyone can define a new rule for changing color, by implementing the functions which are declared in the interface header file. This add-in provides an open method to operate with text in Word. If you are interested in parsing text, this add-in can help you parse text too.

This software consists of a main module (sntxaddn.dll) and a set of highlight rules.


Basically, as an add-in, the principle of this software is the same as the one in: Building an Office2K COM add-in with VC++/ATL, which is an add-in for Outlook.

So, this article will mostly describe the special points of this add-in itself.

Interesting & Special Points

1. Permanent, not temporary CommandBar

A temporary command bar will be removed when Word is closed, and will be re-created when Word is opened. If you drag the newly created command bar to a position, the position will be lost after Word is re-opened. Instead, a permanent command bar will not be removed when Word is closed.

But a new problem is emitted: "When to remove the command bar if the user want to uninstalls it?" My solution: "Remove the command bar in DllUnregisterServer."

Create permanent, not temporary CommandBar:
CComPtr <_CommandBars> spCmdBars = wordApp->
CComPtr <CommandBar> spNewCmdBar = NULL;
// attach command bar if already exists
HRESULT hr = spCmdBars->get_Item(_variant_t(RSTR(
    IDS_SYNTAX_BAR)), &spNewCmdBar);
if( FAILED(hr) || spNewCmdBar == NULL )
    // New Create if not exists
    CComVariant vName (RSTR(IDS_SYNTAX_BAR));
    CComVariant vPos  (msoBarFloating);
    CComVariant vTemp (VARIANT_FALSE); //menu is NOT temporary 
    spNewCmdBar = spCmdBars->Add(vName, vPos, vEmpty, vTemp);
Attach old button if exists:
// attach buttons
int btncnt = spBarControls->GetCount();
for(i=btncnt; i>=1; i--)
    CComPtr <CommandBarControl> spNewBar = 
    CComQIPtr <_CommandBarButton> spButton( spNewBar );
    _bstr_t tag = spButton->GetTag();
    CSyntaxModule * pSyntax = NULL;
    for(int j=0; j<MAX_BUTTONS; j++)
        if( m_pSyntax[j] == NULL )
        if( m_pSyntax[j]->m_szSyntaxName == tag )
            pSyntax = m_pSyntax[j];
    if( pSyntax != NULL )
        // keep reference to button disp
        m_spButtons[nAttachIndex ++] = spButton;
        DispEventAdvise(nAttachIndex, (IDispatch*)spButton);
        pSyntax->m_bAttached = TRUE;
        bUpdated = TRUE;
Remove command bar in 'DllUnregisterServer':
// Attach to Running Word instance
// or Create New Word Application instance
CComPtr <_Application> CWordSntxAddnApp::AttachRunningWord()
    HRESULT hr;
    CLSID   clsid;
    hr = ::CLSIDFromProgID(L"Word.Application", &clsid);
        return NULL;
    IUnknown  * pUnknown = NULL;
    hr = ::GetActiveObject(clsid, NULL, &pUnknown);
    if( !FAILED(hr) )
        return CComQIPtr <_Application> ( pUnknown );
        COleDispatchDriver ddrv;
        return CComQIPtr <_Application> (ddrv.m_lpDispatch);
VOID CWordSntxAddn::RemoveCommandBar(CComPtr <_Application> & wordApp)
    CComPtr <_CommandBars> spCmdBars = wordApp->GetCommandBars();
    CComPtr <CommandBar> spSyntaxCmdBar = NULL;
    HRESULT hr = 
    if( !FAILED(hr) && spSyntaxCmdBar != NULL )
        // Save
        CComQIPtr <Template> custom( wordApp->GetCustomizationContext() );

2. Transparent button icon

In order to be compatible with Office 2000, I used 'PasteFace' to transfer a button icon. According to Microsoft documentation, I was going to use "Toolbar Button Face" and "Toolbar Button Mask" as the clipboard format names.

But I met a problem, 'PasteFace' failed to transfer the transparent button icon if the Office software is not the English version. Indeed, the clipboard format name should be localized if Office software is the German or Chinese version etc.

I asked in many forums, but nobody was able to say anything about it. Afterwards, I found a way to determine the format names by myself.

// to determine localized 'format name'
// Init
_tcscpy(m_szFaceFormatName, _T("Toolbar Button Face"));
_tcscpy(m_szMaskFormatName, _T("Toolbar Button Mask"));
// loop
UINT  format = 0, n = 0, fmtsize[2] = {0};
TCHAR fmtnames[2][100] = {0};
while( (format = ::EnumClipboardFormats(format)) != 0 )
    if( format > 17 && GetClipboardFormatName(format, 
                              fmtnames[n], 100) != 0 )
        fmtsize[n++] = ::GlobalSize(::GetClipboardData(format));
        if( n >= 2 ) break;
if( fmtsize[0] > fmtsize[1] )
    if( fmtnames[0][0] )
       _tcscpy(m_szFaceFormatName, fmtnames[0]);
    if( fmtnames[1][0] )
       _tcscpy(m_szMaskFormatName, fmtnames[1]);
    if( fmtnames[1][0] )
        _tcscpy(m_szFaceFormatName, fmtnames[1]);
    if( fmtnames[0][0] )
        _tcscpy(m_szMaskFormatName, fmtnames[0]);

3. Backup and restore clipboard data around using 'PasteFace'

The 'CopyFace' and 'PasteFace' operations will destroy any old clipboard data, which is copied into the clipboard before Word is opened, and the old clipboard data may be what you are going to paste into Word.

Then, backup the old clipboard data before the toolbar button's Create process:

if( ! ::OpenClipboard(NULL) )
    return FALSE;
UINT format = 0;
while( (format = ::EnumClipboardFormats(format)) != 0 )
    ClipboardData data;
    data.m_nFormat = format;

    // skip some formats
    if( format == CF_BITMAP || format == CF_METAFILEPICT ||
        format == CF_PALETTE || format == CF_OWNERDISPLAY ||
        format == CF_DSPMETAFILEPICT || format == CF_DSPBITMAP ||
        ( format >= CF_PRIVATEFIRST && format <= CF_PRIVATELAST ) )

    // get format name
    if( format <= 14 )
        data.m_szFormatName[0] = 0;
    else if( GetClipboardFormatName(format, 
                  data.m_szFormatName, 100) == 0 )
        data.m_szFormatName[0] = 0;

    // get handle
    HANDLE hMem = ::GetClipboardData( format );
    if( hMem == NULL )
    // copy handle
    switch( format )
        data.m_hData = 
            ::CopyMetaFile((HMETAFILE)hMem, NULL);
            int    size = ::GlobalSize(hMem);
            LPVOID pMem = ::GlobalLock( hMem );
            data.m_hData   = ::GlobalAlloc( GMEM_MOVEABLE | 
                                            GMEM_DDESHARE, size );
            LPVOID pNewMem = ::GlobalLock( data.m_hData );
            memcpy(pNewMem, pMem, size);

Restore the clipboard after the toolbar button's creation is completed:

if( ! ::OpenClipboard(NULL) )
    return FALSE;
POSITION pos = m_lstData.GetHeadPosition();
while( pos != NULL )
    ClipboardData & data = m_lstData.GetNext( pos );
    UINT format = data.m_nFormat;
    if( data.m_szFormatName[0] != 0 )
        UINT u = RegisterClipboardFormat( data.m_szFormatName );
        if( u > 0 ) format = u;
    ::SetClipboardData( format, data.m_hData );

4. Interface of the custom syntax rule

This add-in can load custom rules dynamically. The interface header file is:

// API
#define SYNTAX_MOD_API __declspec(dllexport)
// extern "C"
#ifdef __cplusplus
    extern "C" {
// Caption
// Tooltip ( Optional )
// Button Face ( Optional )
// Parse
// Nextpos
BOOL SYNTAX_MOD_API GetNextPos(INT & pos, INT & len);
// Color
BOOL SYNTAX_MOD_API GetColor(INT & color);
// Background Color ( Optional )
BOOL SYNTAX_MOD_API GetBgColor(INT & bgcolor);

#ifdef __cplusplus

How to implement 'Syntax Rule' easily

Each 'syntax rule' is a single dll file which implements those API's above.

I have provided a 'static library' (lib_syntax.lib) to help you to write 'syntax rule'. This 'static library' has implemented the key API's: 'Parse', 'GetNextPos', and 'GetColor'. Everything you need to do is to provide a 'regular expression pattern' and a 'color definition map'. For example:

// regular expression pattern
LPCWSTR pattern = L"(?<upper>[A-Z]+)|(?<lower>[a-z]+)|(?<number>[0-9]+)";

// color
ColorMap map[] =
    { L"upper" , RGB(0xff, 0, 0) },
    { L"lower" , RGB(0, 0xff, 0) },
    { L"number", RGB(0, 0, 0xff) },

// entrance
                       DWORD ul_reason_for_call, 
                       LPVOID lpReserved
    if( ul_reason_for_call == DLL_PROCESS_ATTACH )
        // when initialization

    return TRUE;

The main point about the 'regular expression pattern' is that: I used 'Named group' of 'regular expression'.

DEELX regular expression engine for C++ supports 'Named group', so I used DEELX in the lib_syntax.lib. DEELX regular expression engine is discussed at, and introduced at DEELX homepage: .

Please pay attention to the 'run-time library' of your dll project and the lib_syntax.lib library. They must be the same before they can be linked successfully.

References and Acknowledgements


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

sswater shi
Software Developer (Senior)
China China
Begin coding from basic, since 1994. Interested in coding and database and website constructing.
My website: - Regular Expression Laboratory
The easiest regex engine:

Comments and Discussions

QuestionCauses Word 2010 to crash Pin
Member 964871812-Aug-12 9:58
MemberMember 964871812-Aug-12 9:58 
AnswerRe: Causes Word 2010 to crash Pin
sswater shi12-Aug-12 14:23
Membersswater shi12-Aug-12 14:23 
GeneralMy vote of 5 Pin
Wonkey6-May-11 5:20
MemberWonkey6-May-11 5:20 
GeneralProposed feature: config files Pin
JARivera17-Feb-11 4:54
MemberJARivera17-Feb-11 4:54 
GeneralRe: Proposed feature: config files Pin
sswater shi17-Feb-11 18:58
Membersswater shi17-Feb-11 18:58 
QuestionDoes it support Office 2007? Pin
Jeason Zhao17-Aug-10 22:23
MemberJeason Zhao17-Aug-10 22:23 
AnswerRe: Does it support Office 2007? Pin
sswater shi18-Aug-10 5:15
Membersswater shi18-Aug-10 5:15 
General_commandbarbutton Image problem Pin
Member 354972315-Apr-09 20:30
MemberMember 354972315-Apr-09 20:30 
GeneralSet button Image Pin
Member 354972314-Apr-09 3:26
MemberMember 354972314-Apr-09 3:26 
GeneralRe: Set button Image Pin
sswater shi14-Apr-09 5:00
Membersswater shi14-Apr-09 5:00 
AnswerSet image on the button Pin
Zhefu Zhang6-Aug-08 19:39
MemberZhefu Zhang6-Aug-08 19:39 
GeneralRe: Set image on the button Pin
sswater shi16-Oct-08 0:43
Membersswater shi16-Oct-08 0:43 
GeneralRe: Set image on the button Pin
Member 354972315-Apr-09 1:56
MemberMember 354972315-Apr-09 1:56 
QuestionProblem with Pin
programvinod26-Jul-07 0:10
Memberprogramvinod26-Jul-07 0:10 
AnswerRe: Problem with Pin
Oren K.22-Oct-07 4:55
MemberOren K.22-Oct-07 4:55 
AnswerRe: Problem with Pin
sswater shi16-Oct-08 0:55
Membersswater shi16-Oct-08 0:55 
GeneralRemove Buttons from "Standard" Menu Bar Pin
klarz25-Jul-07 4:52
Memberklarz25-Jul-07 4:52 
AnswerRe: Remove Buttons from "Standard" Menu Bar Pin
sswater shi25-Jul-07 6:02
Membersswater shi25-Jul-07 6:02 
Questionno matching symbolic information found? Pin
Yakie27-Mar-07 14:13
MemberYakie27-Mar-07 14:13 
AnswerRe: no matching symbolic information found? Pin
sswater shi27-Mar-07 15:43
Membersswater shi27-Mar-07 15:43 
QuestionRe: no matching symbolic information found? Pin
Yakie6-Apr-07 13:58
MemberYakie6-Apr-07 13:58 
AnswerRe: no matching symbolic information found? Pin
sswater shi6-Apr-07 16:23
Membersswater shi6-Apr-07 16:23 
QuestionChinese Resources Pin
ianormy8-Jun-06 2:05
Memberianormy8-Jun-06 2:05 
AnswerRe: Chinese Resources Pin
sswater shi8-Jun-06 5:29
Membersswater shi8-Jun-06 5:29 
QuestionHow did you automatically install the toolbar? Pin
ianormy7-Jun-06 4:31
Memberianormy7-Jun-06 4:31 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.