A colleague, who is an experienced Visio tutor, asked me how to hook VBA macros to the Fluent UI Ribbon. He figured that it must\should be easy, but he can’t see where it is done. Well, this question has resonance because a plea was made to the Microsoft Visio team at our recent MVP Conference that this often asked for feature should be made easy for the macro developer. Now, I must admit that I have been so busy writing .Net Visio Add-Ins and following the pattern for the Fluent UI in VSTO C# code, that I had not appreciated just how convoluted the calling of VBA from a Ribbon button is. So, I thought I would offer a way of doing this in a simple (I hope!) way.
I will show how this can be done for a Visio drawing or template that contains VBA macros, and how this can be also be used for a Visio stencil that contains the code. I know that some macro developers put their code into drawings, but I would always recommend putting the code into a stencil, if the code is to be used by multiple drawings.
The Visio team’s Insight Blog has some useful background at http://blogs.msdn.com/b/visio/archive/2010/02/24/user-interface-extensibility-in-visio-2010.aspx , but it only has one fleeting mention of VBA macros:
For VBA, you simply provide the contents of a RibbonX XML as a string directly to Visio through the CustomUI property.
So, what does that mean? How do you actually do it?
Well, there is some sample code in the Visio 2016 SDK.
I used this code as a starting point to develop my classes and module that I have included in the download ( see Ribbon Macros.vsd ) for this article. The principle is that the opening of the document will load the custom UI, which will then be removed when the document is closed. I have included the public subs LoadRibbon and UnloadRibbon so that you can set the UI without closing and opening the document repeatedly.
The only change that is required to the code if it is moved into a stencil, id for the ThisDocument parameters to be replaced with Nothing. This will have the effect of enabling any code that is in the stencil whilst it is open. Of course, code in the stencil can be used for any open drawings.
There are four areas in the Fluent UI that can call VBA code:
- The Ribbon
- The Backstage View
- The Context Menus
- The Commands
I have provided an example for each. If you want to read about the principles of Fluent UI design, then you could start here Microsoft Fluent Design , but I am only showing basic buttons in this example. Feel free to expand the range of controls to suit your requirements…
Another useful resource is Office 2016 Help Files : Office Fluent User Interface Control Identifier . This is a series of Excel files that list all of the built-in control Ids for all of the Microsoft Office documents, and one of them, VisioControls.xlsx, lists those for Visio.
I decided to create some methods in the CustomUI module to return XML snippets for various parts of XML string required to build the Ribbon xml:
I included carriage return line feeds (vbCrlf) and tabs (vbTab) in the XML to make it easier to understand.
All of these XML snippets are called from the getRibbonXML method, so you only need to edit this function to modify the UI. In fact, I have included four parameters in the header of getRibbonXML to make it easier to switch on/off each of the four Fluent UI elements:
Private Function getRibbonXML(ByVal includeCommands As Boolean, _
ByVal includeRibbonTab As Boolean, ByVal includeBackstage As Boolean, _
ByVal includeContextMenus As Boolean) As String
This function is called from IRibbonExtensibility_GetCustomUI method in the Ribbon class.
The Ribbon
You can add groups to existing tabs in the ribbon, but you will most probably want to add your own tab with groups and buttons on it. In my example, I have created a new tab, labeled Custom Ribbon Tab, with a single group, labeled Custom Group, containing a large button, Macro 1; two small buttons, Macro 2 and Macro 3; and a split button, Macro 4.
In fact, the split button contains two menu items, Macro 4 and Macro 5.
All of the buttons have an icon, see the Office 2010 Add-In : Icons Gallery at http://www.microsoft.com/downloads/en/details.aspx?displaylang=en&FamilyID=2d3a18a2-2e75-4e43-8579-d543c19d0eed , and each has a supertip (a longer description) that is displayed on mouse over. Note that the FriendlyName, My custom Fluent UI, is entered in the CustomUIStart method in the CustomUI module.
The code that creates this button can be found in getRibbon method of the Ribbon class:
'Open the Ribbon element strGetRibbonXML2 = getRibbonBegin 'Open the Tab element strGetRibbonXML2 = strGetRibbonXML2 & getTabBegin(False, "tab1", "Custom Ribbon Tab") 'Open the Group element strGetRibbonXML2 = strGetRibbonXML2 & getGroupBegin(False, "group1", "Custom Group") 'Add custom buttons as required strGetRibbonXML2 = strGetRibbonXML2 & getButton( _ "customMacro1", "Macro 1", "This is macro 1", "GroupSynchronizeWithSite", True) strGetRibbonXML2 = strGetRibbonXML2 & getButton( _ "customMacro2", "Macro 2", "This is macro 2", "GroupViewsInfoPath", False) strGetRibbonXML2 = strGetRibbonXML2 & getButton( _ "customMacro3", "Macro 3", "This is macro 3", "PostReply", False) 'Open the split button element strGetRibbonXML2 = strGetRibbonXML2 & getSplitButtonBegin("customSplit1") 'Open the menu element strGetRibbonXML2 = strGetRibbonXML2 & getMenuBegin("customMenu1") 'Add custom buttons as required strGetRibbonXML2 = strGetRibbonXML2 & getButton( _ "customMacro4", "Macro 4", "This is macro 4", "VisioDiagramGallery", False) strGetRibbonXML2 = strGetRibbonXML2 & getButton( _ "customMacro5", "Macro 5", "This is macro 5", "VisioTransparency", False) 'Close the menu element strGetRibbonXML2 = strGetRibbonXML2 & getMenuEnd 'Close the split button element strGetRibbonXML2 = strGetRibbonXML2 & getSplitButtonEnd 'Close the Group element strGetRibbonXML2 = strGetRibbonXML2 & getGroupEnd 'Close the Tab element strGetRibbonXML2 = strGetRibbonXML2 & getTabEnd 'Close the Ribbon element strGetRibbonXML2 = strGetRibbonXML2 & getRibbonEnd
This produces the XML snippet:
<ribbon>
<tabs>
<tab id="tab1" label="Custom Ribbon Tab">
<group id="group1" label="Custom Group">
<button id="customMacro1" label="Macro 1" supertip="This is macro 1" size="large" imageMso="GroupSynchronizeWithSite" onAction="OnAction"/>
<button id="customMacro2" label="Macro 2" supertip="This is macro 2" imageMso="GroupViewsInfoPath" onAction="OnAction"/>
<button id="customMacro3" label="Macro 3" supertip="This is macro 3" imageMso="PostReply" onAction="OnAction"/>
<splitButton id="customSplit1">
<menu id="customMenu1">
<button id="customMacro4" label="Macro 4" supertip="This is macro 4" imageMso="VisioDiagramGallery" onAction="OnAction"/>
<button id="customMacro5" label="Macro 5" supertip="This is macro 5" imageMso="VisioTransparency" onAction="OnAction"/>
</menu>
</splitButton>
</group>
</tab>
</tabs>
</ribbon>
The Backstage View
I have given an example for two columns in the Backstage View, in a new tab labeled Custom Tab. I have included a large button, labeled BS Macro 1 and; and two normal buttons, labeled BS Macro 2 and BS Macro 3.
The code that creates this button can be found in getRibbon method of the Ribbon class:
'Open the backstage element
strGetRibbonXML3 = getBackstageBegin
'Open the tab element
strGetRibbonXML3 = strGetRibbonXML3 & getTabBegin(False, "tab2", "Custom Tab")
'Open the column element
strGetRibbonXML3 = strGetRibbonXML3 & getBackstageColumnBegin(One)
strGetRibbonXML3 = strGetRibbonXML3 & vbTab & getGroupBegin(False, "group2", "Custom Group 2")
strGetRibbonXML3 = strGetRibbonXML3 & getBackstagePrimaryItemBegin
'Add custom buttons as required
strGetRibbonXML3 = strGetRibbonXML3 & vbTab & vbTab & getButton( _
"customBMacro1", "BS Macro 1", "This is bs macro 1", "GroupSynchronizeWithSite", False)
'Close the primaryitem element
strGetRibbonXML3 = strGetRibbonXML3 & getBackstagePrimaryItemEnd
'
Close the group element
strGetRibbonXML3 = strGetRibbonXML3 & vbTab & getGroupEnd
'Close the column element
strGetRibbonXML3 = strGetRibbonXML3 & getBackstageColumnEnd(One)
'Open the column element
strGetRibbonXML3 = strGetRibbonXML3 & getBackstageColumnBegin(Two)
'Open the group element
strGetRibbonXML3 = strGetRibbonXML3 & vbTab & getGroupBegin(False, "group3", "Custom Group 3")
'Open the topitems element
strGetRibbonXML3 = strGetRibbonXML3 & getBackstageTopItemsBegin
'Add custom buttons as required
strGetRibbonXML3 = strGetRibbonXML3 & vbTab & vbTab & getButton( "customBMacro2", "BS Macro 2", "This is bsmacro 2", "GroupViewsInfoPath", False) strGetRibbonXML3 = strGetRibbonXML3 & vbTab & vbTab & getButton( "customBMacro3", "BS Macro 3", "This is bsmacro 3", "PostReply", False)
'Close the topitems element
strGetRibbonXML3 = strGetRibbonXML3 & getBackstageTopItemsEnd
'Close the group element
strGetRibbonXML3 = strGetRibbonXML3 & vbTab & getGroupEnd
'Close the column element
strGetRibbonXML3 = strGetRibbonXML3 & getBackstageColumnEnd(Two)
'Close the tab element
strGetRibbonXML3 = strGetRibbonXML3 & getTabEnd
'Close the backstage element
strGetRibbonXML3 = strGetRibbonXML3 & getBackstageEnd
This produces the XML snippet:
<backstage>
<tab id="tab2" label="Custom Tab">
<firstColumn>
<group id="group2" label="Custom Group 2">
<primaryItem>
<button id="customBMacro1" label="BS Macro 1" supertip="This is bs macro 1" imageMso="GroupSynchronizeWithSite" onAction="OnAction"/>
</primaryItem>
</group>
</firstColumn>
<secondColumn>
<group id="group3" label="Custom Group 3">
<topItems>
<button id="customBMacro2" label="BS Macro 2" supertip="This is bsmacro 2" imageMso="GroupViewsInfoPath" onAction="OnAction"/>
<button id="customBMacro3" label="BS Macro 3" supertip="This is bsmacro 3" imageMso="PostReply" onAction="OnAction"/>
</topItems>
</group>
</secondColumn>
</tab>
</backstage>
The Context Menus
The second tab, named contextmenus, of the VisioControls.xlsx Excel workbook lists the possible contexts for the menus. In my example, I have used ContextMenuShape so that the button, labeled My Button, will be available on the Action Menu whenever a 2D shape is selected.
The code that creates this button can be found in getRibbon method of the Ribbon class:
'Open the context menus group element
strGetRibbonXML4 = getContextMenusBegin '
Open the context menu element
'See the contextmenus worksheet in C:\Office 2010 Developer Resources\Documents\Office2010ControlIDs\VisioControls.xlsx
strGetRibbonXML4 = strGetRibbonXML4 & getContextMenuBegin("ContextMenuShape")
'Include any menu buttons required
strGetRibbonXML4 = strGetRibbonXML4 & getButton( _ "customContextMacro1", "My Button", "This is my context menu macro", _ "MindMapChangeTopic", False) '
Close the context menu element
strGetRibbonXML4 = strGetRibbonXML4 & getContextMenuEnd
'Close the context menus group element
strGetRibbonXML4 = strGetRibbonXML4 & getContextMenusEnd
This produces the XML snippet:
<contextMenus>
<contextMenu idMso="ContextMenuShape">
<button id="customContextMacro1" label="My Button" supertip="This is my context menu macro" imageMso="MindMapChangeTopic" onAction="OnAction"/>
</contextMenu>
</contextMenus>
The Commands
You can disable or re-purpose built-in commands too. For example, I have provided an example of disabling the Bold button and re-purposing the Copy command …
… so that it runs some custom code:
The code that creates this button can be found in getRibbon method of the Ribbon class:
'Open the Commands element
strGetRibbonXML1 = getCommandsBegin
'Add Command actions as required
'You can disable commands
strGetRibbonXML1 = strGetRibbonXML1 & getDisableCommand("Bold")
'You can re-purpose commands
strGetRibbonXML1 = strGetRibbonXML1 & getRedirectCommand("Copy")
'Close the Commands element
strGetRibbonXML1 = strGetRibbonXML1 & getCommandsEnd
This produces the XML snippet:
<commands>
<command idMso="Bold" enabled="false"/>
<command idMso="Copy" onAction="CommandOnAction"/>
</commands>
Calling Your VBA Code
You may have noticed that the onAction attributes in all of the above XML have the value OnAction or CommandOnAction. I think that centralising the calls for the buttons and the commands like this, makes it easier to follow. I show the OnAction method below, and the CommandOnAction is very similar. So, all you have to do is ensure that you have a Case option for the ID of any control (button) that you have in the Ribbon XML.
Public Sub OnAction(ByVal control As IRibbonControl)
' OnAction
'
' Abstract - This method is a callback specified in the custom UI XML file.
' It is called by Visio when the associated button defined in the XML is pressed.
'
' Parameters
' control The Ribbon UI control that was activated
' To execute a VBA macro, use the Document.ExecuteLine method.
' For example: Document.ExecuteLine("ThisDocument.HelloWorld");
Select Case control.ID
Case "customMacro1"
'Call to your code
ThisDocument.ExecuteLine "HelloWorld" Exit Sub
Case "customMacro2"
'Call to your code
Case "customMacro3"
'Call to your code
Case "customMacro4"
'Call to your code
Case "customMacro5"
'Call to your code
Case "customContextMacro1"
'Call to your code
End Select
MsgBox control.ID, vbInformation, "OnAction"
End Sub
Conclusion
I hope that this provides an easy (well, not quite as easy as I would have liked) way for you to hook your VBA macros into the ribbon.
You have four different areas in the Fluent UI that you can utilise, so, have fun.
Adi says
Thank you very much for taking the time to document this but… Oh my goodness, it’s open heart surgery! How about I just pray that they fix this in the next release! Phew…
Julien says
Thanks for this! It has been enormously helpful for my own Visio VBA solution.
Do you have any experience using custom icons with the technique described above? It seems I may have uncovered a bug where none of my image callbacks (loadImage or getImage) are ever being called by Visio (even after Invalidate!), leaving me high in dry in automation land.
Any thoughts/experience with this? Thanks!
j.
davidjpp says
I haven’t tried the image callback yet in VBA but this Excel blog http://www.rondebruin.nl/getimage.htm appears to have it working ok.
Bernie says
David, great blogs, glad I stumbled across them, this one in particular.
I’m not sure that this entry’s results are exactly what I had hoped to achieve; I would like to associate/ deliver “trigger” code (_documentOpened, _beforeDocumentClose) to insert r remove the custom ribbon within a stencil, and would hope to only have that available if the stencil item is actually added to an open diagram, making it “one of ours”. The code to invoke, I would like to deliver via a VS2010 com addin that would be installed in the client environment. That way, only those explicitly installing and enabling the addin and further, opening and pasting an item from our macro-enabling stencil to “embed/ enable” the macro code, would see the additional ribbon elements and only in those documents for which it was valid. Reopening such a document with that pasted stencil item would automatically reopen the additional Ribbon UI elements and customizations, regardless if the stencil was open at the time or not.
Is this viable or in line with this capability?
davidjpp says
You are mixing a COM Addin and Macros?
Why not do a VSTO addin for the lot?
Have you looked at Persistent Events?
http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=12365
http://office.microsoft.com/en-us/visio-help/HV080351058.aspx
Bernie says
I had thought the vsto would be present and shown for any document, and the stencil macros would provide a per-document means of presenting the custom UI. These were initial ideas when attempting to address a complex problem with a new UI that I am still trying to understand with regards to integration with code (com/ vba). How to best address my solution, I am still formulating the approach, thus I am very thankful for your blog and for these additional links -I will look into each to see if part of my puzzle pops. I do have VS2010 for the vsto/ com addin development; I too would prefer a single point of delivery but my above perception had me thinking otherwise.
Thank you again.
Bernie says
the 1st link to the 2010 sdk -the example code I followed in there to build the visio-ribbon customization test vsto had ‘dead code’ and the intent, active UI only for a specific document, does not reflect in the result because no code is set to callback to the SDK’s sample “DemoCustomUIStart/Stop” and this SDK hadn’t been updated since march ’10.
what in the SDK were you inkling at, is there a specific section I should look into re this approach? Thanks again
davidjpp says
I think that you should be able to add PersistentEvents to you Stencil (I normally add it to my Template), then you can listen for the opening and closing of your stencil from your Add-in, and then modify the UI to suit.
If you could use the PersistentEvent tool, then the Event = DocumentOpened, Target Addon = QueueMarkerEvent, Arguments = /solution=PEvtTest /cmd=1 (or similar) … you should then be able to listen for the QueueMarkerEvent
Bernie says
excellent- I’ll give that a try and let you know of the success. Thank you for the guidance.
How do I “add” PersistentEvents to a stencil? you add to a template, same difference? pro/con to stencil vs. template?
davidjpp says
I just tried adding Persistent Events to a stencil, then checked them with the following VBA code:
For Each evt In doc.EventList
If evt.Persistent = True Then
Debug.Print evt.Persistable, evt.Persistent, evt.Action, evt.Event, evt.Target, evt.TargetArgs, doc.Name
End If
Next
Next
Unfortunately, opening a stencil did not fire the persistent event like it does when opening a normal document does.
…. I’m still pondering…..
davidjpp says
Public Sub StartListening()
Set mapp = Visio.Application
End Sub
Public Sub StopListening()
Set mapp = Nothing
End Sub
Private Sub mapp_BeforeDocumentClose(ByVal Doc As IVDocument)
If Doc.DocumentSheet.CellExists(“User.MySpecialStencil”, Visio.VisExistsFlags.visExistsAnywhere) Then
Debug.Print Doc.Name, “closed”
End If
End Sub
okay, my thoughts are that your addin should listen to the Application DocumentOpened and BeforeDocumentClosed events, and add a user cell into the documentsheet.
Then you can check for the presence of this User cell when ever a document is opened or closed.
The following is VBA, but you should use AddAvise with vb.net or just Add with C# :
Dim WithEvents mapp As Visio.Application
Private Sub mapp_DocumentOpened(ByVal Doc As IVDocument)
If Doc.DocumentSheet.CellExists(“User.MySpecialStencil”, Visio.VisExistsFlags.visExistsAnywhere) Then
Debug.Print Doc.Name, “opened”
End If
End Sub
Bernie says
thanks David, I had found the SDK tool as you replied… the above code will help greatly, along the same lines I had thought, where dropping a stencil-specific item into the document would ‘validate’ it as customUI using doc (you mention user cell above),
Bernie says
I found in the VB macro editor, in the “this document” codepage, the attribute/ property PersistsEvents. I am guessing I set this to True. I have not found what you allude to as the “PersistentEvent tool”… still looking.
davidjpp says
When you install the SDK, you will get an extra group SDK Tools on the Devloper tab (assuming that you have found the Run in Developer mode switch in the File \ Options \ Advanced )
brrrknee says
David, of the 3 tools, only the “event monitor” starts, the Persistent Events and Print Shapesheet tools do nothing. macro recording doesn’t capture clicks in the ribbon or its commands either. what might be conflicting on my environment?
I’m just trying to find a way to simply -as commandbuttons/ commandbars were -locate and ‘click’ the orgchart “relayout” and a few other org chart buttons from my VBA code. I cannot believe the dearth of info re the programmatic access to the ribbon, but there are plenty of examples to customize it. I see one example where someone is forced to use the MS IAccessible interface of oleacc.dll; why is such a simple task taken to such an excruciating level of complexity to perform in the new UI? What am I missing here?
Thank you for the assistance.
davidjpp says
I had a problem recently where my Persistent Events and Print SHapeSheet tools were not working either … I had installed the 64bit version of the SDK accidently, and installing the 32bit version fixed that.
I found this blog article – http://www.wordarticles.com/Shorts/RibbonVBA/RibbonVBADemo.php which has code to give you access to the Ribbon from VBA – the only change I had to do in Visio was to insert Application. in front of CommandBars(“Ribbon”).
As far as running the Org Chart addon from VBA … I guess you could if you knew the arguments for each command.
brrrknee says
David, I am not “running the Org Chart addon” from VBA, but navigating the org chart Command Bar/ Buttons to apply layouts and relayout after resizing the elements. very simple with command bars and buttons, 5-10 lines, no need to know any APIs. However, now it seems to “navigate to and press” an org chart button, I have to write large amounts of code in C/C++ to use the newer MS UI Automation (or the many lines of VBA code referenced to use MSAA IAccessible). I find no VB support for this newer accessibility interface, MS stating that UIA will replace the MSAA IAccessible interface. Not having access to the accessibility interface from the Office support VBA is difficult to grasp for rationale. The example code you link to above, is a VBA use of the “decade old (MS’ description to steer folks to the UIA)” MSAA IAccessible interface, and I may have to just go with that MSAA for the near term. I had looked at that example before, but was hunting for a VBA implementation of the UIA ‘newer’ technology. Apparently MS is not looking to support its office VBA products in this fashion. Thank you for your help, I am much better informed through you!
Bernie says
ahhh, in the SDK… 🙂
brrrknee says
I’m running 64b office on a 64b system w win7 64b. therefore I loaded the 64b SDK; it isn’t working as noted above; does the SDK have a 32b limitation for those 2 tools?
brrrknee says
David, just noticed in the active add-on tab, the ‘working’ active add-on “monitor events” is an .exe, while the other two active ‘non responsive’ add-ons “Print Shape Sheet…” and Persistent Events…” are both .VSLs is there a setting I might have turned off disabling VSLs?
Shaul says
Hi David,
Great post!
I can’t download your example, maybe you can re-upload it?
Thanks in advance
Shaul
musoitank says
Please re-upload the .vsd example – someone?
frankki says
I really love this (working!) sample, but I struggle in getting the split button large.
Could it be that you forgot a variable for that or is it me just being blind?
Thanks for a short advise
davidjpp says
size=”large” ?
brrrknee says
moreover, this example is written off of stubs of the old interface, and nowhere is there a pure example written using the new test/automation UI. why cannot the MS/ MVP teams see that stating the new UI is the way of the future development would make using such old-form examples a wary step for us? We still need to access buttons and commands. HOW DO WE DO IT using purely the new test/automation approach and not have to rely upon past techniques?
davidjpp says
MVPs are not a team … we are all independent (and unpaid) Visio enthusiasts.
I’m not sure what you are saying?
If you are building a system that needs to be subjected to a test harness, then you need to have separation of concerns.
All of the UI elements should be distinct from any calls that you make, thus you should be able to test the calls directly, without simulating clicking or selecting any UI elements.
This is one of the reasons why I like to use the MVVM model with WPF … even within Visio add-ins.
Hooking in the Ribbon within a VIsio add-in is far easier than the VBA code that I offered, but I recognise that some people want to use the ribbon with VBA too.
brrrknee says
I understand that the MVPs are not ‘a team’ that was my mistake in this description.
I don’t want to have to do any of this, but since I had a simple command-bar /button access in a prior, very important, macro. now it doesn’t work in ribbon interfaces, so rather than the few lines of code that had previously worked, I am now wrestling with all of this workaround to simply “find the button and click it” from within the macro vba has become quite frustrating, and examples of UIA to do this ‘find the button and click it’ vs. the ribbon, I have yet to find. Your forum is great, I am merely frustrated with the blind MS push to the ribbon and the UIA with apparent disregard to the impact of simple business users.
davidjpp says
I actually agree with you about that. It is really disappointing that there is not a simple way to add a button to the Ribbon to run a VBA macro in Visio. It is something that several of us MVPs have complained to Microsoft about. My code was aimed at providing a way to create/remove buttons when the document opens/closes. My fellow MVP, Chris Roth aka VisGuy, has responded to me as follows:
Ok, I found a simpler way after hacking a bit.
1. Create a custom tab, group, etc.
2. Export the custom UI
3. Edit it in notepad to call your macro
The trick is to add or edit the onAction xml, which I learned from David’s article. Here I’ve set it to ThisDocument.DoStuff.
You can now import this Ribbon UI. If the VBA macro is present, it will run. If not, it won’t but the button will still be there.
brrrknee says
even simpler: take an existing, in fact pre-existing commandbar /buttons, the OrgChart Wizard. I do not want to reinvent the wheel, I just look up the commandbar that ‘is’ the wizard (almost always found at cb index 100 or 101) and select its ‘relayout’ button. no new commands or buttons. just “find org chart stuff” select and execute “relayout”. a handful of lines of code pre-ribbon; all ribbon-influenced examples, though not addressing this locate-subject but a build-it custom focus, are many many pages of code that obfuscate the simple request: locate and execute a known-to-exist command. now I am confounded in finding MSAA (the “old” UI accessibility) and/or UIA (the “new” and to replace MSAA UI accessibility) means of finding the reshuffled needles in the haystack called the ribbon. I’d also rather code to the UIA to obviate any need to rewrite after MSAA methods are tossed aside like commandbars… it happened once, it’ll happen again.
David, I do appreciate your feedback and ideas, thank you, I hope to be able to read more of your blogs and of your partners’.
brrrknee says
Working through several differing samples, I’ve noticed some things that you likely can clarify:
When I add “oleacc.dll” as a resource to my visio 2010 VBA reference list(the library that implements IAccessible according to MS, etc.), the exposed interfaces (within VBA IDE for oleacc.dll) do not include IAccessible.
While code that uses the IAccessible such as x.accName and x.accParent seem to be working, I am hitting several cases where the IAccessible element has no name where I believe it should, (perhaps it is a IDispatch object?) but cannot find the means to view the objects.
Also, one sample I have found helpful uses the x.accNavigate method to get to “FirstChild” of an IAccessible element. MS on 9/7/11 posted a statement (perhaps earlier) that .accNavigate is deprecated and will trigger an error. No suggestions online other than “use other methods”… it is my understanding that this call is essentially “getChildren” and then referencing the top/first of that list; am I close? If not how(which .accXxxx methods) can I achieve the “firstChild” nav utility?
If I could ‘see’ the object via the IDE it would help me here, but as noted at top, the VBA IDE is not edit-or-view aware of IAccessible methods and properties, though the compiled code seems to be… perplexing.
Thanks David!
spols says
Great article.
However, I can’t seem to collect the sample vsd download – skydrive.live.com returns: “An error has occurred. Please try again.”
davidjpp says
I have refreshed the link for you to try again…
Kedas says
This requires ‘IRibbonControl’ as parameter -> Public Sub OnAction(ByVal control As IRibbonControl) in VBA
Is there a way you call a function in the add-in and then this function calls a macro like Sub Refresh() ?
This to stay compatible with existing documents (from templates) with existing macros.
I can change the templates but not all the documents.
Thanks
Prasanna says
David,
Thanks for the help on this topic.
I had a couple of issues; The Macro 1,2,3,4 buttons only execute the code once.
For example, while debugging, if I stop the code, make changes to my custom macro and click again, it won’t work.
I have to restart Visio again for that button to work.
Also, if I only close the Visio sheet (and not Visio program), and reload the sheet, I have two ribbon tabs of the same name instead of the single “Custom Ribbon” tab.
Any clue as why this may be happening.
davidjpp says
Are you running the code in a drawing or a stencil ?
You should run UnloadRibbon() before editing, then LoadRibbon() when you have finished editing your macros
francisco says
I’ve tried to build “two groups” usiing “begin and end group functions” but it doesn’t works. Aparentilly the xml is correct, comparing with others xml in microsoft website. Do you know the probable cause?
Gilles says
Hi, I had exactly the same issue as Francisco:
If includeContextMenus Then
‘Open the context menus group element
strGetRibbonXML4 = getContextMenusBegin
‘Open the context menu element
‘See the contextmenus worksheet in C:\Data\Perso\Toolbox\@Visio\Macros\VisioControls.xlsx
strGetRibbonXML4 = strGetRibbonXML4 & getContextMenuBegin(“ContextMenuShape”)
‘Include any menu buttons required
strGetRibbonXML4 = strGetRibbonXML4 & getButton( _
“SelectSimilarShapesByMaster”, “Select Shapes with same Master”, “Select all Shapes which descend from the same Master”, _
“SourceControlShowHistory”, False)
‘Close the context menu element
strGetRibbonXML4 = strGetRibbonXML4 & getContextMenuEnd
‘Open the context menu element
strGetRibbonXML4 = strGetRibbonXML4 & getContextMenuBegin(“ContextMenuShape1D”)
‘Include any menu buttons required
strGetRibbonXML4 = strGetRibbonXML4 & getButton( _
“SelectSimilarShapesByMaster”, “Select Shapes with same Master”, “Select all Shapes which descend from the same Master”, _
“SourceControlShowHistory”, False)
‘Close the context menu element
strGetRibbonXML4 = strGetRibbonXML4 & getContextMenuEnd
‘Close the context menus group element
strGetRibbonXML4 = strGetRibbonXML4 & getContextMenusEnd
strGetRibbonXML = strGetRibbonXML & strGetRibbonXML4
End If
does not work, even if each the xml code seems to be correct.
If I try to add the menus individually it works.
If I create two “getContextMenusBegin / getContextMenusEnd” blocks, only the last works.
But I do not manage to have both menus working.
Can somebody help?
Roman says
francisco, did you find a solution? I am having the same trouble.
Thomas says
Thanks for this excellent tutorial.
I added a checkbox to your demo and want to initialize its state with a getPressed callback.
But this is never called.
Same problem with getLabel while onAction and onLoad are working properly.
Please find more information here:
http://visguy.com/vgforum/index.php?topic=4954.0
Any idea?
Thanks,
Thomas
davidjpp says
Hmmm, the following thread is not filling me with great hope : http://social.microsoft.com/Forums/ar-SA/988b3569-8519-4253-b8a9-222740c473d8/problems-with-vba-ribbon-customization-in-project-2010-pro
Thomas says
Thanks, David.
Really sad, that Visio still behaves so different to other Office products…
The method, described in your link would be OK for me.
But unfortunately there is no “pressed” attribute defined, as it is for other callbacks (getLabel => label).
Thomas says
Solved.
The function declaration must be:
Public Function Checkbox_getPressed(control As IRibbonControl) As Boolean
Martin says
David,
Great article, thanks a lot. I’m not sure on how I can have this ribbon extension to appear in visio on all times. I have a solution in mind like a Word Template placed in the Auto-Start folder of Word which contains the UI extension and will be loaded on every start of Word.
Can you guid me in the right direction maybe with even a runable sample?
Thanks so much for your help.
Martin
davidjpp says
Visio does not have a personal macros file that is opened automatically.
Of course, you could write an add-in …
RichZ says
So, I’m still modifying my code… but I seem to have the same problem that someone else reported. For whatever reason, the buttons on the ribbon will only run my macro once. Currently I am just testing, so I’ve placed your code within the VSD document, but my macros are stored in a VSS; the stencil of course opens upon DocumentOpen, so that should not be the issue.
I can only imagine that there is some issue with having this code stored in the local document, but calling a macro in a stencil file?
RichZ says
Hmm..; well I tested my previous theory and this is not the case. I placed the macros local to the VSD document, and the results are the same; the buttons I’ve added to the ribbon stop working after I click any of the buttons once. Very odd.
RichZ says
okay, I’ve narrowed down the issue. It seems that the macros I’ve added to the custom ribbon work until I call a macro that drops a stencil on the page that has an activex textbox inside of it. I’m not sure why this breaks ribbon. I’ve tried doing this using the code you have shared with us here, and also by using the example provided by Microsoft in the SDK. If anyone has any thoughts on this then I would greatly appreciate any advice you may have.
davidjpp says
Does VBA Editor / Debug / Compile still process OK ?
Stephen says
Can the methods developed here also be used in Excel?
davidjpp says
Possibly, but I find that creating a proper ribbon with a VSTO app to be the best solution in most cases.
James says
Very nice.
Was wondering if it is possible to put the custom group into an exsiting Tab?
Eg. Create a group called ‘Custom’ and place it in the default Home group.
David Parker says
Certainly you can!
Open the Ribbon class and find the line:
strGetRibbonXML2 = strGetRibbonXML2 & getTabBegin(False, “tab1”, “Custom Ribbon Tab”)
and replace it with:
strGetRibbonXML2 = strGetRibbonXML2 & getTabBegin(True, “TabHome”, “Home”)
Generally I don’t like putting any macros in diagram documents, so I will write an article about how put all the code into a stencil, then it can be used on many diagrams.
David Parker says
Okay, here is the article Adding Macro Ribbon Buttons to Visio Documents-from-a-stencil/
Dmitry says
Thank you! This article is very useful!
Marco says
This is great news! I’m trying to do some coding on my Visio Drawings and find this extremely helpful! Sadly, I couldn’t download your VSD file, perhaps the link changed?
Thanks for this excellent article!
David Parker says
I have updated thee link 🙂