2

In my PowerPoint 2010 Addin I subscribed to the CommandBars.OnUpdate event to register movement of shapes and similar events:

 ppt = Globals.ThisAddIn.Application;
 ppt.CommandBars.OnUpdate += CommandBars_OnUpdate;

This works great for some time. However, eventually the event stops being fired. Well, at least the registered event handler is not being called. I couldn't figure out, what causes this behaviour. It seems a bit indeterministic. No exception is thrown that would appear in the Debug output. It seems, this happens after some time and is not caused by a user action.

I assumed, this would be due to a change of the CommandBars object. So I added a timer, which checked for those changes. But both == and .Equals() comparisons to the last object result in a recognized change every tick, which is very unlikely.

I also tried to refresh the event handler periodically (every 1 minute), but this doesn't work either:

ppt.CommandBars.OnUpdate -= CommandBars_OnUpdate;
ppt.CommandBars.OnUpdate += CommandBars_OnUpdate;

Does the event really stop after some time? Is there any other method to detect object movement, resize, deletion etc.?


Update

In the meanwhile I restructured the addin. I am now able to reproduce the problem. Here is how:

In the addin's ribbon I have a button, which calls the method CreateRightEyeCopy() on the ViewModel. In this method another method GetNextPairId() of the ViewModel is called. And this call seems problematic. I changed the GetNextPairId() to immediately return 0 to ensure that the method is the problem.

Here is the resulting stack trace in the return 0 line:

ViewModel.GetNextPairId()
[External Code]
ViewModel.CreateRightEyeCopy()
Button's event handler

I wonder, why there is external code in between my two functions. Can this code cause the OnUpdate event to stop?

If someone's interested, here is the code of the two functions:

CreateRightEyeCopy():

try
{
    var sel = ppt.ActiveWindow.Selection;
    if (sel.Type == PpSelectionType.ppSelectionShapes)
    {
        foreach (Shape s in sel.ShapeRange)
        {
            var pair = FindStereoPair(s);
            //Only add a new pair, if shape is not in a pair already
            if (pair == null)
            {
                // ** return; **
                int id = GetNextPairId(s.Parent);
                return; //for debugging purposes
            }
        }
    }
}
catch (Exception x)
{
    Debug.WriteLine("Exception occured during creation of stereo pair: " + x.Message);
}

GetNextPairId():

return 0;

If I insert a return statement before the call to GetNextPairId(), then OnUpdate continues.

I also tried to invoke CreateRightEyeCopy() asynchronously, but that doesn't change anything.

Are there any further thoughts on this issue?

Nico Schertler
  • 32,049
  • 4
  • 39
  • 70
  • I'd be curious to hear if you made any more progress on this, what approach did you end up with / did you discover? – Cilvic Sep 19 '14 at 07:58
  • 1
    @Cilvic I worked around this problem with the `WindowSelectionChange` event, which is fired reliably. Additionally, I used a timer to reflect partial changes. – Nico Schertler Sep 19 '14 at 10:03

2 Answers2

1

Not a real answer but MSDN says: "It is strongly recommended that this event be used primarily for checking that a custom command bar has been added or removed by a COM AddIn."

You should probably choose a different approach to track other events.

As an afterthought, are you sure you are capturing all exceptions (UnhandledException, ThreadException)?

Paul B.
  • 2,394
  • 27
  • 47
  • I know, what the MSDN says. But I see no other option. Events in VSTO seem very rare. There is definitely no exception which could be caught by my code. – Nico Schertler Sep 11 '12 at 10:24
  • Have you considered if subscribing to `OnWindowSelectionChange` and checking the command bar/ribbon state in the handler method could be helpful? – Paul B. Sep 11 '12 at 15:01
  • Yes, but this event does not fire when a shape is being moved. I am not really interested in the state of a command bar / ribbon. – Nico Schertler Sep 11 '12 at 18:18
  • Actually I am surprised that a CommandBars.OnUpdate event is raised when a shape is moved. But anyway, you might want to look into window subclassing for a reliable solution. That's the best idea I have right now -- sorry, I couldn't be of more help. – Paul B. Sep 12 '12 at 17:05
  • @PaulB. can you give me a little pointer what window you would try to subclass / how to capture change events that way? – Cilvic Sep 19 '14 at 08:00
  • For the subclassing you would get a handle (hWnd) for the window, then send that to a custom `NativeWindow` implementation via `base.AssignHandle()` and then override the `WndProc` method. – Peter Oct 23 '19 at 13:46
1

I know this is a very old question, but I had a similar problem. In Outlook I lost events for the CommandBars.OnUpdate. It would never run on the first time I opened a meeting but always when I opened an Appointment. Very random behavior overall.

The fix was described in the snipped in the following post: https://social.msdn.microsoft.com/Forums/en-US/c6472472-2ae4-496a-b553-a931aeb7a8f6/excel-commandbars-onupdate-event-handler-stops-responding?forum=vsto

I changed two things:

  • The reference should not be to the direct CommandBarsObject but it should be stored in a local variable (I assume that somehow the reference is being garbage collected)
  • The actual event subscription is explicitly with the _CommandBarsEvents_OnUpdateEventHandler (I don't think that it is strictly necessary but now it works)

A global reference to the CommandBars object

private Microsoft.Office.Core.CommandBars bars = Globals.ThisAddIn.Application.CommandBars

And in the assignment function

 bars.OnUpdate += new Microsoft.Office.Core._CommandBarsEvents_OnUpdateEventHandler(CommandBars_OnUpdate);
Peter
  • 745
  • 6
  • 17