Поделиться через


Перенос функций управления потоками

В этом разделе описывается перенос кода потоков в приложении универсальная платформа Windows (UWP) в пакет SDK для приложений Windows.

Сводка различий между API и (или) функциями

Модель потоков UWP — это вариация модели однопоточной квартиры (STA) с именем Application STA (ASTA), которая блокирует повторное выполнение и помогает избежать различных ошибок повторного входа и взаимоблокировок. Поток ASTA также называется потоком пользовательского интерфейса.

Пакет SDK для приложений Windows использует стандартную модель потоков STA, которая не обеспечивает те же гарантии повторного входа.

Тип CoreDispatcher переносится в DispatcherQueue. И метод CoreDispatcher.RunAsync переносится в DispatcherQueue.TryEnqueue.

C++/WinRT. Если вы используете winrt::resume_foreground с CoreDispatcher, перенесите их на использование DispatcherQueue .

Переход с модели ASTA на модель STA

Дополнительные сведения о модели потоков ASTA см. в записи блога о том, что такое особенное о приложении STA?.

Так как модель потокового потока пакета SDK для Приложений Windows не имеет одинаковых гарантий, связанных с предотвращением проблем повторного ввода данных, если приложение UWP предполагает, что не выполняется повторная запись модели потоков ASTA, код может не вести себя должным образом.

Одно из действий, чтобы следить за повторной отступом в элементы управления XAML (см. пример миграции примера приложения UWP (C++/WinRT)). И для некоторых сбоев, таких как нарушения доступа, прямой вызов вызовов аварийного сбоя обычно является правильным стеком для использования. Но если это сбой с застроченным исключением, который имеет код исключения : 0xc000027b, то для получения правильного вызова требуется дополнительная работа.

Застраиваемые исключения

Неустраченное исключение сохраняет возможную ошибку и используется позже, если часть кода не обрабатывает исключение. XAML иногда решает, что ошибка неустранима, в этом случае прямой стек аварийного сбоя может быть хорошим. Но чаще стек расправился до того, как он был определен, чтобы быть смертельным. Дополнительные сведения об устраченных исключениях см. в эпизоде "Внутри шоу" C000027B.

Для аварийного сбоя исключения (чтобы увидеть вложенный насос сообщений или увидеть конкретное исключение элемента управления XAML), вы можете получить дополнительные сведения о сбое, загрузив аварийный дамп в отладчик Windows (WinDbg) (см. статью "Скачать средства отладки для Windows"), а затем использовать для !pde.dse дампа заглушенных исключений.

Расширение отладчика PDE (для !pde.dse команды) доступно путем скачивания PDE*.zip файла из OneDrive. Поместите соответствующий файл x64 или x86 .dll из этого ZIP-файла в winext каталог установки WinDbg, а затем !pde.dse будет работать над аварийными дампами исключений.

Часто возникает несколько заглушитых исключений, при этом некоторые из нее были обработаны или проигнорированы. Чаще всего первое застраиваемое исключение является интересным. В некоторых случаях первое закрепленное исключение может быть повторным вызовом второго, поэтому если второе застраивание исключения отображается глубже в том же стеке, что и первая, то второе исключение может быть источником ошибки. Код ошибки, показанный с каждым застраанным исключением, также ценен, так как предоставляет HRESULT , связанный с этим исключением.

Изменение Windows.UI.Core.CoreDispatcher на Microsoft.UI.Dispatching.DispatcherQueue

Этот раздел применяется, если вы используете класс Windows.UI.Core.CoreDispatcher в приложении UWP. Это включает использование любых методов или свойств, которые принимают или возвращают CoreDispatcher, например свойства DependencyObject.Dispatcher и CoreWindow.Dispatcher. Например, вы будете вызывать DependencyObject.Dispatcher при получении CoreDispatcher, принадлежащих Windows.UI.Xaml.Controls.Page.

// MainPage.xaml.cs in a UWP app
if (this.Dispatcher.HasThreadAccess)
{
    ...
}
// MainPage.xaml.cpp in a UWP app
if (this->Dispatcher().HasThreadAccess())
{
    ...
}

Вместо этого в приложении пакета SDK для приложений Windows необходимо использовать класс Microsoft.UI.Dispatching.DispatcherQueue. И соответствующие методы или свойства, которые принимают или возвращают свойства DispatcherQueue, такие как свойства DependencyObject.DispatcherQueue и Microsoft.UI.Xaml.Window.DispatcherQueue. Например, вы будете вызывать DependencyObject.DispatcherQueue при получении диспетчераQueue, принадлежащих Microsoft.UI.Xaml.Controls.Page (большинство объектов XAML — DependencyObject).

// MainPage.xaml.cs in a Windows App SDK app
if (this.DispatcherQueue.HasThreadAccess)
{
    ...
}
// MainPage.xaml.cpp in a Windows App SDK app
#include <winrt/Microsoft.UI.Dispatching.h>
...
if (this->DispatcherQueue().HasThreadAccess())
{
    ...
}

Изменение CoreDispatcher.RunAsync на DispatcherQueue.TryEnqueue

Этот раздел применяется, если вы используете метод Windows.UI.Core.CoreDispatcher.RunAsync, чтобы запланировать выполнение задачи в основном потоке пользовательского интерфейса (или в потоке, связанном с определенным Windows.UI.Core.CoreDispatcher).

// MainPage.xaml.cs in a UWP app
public void NotifyUser(string strMessage)
{
    if (this.Dispatcher.HasThreadAccess)
    {
        StatusBlock.Text = strMessage;
    }
    else
    {
        var task = this.Dispatcher.RunAsync(
            Windows.UI.Core.CoreDispatcherPriority.Normal,
            () => StatusBlock.Text = strMessage);
    }
}
// MainPage.cpp in a UWP app
void MainPage::NotifyUser(std::wstring strMessage)
{
    if (this->Dispatcher().HasThreadAccess())
    {
        StatusBlock().Text(strMessage);
    }
    else
    {
        auto task = this->Dispatcher().RunAsync(
            Windows::UI::Core::CoreDispatcherPriority::Normal,
            [strMessage, this]()
            {
                StatusBlock().Text(strMessage);
            });
    }
}

В приложении пакета SDK для приложений для Windows используйте вместо этого метод Microsoft.UI.Dispatching.DispatcherQueue.TryEnqueue. Он добавляет в Microsoft.UI.Dispatching.DispatcherQueue задачу, которая будет выполняться в потоке, связанном с DispatcherQueue.

// MainPage.xaml.cs in a Windows App SDK app
public void NotifyUser(string strMessage)
{
    if (this.DispatcherQueue.HasThreadAccess)
    {
        StatusBlock.Text = strMessage;
    }
    else
    {
        bool isQueued = this.DispatcherQueue.TryEnqueue(
        Microsoft.UI.Dispatching.DispatcherQueuePriority.Normal,
        () => StatusBlock.Text = strMessage);
    }
}
// MainPage.xaml.cpp in a Windows App SDK app
#include <winrt/Microsoft.UI.Dispatching.h>
...
void MainPage::NotifyUser(std::wstring strMessage)
{
    if (this->DispatcherQueue().HasThreadAccess())
    {
        StatusBlock().Text(strMessage);
    }
    else
    {
        bool isQueued = this->DispatcherQueue().TryEnqueue(
            Microsoft::UI::Dispatching::DispatcherQueuePriority::Normal,
            [strMessage, this]()
            {
                StatusBlock().Text(strMessage);
            });
    }
}

Миграция winrt::resume_foreground (C++/WinRT)

Этот раздел применяется, если вы используете функцию winrt::resume_foreground в корутине в приложении UWP C++/WinRT.

В UWP вариант использования winrt::resume_foreground заключается в переключении выполнения на поток переднего плана (этот поток переднего плана часто связан с Windows.UI.Core.CoreDispatcher). Вот пример этого.

// MainPage.cpp in a UWP app
winrt::fire_and_forget MainPage::ClickHandler(IInspectable const&, RoutedEventArgs const&)
{
    ...
    co_await winrt::resume_foreground(this->Dispatcher());
    ...
}

В приложении пакета SDK для приложений для Windows:

Поэтому сначала добавьте ссылку на пакет NuGet Microsoft.Windows.ImplementationLibrary .

Затем добавьте в целевой проект следующую команду pch.h .

#include <wil/cppwinrt_helpers.h>

Затем следуйте приведенному ниже шаблону.

// MainPage.xaml.cpp in a Windows App SDK app
...
winrt::fire_and_forget MainPage::ClickHandler(IInspectable const&, RoutedEventArgs const&)
{
    ...
    co_await wil::resume_foreground(this->DispatcherQueue());
    ...
}

См. также