CoreDispatcher.ProcessEvents() causes an indirect crash?
-
Monday, September 03, 2012 9:21 AM
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
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.


