Is it possible to reverse-engineer a toolbar button?

New Daddy
4StarLounger
Posts: 437
Joined: 05 Nov 2012, 20:02

Is it possible to reverse-engineer a toolbar button?

Post by New Daddy »

I have quite a few toolbar buttons that I've carried over from Word 2002 and probably before.
I still use them, but I'd like to find out what Word command or macro some of these buttons represent. (The purpose is to incorporate the underlying Word command in a new macro.)

Is there any way to reverse-engineer a toolbar button and find out which Word command/macro/font/style it represents? I tried Customization but couldn't find out the underlying command/macro/etc. of a button.

User avatar
HansV
Administrator
Posts: 78483
Joined: 16 Jan 2010, 00:14
Status: Microsoft MVP
Location: Wageningen, The Netherlands

Re: Is it possible to reverse-engineer a toolbar button?

Post by HansV »

If nobody else replies, I'll post a macro later.
Best wishes,
Hans

User avatar
bjsatola
NewLounger
Posts: 22
Joined: 24 Jul 2013, 17:55
Location: Worldly

Re: Is it possible to reverse-engineer a toolbar button?

Post by bjsatola »

Why don't you just record a macro and find out what the command call is?

Alternatively you can loop through the CommandBar collection and print all the names:

Code: Select all

Sub PrintCommandBarInfo()
   
    Dim cbr             As CommandBar           '// collection of CommandBar objects
    Dim ctrl            As CommandBarControl    '// collection of CommandBarControl objects contained in a CommandBar object
    
    '// Loop through each member (or index) of the CommandBar collection
    For Each cbr In Application.CommandBars

        Debug.Print "______________________________________________________________________"
        Debug.Print "CommandBar:= " & cbr.Name
        Debug.Print "CommandBars(Idx):= " & cbr.Index '// index of the CommandBars collection
        Debug.Print "Type:= " & VBA.IIf(cbr.BuiltIn, "Built-in", "**Custom")
        Debug.Print "______________________________________________________________________"

        '// Loop through each member (or index) of the CommandBarControl collection for the current CommandBar
        For Each ctrl In cbr.Controls
        
            With ctrl
            
                Debug.Print "----------------------------------------------------------------------"
                Debug.Print "Parent:= " & """" & .Parent.Name & """"
                Debug.Print "cbr.Controls(Idx):= " & .Index '// control index of the current CommandBar object
                Debug.Print "ID:= " & .ID '// internal (Microsoft) unique identifier
                Debug.Print "Type:= <" & .Type & "> " & GetControlTypeName(.Type)
                Debug.Print "Caption:= " & .Caption
                Debug.Print "TooltipText:= " & .TooltipText
                Debug.Print "Description:= " & .DescriptionText
                
            End With
            
        Next ctrl '// In cbr.Controls
        
        DoEvents

    Next cbr '// In Application.CommandBars

End Sub
It looks like the newer versions of Word changed from msoControls to msoControlTypes for the enumerations, which is why you also need the following function (which I used in the code above):

Code: Select all

Function GetControlTypeName(vType As MsoControlType) As String

    Dim sType As String

    Select Case vType
        Case Is = MsoControlType.msoControlActiveX
            sType = "ActiveX"
        Case Is = MsoControlType.msoControlAutoCompleteCombo
            sType = "Auto Complete Combo"
        Case Is = MsoControlType.msoControlButton
            sType = "Button"
        Case Is = MsoControlType.msoControlButtonDropdown
            sType = "Button Dropdown"
        Case Is = MsoControlType.msoControlButtonPopup
            sType = "Button Popup"
        Case Is = MsoControlType.msoControlComboBox
            sType = "Combo Box"
        Case Is = MsoControlType.msoControlCustom
            sType = "Custom"
        Case Is = MsoControlType.msoControlDropdown
            sType = "Dropdown"
        Case Is = MsoControlType.msoControlEdit
            sType = "Edit"
        Case Is = MsoControlType.msoControlExpandingGrid
            sType = "Expanding Grid"
        Case Is = MsoControlType.msoControlGauge
            sType = "Gauge"
        Case Is = MsoControlType.msoControlGenericDropdown
            sType = "Generic Dropdown"
        Case Is = MsoControlType.msoControlGraphicCombo
            sType = "Graphic Combo"
        Case Is = MsoControlType.msoControlGraphicDropdown
            sType = "Graphic Dropdown"
        Case Is = MsoControlType.msoControlGraphicPopup
            sType = "Graphic Popup"
        Case Is = MsoControlType.msoControlGrid
            sType = "Grid"
        Case Is = MsoControlType.msoControlLabel
            sType = "Label"
        Case Is = MsoControlType.msoControlLabelEx
            sType = "Label Ex"
        Case Is = MsoControlType.msoControlOCXDropdown
            sType = "OCX Dropdown"
        Case Is = MsoControlType.msoControlPane
            sType = "Pane"
        Case Is = MsoControlType.msoControlPopup
            sType = "Popup"
        Case Is = MsoControlType.msoControlSpinner
            sType = "Spinner"
        Case Is = MsoControlType.msoControlSplitButtonMRUPopup
            sType = "Split Button MRU Popup"
        Case Is = MsoControlType.msoControlSplitButtonPopup
            sType = "Split Button Popup"
        Case Is = MsoControlType.msoControlSplitDropdown
            sType = "Split Dropdown"
        Case Is = MsoControlType.msoControlSplitExpandingGrid
            sType = "Split Expanding Grid"
        Case Is = MsoControlType.msoControlWorkPane
            sType = "Work Pane"
        Case Else
            sType = "Unknown control type"
    End Select

    GetControlTypeName = sType
    
End Function
Then you should be able to call a specific control using one or a combo of the following:

(1.) Application.CommandBars(>>Name here<<).Controls(>>Name here<<)
(2.) Application.CommandBars(>>CommandBar Index here<<).Controls(>>CommandBarControl Index for the current CommandBar here<<)

Should be enough to get you started I think.

User avatar
HansV
Administrator
Posts: 78483
Joined: 16 Jan 2010, 00:14
Status: Microsoft MVP
Location: Wageningen, The Netherlands

Re: Is it possible to reverse-engineer a toolbar button?

Post by HansV »

Thanks! Saves me a lot of work... :smile:
Best wishes,
Hans

New Daddy
4StarLounger
Posts: 437
Joined: 05 Nov 2012, 20:02

Re: Is it possible to reverse-engineer a toolbar button?

Post by New Daddy »

How is this supposed be run?
I ran PrintCommandBarInfo as a macro, but nothing. (I did copy the GetControlTypeName function as well.)
bjsatola wrote:Why don't you just record a macro and find out what the command call is?

Alternatively you can loop through the CommandBar collection and print all the names:

Code: Select all

Sub PrintCommandBarInfo()
   
    Dim cbr             As CommandBar           '// collection of CommandBar objects
    Dim ctrl            As CommandBarControl    '// collection of CommandBarControl objects contained in a CommandBar object
    
    '// Loop through each member (or index) of the CommandBar collection
    For Each cbr In Application.CommandBars

        Debug.Print "______________________________________________________________________"
        Debug.Print "CommandBar:= " & cbr.Name
        Debug.Print "CommandBars(Idx):= " & cbr.Index '// index of the CommandBars collection
        Debug.Print "Type:= " & VBA.IIf(cbr.BuiltIn, "Built-in", "**Custom")
        Debug.Print "______________________________________________________________________"

        '// Loop through each member (or index) of the CommandBarControl collection for the current CommandBar
        For Each ctrl In cbr.Controls
        
            With ctrl
            
                Debug.Print "----------------------------------------------------------------------"
                Debug.Print "Parent:= " & """" & .Parent.Name & """"
                Debug.Print "cbr.Controls(Idx):= " & .Index '// control index of the current CommandBar object
                Debug.Print "ID:= " & .ID '// internal (Microsoft) unique identifier
                Debug.Print "Type:= <" & .Type & "> " & GetControlTypeName(.Type)
                Debug.Print "Caption:= " & .Caption
                Debug.Print "TooltipText:= " & .TooltipText
                Debug.Print "Description:= " & .DescriptionText
                
            End With
            
        Next ctrl '// In cbr.Controls
        
        DoEvents

    Next cbr '// In Application.CommandBars

End Sub
It looks like the newer versions of Word changed from msoControls to msoControlTypes for the enumerations, which is why you also need the following function (which I used in the code above):

Code: Select all

Function GetControlTypeName(vType As MsoControlType) As String

    Dim sType As String

    Select Case vType
        Case Is = MsoControlType.msoControlActiveX
            sType = "ActiveX"
        Case Is = MsoControlType.msoControlAutoCompleteCombo
            sType = "Auto Complete Combo"
        Case Is = MsoControlType.msoControlButton
            sType = "Button"
        Case Is = MsoControlType.msoControlButtonDropdown
            sType = "Button Dropdown"
        Case Is = MsoControlType.msoControlButtonPopup
            sType = "Button Popup"
        Case Is = MsoControlType.msoControlComboBox
            sType = "Combo Box"
        Case Is = MsoControlType.msoControlCustom
            sType = "Custom"
        Case Is = MsoControlType.msoControlDropdown
            sType = "Dropdown"
        Case Is = MsoControlType.msoControlEdit
            sType = "Edit"
        Case Is = MsoControlType.msoControlExpandingGrid
            sType = "Expanding Grid"
        Case Is = MsoControlType.msoControlGauge
            sType = "Gauge"
        Case Is = MsoControlType.msoControlGenericDropdown
            sType = "Generic Dropdown"
        Case Is = MsoControlType.msoControlGraphicCombo
            sType = "Graphic Combo"
        Case Is = MsoControlType.msoControlGraphicDropdown
            sType = "Graphic Dropdown"
        Case Is = MsoControlType.msoControlGraphicPopup
            sType = "Graphic Popup"
        Case Is = MsoControlType.msoControlGrid
            sType = "Grid"
        Case Is = MsoControlType.msoControlLabel
            sType = "Label"
        Case Is = MsoControlType.msoControlLabelEx
            sType = "Label Ex"
        Case Is = MsoControlType.msoControlOCXDropdown
            sType = "OCX Dropdown"
        Case Is = MsoControlType.msoControlPane
            sType = "Pane"
        Case Is = MsoControlType.msoControlPopup
            sType = "Popup"
        Case Is = MsoControlType.msoControlSpinner
            sType = "Spinner"
        Case Is = MsoControlType.msoControlSplitButtonMRUPopup
            sType = "Split Button MRU Popup"
        Case Is = MsoControlType.msoControlSplitButtonPopup
            sType = "Split Button Popup"
        Case Is = MsoControlType.msoControlSplitDropdown
            sType = "Split Dropdown"
        Case Is = MsoControlType.msoControlSplitExpandingGrid
            sType = "Split Expanding Grid"
        Case Is = MsoControlType.msoControlWorkPane
            sType = "Work Pane"
        Case Else
            sType = "Unknown control type"
    End Select

    GetControlTypeName = sType
    
End Function
Then you should be able to call a specific control using one or a combo of the following:

(1.) Application.CommandBars(>>Name here<<).Controls(>>Name here<<)
(2.) Application.CommandBars(>>CommandBar Index here<<).Controls(>>CommandBarControl Index for the current CommandBar here<<)

Should be enough to get you started I think.

User avatar
HansV
Administrator
Posts: 78483
Joined: 16 Jan 2010, 00:14
Status: Microsoft MVP
Location: Wageningen, The Netherlands

Re: Is it possible to reverse-engineer a toolbar button?

Post by HansV »

The code produces output in the Immediate window in the Visual Basic Editor. Press Ctrl+G in the Visual Basic Editor to activate this window.

The following version will create a new document and fill it:

Code: Select all

Sub PrintCommandBarInfo()
    Dim doc             As Document
    Dim cbr             As CommandBar           '// collection of CommandBar objects
    Dim ctrl            As CommandBarControl    '// collection of CommandBarControl objects contained in a CommandBar object
    
    Application.ScreenUpdating = False
    Set doc = Documents.Add
    '// Loop through each member (or index) of the CommandBar collection
    For Each cbr In Application.CommandBars

        doc.Content.InsertAfter "______________________________________________________________________"
        doc.Content.InsertParagraphAfter
        doc.Content.InsertAfter "CommandBar:= " & cbr.Name
        doc.Content.InsertParagraphAfter
        doc.Content.InsertAfter "CommandBars(Idx):= " & cbr.Index '// index of the CommandBars collection
        doc.Content.InsertParagraphAfter
        doc.Content.InsertAfter "Type:= " & VBA.IIf(cbr.BuiltIn, "Built-in", "**Custom")
        doc.Content.InsertParagraphAfter
        doc.Content.InsertAfter "______________________________________________________________________"
        doc.Content.InsertParagraphAfter

        '// Loop through each member (or index) of the CommandBarControl collection for the current CommandBar
        For Each ctrl In cbr.Controls
        
            With ctrl
            
                doc.Content.InsertAfter "----------------------------------------------------------------------"
                doc.Content.InsertParagraphAfter
                doc.Content.InsertAfter "Parent:= " & """" & .Parent.Name & """"
                doc.Content.InsertParagraphAfter
                doc.Content.InsertAfter "cbr.Controls(Idx):= " & .Index '// control index of the current CommandBar object
                doc.Content.InsertParagraphAfter
                doc.Content.InsertAfter "ID:= " & .ID '// internal (Microsoft) unique identifier
                doc.Content.InsertParagraphAfter
                doc.Content.InsertAfter "Type:= <" & .Type & "> " & GetControlTypeName(.Type)
                doc.Content.InsertParagraphAfter
                doc.Content.InsertAfter "Caption:= " & .Caption
                doc.Content.InsertParagraphAfter
                doc.Content.InsertAfter "TooltipText:= " & .TooltipText
                doc.Content.InsertParagraphAfter
                doc.Content.InsertAfter "Description:= " & .DescriptionText
                doc.Content.InsertParagraphAfter
                
            End With
            
        Next ctrl '// In cbr.Controls
        
        DoEvents

    Next cbr '// In Application.CommandBars
    Application.ScreenUpdating = True
End Sub
This version replaces the macro PrintCommandBarInfo posted by BJSatola. You need to keep the GetControlTypeName function.
Best wishes,
Hans

New Daddy
4StarLounger
Posts: 437
Joined: 05 Nov 2012, 20:02

Re: Is it possible to reverse-engineer a toolbar button?

Post by New Daddy »

Ok, it now works as a macro and outputs the result in a document.

But the only identifiable information in the result is the "ID" of the button. Caption, TooltipText and Description don't provide which command/style they represent. (The exception is macro. The result displays the underlying macro in Caption and TooltipText.)

User avatar
HansV
Administrator
Posts: 78483
Joined: 16 Jan 2010, 00:14
Status: Microsoft MVP
Location: Wageningen, The Netherlands

Re: Is it possible to reverse-engineer a toolbar button?

Post by HansV »

I'm afraid this is as much information as you can get. (If someone else has a better solution, I'll gladly concede my error)
Best wishes,
Hans

New Daddy
4StarLounger
Posts: 437
Joined: 05 Nov 2012, 20:02

Re: Is it possible to reverse-engineer a toolbar button?

Post by New Daddy »

HansV wrote:I'm afraid this is as much information as you can get. (If someone else has a better solution, I'll gladly concede my error)
I found this. I think the lists contain the Control IDs that your macro will reveal.

http://www.microsoft.com/en-us/download ... px?id=3582" onclick="window.open(this.href);return false;
Last edited by New Daddy on 04 Feb 2014, 22:02, edited 1 time in total.

User avatar
bjsatola
NewLounger
Posts: 22
Joined: 24 Jul 2013, 17:55
Location: Worldly

Re: Is it possible to reverse-engineer a toolbar button?

Post by bjsatola »

You just need to scroll over the buttons you are wanting to reference from within Word and then do an equivalent search within the *.doc file that was previously outputted (thanks Hans) to find the appropriate matches.

So you can search, for instance, "Save (Ctrl+S)"

And you quickly find that the control's ID:= 3, and turns up in more than one CommandBar collection (e.g. "Standard", "Outlook Send Mail" etc.).

It is just a control and can be re-used by other CommandBars, which is why you need to also reference the appropriate CommandBar that uses it to get the action that you are looking for.

At least that is my thinking... I did a few searches, and it seems to work for me.