Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
W tym temacie opisano sposób migrowania kodu wątkowego w aplikacji platformy uniwersalnej systemu Windows (UWP) do zestawu SDK aplikacji systemu Windows.
Podsumowanie różnic między interfejsami API i/lub funkcjami
Model wątkowy UWP jest odmianą modelu jednowątkowego apartamentu (STA) o nazwie Application STA (ASTA), który uniemożliwia ponowne wejście i pomaga unikać różnych błędów oraz zakleszczeń. Wątek ASTA jest również nazywany wątkiem interfejsu użytkownika.
Zestaw SDK aplikacji systemu Windows używa standardowego modelu wątkowania STA, który nie zapewnia tych samych zabezpieczeń ponownego instalowania.
Typ CoreDispatcher migruje do DispatcherQueue. Metoda CoreDispatcher.RunAsync migruje do metody DispatcherQueue.TryEnqueue.
C++/WinRT. Jeśli używasz winrt::resume_foreground z CoreDispatcher, przeprowadź migrację, aby zamiast tego użyć DispatcherQueue.
Model przejścia z ASTA do STA
Aby uzyskać więcej informacji na temat modelu wątkowania ASTA, zobacz wpis na blogu Co jest tak wyjątkowego w Application STA?.
Ponieważ w modelu wątkowania STA zestawu Windows App SDK nie ma tych samych gwarancji dotyczących zapobiegania problemom z ponownym wejściem, jeśli Twoja aplikacja UWP zakłada niepowtarzalne (non-reentrant) zachowanie modelu wątkowania ASTA, kod może nie działać zgodnie z oczekiwaniami.
Jedną z rzeczy, na które należy zwrócić uwagę, jest ponowny wstęp do kontrolek XAML (zobacz przykład w z migracji zestawu SDK aplikacji Windows dla przykładowej aplikacji Edytora zdjęć UWP (C++/WinRT)). A w przypadku niektórych awarii, takich jak naruszenia dostępu, bezpośredni stos wywołań awaryjnych jest zwykle właściwym stosem do użycia. Ale jeśli jest to awaria typu stowed exception, który ma kod wyjątku: 0xc000027b, to wymaga podjęcia dalszych działań, aby uzyskać odpowiedni stos wywołań.
Wyjątki przechowywane
Zachowana wyjątek przechowuje możliwy błąd, który zostanie wykorzystany później, jeśli żadna część kodu nie obsłuży tego wyjątku. XAML czasami natychmiast decyduje, że błąd jest krytyczny, w takim przypadku bezpośredni stos wywołań związanych z awarią może być przydatny. Ale częściej stos rozpadł się, zanim uznano go za śmiertelny. Aby uzyskać więcej informacji na temat wyjątków stowed, zobacz Inside Show episode Stowed Exception C000027B.
W przypadku awarii z wyjątkami specjalnymi (aby zobaczyć zagnieżdżoną pętlę komunikatów lub zobaczyć specyficzny wyjątek kontrolki XAML), możesz uzyskać więcej informacji o awarii, ładując zrzut awarii w debugerze systemu Windows (WinDbg) (zobacz Pobierz narzędzia debugowania dla systemu Windows), a następnie używając !pde.dse do zrzutu zapisanych wyjątków.
Rozszerzenie debugera pdE (dla !pde.dse polecenia) jest dostępne, pobierając plik PDE*.zip z usługi OneDrive. Umieść odpowiedni plik z architekturą x64 lub x86 .dll z tego pliku ZIP w katalogu winext instalacji WinDbg, a następnie !pde.dse będzie działać na zrzutach pamięci z wyjątkami przechowywanymi.
Często będzie wiele zmagazynowanych wyjątków, z których niektóre na końcu zostały obsłużone lub zignorowane. Najczęściej pierwszym schowanym wyjątkiem jest interesujący. W niektórych przypadkach pierwszy przechowywany wyjątek może być ponownym rzutem drugiego, więc jeśli drugi przechowywany wyjątek jest głębiej w tym samym stosie co pierwszy, to drugi wyjątek może być źródłem błędu. Kod błędu wyświetlany przy każdym przechowywanym wyjątku jest również wartościowy, ponieważ zawiera HRESULT skojarzone z tym wyjątkiem.
Zmień wartość Windows.UI.Core.CoreDispatcher na Microsoft.UI.Dispatching.DispatcherQueue
Ta sekcja ma zastosowanie, jeśli używasz klasy Windows.UI.Core.CoreDispatcher w aplikacji platformy UWP. Obejmuje to użycie dowolnych metod lub właściwości, które przyjmują lub zwracają CoreDispatcher, takie jak DependencyObject.Dispatcher i CoreWindow.Dispatcher. Na przykład wywołasz DependencyObject.Dispatcher podczas pobierania CoreDispatcher należącego do 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())
{
...
}
Zamiast tego w aplikacji Zestawu SDK aplikacji systemu Windows należy użyć klasy Microsoft.UI.Dispatching.DispatcherQueue. A odpowiednie metody lub właściwości, które przyjmują lub zwracają DispatcherQueue, takie jak właściwości DependencyObject.DispatcherQueue i Microsoft.UI.Xaml.Window.DispatcherQueue. Na przykład, wywołasz DependencyObject.DispatcherQueue podczas pobierania DispatcherQueue należącego do Microsoft.UI.Xaml.Controls.Page (większość obiektów XAML to DependencyObjects).
// 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())
{
...
}
Zmień metodę CoreDispatcher.RunAsync na DispatcherQueue.TryEnqueue
Ta sekcja ma zastosowanie, jeśli używasz metody Windows.UI.Core.CoreDispatcher.RunAsync, aby zaplanować zadanie do uruchomienia w głównym wątku interfejsu użytkownika (lub w wątku skojarzonym z określonym 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);
});
}
}
Zamiast tego w aplikacji Zestawu SDK aplikacji systemu Windows użyj metody Microsoft.UI.Dispatching.DispatcherQueue.TryEnqueue). Dodaje do Microsoft.UI.Dispatching.DispatcherQueue zadanie, które zostanie wykonane na wątku skojarzonym z 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);
});
}
}
Migracja winrt::resume_foreground (C++/WinRT)
Ta sekcja ma zastosowanie, jeśli używasz funkcji winrt::resume_foreground w korutynie w swojej aplikacji C++/WinRT UWP.
Na platformie UWP przypadek użycia winrt::resume_foreground polega na przełączeniu wykonywania na wątek pierwszego planu (ten wątek jest często tym, który jest skojarzony z Windows.UI.Core.CoreDispatcher). Oto przykład tego.
// MainPage.cpp in a UWP app
winrt::fire_and_forget MainPage::ClickHandler(IInspectable const&, RoutedEventArgs const&)
{
...
co_await winrt::resume_foreground(this->Dispatcher());
...
}
W aplikacji Windows App SDK:
- Zamiast winrt::resume_foreground, należy użyć wil::resume_foreground (z Windows Implementation Libraries (WIL)).
- Zamiast coreDispatcher należy użyć klasy Microsoft.UI.Dispatching.DispatcherQueue , zgodnie z opisem w temacie Change Windows.UI.Core.CoreDispatcher to Microsoft.UI.Dispatching.DispatcherQueue.
Najpierw dodaj odwołanie do pakietu NuGet Microsoft.Windows.ImplementationLibrary .
Następnie dodaj następujące include do pch.h w projekcie docelowym.
#include <wil/cppwinrt_helpers.h>
Następnie postępuj zgodnie ze wzorcem pokazanym poniżej.
// 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());
...
}
Zobacz też
Windows developer