1
votes

We have custom ribbons on many Excel workbooks. Occasionally we experience an error message from Excel saying the '_getEnabled' macro is disabled (see image). This message appears for every ribbon control that uses a macro to control the enabled property.
macro is disabled error message

The xml in the ribbon is (some names are redacted):

<button id="name_btn" size="large" image="imagename" label="somelabel" getEnabled="VBA_####.######_getEnabled" onAction="VBA_####.######_onAction"/>

and the VBA is:

Sub ######_getEnabled(control As IRibbonControl, ByRef returnedVal)
    returnedVal = CheckPermissions("SomeName")
End Sub

Has anyone else seen this error? The error messages appear when another workbook is the active workbook but Excel seems to be trying to refresh the ribbon controls for the workbook that contains the code. As mentioned earlier, this happens occasionally and we have not seen any identifiable pattern.

1
Yes, if the ribbon is refreshing and another workbook is active then the ribbon is trying to call the defined methods on the active workbook instead of the workbook containing the code. I've experienced this many times. I haven't tried to solve this yet. - Cristian Buse

1 Answers

1
votes

You can replicate the behaviour if you set a breakpoint in one of the callbacks in VBA (GetImage, GelLabel, GetEnabled etc.) and when the code breaks you go and activate another workbook. Finally, when you continue running the code (ex. press F5) the error will occur.

You can force a ribbon refresh using the ribbon .Invalidate method (if you previously saved the ribbon object). You can save the ribbon object by defining an onLoad callback:

<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui" onLoad="InitRibbon">

with this in VBA:

Private moduleLevelRibbonObject As IRibbonUI

Public Sub InitRibbon(ribbon As IRibbonUI)
    Set moduleLevelRibbonObject = ribbon
End Sub

Calling moduleLevelRibbonObject.Invalidate will refresh the ribbon (if state was not lost - but that is a different topic).

Quick fix that I've found. Just add something like this:

If Not ThisWorkbook Is ActiveWorkbook Then ThisWorkbook.Activate

to all your callbacks, so that when the callback returns to the caller, the correct workbook is active and the next callback is called correctly. Add the line preferably at the end of the method just before End Sub/Function. Example:

Public Sub GetPressed(ctrl As IRibbonControl, ByRef isChecked As Variant)
    Select Case ctrl.ID
    Case "AdminMode"
        isChecked = IsAdminModeOn()
    Case Else
        Debug.Print "Toggle <" & ctrl.ID & "> does not have a return " _
            & "boolean for GetPressed!"
    End Select
    If Not ThisWorkbook Is ActiveWorkbook Then ThisWorkbook.Activate
End Sub