PDA

View Full Version : Solved: Creating CommandBars



dotNetNerd
02-04-2009, 03:19 PM
I have just inherited a lot of Word VBA macros that I need to maintain. I am a .NET developer and also have quite a bit of experience with Excel VBA. However, I am having difficulty with these Word macros.

The macro resides in a .DOT file that is stored in C:\Program Files\Microsoft Office\OFFICE11\STARTUP. When Word starts, the macro creates a bunch of CommandBars. I can't find where these CommandBars are getting created in the code. I did a project-wide search for "CommandBar" but nothing came up (only a couple of lines of code that simply show/hide the existing bars).

I also searched for Auto_Open and AutoOpen and nothing came up.

I tried removing the .DOT file from the STARTUP folder and the CommandBars didn't get created when I restart Word. As soon as I put the file back and restart Word, the CommandBars get created again. So I'm concluding that these CommandBars get created by the macros in this file. There is also nothing else in the STARTUP folder.

Can someone point me in the right direction as to how to find out where these CommandBars get created? Thanks!

Oorang
02-04-2009, 04:46 PM
Are you sure that they are weren't created manually and attached to Normal.Dot and or the template file? Open the template file in bypass mode and go to tools>customize and see if the bars already exist. If they do they are probably manual.

lucas
02-04-2009, 08:30 PM
As Aaron has pointed out, these menu's are probably created like this and then saved as a template or .dot file.

http://slucas.virtualave.net/Wink/CustomMenuItem.htm

No code involved whatsoever.

dotNetNerd
02-05-2009, 06:13 AM
Thanks to both Aaron and Lucas. I wasn't aware of this option. It does look like that's what's going on here.

Based on the posted tutorial, the toolbars are saved in Normal.dot. However, is it not possible (and wouldn't it make more sense) to save them as part of the custom .DOT file (where the VBA code resides as well)? I can see that the only option is to save the toolbar in Normal.dot or the open doc while creating a new toolbar in Word. Why is that? Or am I missing something fundamental?

Again, thanks for clarifying all this. Tremendous help!

dotNetNerd
02-05-2009, 06:46 AM
Never mind about my last question. I figured it out. I'm marking this thread as resolved. Thanks all for your guidance!!! I really appreciate it.

dotNetNerd
02-05-2009, 07:21 AM
Given a button on a toolbar, how do I check which macro it executes? If I go to Customize and then right-click on the button, I see the following menu, which doesn't tell me which macro will be executed. There also doesn't appear to be a properties button. See the attachment for what I see in that menu.

lucas
02-05-2009, 07:59 AM
re post # 4:

It's probably not saved in normal, if you remove the dot file from startup and the menu's dissappear then they are in the dot file, not normal. The demo demonstrates that you can save these menu's in any file, not just a dot file and not just in normal........putting the .dot file in startup is why it loads every time you open word.......

re post #6 I know of no way to see which macro is being run this way. Does the .dot file have any macro's in it?

Your attachment did not come through.....

hit post reply and then scroll down and look for manage attachments....

Oorang
02-05-2009, 08:09 AM
RE #6:
AFAIK there are 3 things a control can be doing. Executing a hyperlink, using a macro action, or performing an action predefined and selected off of the customize menu. The properties to check are CommandBarButton.OnAction and CommandBarButton.HyperlinkType. If OnAction is an empty string and the hyperlinktype = msoCommandBarButtonHyperlinkNone then it was likely a control selected off of the customize menu.

lucas
02-05-2009, 08:29 AM
You can drag the menu's off of the command bar just as you add them to get rid of them......drag them to the customize dialog box.

fumei
02-05-2009, 12:17 PM
I know this is marked as Solved, but what is the question?

Buttons on a toolbar can be created dynamically, OR they can be inherent in a global template.

Normal.dot is a global template, albeit a special case one.

Toolbar buttons can also be in ANY global template, and for most purposes it is better that this is the case.

Steve, re: "re post #6 I know of no way to see which macro is being run this way."

This refers to (from OP): "Given a button on a toolbar, how do I check which macro it executes? "

As Oorang mentions, buttons have an .OnAction property - even the ones dragged to the toolbar via Customize > Macros. In that, Oorang is technically incorrect.

"AFAIK there are 3 things a control can be doing. Executing a hyperlink, using a macro action, or performing an action predefined and selected off of the customize menu. "

There are really only 2 - as "using a macro action" and "performing an action predefined and selected off of the customize menu" are essentially identical.

Say I have a global template (not Normal), and it is loaded. It has a procedure (a Sub) named PrintAllDocs.

If that macro (Sub) is dragged to a toolbar via Customize, and its name changed to "Biwaz^qa3", then "Biwaz^qa3" appears on the toolbar.

Quite true that if you go into Customize again, there is no way to see the REAL name of the procedure. Once the name is changed, the actual procedure name is not part of the Customize dialog.

Which is where .OnAction comes in.

Yes, you can get the original procedure name, AND module. You can look through the Caption properties for the caption ("Biwaz^qa3"), and if found displays it OnAction property.
Dim oCB As CommandBarButton
For Each oCB In CommandBars(1).Controls
If InStr(1, oCB.Caption, "Biwaz^qa3") > 0 Then
MsgBox oCB.OnAction
End If
Next
which in my case displays:

modPrintUtilities:PrintAllDocs

NOTE: it does return the module, but does NOT return the container.

In this case, modPrintUtilities is a module in VBA_XTools.dot, which is in my Startup folder.

AFAIK, as Word lumps ALL available procedures together (as you can see in the macro listing in the Customize dialog), and it keeps the true pointers to itself (i.e. they are not exposed to VBA), you can not find out the parent code container.

In other words, even code modules in Normal.dot are NOT identified as being in Normal.dot.

.OnAction = Module1.NameAllTables

Is that Module1 in my Normal.dot or my VBA_XTools.dot?

There is no way to find out.

Which is ANOTHER reason for careful explicit names of things.

On the other hand...who cares? You can get the procedure name.

Note also that the .OnAction value of a button is stored on startup (either Word startup, or when/if a template is installed).

If the template is uninstalled (but still listed), then a button will return the correct .OnAction value, but the procedure will (obviously) not execute.

E.g. I have my global VBA_XTools.dot in my startup, therefore it is both listed AND loaded.

It has a procedure PrintAllDocs. There is a button on the toolbar that executes PrintAllDocs. Its .OnAction is modPrintUtilities:PrintAllDocs.

Now if VBA_XTools.dot is uninstalled (but still listed), clicking the button will give an error - there is no procedure to execute.

However, checking its .OnAction will still return modPrintUtilities:PrintAllDocs.....IF, the button is actually in Normal.

That would happen if you used Customized and dragged the macro to a toolbar, when you do NOT have the global template file open.

If you have the template file itself open, and dragged a macro to a toolbar, then that button will only be visible when the template is installed.

In other words, this reinforces careful use of global templates. Do not put buttons executing global (other than Normal) template procedures on a toolbar unless the ActiveDocument IS the template file itself.

Oorang
02-05-2009, 03:00 PM
As Oorang mentions, buttons have an .OnAction property - even the ones dragged to the toolbar via Customize > Macros. In that, Oorang is technically incorrect.
No I'm not :) Perhaps a clarification...
The OP asked:

Given a button on a toolbar, how do I check which macro it executes?
To which I said:

IfOnAction is an empty string and the hyperlinktype = msoCommandBarButtonHyperlinkNone then it was likely a control selected off of the customize menu.
If you added a macro off the "Macros" section of the customize menu then it will have a value in OnAction. But I didn't say "having a value in OnAction means it was not added via the interface." I said "not having a value in OnAction means it was added to the interface." You can further parse this down by checking the hyperlinktype property. This is accurate.

fumei
02-06-2009, 11:36 AM
Excuse me, but I thought I was clear. I made no comment about anything else being incorrect other than stating that there are really TWO "things a control can be doing". You stated there are 3.


"AFAIK there are 3 things a control can be doing. Executing a hyperlink, using a macro action, or performing an action predefined and selected off of the customize menu. "

I simply stated:

There are really only 2 - as "using a macro action" and "performing an action predefined and selected off of the customize menu" are essentially identical.

a "macro action" and "an action predefined" are essentially the same thing.


I said "not having a value in OnAction means it was added to the interface."

Really? Every macro I add to the interface via Customize has an .OnAction value. So I do not know how you can get no value.

Remember we are NOT talking about controls in general, we are talking about controls that DO execute macros. If they do execute something...then they have an .OnAction value.

To go back to your original post:
AFAIK there are 3 things a control can be doing. Executing a hyperlink, using a macro action, or performing an action predefined and selected off of the customize menu. The properties to check are CommandBarButton.OnAction and CommandBarButton.HyperlinkType. If OnAction is an empty string and the hyperlinktype = msoCommandBarButtonHyperlinkNone then it was likely a control selected off of the customize menu.May I point out that you state there are 3 things...then state only TWO properties (which is correct).

I only pointed out the difference between "3 things" and "2 things"....BECAUSE (to repeat) a "macro action" and "an action predefined" are essentially the same thing.

Sorry if I offended you.

fumei
02-06-2009, 11:45 AM
Just as a followup...

If you have a control, and give a value to its .OnAction what is that value?

It is a procedure. An .OnAction value must point to a valid procedure. Or.....a macro in other words.

Perhaps I am failing to see the significance about HOW the value gets there.

a) you create a commandbarbutton via code, and give the value "DoThis" to .OnAction

b) you use Customize and drag the DoThis macro to a toolbar, making a button.

BOTH have the same .OnAction value (DoThis).

"using a macro action, or performing an action predefined and selected off of the customize menu"

My bolding.

Again, I am sorry if I offended you. It was intended as a small, wee, correction. IMO, there is no "or".

a "macro action" and "an action predefined" are the same thing. No "or".

geekgirlau
02-13-2009, 11:49 PM
I've used the following code to print a list of all macros assigned to a custom toolbar (complete with sub-menus) - it may be of use.

IMHO I find it irritating that there is no method to quickly check on this through the front-end ...

Sub GetToolbarMacros()
Dim cbLevel1 As CommandBarControl
Dim cbLevel2 As CommandBarControl
Dim cbLevel3 As CommandBarControl

For Each cbLevel1 In CommandBars.Item("CustomTB").Controls
Debug.Print Chr(13) & cbLevel1.Caption & ": " & cbLevel1.OnAction

On Error Resume Next
For Each cbLevel2 In cbLevel1.Controls
Debug.Print cbLevel2.Caption & ": " & cbLevel2.OnAction

For Each cbLevel3 In cbLevel2.Controls
Debug.Print cbLevel3.Caption & ": " & cbLevel3.OnAction
Next cbLevel3
Next cbLevel2
Next cbLevel1
End Sub

fumei
02-18-2009, 01:26 PM
Well I have to sort of agree with you. How difficult would it be to say right click a control, or menu item, and be able to see what procedure is executed? After all, Word has to "know" in order to actually execute it.