CoreDispatcher.ProcessEvents() causes an indirect crash?

שאלה CoreDispatcher.ProcessEvents() causes an indirect crash?

  • Monday, September 03, 2012 9:21 AM
     
      Has Code

    I have to port some legacy code, that uses modal dialog boxes all over the place to Metro/WinRT. Because these dialog boxes provide their own message loop (using DialogBoxParam()), the calling code will wait until the user has clicked a button on the message box.

    I'm currently trying to write a replacement for the old message box class, that uses XAML and the popup control. To reproduce the same behavior, I have to wait in the calling thread, but also have to keep the UI responsive. I've found out, that CoreDispatcher::ProcessEvents() can be used in a loop, to keep processing events (yeah I realize that this isn't very beautiful, but I don't want to change all of our legacy code to a new threading model). However I'm running into an issue that keeps crashing my app.

    Here is a minimal example that reproduces the issue (just create a XAML app and wire this to a button):

    void CPPXamlTest::MainPage::Button_Click_1(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
    {
        bool cancel = false;
    
        auto popup = ref new Popup();
        auto button = ref new Button();
        button->Content = "Boom";
        auto token = (button->Click += ref new RoutedEventHandler([&cancel] (Object ^, RoutedEventArgs ^) { cancel = true; }));
        popup->Child = button;
        popup->IsOpen = true;
    
        while (!cancel)
        {
            Window::Current->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
        }
    
        popup->IsOpen = false;
        button->Click -= token;
    }

    This seems to work well for the first one or two tries of opening and closing the popup, using the two buttons. After a few tries however, the application will crash in Windows.UI.Xaml.dll, while trying to dereference a null pointer. I can also reproduce this in C# (with practically the same code).

    Does anyone have an idea, what is going on in here? Or a suggestion for an alternative approach?

    • Edited by ollb Monday, September 03, 2012 9:21 AM
    •  

All Replies

  • Monday, September 03, 2012 9:22 PM
     
      Has Code

    WinRT blocks nested message loops, so porting this directly won't work.

    instead you need to model this as an async operation.

    I'm new to Xaml but am familiar with WinRT. I put together this sample to demonstrate... the code that you would place after the "Show dialog" returns needs to be placed in the Popup Closed event handler. 

    void MainPage::PopupButtonClick(Object ^, RoutedEventArgs ^)
    {
        buttonClicked = true;   // record that a button was pressed here
        popup->IsOpen = false; // close popup
    }
    
    void MainPage::PopupClosed(Object ^popup, Object ^args)
    { 
        Output->Text = buttonClicked ? "Button Clicked" : "Light dismiss invoked";
        this->IsEnabled = true; // re-enable the main UI
    }
    
    void MainPage::PickFolder_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
    {
        popup = ref new Popup(); // its best to define this in a .xaml file so you don't have to construct it in code
        auto button = ref new Button();
        button->Content = "OK";
        button->Click += ref new RoutedEventHandler(this, &MainPage::PopupButtonClick);
        popup->Child = button;
        popup->Closed += ref new EventHandler<Object^>(this, &MainPage::PopupClosed);
        this->IsEnabled = false; // disable the main UI to keep it from getting input
        popup->IsLightDismissEnabled = true;
        buttonClicked = false;
        popup->IsOpen = true; // show the dialog
    }

     

    • Edited by Chris Guzak Tuesday, September 04, 2012 3:35 AM
    • Edited by Chris Guzak Tuesday, September 04, 2012 3:36 AM
    •  
  • Tuesday, September 04, 2012 2:29 PM
     
     

    Thanks for your answer and code sample. I'm looking into ways to rewrite parts of the existing code, but I'm afraid that this will be a lot of work.

    Are you sure that this is in fact unsupported? If WinRT would block nested message loops, shouldn't I get a nice and clean exception, when trying to do this? Right now the behavior is just confusing, because it partially works, but MAY also crash. Frankly, I think it looks like a bug in the WinRT libraries. They shouldn't just crash the program if the user uses them incorrectly.


    • Edited by ollb Tuesday, September 04, 2012 2:30 PM
    •  
  • Tuesday, September 11, 2012 4:24 AM
     
     

    it is a bug that it does not fail directly.