Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Artikel ini memberikan gambaran umum tentang menggunakan tugas latar belakang dan menjelaskan cara membuat tugas latar belakang baru di aplikasi WinUI 3. Untuk informasi tentang memigrasikan aplikasi UWP Anda dengan tugas latar belakang ke WinUI, lihat strategi migrasi tugas latar belakang Windows App SDK Tugas Latar Belakang.
Tugas latar belakang adalah komponen aplikasi yang berjalan di latar belakang tanpa antarmuka pengguna. Mereka dapat melakukan tindakan seperti mengunduh file, menyinkronkan data, mengirim pemberitahuan, atau memperbarui petak peta. Mereka dapat dipicu oleh berbagai peristiwa, seperti waktu, perubahan sistem, tindakan pengguna, atau pemberitahuan push. Tugas-tugas ini dapat dijalankan ketika pemicu yang sesuai terjadi bahkan ketika aplikasi tidak dalam status berjalan.
Implementasi tugas latar belakang berbeda untuk aplikasi UWP dan WinUI. Untuk informasi tentang memigrasikan aplikasi UWP Anda dengan tugas latar belakang ke WinUI, lihat Windows App SDK strategi migrasi tugas latar belakang.
Task Scheduler membantu aplikasi desktop mencapai fungsionalitas yang sama yang disediakan oleh BackgroundTaskBuilder di aplikasi UWP. Detail selengkapnya tentang implementasi menggunakan TaskScheduler tersedia di sini.
Mendaftarkan tugas latar belakang
Gunakan kelas BackgroundTaskBuilder yang disertakan dengan Windows App SDK untuk mendaftarkan tugas latar belakang yang menggunakan komponen COM kepercayaan penuh.
Contoh berikut menunjukkan cara mendaftarkan tugas latar belakang menggunakan C++. Dalam sampel Windows App SDK github, Anda dapat melihat kode pendaftaran ini di MainWindow.Xaml.cpp
auto access = co_await BackgroundExecutionManager::RequestAccessAsync();
// Unregister all existing background task registrations
auto allRegistrations = BackgroundTaskRegistration::AllTasks();
for (const auto& taskPair : allRegistrations)
{
IBackgroundTaskRegistration task = taskPair.Value();
task.Unregister(true);
}
//Using the Windows App SDK API for BackgroundTaskBuilder
winrt::Microsoft::Windows::ApplicationModel::Background::BackgroundTaskBuilder builder;
builder.Name(L"TimeZoneChangeTask");
SystemTrigger trigger = SystemTrigger(SystemTriggerType::TimeZoneChange, false);
auto backgroundTrigger = trigger.as<IBackgroundTrigger>();
builder.SetTrigger(backgroundTrigger);
builder.AddCondition(SystemCondition(SystemConditionType::InternetAvailable));
builder.SetTaskEntryPointClsid(__uuidof(winrt::BackgroundTaskInProcCPP::BackgroundTask));
try
{
builder.Register();
}
catch (...)
{
// Indicate an error was encountered.
}
Contoh berikut menunjukkan cara mendaftarkan tugas latar belakang menggunakan C#. Dalam sampel Windows App SDK github, Anda dapat melihat kode pendaftaran ini di MainWindow.Xaml.cpp.
await BackgroundExecutionManager.RequestAccessAsync();
// Unregister all existing background task registrations
var allRegistrations = BackgroundTaskRegistration.AllTasks;
foreach (var taskPair in allRegistrations)
{
IBackgroundTaskRegistration task = taskPair.Value;
task.Unregister(true);
}
//Using the Windows App SDK API for BackgroundTaskBuilder
var builder = new Microsoft.Windows.ApplicationModel.Background.BackgroundTaskBuilder();
builder.Name = "TimeZoneChangeTask";
var trigger = new SystemTrigger(SystemTriggerType.TimeZoneChange, false);
var backgroundTrigger = trigger as IBackgroundTrigger;
builder.SetTrigger(backgroundTrigger);
builder.AddCondition(new SystemCondition(SystemConditionType.InternetAvailable));
builder.SetTaskEntryPointClsid(typeof(BackgroundTask).GUID);
builder.Register();
Perhatikan bahwa pemanggilan metode SetEntryPointClsid menggunakan GUID sebagai argumen untuk kelas yang didefinisikan oleh aplikasi dan mengimplementasikan IBackgroundTask. Antarmuka ini dibahas di bagian Terapkan IBackgroundTask nanti di artikel ini.
Praktik terbaik untuk pendaftaran tugas latar belakang
Gunakan praktik terbaik berikut saat mendaftarkan tugas latar belakang.
Panggil BackgroundExecutionManager.RequestAccessAsync sebelum mendaftarkan tugas latar belakang.
Jangan mendaftarkan tugas latar belakang beberapa kali. Verifikasi bahwa tugas latar belakang belum terdaftar sebelum mendaftar atau, seperti dalam sampel Windows App SDK, batalkan pendaftaran semua tugas latar belakang lalu daftarkan ulang tugas. Gunakan kelas BackgroundTaskRegistration untuk mengkueri tugas latar belakang yang ada.
Gunakan properti BackgroundTaskBuilder.Name untuk menentukan nama yang bermakna untuk tugas latar belakang guna menyederhanakan penelusuran kesalahan dan pemeliharaan.
Menerapkan IBackgroundTask
IBackgroundTask adalah antarmuka yang mengekspos satu metode, Jalankan, yang dijalankan ketika tugas latar belakang dipanggil. Aplikasi yang menggunakan tugas latar belakang harus menyertakan kelas yang mengimplementasikan IBackgroundTask.
Contoh berikut menunjukkan cara mengimplementasikan IBackgroundTask menggunakan C++. Dalam sampel Windows App SDK github, Anda dapat melihat kode pendaftaran ini di BackgroundTask.cpp.
void BackgroundTask::Run(_In_ IBackgroundTaskInstance taskInstance)
{
// Get deferral to indicate not to kill the background task process as soon as the Run method returns
m_deferral = taskInstance.GetDeferral();
m_progress = 0;
taskInstance.Canceled({ this, &BackgroundTask::OnCanceled });
// Calling a method on the Window to inform that the background task is executed
winrt::Microsoft::UI::Xaml::Window window = winrt::BackgroundTaskBuilder::implementation::App::Window();
m_mainWindow = window.as<winrt::BackgroundTaskBuilder::IMainWindow>();
Windows::Foundation::TimeSpan period{ std::chrono::seconds{2} };
m_periodicTimer = Windows::System::Threading::ThreadPoolTimer::CreatePeriodicTimer([this, lifetime = get_strong()](Windows::System::Threading::ThreadPoolTimer timer)
{
if (!m_cancelRequested && m_progress < 100)
{
m_progress += 10;
}
else
{
m_periodicTimer.Cancel();
// Indicate that the background task has completed.
m_deferral.Complete();
if (m_cancelRequested) m_progress = -1;
}
m_mainWindow.BackgroundTaskExecuted(m_progress);
}, period);
}
void BackgroundTask::OnCanceled(_In_ IBackgroundTaskInstance /* taskInstance */, _In_ BackgroundTaskCancellationReason /* cancelReason */)
{
m_cancelRequested = true;
}
Contoh berikut menunjukkan cara menerapkan IBackgroundTask menggunakan C#. Dalam sampel Windows App SDK github, Anda dapat melihat kode pendaftaran ini di BackgroundTask.cpp.
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[Guid("00001111-aaaa-2222-bbbb-3333cccc4444")]
[ComSourceInterfaces(typeof(IBackgroundTask))]
public class BackgroundTask : IBackgroundTask
{
/// <summary>
/// This method is the main entry point for the background task. The system will believe this background task
/// is complete when this method returns.
/// </summary>
[MTAThread]
public void Run(IBackgroundTaskInstance taskInstance)
{
// Get deferral to indicate not to kill the background task process as soon as the Run method returns
_deferral = taskInstance.GetDeferral();
// Wire the cancellation handler.
taskInstance.Canceled += this.OnCanceled;
// Set the progress to indicate this task has started
taskInstance.Progress = 0;
_periodicTimer = ThreadPoolTimer.CreatePeriodicTimer(new TimerElapsedHandler(PeriodicTimerCallback), TimeSpan.FromSeconds(1));
}
// Simulate the background task activity.
private void PeriodicTimerCallback(ThreadPoolTimer timer)
{
if ((_cancelRequested == false) && (_progress < 100))
{
_progress += 10;
}
else
{
if (_cancelRequested) _progress = -1;
if (_periodicTimer != null) _periodicTimer.Cancel();
// Indicate that the background task has completed.
if (_deferral != null) _deferral.Complete();
}
BackgroundTaskBuilder.MainWindow.taskStatus(_progress);
}
/// <summary>
/// This method is signaled when the system requests the background task be canceled. This method will signal
/// to the Run method to clean up and return.
/// </summary>
[MTAThread]
public void OnCanceled(IBackgroundTaskInstance taskInstance, BackgroundTaskCancellationReason cancellationReason)
{
// Handle cancellation operations and flag the task to end
_cancelRequested = true;
}
Praktik terbaik untuk menerapkan IBackgroundTask
Gunakan praktik terbaik berikut saat menerapkan IBackgroundTask.
- Jika tugas latar belakang akan melakukan operasi asinkron, dapatkan objek tunda dengan memanggil GetDeferral pada objek ITaskInstance yang diteruskan ke Run. Ini mencegah host tugas latar belakang,
backgroundtaskhost.exe, menghentikan secara prematur sebelum operasi selesai. Lepaskan penundaan setelah semua tugas asinkron selesai. - Jaga tugas se-ringan mungkin. Tugas yang berjalan lama dapat dihentikan oleh sistem dan tidak disarankan.
- Gunakan pengelogan untuk menangkap detail eksekusi untuk pemecahan masalah.
- Untuk praktik terbaik lainnya untuk menerapkan tugas latar belakang, lihat Panduan untuk tugas latar belakang.
Mendeklarasikan ekstensi aplikasi tugas latar belakang di Manifes Aplikasi
Anda harus mendeklarasikan ekstensi aplikasi dalam file aplikasi Package.appxmanifest untuk mendaftarkan tugas latar belakang Anda dengan sistem saat aplikasi diinstal dan untuk memberikan informasi yang dibutuhkan sistem untuk meluncurkan tugas latar belakang Anda.
Anda harus menambahkan ekstensi dengan kategori windows.backgroundTasks ke manifes aplikasi Anda agar tugas latar belakang berhasil didaftarkan saat aplikasi diinstal. Aplikasi C# harus menentukan nilai atribut EntryPoint "Microsoft.Windows.ApplicationModel.Background.UniversalBGTask.Task". Untuk aplikasi C++, ini akan ditambahkan secara otomatis dengan mengatur WindowsAppSDKBackgroundTask ke true dalam file project.
Anda juga harus mendeklarasikan com:Extension dengan nilai kategori "windows.comServer". Anda harus menentukan atribut LaunchAndActivationPermission di elemen com:ExeServer untuk secara eksplisit memberikan backgroundtaskhost.exe izin proses untuk memanggil kelas COM. Untuk informasi tentang format string ini, lihat Format String Deskriptor Keamanan.
Pastikan ID kelas yang Anda tentukan dalam elemen com:Class cocok dengan ID kelas untuk implementasi IBackgroundTask Anda.
Contoh berikut menunjukkan sintaksis deklarasi ekstensi aplikasi dalam file manifes aplikasi untuk memungkinkan sistem menemukan dan meluncurkan tugas latar belakang. Untuk melihat file manifes aplikasi lengkap untuk tugas latar belakang di github, lihat Package.appxmanifest.
<Extensions>
<Extension Category="windows.backgroundTasks" EntryPoint="Microsoft.Windows.ApplicationModel.Background.UniversalBGTask.Task">
<BackgroundTasks>
<Task Type="general"/>
</BackgroundTasks>
</Extension>
<com:Extension Category="windows.comServer">
<com:ComServer>
<com:ExeServer Executable="BackgroundTaskBuilder.exe" DisplayName="BackgroundTask"
LaunchAndActivationPermission="O:PSG:BUD:(A;;11;;;IU)(A;;11;;;S-1-15-2-1)S:(ML;;NX;;;LW)">
<com:Class Id="00001111-aaaa-2222-bbbb-3333cccc4444" DisplayName="BackgroundTask" />
</com:ExeServer>
</com:ComServer>
</com:Extension>
</Extensions>
Mendaftarkan server COM untuk tugas latar belakang
Mendaftarkan server COM memastikan bahwa sistem mengetahui cara untuk menginstansiasi kelas tugas latar belakang Anda ketika CoCreateInstance dipanggil oleh backgroundtaskhost.exe. Anda harus mendaftarkan pabrik kelas COM untuk tugas latar belakang Anda dengan memanggil CoRegisterClassObject atau aktivasi COM akan gagal.
Pendaftaran server COM di C++
Contoh berikut menunjukkan fungsi pembantu C++, RegisterBackgroundTaskFactory yang mendaftarkan pabrik kelas untuk kelas yang mengimplementasikan IBackgroundTask. Dalam contoh ini kelas ini disebut BackgroundTask. Di destruktor kelas pembantu, CoRevokeClassObject dipanggil untuk mencabut registrasi pabrik kelas.
Anda dapat melihat kelas pembantu ini di repositori sampel dalam file RegisterForCOM.cpp.
hresult RegisterForCom::RegisterBackgroundTaskFactory()
{
hresult hr;
try
{
com_ptr<IClassFactory> taskFactory = make<BackgroundTaskFactory>();
check_hresult(CoRegisterClassObject(__uuidof(BackgroundTask),
taskFactory.detach(),
CLSCTX_LOCAL_SERVER,
REGCLS_MULTIPLEUSE,
&ComRegistrationToken));
OutputDebugString(L"COM Registration done");
hr = S_OK;
}
CATCH_RETURN();
}
RegisterForCom::~RegisterForCom()
{
if (ComRegistrationToken != 0)
{
CoRevokeClassObject(ComRegistrationToken);
}
}
Untuk pendaftaran server in-proc di C++, panggil kelas pembantu untuk mendaftarkan factory kelas dari dalam metode Application.OnLaunched. Lihat panggilan ke metode pembantu dalam repositori sampel di App.xaml.cpp.
void App::OnLaunched([[maybe_unused]] LaunchActivatedEventArgs const& e)
{
window = make<MainWindow>();
window.Activate();
// Start COM server for the COM calls to complete
comRegister.RegisterBackgroundTaskFactory();
}
Untuk tugas latar belakang di luar proc, pendaftaran server COM harus dilakukan selama proses startup. Anda dapat melihat panggilan ke kelas bantu di App.xaml.cpp.
int WINAPI wWinMain(_In_ HINSTANCE, _In_opt_ HINSTANCE, _In_ LPWSTR lpCmdLine, _In_ int)
{
if (std::wcsncmp(lpCmdLine, RegisterForCom::RegisterForComToken, sizeof(RegisterForCom::RegisterForComToken)) == 0)
{
winrt::init_apartment(winrt::apartment_type::multi_threaded);
RegisterForCom comRegister;
// Start COM server and wait for the COM calls to complete
comRegister.RegisterAndWait(__uuidof(BackgroundTask));
OutputDebugString(L"COM Server Shutting Down");
}
else
{
// put your fancy code somewhere here
::winrt::Microsoft::UI::Xaml::Application::Start(
[](auto&&)
{
::winrt::make<::winrt::BackgroundTaskBuilder::implementation::App>();
});
}
return 0;
}
Pendaftaran server COM di C#
Contoh berikut menunjukkan fungsi pembantu C#, CreateInstance yang mendaftarkan pabrik kelas untuk kelas yang mengimplementasikan IBackgroundTask. Dalam contoh ini kelas ini disebut BackgroundTask. Kelas pembantu menggunakan LibraryImportAttribute untuk mengakses metode pendaftaran COM asli dari C#. Untuk informasi selengkapnya, lihat Generasi sumber untuk pemanggilan platform. Anda dapat melihat implementasi kelas pembantu dalam repositori sampel di ComServer.cs.
static partial class ComServer
{
[LibraryImport("ole32.dll")]
public static partial int CoRegisterClassObject(
ref Guid classId,
[MarshalAs(UnmanagedType.Interface)] IClassFactory objectAsUnknown,
uint executionContext,
uint flags,
out uint registrationToken);
[LibraryImport("ole32.dll")]
public static partial int CoRevokeObject(out uint registrationToken);
public const uint CLSCTX_LOCAL_SERVER = 4;
public const uint REGCLS_MULTIPLEUSE = 1;
public const uint S_OK = 0x00000000;
public const uint CLASS_E_NOAGGREGATION = 0x80040110;
public const uint E_NOINTERFACE = 0x80004002;
public const string IID_IUnknown = "00000000-0000-0000-C000-000000000046";
public const string IID_IClassFactory = "00000001-0000-0000-C000-000000000046";
[GeneratedComInterface]
[Guid(IID_IClassFactory)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public partial interface IClassFactory
{
[PreserveSig]
uint CreateInstance(IntPtr objectAsUnknown, in Guid interfaceId, out IntPtr objectPointer);
[PreserveSig]
uint LockServer([MarshalAs(UnmanagedType.Bool)] bool Lock);
}
[GeneratedComClass]
internal sealed partial class BackgroundTaskFactory : IClassFactory
{
public uint CreateInstance(IntPtr objectAsUnknown, in Guid interfaceId, out IntPtr objectPointer)
{
if (objectAsUnknown != IntPtr.Zero)
{
objectPointer = IntPtr.Zero;
return CLASS_E_NOAGGREGATION;
}
if ((interfaceId != typeof(BackgroundTask).GUID) && (interfaceId != new Guid(IID_IUnknown)))
{
objectPointer = IntPtr.Zero;
return E_NOINTERFACE;
}
objectPointer = MarshalInterface<IBackgroundTask>.FromManaged(new BackgroundTask());
return S_OK;
}
public uint LockServer(bool lockServer) => S_OK;
}
}
Untuk tugas latar belakang dalam-proses di C#, pendaftaran COM dilakukan selama startup aplikasi, pada konstruktor objek Aplikasi. Anda dapat melihat panggilan ke metode pembantu dalam repositori sampel di App.xaml.cs.
public App()
{
this.InitializeComponent();
Guid taskGuid = typeof(BackgroundTask).GUID;
ComServer.CoRegisterClassObject(ref taskGuid,
new ComServer.BackgroundTaskFactory(),
ComServer.CLSCTX_LOCAL_SERVER,
ComServer.REGCLS_MULTIPLEUSE,
out _RegistrationToken);
}
~App()
{
ComServer.CoRevokeObject(out _RegistrationToken);
}
Untuk tugas di luar proc di C#, Anda harus melakukan pendaftaran COM di startup aplikasi. Untuk melakukan ini, Anda harus menonaktifkan titik masuk Main yang dihasilkan XAML dengan memperbarui file proyek aplikasi Anda.
Dalam templat project default, titik entri metode Main dibuat secara otomatis oleh pengompilasi. Contoh ini akan menonaktifkan pembuatan otomatis Main sehingga kode aktivasi yang diperlukan dapat dijalankan saat startup.
- Di Solution Explorer, klik kanan ikon project dan pilih Edit File Project.
- Dalam elemen PropertyGroup , tambahkan elemen turunan berikut untuk menonaktifkan fungsi utama yang dihasilkan secara otomatis.
<DefineConstants>$(DefineConstants);DISABLE_XAML_GENERATED_MAIN</DefineConstants>
Anda dapat melihat panggilan ke kelas pembantu untuk mendaftarkan kelas COM di repositori sampel di Program.cs
public class Program
{
static private uint _RegistrationToken;
static private ManualResetEvent _exitEvent = new ManualResetEvent(false);
static void Main(string[] args)
{
if (args.Contains("-RegisterForBGTaskServer"))
{
Guid taskGuid = typeof(BackgroundTask).GUID;
ComServer.CoRegisterClassObject(ref taskGuid,
new ComServer.BackgroundTaskFactory(),
ComServer.CLSCTX_LOCAL_SERVER,
ComServer.REGCLS_MULTIPLEUSE,
out _RegistrationToken);
// Wait for the exit event to be signaled before exiting the program
_exitEvent.WaitOne();
}
else
{
App.Start(p => new App());
}
}
public static void SignalExit()
{
_exitEvent.Set();
}
}
Konten terkait
- Panduan untuk tugas latar belakang di aplikasi UWP
- strategi migrasi tugas latar belakang
Windows developer