2

I'm getting perhaps the least useful exception I've seen (outside of VBA), a System.ComponentModel.Win32Exception: "The operation completed successfully"

enter image description here

Stack trace:

   at MS.Win32.UnsafeNativeMethods.CreateWindowEx(Int32 dwExStyle, String lpszClassName, String lpszWindowName, Int32 style, Int32 x, Int32 y, Int32 width, Int32 height, HandleRef hWndParent, HandleRef hMenu, HandleRef hInst, Object pvParam)
   at MS.Win32.HwndWrapper..ctor(Int32 classStyle, Int32 style, Int32 exStyle, Int32 x, Int32 y, Int32 width, Int32 height, String name, IntPtr parent, HwndWrapperHook[] hooks)
   at System.Windows.Interop.HwndSource.Initialize(HwndSourceParameters parameters)
   at System.Windows.Interop.HwndSource..ctor(HwndSourceParameters parameters)
   at System.Windows.Controls.Primitives.Popup.PopupSecurityHelper.BuildWindow(Int32 x, Int32 y, Visual placementTarget, Boolean transparent, HwndSourceHook hook, AutoResizedEventHandler handler)
   at System.Windows.Controls.Primitives.Popup.BuildWindow(Visual targetVisual)
   at System.Windows.Controls.Primitives.Popup.CreateWindow(Boolean asyncCall)
   at System.Windows.Controls.Primitives.Popup.OnIsOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
   at System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
   at System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
   at System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args)
   at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType)
   at System.Windows.DependencyObject.InvalidateProperty(DependencyProperty dp, Boolean preserveCurrentValue)
   at System.Windows.Data.BindingExpressionBase.Invalidate(Boolean isASubPropertyChange)
   at System.Windows.Data.BindingExpression.TransferValue(Object newValue, Boolean isASubPropertyChange)
   at MS.Internal.Data.ClrBindingWorker.NewValueAvailable(Boolean dependencySourcesChanged, Boolean initialValue, Boolean isASubPropertyChange)
   at MS.Internal.Data.PropertyPathWorker.UpdateSourceValueState(Int32 k, ICollectionView collectionView, Object newValue, Boolean isASubPropertyChange)
   at MS.Internal.Data.ClrBindingWorker.OnSourcePropertyChanged(Object o, String propName)
   at System.Windows.WeakEventManager.ListenerList`1.DeliverEvent(Object sender, EventArgs e, Type managerType)
   at System.ComponentModel.PropertyChangedEventManager.OnPropertyChanged(Object sender, PropertyChangedEventArgs args)
   at System.ComponentModel.PropertyChangedEventHandler.Invoke(Object sender, PropertyChangedEventArgs e)
   at MVVMSeaCores.Controls.HelpTip.NotifyOfPropertyChange(String propertyName) in D:\Projects\MVVMSeaCores\MVVMSeaCores\Controls\HelpTip.cs:line 140
   at MVVMSeaCores.Controls.HelpTip.set_IsOpen(Boolean value) in D:\Projects\MVVMSeaCores\MVVMSeaCores\Controls\HelpTip.cs:line 181
   at MVVMSeaCores.Controls.HelpTipManager.OpenNext() in D:\Projects\MVVMSeaCores\MVVMSeaCores\Controls\HelpTip.cs:line 102
   at MVVMSeaCores.Controls.HelpTipManager.AddedToScreen(HelpTip helpTip) in D:\Projects\MVVMSeaCores\MVVMSeaCores\Controls\HelpTip.cs:line 115
   at MVVMSeaCores.Controls.HelpTipManager.HelpTip_PropertyChanged(Object sender, PropertyChangedEventArgs e) in D:\Projects\MVVMSeaCores\MVVMSeaCores\Controls\HelpTip.cs:line 67
   at System.ComponentModel.PropertyChangedEventHandler.Invoke(Object sender, PropertyChangedEventArgs e)
   at MVVMSeaCores.Controls.HelpTip.NotifyOfPropertyChange(String propertyName) in D:\Projects\MVVMSeaCores\MVVMSeaCores\Controls\HelpTip.cs:line 140
   at MVVMSeaCores.Controls.HelpTip.set_IsOnscreen(Boolean value) in D:\Projects\MVVMSeaCores\MVVMSeaCores\Controls\HelpTip.cs:line 195
   at MVVMSeaCores.Controls.HelpPopup.View1_Loaded(Object sender, RoutedEventArgs e) in D:\Projects\MVVMSeaCores\MVVMSeaCores\Controls\HelpPopup.xaml.cs:line 181
   at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
   at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
   at System.Windows.BroadcastEventHelper.BroadcastEvent(DependencyObject root, RoutedEvent routedEvent)
   at System.Windows.BroadcastEventHelper.BroadcastLoadedEvent(Object root)
   at MS.Internal.LoadedOrUnloadedOperation.DoWork()
   at System.Windows.Media.MediaContext.FireLoadedPendingCallbacks()
   at System.Windows.Media.MediaContext.FireInvokeOnRenderCallbacks()
   at System.Windows.Media.MediaContext.RenderMessageHandlerCore(Object resizedCompositionTarget)
   at System.Windows.Media.MediaContext.RenderMessageHandler(Object resizedCompositionTarget)
   at System.Windows.Interop.HwndTarget.OnResize()
   at System.Windows.Interop.HwndTarget.HandleMessage(WindowMessage msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Interop.HwndSource.HwndTargetFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)

It's consistently occurring on a single line, raising a property changed event for a property IsOpen, but it happens seemingly at random (sometimes everything works fine!):

    private void NotifyOfPropertyChange(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName)); //<-here
        }
    }

For context, IsOpen is bound to a popup's open property:

<Popup x:Name="Popup"
               DataContext="{Binding HelpTip, ElementName=userControl}"
               IsOpen="{Binding IsOpen}"
               StaysOpen="True" PopupAnimation="Fade"
               AllowsTransparency="True"
               Placement="{Binding Placement, ElementName=userControl}">

and is set by a static class, which ensures only a single one is displayed on screen at a time using loaded events to update a IsOnscreen property and this method in the static manager class:

    private static void HelpTip_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        HelpTip helpTip = sender as HelpTip;
        if (helpTip != null)
        {
            //is this on screen or not?
            switch (e.PropertyName)
            {
                case "IsOnscreen":
                    //Update our onscreen lists and perform related behaviour
                    if (helpTip.IsOnscreen)
                    {
                        AddedToScreen(helpTip);
                    }
                    else
                    {
                        RemovedFromScreen(helpTip);
                    }
                    break;
                case "IsOpen":
                    lock (helpTip.Lock)
                    {
                        if (!helpTip.IsOpen)
                        {
                            OpenNext();
                        }
                    }
                    break;
            }
        }
    }

OpenNext picks one of the helpTip's added to the screen and sets it to open using the IsOpen, which seems to be causing the error.

At first I thought it might have been some problem with concurrency, but I removed all threading and simplified things, and now everything is actually done on the Main thread.

I've never had notify property changed stuff fail before, and I've no idea what could be going wrong. Taking a look at this: System.ComponentModel.Win32Exception: The operation completed successfully it seems to be related to using too many handles (but I'm not sure how I'm reaching that limit opening and closing 6 or 7 popups - edit: also checked using taskmanager, it uses about 530 at time of crash.) or using too large graphics or buffers that are too large, both of which I don't think I'm doing, as these popups are only a handful of components.

Community
  • 1
  • 1
Joe
  • 6,773
  • 2
  • 47
  • 81
  • Monitor your process with the windows task manager to see how many Handles it is consuming. – CathalMF May 04 '16 at 12:54
  • Hadn't thought to do that. It gets up to and stays around 530, occasionally increasing to about 540. So doesn't seem to be handles. – Joe May 04 '16 at 13:01
  • Well i guess you wont see excess handles until you can replicate the crash. – CathalMF May 04 '16 at 13:06
  • It's pretty easily to replicate. Seemingly random, but frequent, made it crash on 530 – Joe May 04 '16 at 13:08

2 Answers2

2

Not a great answer. But as it's a work around at least. The error happens in MS.Win32.UnsafeNativeMethods.CreateWindowEx, and is as a result of the WPF opening the Popup. It seems this is a bug in WPF, and there's little way for me to solve it. I'm still not sure why it's affecting these pop-ups specifically. (Other popups work fine, clearly this isn't a common problem with popups, but it's very reproducible for me).

I used the following (not very pleasant) work around. Simply closing and opening the popup using something bound to it's IsOpen did not work - once it had crashed opening, the popup was completely broken until it was unloaded (changing views) and loaded again.

So the solution was to catch the error, remove the popup from it's parent, then schedule it to be added asynchronously on the dispatch thread. I had to stop simply binding to IsOpen and instead listened to the property change in the code-behind.

I've found no other instances of this error to do with popups on the internet, though there are various other causes. This might be some use for someone in the future:

    private void HelpPopup_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName.Equals("IsOpen"))
        {
            //re-try opening
            try {
                Popup.IsOpen = (sender as HelpTip).IsOpen;
            }
            catch (System.ComponentModel.Win32Exception ex)
            {
                Canvas parent = Popup.Parent as Canvas;
                Popup.IsOpen = false;
                parent.Children.Remove(Popup);
                Application.Current.Dispatcher.BeginInvoke(new Action(() => {
                    Popup.IsOpen = true;
                    parent.Children.Add(Popup);

                    //known method of updating position (for some reason it was incorrectly positioned on open)
                    var offset = Popup.HorizontalOffset;
                    Popup.HorizontalOffset = offset + 1;
                    Popup.HorizontalOffset = offset;

                }), DispatcherPriority.SystemIdle);

            }
        }
    }
Joe
  • 6,773
  • 2
  • 47
  • 81
0

If you use any grid in your popup then you should provide the height of that grid. otherwise it will take infinite height and during render, it will try to show that popup with grid of infinite height and will be crashed.

Khabir
  • 5,370
  • 1
  • 21
  • 33