"The window has already been destroyed" causes std::bad_function_call

0

I am writing C++/WinRT UWP app and there are places in the code where exceptions can be thrown; because of connectivity issues or wrong permissions. I want then ask the user if he or she wants to close the app, or try again (to run the same function again, with same arguments and target).

Let's say this is my may-fail function:

//MainPage.cpp
IAsyncAction MainPage::ConnectAsync(std::function<IAsyncAction(hstring, hstring)> CallCritical)
{
    static int32_t i = 0;
    ++i;

    if (i < 5)
        co_await CallCritical(L"Error", L"Test error, try no " + to_hstring(i));
}

It's just for testing so it will simply fail 4 times before it succeeded. This is how it's called for the first time:

MainMage.cpp
IAsyncAction MainPage::ClickHandler(IInspectable const&, RoutedEventArgs const&)
{
    DispatcherQueue main_thread = DispatcherQueue::GetForCurrentThread();
    co_await resume_background();

    std::function<IAsyncAction(hstring, hstring)> CallCritical;
    CallCritical = [=, &CallCritical](hstring title, hstring msg)->IAsyncAction
    {
        co_await this->CriticalAsync(title, msg, main_thread, [=, &CallCritical](IUICommand const&)->IAsyncAction
        {
            co_await this->ConnectAsync(CallCritical);
        });
    };
    co_await this->ConnectAsync(CallCritical);

    auto info_box = box_value(L"Connected");
    co_await resume_foreground(main_thread);
    myButton().Content(info_box);
}

I've used recursive lambda calling a method which asks the user if he wants to try again:

//MainPage.h
template<typename Lambda>
Windows::Foundation::IAsyncAction CriticalAsync(winrt::hstring title, winrt::hstring msg, Windows::System::DispatcherQueue main_thread, Lambda retry)
{
    MessageDialog dialog{ msg, title };

    UICommand try_again
    {
        L"Try again",
        { retry }
    };
    dialog.Commands().Append(try_again);

    UICommand give_up
    {
        L"Close",
        { [](IUICommand const&) { Windows::ApplicationModel::Core::CoreApplication::Exit(); } }
    };
    dialog.Commands().Append(give_up);

    dialog.DefaultCommandIndex(0);
    dialog.CancelCommandIndex(dialog.Commands().Size() - 1);

    co_await resume_foreground(main_thread);
    co_await dialog.ShowAsync();
}

It also takes the main window's thread and passes it here.

The code WORKS. The app is asking me two or three times if I want to try again but I'm never getting out of the loop. First I see this error:

Exception thrown at 0x00007FFC529DA839 (KernelBase.dll) in TestApp.exe: WinRT originate error - 0x80004005 : 'The window has already been destroyed.'.

Then after I click to try_again, the exception is thrown on CallCritical inside ConnectAsync:

Exception thrown at 0x00007FFC529DA839 in TestApp.exe: Microsoft C++ exception: std::bad_function_call at memory location 0x000000B9F94FBA70.

Exception thrown at 0x00007FFC529DA839 in TestApp.exe: Microsoft C++ exception: [rethrow] at memory location 0x0000000000000000.

Exception thrown at 0x00007FFC529DA839 (KernelBase.dll) in TestApp.exe: WinRT originate error - 0x80004005 : 'bad function call'.

Exception thrown at 0x00007FFC529DA839 in TestApp.exe: Microsoft C++ exception: winrt::hresult_error at memory location 0x000000B9F94FC138.

What does it mean that the window was already destroyed? Which window - dialog or main? Either way, I don't know what to do with it...

c++
uwp
c++17
std
c++-winrt
asked on Stack Overflow Jul 19, 2019 by smsware • edited Jul 19, 2019 by smsware

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0