2
votes

I have created an add-in for PowerPoint which creates a grid of objects from a selection of objects that you select.

The add-in uses a context-sensitive control in the ribbon so that the control is only available when one or more shapes are selected (otherwise it is greyed out).

When I open PowerPoint (with this add-in enabled), I may get the following error message: "PowerPoint can't start this feature because you currently have a Visual Basic for Applications project in break mode."

The message repeats as each custom control is loaded onto the ribbon (the controls progressively appear as you click ok to each error), and once PowerPoint has started the controls are present in the ribbon but are greyed out, and do not get activated when a shape is selected.

The error is very hard to fault find: it may just disappear and not re-appear on a particular machine, but then may be present on a different machine for the same set-up (and exactly the same add-in code). It may occur if this add-in is loaded on its own, or it might only occur if it is loaded with other add-ins.

When the error messages appear, I may fault-find by commenting out sections of code, save and re-add it as a ppam add-in until the error messages disappear: and then to try and verify that I'd found the source of the problem, uncomment out the code I'd commented out until the error re-appears - except that usually the error does not re-appear.

The error is not seen if PowerPoint starts with an open document. Also the error might only be seen when PowerPoint is set up to start up with its welcome screen rather than a new document.

My current office version is: 1812 (office 365 - desktop), build 11126.20196 (but I have seen this on other versions) and Windows 10 version 1803.

I have tried:

  • Exporting all my code to text files and importing it back using a version of Rob Bovey's code cleaner adapted for PowerPoint: http://www.tushar-mehta.com/powerpoint/vba_codecleaner/index.htm

  • Trying to force the error messages to appear to try and work out what a possible source of the errors could be - but have so far been unable to do this:

    • Deliberately inserting an error in any of the code run when PowerPoint loads (such as divide by zero) results in the usual debug error messages and not the error messages that I am having a problem with.

    • Introducing delays in Auto_Open, onLoad and getEnabled calls to try and get any of these calls that might run asynchronously to overlap following a suggestion that Auto_Open and onLoad calls may be fighting with each other: but although I can get Auto_Open and onLoad calls to overlap, this hasn't caused the re-appearance of the error messages.

    • Seeing if the problem might happen due to a problem when PowerPoint was last closed: I put PowerPoint in break mode, then forced it to stop with the task manager and then re-started PowerPoint - but no errors seen. Also I have tried having another office VBA project in break mode (Excel) and then start PowerPoint - again no errors seen.

  • I've tried comparing the registry (HKCU) for when PowerPoint is in break mode and when it isn't to see if that might give a clue - but there was nothing significant that was different.

The XML for the GridMaker add-in looks like this (in customUI.xml - I open the pptm file in Visual Studio with the Open XML Package Editor extension):

<customUI onLoad="GMApplicationEventsModule.gmRibbonUI_onLoad" xmlns="http://schemas.microsoft.com/office/2006/01/customui" xmlns:nsCommtap="CommtapNamespace">
  <ribbon startFromScratch="false">
    <tabs>
      <tab idMso="TabHome">
        <group id="gridMakerGroup" label="Grid Maker">
          <button id="gmMakeGrid"
                  label="Make Into Grid"
                  imageMso="TableInsert"
                  size="normal"
                  onAction="MainModule.makeGrid"
                  getEnabled="GMApplicationEventsModule.gm_GetEnabled" />
        </group>
      </tab>
    </tabs>
  </ribbon>
</customUI>

The GMApplicationEventsModule looks like this:

Option Explicit

Private m_oMyRibbon As IRibbonUI
Private m_boolShapeSelected As Boolean
Private m_oAppEvents As CGMApplicationEvents

Public Function get_m_oMyRibbon() As IRibbonUI
  Set get_m_oMyRibbon = m_oMyRibbon
End Function

Public Sub set_m_boolShapeSelected(value As Boolean)
  m_boolShapeSelected = value
End Sub

Public Function get_m_boolShapeSelected() As Boolean
  get_m_boolShapeSelected = m_boolShapeSelected
End Function

Public Sub gm_GetEnabled(control As IRibbonControl, ByRef returnedVal)
  returnedVal = True
  If control.Id = "gmMakeGrid" Then
    returnedVal = GMApplicationEventsModule.get_m_boolShapeSelected
  End If
End Sub

Public Sub gmRibbonUI_onLoad(Ribbon As IRibbonUI)
  Set m_oMyRibbon = Ribbon
End Sub

Public Sub Auto_Open()
  If m_oAppEvents Is Nothing Then
    Set m_oAppEvents = New CGMApplicationEvents
  End If
  Set m_oAppEvents.App = Application
End Sub

Class CGMApplicationEvents:

Option Explicit

Public WithEvents App As Application

Private Sub App_WindowSelectionChange(ByVal Sel As Selection)

  If Application.ActiveWindow.Selection.Type <> ppSelectionShapes Then
    GMApplicationEventsModule.set_m_boolShapeSelected False
  Else
    GMApplicationEventsModule.set_m_boolShapeSelected True
  End If

  If Not GMApplicationEventsModule.get_m_oMyRibbon Is Nothing Then
    Dim oRibbon As IRibbonUI
    Set oRibbon = GMApplicationEventsModule.get_m_oMyRibbon
    oRibbon.InvalidateControl "gmMakeGrid"
  End If

End Sub

I have another two add-ins which look like this. The onAction on the gmMakeGrid button (above) runs some code which creates a grid of shapes from a shape selection. The other two add-ins simply show a message when their buttons are clicked. But it should be possible (or not - as the errors seem to be intermittent) to see the errors if the code shown here is just linked to showing a message box.

Making the error message appear

I am now able to make the error message ("PowerPoint can't start this feature...") appear, which also shows that the source of the error could originate from somewhere other than the add-in where the error is seen.

I have one add-in - app1-basic (using the code as described above) which is enabled. I have a second macro (app2-basic.pptm) file (also as described above) in which I have put a "Stop" statement in the onLoad procedure. With PowerPoint closed, open app2-basic.pptm. Whilst opening, the VBE will open and code execution will stop at the stop statement. Now close PowerPoint (by clicking on the "X" in the partially opened PowerPoint). This will display the error message.

The error message appears to be triggered because PowerPoint is trying to call the getEnabled procedure in the add-in but is unable to because the macro being opened has put it in break mode. Logging seems to support this:

Time                    Time tick       VBA Project     Module                  Procedure               Comment

Stop in app2-basic onLoad which is opened as pptm (not add-in), one other add-in enabled (app1-basic)                   
25/02/19 15:17:58:258   158,650,603,696 app1-basic      ApplicationEventsModule Auto_Open               Called
25/02/19 15:17:58:258   158,650,619,479 app1-basic      ApplicationEventsModule Auto_Open               Completed
25/02/19 15:17:59:259   158,653,089,479 app1-basic      ApplicationEventsModule set_m_boolShapeSelected Called
25/02/19 15:17:59:259   158,653,105,936 app1-basic      ApplicationEventsModule get_m_oMyRibbon         Called
25/02/19 15:17:59:259   158,653,421,625 app1-basic      ApplicationEventsModule gmRibbonUI_onLoad       Called.
25/02/19 15:17:59:259   158,653,477,892 app1-basic      ApplicationEventsModule gmRibbonUI_onLoad       Completed
25/02/19 15:17:59:259   158,653,560,560 app2-basic      ApplicationEventsModule gmRibbonUI_onLoad       Called.

Normal open then close - app1 - with no errors                  
25/02/19 15:34:45:245   161,505,047,523 app1-basic      ApplicationEventsModule Auto_Open               Called
25/02/19 15:34:45:245   161,505,061,039 app1-basic      ApplicationEventsModule Auto_Open               Completed
25/02/19 15:34:54:254   161,531,088,269 app1-basic      ApplicationEventsModule gmRibbonUI_onLoad       Called.
25/02/19 15:34:54:254   161,531,110,752 app1-basic      ApplicationEventsModule gmRibbonUI_onLoad       Completed
25/02/19 15:34:54:254   161,531,169,707 app1-basic      ApplicationEventsModule app1_GetEnabled Called: Control.id: app1ShapeSelectedMsg
25/02/19 15:34:54:254   161,531,200,726 app1-basic      ApplicationEventsModule get_m_boolShapeSelected Called
25/02/19 15:34:54:254   161,531,215,706 app1-basic      ApplicationEventsModule app1_GetEnabled         Completed: Control.id: app1ShapeSelectedMsg

Further comments:

  • From time to time, after a number of rounds of making errors appear and then correcting them, this error message can then appear when loading add-ins where there are no errors. I've still not been able to come up with a repeatable sequence of actions that causes this to happen.

  • It is looking like the error is likely to be arising from somewhere else other than the add-in which is failing to load properly because of the error. It also seems possible that the error could be due to a problem with the state in which PowerPoint is opened - perhaps due to a problem encountered when it was last closed.

Code to demonstrate the errors

Full code which produces this error message from time to time.

2
I've added a link to code for two minimal add-ins which will show the error messages (from time to time).neilt17

2 Answers

1
votes

I ran into this same situation just yesterday, and from your description, we may have encountered something similar.

You can get this error when you reference e.g. the current presentation's path or the current selection while the add-in is loading ... ie, there IS no open presentation and by extension there can be no current selection.

I was able to track down the exact line of code that triggered the error by writing a little function that pops a message box with some descriptive text and optionally the name of the current subroutine in the title:

Public Sub UberMsg(sMsgString As String, Optional sRoutine As String = "Debug Msg")
    If UberMsg Then
        Call MsgBox(sMsgString, vbOKOnly, sRoutine)
    End If
End Sub

Declared as globals a string called sRoutine and a bool called UberMsg (set to True)

Then at various points in my AutoOpen sub and subs called from it:

This, once at the begging of the routine:

sRoutine = "{the current procedure name}"

And copy/paste/edit this just before every suspect code point:

UberMsg "AppInit entry point", sRoutine

It only took a few iterations of saving PPAMs and retesting to locate the problem area and fix it.

I'll set the UberMsg boolean to false and leave all of this in place in case it's needed later.

1
votes

Unfortunately I have been unable to make it so this problem will always appear - whatever set up I have, the problem seems to appear randomly and to disappear randomly.

My solution is to sidestep the problem completely and not to use Auto_Open (this problem never occurs if Auto_Open is not used) and not to use _onLoad which can also be problematic. This means that the buttons will always be available even for contexts where they won't work.

To make this situation a bit more user friendly (and not just have some irritating message box error popping up to tell people they've clicked on an invalid button), I have arranged it so that if a user selects a button which doesn't apply to the current context - for example the operation requires them to select some text for it to work but they haven't - a modeless dialog will pop up which contains an explanation of what they need to do to get the button to work (e.g. select some text) plus an exact replica of the buttons from the group in the ribbon in which the buttons enable/disable themselves correctly according to the context.

I've created these buttons by cropping screenshots of each button in each of their three states (hover, enabled, disabled) and layering them on top of each other in a userform. I use the App_WindowSelectionChange event to change the ZOrder of the relevant buttons so that when the appropriate thing is selected the enabled button comes to the top, and, given that the right thing is selected, the hover version of the button will come to the top when the mouse is over it (MouseMove trigger in the userform) - this is also the version of the button which will trigger any code when clicked.

I think this is not a bad solution because the user gets more information about when they can use the buttons and they can have a dialog present that works in the same way as the ribbon should have worked if they so wish. Our button groups are quite small (no more than four buttons) so the dialog is quite small too and easy to have displayed and pushed out of the way - it might not be so satisfactory for groups with lots of buttons in them.