Create a right-click context menu in Outlook 2003 - vba

I'm already able to create a new menu in the top menubar of Outlook 2003 but would like to do the same when the user right-click on an email (but not anywhere else in the interface if possible).
Here is what I got:
Sub AddMenus()
Dim cbMainMenuBar As CommandBar
Dim cbcCustomMenu As CommandBarControl
Dim cbcTest As CommandBarControl
Dim iHelpMenu as Integer
Set cbMainMenuBar = Application.ActiveExplorer.CommandBars.ActiveMenuBar
iHelpMenu = cbMainMenuBar.Controls("&?").index
Set cbcCustomMenu = cbMainMenuBar.Controls.Add(Type:=msoControlPopup, before:=iHelpMenu)
cbcCustomMenu.caption = "Menu &Name"
Set cbcTest = cbcCustomMenu.Controls.Add(Type:=msoControlPopup)
cbcTest.caption = "&Test"
With cbcTest.Controls.Add(Type:=msoControlButton)
.caption = "&Submenu item"
.OnAction = "macro"
End With
With cbcTest.Controls.Add(Type:=msoControlButton)
.caption = "Another submenu item"
.OnAction = "macro"
End With
With cbcCustomMenu.Controls.Add(Type:=msoControlButton)
.caption = "About"
.OnAction = "macro"
End With
End Sub
What do I have to change to make this works when right-clicking?

The definitive answer to the problem can be found here: http://www.outlookcode.com/codedetail.aspx?id=314
Here is what I come with after removing some of the code/comments I didn't need:
Option Explicit
Private WithEvents ActiveExplorerCBars As CommandBars
Private WithEvents ContextButton As CommandBarButton
Private IgnoreCommandbarsChanges As Boolean
Private Sub Application_Startup()
Set ActiveExplorerCBars = ActiveExplorer.CommandBars
End Sub
Private Sub ActiveExplorerCBars_OnUpdate()
Dim bar As CommandBar
If IgnoreCommandbarsChanges Then Exit Sub
On Error Resume Next
Set bar = ActiveExplorerCBars.Item("Context Menu")
On Error GoTo 0
If Not bar Is Nothing Then
AddContextButton bar
End If
End Sub
Sub AddContextButton(ContextMenu As CommandBar)
Dim b As CommandBarButton
Dim subMenu As CommandBarControl
Dim cbcCustomMenu As CommandBarControl, cbcLink As CommandBarControl
Set ContextMenu = ActiveExplorerCBars.Item("Context Menu")
'Unprotect context menu
ChangingBar ContextMenu, Restore:=False
'Menu
Set cbcCustomMenu = ContextMenu.Controls.Add(Type:=msoControlPopup)
cbcCustomMenu.caption = "&Menu"
'Link in Menu
Set cbcLink = cbcCustomMenu.Controls.Add(Type:=msoControlButton)
cbcLink.caption = "Link 1"
cbcLink.OnAction = "macro"
'Reprotect context menu
ChangingBar ContextMenu, Restore:=True
End Sub
'Called once to prepare for changes to the command bar, then again with
'Restore = true once changes are complete.
Private Sub ChangingBar(bar As CommandBar, Restore As Boolean)
Static oldProtectFromCustomize, oldIgnore As Boolean
If Restore Then
'Restore the Ignore Changes flag
IgnoreCommandbarsChanges = oldIgnore
'Restore the protect-against-customization bit
If oldProtectFromCustomize Then bar.Protection = bar.Protection And msoBarNoCustomize
Else
'Store the old Ignore Changes flag
oldIgnore = IgnoreCommandbarsChanges
IgnoreCommandbarsChanges = True
'Store old protect-against-customization bit setting then clear
'CAUTION: Be careful not to alter the property if there is no need,
'as changing the Protection will cause any visible CommandBarPopup
'to disappear unless it is the popup we are altering.
oldProtectFromCustomize = bar.Protection And msoBarNoCustomize
If oldProtectFromCustomize Then bar.Protection = bar.Protection And Not msoBarNoCustomize
End If
End Sub

I no longer have Outlook 2003 installed and Outlook 2010 doesn't let you mess with right-click menus the same way. So this compiles and is, hopefully close to what you need to do.
Before writing any code, you'll want to show hidden items, I think, to get the Intellisense for a couple of objects. In 2010 the ActiveExporer and ActiveInspector objects - which are the two types of view in Outlook, e.g., looking at all you email, or looking at a single email - are hidden. To unhide them, go into the Object Explorer by clicking F2 in the VBE, and right-click just about anywhere and check "Show Hidden Items".
So now you're ready to code:
First you need a way to determine the name of the right-click menu you are interested in. This tries to add a button to every menu, with the button's caption being the name and index of the menu. It resets the menu first, so as to not create more than one such button. The button should be at the bottom of the menu. The buttons are temporary, meaning they'll be gone the next time you open Outlook:
Sub GetCommandBarNames()
Dim cbar As Office.CommandBar
Dim cbarButton As Office.CommandBarButton
For Each cbar In ActiveInspector.CommandBars
On Error Resume Next
cbar.Reset
Set cbarButton = cbar.Controls.Add(Type:=msoControlButton, temporary:=True)
With cbarButton
.Caption = cbar.Name
.Style = msoButtonCaption
.Visible = True
End With
On Error GoTo 0
Next cbar
For Each cbar In ActiveExplorer.CommandBars
On Error Resume Next
cbar.Reset
Set cbarButton = cbar.Controls.Add(Type:=msoControlButton, temporary:=True)
With cbarButton
.Caption = cbar.Name & "-" & cbar.Index
.Style = msoButtonCaption
.Visible = True
End With
On Error GoTo 0
Next cbar
End Sub
After running this, right-click in Outlook and get the name of the menu you want. It will be the part before the dash on the last button. Let's say it's "foobar".
You should then be able to do this:
Sub AddButton()
Dim cbar As Office.CommandBar
Dim cbarButton As Office.CommandBarButton
Set cbar = ActiveExplorer.CommandBars("foobar") 'or maybe it's ActiveInspector
Set cbarButton = cbar.Controls.Add(Type:=msoControlButton, temporary:=True)
With cbarButton
.Caption = "&Submenu item"
.OnAction = "macro"
.Style = msoButtonCaption
'etc.
End With
'do the next button
Set cbarButton = cbar.Controls.Add(Type:=msoControlButton, temporary:=True)
'...
End Sub
Like I say, I'm doing this a bit blind, but I've done it many times in Excel (I even wrote two addins), so if this doesn't work, I should be able to get you there.

Related

Get the selected item of a dropdown in a custom menu (and run a macro accordingly)

I have this simple menu setup and I am trying to run a macro based on user selection of the label item from a dropdown list. The OnAction only works on the entire dropdown object and not executing macros per dropdown-list-item selection:
Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As Boolean)
Dim oMenu As CommandBar
Set oMenu = CommandBars.Add("", msoBarPopup, , True)
Dim cbcm1 As CommandBarButton
Set cbcm1 = oMenu.Controls.Add(Type:=msoControlButton, Temporary:=True)
cbcm1.Caption = "Add new label"
cbcm1.OnAction = "AddNewLabel"
Dim cbcm2 As CommandBarComboBox
Set cbcm2 = oMenu.Controls.Add(Type:=msoControlDropdown, Temporary:=True)
cbcm2.Caption = "Select label:"
cbcm2.AddItem "NVPE" ' << this should run a macro that adds a 'NVPE' in some other range..
cbcm2.AddItem "COMP" ' << this should run a macro that adds a 'COMP' in some other range.. and so on.
cbcm2.AddItem "HOLD"
cbcm2.AddItem "INPROG"
cbcm2.AddItem "CANC"
cbcm2.Width = 150
cbcm2.ListIndex = 1 'default
cbcm2.OnAction = "NewCommand_OnAction"
cbcm2.Style = msoComboLabel
oMenu.ShowPopup 'display the menu
Cancel = True
End Sub
Any suggestions?
I can't think of a way to get the selected index or value (caption) of the selected item.
Thanks!
All you are missing is a Select Case in your event handler. Using your existing code, simply add the string cbcm2Text and set it to equal cbcm2.Text. Then, add the necessary Select Case prior to your Cancel = True statement to call your macros.
Example:
Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As Boolean)
Dim oMenu As CommandBar
Dim cbcm2Text As String
Dim cbcm1 As CommandBarButton
Dim cbcm2 As CommandBarComboBox
Set oMenu = CommandBars.Add("", msoBarPopup, , True)
Set cbcm1 = oMenu.Controls.Add(Type:=msoControlButton, Temporary:=True)
Set cbcm2 = oMenu.Controls.Add(Type:=msoControlDropdown, Temporary:=True)
cbcm1.Caption = "Add new label"
cbcm1.OnAction = "AddNewLabel"
cbcm2.Caption = "Select label:"
cbcm2.AddItem "NVPE"
cbcm2.AddItem "COMP"
cbcm2.AddItem "HOLD"
cbcm2.AddItem "INPROG"
cbcm2.AddItem "CANC"
cbcm2.Width = 150
cbcm2.ListIndex = 1
cbcm2.OnAction = "NewCommand_OnAction"
cbcm2.Style = msoComboLabel
oMenu.ShowPopup
cbcm2Text = cbcm2.Text
Select Case cbcm2Text
Case "NVPE"
Call NVPE
Case "COMP"
Call COMP
Case "HOLD"
Call HOLD
Case "INPROG"
Call INPROG
Case "CANC"
Call CANC
End Select
Cancel = True
End Sub
Sub NVPE()
MsgBox "You selected NVPE"
End Sub
Sub COMP()
MsgBox "You selected COMP"
End Sub
Sub HOLD()
MsgBox "You selected HOLD"
End Sub
Sub INPROG()
MsgBox "You selected INPROG"
End Sub
Sub CANC()
MsgBox "You selected CANC"
End Sub
The preceding code produces the following result:
Here is the relevant Microsoft Documentation if you would like to see more examples of how to utilize combobox change events.

VBA to add a macro to the right mouse click in word

I'm running Word in Office 365; I have a Macro which I can run from a button added to the ribbon, but that requires access to the machine it's running on (at least, the way I did it) and this file is to go out to a distributed workforce.
I'm trying to write a macro in the document which will add a button to the drop-down menu that comes up when you right click on a text selection, but the code below doesn't add anything to the menu.
Sub AddToShortcut()
Dim Bar As CommandBar
Dim NewControl As CommandBarButton
DeleteFromShortcut
Set Bar = Application.CommandBars("Standard")
Set NewControl = Bar.Controls.Add(Type:=msoControlButton, ID:=1, Temporary:=True)
With NewControl
.Caption = "&New Action"
.OnAction = "AddAction"
.Style = msoButtonIconAndCaption
End With
End Sub
Private Sub document_open()
'adds the right-click shortcut when the document opens
Call AddToShortcut
End Sub
I got the core of the code from John Walkenbach's Excel VBA Programming for Dummies, so I'm presuming there's some difference between the way Word and Excel operate that's causing the issue?
You want to add it to the "Text" contextual menu, not "Standard."
The following is straight from Greg Maxey's page that you said was too much. It is the answer, though. Your code would be around oBtn.
You would put this in a Global Template stored in your Word Startup Folder (links to my pages). It could be renamed AutoExec or called from an AutoExec procedure in that template.
Option Explicit
Dim oPopUp As CommandBarPopup
Dim oCtr As CommandBarControl
Sub BuildControls()
Dim oBtn As CommandBarButton
'Make changes to the Add-In template
CustomizationContext = ThisDocument.AttachedTemplate
'Prevent double customization
Set oPopup = CommandBars.FindControl(Tag:="custPopup")
If Not oPopup Is Nothing Then GoTo Add_Individual
'Add PopUp menu control to the top of the "Text" short-cut menu
Set oPopUp = CommandBars("Text").Controls.Add(msoControlPopup, , , 1)
With oPopUp
.Caption = "My Very Own Menu"
.Tag = "custPopup"
.BeginGroup = True
End With
'Add controls to the PopUp menu
Set oBtn = oPopUp.Controls.Add(msoControlButton)
With oBtn
.Caption = "My Number 1 Macro"
.FaceId = 71
.Style = msoButtonIconAndCaption
'Identify the module and procedure to run
.OnAction = "MySCMacros.RunMyFavMacro"
End With
Set oBtn = Nothing
'Add a Builtin command using ID 1589 (Co&mments)
Set oBtn = oPopUp.Controls.Add(msoControlButton, 1589)
Set oBtn = Nothing
'Add the third button
Set oBtn = oPopUp.Controls.Add(msoControlButton)
With oBtn
.Caption = "AutoText Complete"
.FaceId = 940
.Style = msoButtonIconAndCaption
.OnAction = "MySCMacros.MyInsertAutoText"
End With
Set oBtn = Nothing
Add_Individual:
'Or add individual commands directly to menu
Set oBtn = CommandBars.FindControl(Tag:="custCmdBtn")
If Not oBtn Is Nothing Then Exit Sub
'Add control using built-in ID 758 (Boo&kmarks...)
Set oBtn = Application.CommandBars("Text").Controls.Add(msoControlButton, 758, , 2)
oBtn.Tag = "custCmdBtn"
If MsgBox("This action caused a change to your Add-In template." _
& vbCr + vbCr & "Recommend you save those changes now.", vbInformation + vbOKCancel, _
"Save Changes") = vbOK Then
ThisDocument.Save
End If
Set oPopUp = Nothing
Set oBtn = Nothing
lbl_Exit:
Exit Sub
End Sub

VBA CommandBar does not execute the OnAction subrutine

The following code is not doing anything in my Access application.
I expected to run the Subrutine TestMacro.
It shows up the menu but not reaction at all after selecting.
Any idea?
Private Sub Check_Status_Click()
Set The_Menu = CreateSubMenu
The_Menu.ShowPopup
End Sub
Function CreateSubMenu() As CommandBar
Const pop_up_menu_name = "Pop-up Menu"
Dim the_command_bar As CommandBar
Dim the_command_bar_control As CommandBarControl
Set the_command_bar = CommandBars.Add(Name:=pop_up_menu_name, Position:=msoBarPopup, MenuBar:=False, Temporary:=False)
Set the_command_bar_control = the_command_bar.Controls.Add
the_command_bar_control.Caption = "Run Macro Hello World!"
the_command_bar_control.OnAction = "TestMacro"
Set CreateSubMenu = the_command_bar
End Function
Public Sub TestMacro()
MsgBox "Hello World"
End Sub
Make sure that TestMacro is in common module, not in the form's one.
Also before adding new menu delete existing one if it exists:
On Error Resume Next
CommandBars.Item(pop_up_menu_name).Delete
On Error GoTo 0
Otherwise, you'll get an error

How to add a macro to mutiple excel files using VBA

Is there any way to write a VBA Macro to input another VBA Macro into multiple excel workbooks? If so, how do I start?
Any and all help is greatly appreciated.
you'll need a reference first
Microsoft Visual Basic For Applications Extensibility 5.3
And here you go. Have fun
Public Sub AddNewModule()
Dim proj As VBIDE.VBProject
Dim comp As VBIDE.VBComponent
Set proj = ActiveWorkbook.VBProject
Set comp = proj.VBComponents.Add(vbext_ct_StdModule)
comp.Name = "MyNewModule"
Set codeMod = comp.CodeModule
With codeMod
lineNum = .CountOfLines + 1
.InsertLines lineNum, "Public Sub ANewSub()"
lineNum = lineNum + 1
.InsertLines lineNum, " MsgBox " & """" & "I added a module!" & """"
lineNum = lineNum + 1
.InsertLines lineNum, "End Sub"
End With
End Sub
You can also just use the workbook with the code in it as a reference as well. Then you can call the module remotely.
As #BruceWayne mentioned, there is also sotring it in the personal book.
tl;dr - there's a few options that can get you there.
I recommend storing them in the Personal.xslb file which is accessible across Excel.
See this page or this page for more detail, but generally a quick way to get started is:
Press ALT+F11 to open the VBEditor.
Right click the "VBAProject (PERSONAL.XLSB)" and Add a new module
Add your code in the module.
Now, when you go to View --> Macros, you can choose to see those stored in the Personal.xlsb file:
(I "whited out" my macros for privacy, but they'll be listed by name)
Note: If you do not have a "Personal.xlsb", then you must create it. Simply record a new macro, but choose to store it in "Personal Macro Workbook". Then you should see it in the VBEditor.
I would think the easiest way to have the same code in slightly different Excel files is to have one 'template' and save it several times as several slightly different files. Or, if you want to get fancy, you can create an AddIn to make an Excel Macro available to all workbooks.
Option Explicit
Dim cControl As CommandBarButton
Private Sub Workbook_AddinInstall()
On Error Resume Next 'Just in case
'Delete any existing menu item that may have been left.
Application.CommandBars("Worksheet Menu Bar").Controls("Super Code").Delete
'Add the new menu item and Set a CommandBarButton Variable to it
Set cControl = Application.CommandBars("Worksheet Menu Bar").Controls.Add
'Work with the Variable
With cControl
.Caption = "Super Code"
.Style = msoButtonCaption
.OnAction = "MyGreatMacro"
'Macro stored in a Standard Module
End With
On Error GoTo 0
End Sub
Private Sub Workbook_AddinUninstall()
On Error Resume Next 'In case it has already gone.
Application.CommandBars("Worksheet Menu Bar").Controls("Super Code").Delete
On Error GoTo 0
End Sub
This code will be all you need to add a single menu item (called Super Code) to the end of the existing Worksheet Menu Bar as soon as the Add-in is installed by the user via Tools>Add-ins. When the Super Code menu item is clicked a macro (that is within a standard module of the add-in) is run. As mentioned earlier, the above code MUST be placed in the Private Module of ThisWorkbook for the Add-in.
If you want the Super Code menu item added, say before the Format menu item, you could use some code like this.
Option Explicit
Dim cControl As CommandBarButton
Private Sub Workbook_AddinInstall()
Dim iContIndex As Integer
On Error Resume Next 'Just in case
'Delete any existing menu item that may have been left
Application.CommandBars("Worksheet Menu Bar").Controls("SuperCode").Delete
'Pass the Index of the "Format" menu item number to a Variable.
'Use the FindControl Method to find it's Index number. ID number _
is used in case of Customization
iContIndex = Application.CommandBars.FindControl(ID:=30006).Index
'Add the new menu item and Set a CommandBarButton Variable to it.
'Use the number passed to our Integer Variable to position it.
Set cControl = Application.CommandBars("Worksheet Menu Bar").Controls.Add(Before:=iContIndex)
'Work with the Variable
With cControl
.Caption = "Super Code"
.Style = msoButtonCaption
.OnAction = "MyGreatMacro"
'Macro stored in a Standard Module
End With
On Error GoTo 0
End Sub
There would be no need to change the Workbook_AddinUninstall() code in this case.
We have covered ID numbers while working with CommandBars etc in a P rior Newsletter Issue The link to the Microsoft site that has a BIG list of all the ID numbers for working with CommandBars can be Found Here
The above examples actually have the all the menu item code in the Workbook_AddinInstall and Workbook_AddinUnInstall Not a problem when the code is only adding one menu item. If however, you will be adding more then one and perhaps even Sub menus, you should place it in a Procedure (or 2) inside a standard Module. Then use some code as shown below
Private Sub Workbook_AddinInstall()
Run "AddMenus"
End Sub
Private Sub Workbook_AddinUninstall()
Run "DeleteMenu"
End Sub
Then in the standard module put some code perhaps like this
Sub AddMenus()
Dim cMenu1 As CommandBarControl
Dim cbMainMenuBar As CommandBar
Dim iHelpMenu As Integer
Dim cbcCutomMenu As CommandBarControl
'(1)Delete any existing one.We must use On Error Resume next _
in case it does not exist.
On Error Resume Next
Application.CommandBars("Worksheet Menu Bar").Controls("&NewMenu").Delete
'(2)Set a CommandBar variable to Worksheet menu bar
Set cbMainMenuBar = Application.CommandBars("Worksheet Menu Bar")
'(3)Return the Index number of the Help menu. We can then use _
this to place a custom menu before.
iHelpMenu = cbMainMenuBar.Controls("Help").Index
'(4)Add a Control to the "Worksheet Menu Bar" before Help
'Set a CommandBarControl variable to it
Set cbcCutomMenu = cbMainMenuBar.Controls.Add(Type:=msoControlPopup, Before:=iHelpMenu)
'(5)Give the control a caption
cbcCutomMenu.Caption = "&New Menu"
'(6)Working with our new Control, add a sub control and _
give it a Caption and tell it which macro to run (OnAction).
With cbcCutomMenu.Controls.Add(Type:=msoControlButton)
.Caption = "Menu 1"
.OnAction = "MyMacro1"
End With
'(6a)Add another sub control give it a Caption _
and tell it which macro to run (OnAction)
With cbcCutomMenu.Controls.Add(Type:=msoControlButton)
.Caption = "Menu 2"
.OnAction = "MyMacro2"
End With
'Repeat step "6a" for each menu item you want to add.
'Add another menu that will lead off to another menu
'Set a CommandBarControl variable to it
Set cbcCutomMenu = cbcCutomMenu.Controls.Add(Type:=msoControlPopup)
' Give the control a caption
cbcCutomMenu.Caption = "Next Menu"
'Add a control to the sub menu, just created above
With cbcCutomMenu.Controls.Add(Type:=msoControlButton)
.Caption = "&Charts"
.FaceId = 420
.OnAction = "MyMacro2"
End With
On Error GoTo 0
End Sub
Sub DeleteMenu()
On Error Resume Next
Application.CommandBars("Worksheet Menu Bar").Controls("&NewMenu").Delete
On Error GoTo 0
End Sub
You can find all details here.
http://www.ozgrid.com/VBA/excel-add-in-create.htm

How do I capture a PowerPoint VSTO Text Changed Event?

I'm developing a PowerPoint C# VSTO add-in. I want to be able to capture a text changed event whenever the Title text of a slide is changed.
How can I attach a custom event handler that will fire whenever the Title text is changed?
Two things: 1) this is in VBA, but should be easily portable to C# and VSTO, 2) The "text changed" thing is a bit tricky. I can get you as far as "are you in a Title box" - the rest is more trival. It has to do with finding original state versus any changes. Probably doable, I just haven't done it.
To hook a selection change in PPT VBA, you'll need one class and one module. In the class, put this:
Public WithEvents PPTEvent As Application
Private Sub PPTEvent_WindowSelectionChange(ByVal Sel As Selection)
With Sel
If .Type = ppSelectionText Then
Dim sh As Shape: Set sh = .ShapeRange(1)
If sh.Type = msoPlaceholder Then
originalText = sh.TextFrame.Text
Dim placeHolderType As Integer
placeHolderType = sh.PlaceholderFormat.Type
If placeHolderType = ppPlaceholderTitle Then
MsgBox "this is a title placeholder"
End If
End If
End If
End With
End Sub
Name the class "clsPPTEvents". Then in any module, put the following:
Public newPPTEvents As New clsPPTEvents
Sub StartEvents()
Set newPPTEvents.PPTEvent = Application
End Sub
Sub EndEvents()
Set newPPTEvents.PPTEvent = Nothing
Set newPPTEvents = Nothing
End Sub
Press F5 on the StartEvents and that will enable the hook. Press F5 on the EndEvents to disable it.