Search code examples
c++winui-3c++-winrt

I'm using PropertyChanged to update textblock, but when clicked, crashed: Application called an interface that was marshalled for a different thread


Now I'm trying to use PropertyChangedEvent to test update the textblock, but when I click, it crashed: WinRT originate error - 0x8001010E : The application called an interface that was marshalled for a different thread.

//in WordArray.cpp

namespace winrt::Lexical_Frequency::implementation
{
    WordArray::WordArray(winrt::hstring const& allword) : m_allword{ allword }
    {
    }

    winrt::hstring WordArray::AllWord()
    { 
        return m_allword;
    }

    void WordArray::AllWord(winrt::hstring const& value)
    {
        if (m_allword != value)
        {
            m_allword = value;
            m_propertyChanged(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"AllWord" });
        }
    }
    
    winrt::event_token WordArray::PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler)
    {
        return m_propertyChanged.add(handler);
    }

    void WordArray::PropertyChanged(winrt::event_token const& token)
    {
        m_propertyChanged.remove(token);
    }
}

//in DataPage.xaml.cpp
namespace winrt::Lexical_Frequency::implementation
{
    DataPage::DataPage()
    {
        m_mainviewModel = winrt::make<Lexical_Frequency::implementation::WordArrayViewModel>();
        InitializeComponent();
    }

    void DataPage::ClickHandler(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e)
    {
        MainViewModel().WordArray().AllWord(L"xxx");
    }

    void DataPage::SaveFileButton_Click(IInspectable const&, RoutedEventArgs const&)
    {
        GetFileNameSave();
    }

    Lexical_Frequency::WordArrayViewModel DataPage::MainViewModel()
    {
        return m_mainviewModel;
    }
}

Now I'm trying to use MainViewModel().WordArray().AllWord(L"To Kill a Mockingbird"); to test update the textblock, but when I click, it crashed: WinRT originate error - 0x8001010E : The application called an interface that was marshalled for a different thread.


Solution

  • You'll frequently encounter this error when dropping code written for Microsoft's "Modern" UI platform (that never got a name) into a WinUI 3 application.

    A bit of historic context: Alongside the "Modern" UI platform, Windows 8 introduced a variation of the STA, the Application STA (wildly undocumented1, no surprises there). Windows 10 finally exposed the "Modern" UI platform (still unnamed) through Windows Runtime types under the Windows.UI.Xaml namespace. (Most) of those types will want to be accessed from the ASTA (which is apparently enforced at run time, evidenced by the RPC_E_WRONG_THREAD "exception").

    Fast forward to today, the "Modern" UI platform mostly gone, together with its clean design language. The UWP sharing a coffin with Windows 10 Mobile, and the ASTA history, too. WinUI 3 has come full circle, ultimately supporting the classic Desktop application model only, back to the classic COM threading architecture: Zero or one MTA, and any number of STAs.

    No ASTA, anywhere.

    After that bit of a detour it should be easy to understand, what the issue is: The code is trying to access objects designed for the ASTA from a regular STA thread.

    The solution is pretty straight forward, too: Replace all types from the Windows.UI.Xaml namespace with their WinUI 3 twins from the Microsoft.UI.Xaml namespace:

    To do this you will also have to update the respective #include directives that reference <winrt/Windows.UI.Xaml. ... .h> header files to use <winrt/Microsoft.UI.Xaml. ... .h> instead, and replace any using namespace directives accordingly.


    1 Raymond Chen explains what problem it is trying to solve in his blog entry What is so special about the Application STA?.