Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Önemli
Windows Uygulama SDK'sı BackgroundTaskBuilder kullanan arka plan görevleri, uygulamanızın MSIX ile paketlenmiş olmasını gerektirir. MSIX paketlemesi olmadan dağıtılan WPF veya Windows Forms uygulamaları için Task Scheduler veya .NET Çalışan Hizmetleri kullanın.
Bu makalede, arka plan görevlerini kullanmaya genel bir bakış sağlanır ve WinUI 3 veya diğer MSIX paketli uygulamada (WPF ve Windows Forms dahil) yeni bir arka plan görevinin nasıl oluşturulacağı açıklanır. Arka plan görevleriyle UWP uygulamalarınızı WinUI'ye geçirme hakkında bilgi için bkz. Windows Uygulama SDK'sı Background görev geçiş stratejisi.
Arka plan görevleri, kullanıcı arabirimi olmadan arka planda çalışan uygulama bileşenleridir. Dosyaları indirme, verileri eşitleme, bildirim gönderme veya kutucukları güncelleştirme gibi eylemler gerçekleştirebilirler. Bunlar zaman, sistem değişiklikleri, kullanıcı eylemleri veya anında iletme bildirimleri gibi çeşitli olaylar tarafından tetiklenebilir. Bu görevler, uygulama çalışır durumda olmadığında bile ilgili tetikleyici gerçekleştiğinde yürütülebilir.
Arka plan görevlerinin uygulanması UWP ve WinUI uygulamaları için farklıdır. Arka plan görevleriyle UWP uygulamalarınızı WinUI'ye geçirme hakkında bilgi için bkz. Windows Uygulama SDK'sı Background görev geçiş stratejisi.
Görev Zamanlayıcı, masaüstü uygulamalarının UWP uygulamalarında BackgroundTaskBuilder tarafından sağlanan işlevlerin aynısını elde etmelerine yardımcı olur. TaskScheduler kullanan uygulamalar hakkında daha fazla ayrıntıya buradan ulaşabilirsiniz.
Arka plan görevini kaydetme
Tam güven COM bileşeni kullanan bir arka plan görevini kaydetmek için Windows Uygulama SDK'sı dahil BackgroundTaskBuilder sınıfını kullanın.
Aşağıdaki örnekte, C++ kullanarak bir arka plan görevinin nasıl kaydedilecekleri gösterilmektedir. Windows Uygulama SDK'sı github örneğinde bu kayıt kodunu
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.
}
Aşağıdaki örnekte, C# kullanarak bir arka plan görevinin nasıl kaydedilecekleri gösterilmektedir. Windows Uygulama SDK'sı github örneğinde bu kayıt kodunu MainWindow.Xaml.cpp görebilirsiniz.
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();
SetEntryPointClsid yöntemi çağrısında, IBackgroundTask uygulayan uygulama tanımlı bir sınıfın GUID'sinin bağımsız değişken olarak alındığını unutmayın. Bu arabirim, bu makalenin devamında IBackgroundTask Uygulama bölümünde ele alınmalıdır.
Arka plan görevi kaydı için en iyi yöntemler
Arka plan görevlerini kaydederken aşağıdaki en iyi yöntemleri kullanın.
Arka plan görevlerini kaydetmeden önce BackgroundExecutionManager.RequestAccessAsync çağrısı yapın.
Arka plan görevini birden çok kez kaydetmeyin. Kaydetmeden önce bir arka plan görevinin henüz kaydedilmediğini doğrulayın veya Windows Uygulama SDK'sı örneğinde olduğu gibi tüm arka plan görevlerinin kaydını kaldırın ve sonra görevleri yeniden kaydedin. Mevcut arka plan görevlerini sorgulamak için BackgroundTaskRegistration sınıfını kullanın.
Hata ayıklamayı ve bakımı basitleştirmek amacıyla arka plan görevi için anlamlı bir ad belirtmek üzere BackgroundTaskBuilder.Name özelliğini kullanın.
IBackgroundTask'ı Uygulama
IBackgroundTask, arka plan görevi çağrıldığında yürütülen Run adlı tek bir yöntemi kullanıma sunan bir arabirimdir. Arka plan görevlerini kullanan uygulamalar , IBackgroundTask uygulayan bir sınıf içermelidir.
Aşağıdaki örnekte, C++ kullanarak IBackgroundTask'ın nasıl uygulandığı gösterilmektedir. Windows Uygulama SDK'sı github örneğinde bu kayıt kodunu BackgroundTask.cpp görebilirsiniz.
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;
}
Aşağıdaki örnekte, C# kullanarak IBackgroundTask'in nasıl uygulandığı gösterilmektedir. Windows Uygulama SDK'sı github örneğinde bu kayıt kodunu BackgroundTask.cpp görebilirsiniz.
[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;
}
IBackgroundTask uygulamak için en iyi yöntemler
IBackgroundTask'i uygularken aşağıdaki en iyi yöntemleri kullanın.
- Arka plan görevi zaman uyumsuz işlemler gerçekleştirecekse, Çalıştır'a geçirilen ITaskInstancenesnesindeGetDeferral'ı çağırarak bir erteleme nesnesi alın. Bu,
backgroundtaskhost.exeişlemleri tamamlanmadan önce arka plan görev konağının erken sonlandırılmasını engeller. Zaman uyumsuz görevlerin tümü tamamlandıktan sonra ertelemeyi bırakın. - Görevleri olabildiğince basit tutun. Uzun süre çalışan görevler sistem tarafından sonlandırılabilir ve önerilmez.
- Sorun giderme için yürütme ayrıntılarını yakalamak için günlüğe kaydetmeyi kullanın.
- Arka plan görevlerini uygulamaya yönelik diğer en iyi yöntemler için bkz. Arka plan görevleri için yönergeler.
Uygulama Bildirimi'nde arka plan görev uygulaması uzantısını bildirme
Uygulamanız yüklendiğinde arka plan görevinizi Package.appxmanifest sisteme kaydetmek ve arka plan görevinizi başlatmak için sistemin ihtiyaç duyduğu bilgileri sağlamak için uygulamanızın dosyasında bir uygulama uzantısı bildirmeniz gerekir.
Uygulama yüklendiğinde arka plan görevinin başarıyla kaydedilmesi için uygulama bildiriminize windows.backgroundTasks kategorisine sahip bir uzantı eklemeniz gerekir. C# uygulamaları, EntryPoint öznitelik değerini "Microsoft.Windows.ApplicationModel.Background.UniversalBGTask.Task" olarak belirtmelidir. C++ uygulamaları için bu, project dosyasında WindowsAppSDKBackgroundTasktrue olarak ayarlanarak otomatik olarak eklenir.
Ayrıca, "windows.comServer" kategori değeriyle bir com:Extension bildirmelisiniz. COM sınıfını çağırma işlemine açıkça izin vermek için com:ExeServer öğesinde backgroundtaskhost.exe özniteliğini belirtmeniz gerekir. Bu dizenin biçimi hakkında bilgi için bkz. Güvenlik Tanımlayıcısı Dize Biçimi.
com:Class öğesinde belirttiğiniz sınıf kimliğinin IBackgroundTask uygulamanız için sınıf kimliğiyle eşleştiğinden emin olun.
Aşağıdaki örnekte, sistemin bir arka plan görevini bulmasına ve başlatmasına olanak tanımak için uygulama bildirim dosyasındaki uygulama uzantısı bildirimlerinin söz dizimi gösterilmektedir. Arka plan görevinin tam uygulama bildirim dosyasını GitHub'da görmek için bkz. 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>
Arka plan görevi için COM sunucusunu kaydetme
COM sunucusunun kaydedilmesi, CoCreateInstance işlevi backgroundtaskhost.exe tarafından çağrıldığında sistemin arka plan görev sınıfınızı nasıl başlatacağını bilmeyi sağlar.
CoRegisterClassObject çağrısı yaparak arka plan göreviniz için COM sınıf fabrikasını kaydetmeniz gerekir, aksi takdirde COM etkinleştirmesi başarısız olur.
C++ içinde COM sunucusu kaydı
Aşağıdaki örnekte, IBackgroundTask uygulayan sınıf için sınıf fabrikasını kaydeden RegisterBackgroundTaskFactory adlı bir C++ yardımcı işlevi gösterilmektedir. Bu örnekte bu sınıf BackgroundTask olarak adlandırılır. Yardımcı sınıfın yıkıcısında, sınıf fabrikası kaydını iptal etmek için CoRevokeClassObject çağrılır.
Bu yardımcı sınıfını RegisterForCOM.cpp dosyasındaki örnek depoda görebilirsiniz.
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);
}
}
C++'da proc içi sunucu kaydı için, application.OnLaunched yönteminin içinden sınıf fabrikasını kaydetmek için yardımcı sınıfını çağırın. App.xaml.cpp içindeki örnek depoda yardımcı yöntemine yapılan çağrıya bakın.
void App::OnLaunched([[maybe_unused]] LaunchActivatedEventArgs const& e)
{
window = make<MainWindow>();
window.Activate();
// Start COM server for the COM calls to complete
comRegister.RegisterBackgroundTaskFactory();
}
İşlem dışı arka plan görevleri için, başlangıç işlemi sırasında COM sunucu kaydı yapılmalıdır. yardımcı sınıfına yapılan çağrıyı App.xaml.cpp içinde görebilirsiniz.
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;
}
C'de COM sunucusu kaydı#
Aşağıdaki örnekte, IBackgroundTask uygulayan sınıf için sınıf fabrikasını kaydeden CreateInstance adlı bir C# yardımcı işlevi gösterilmektedir. Bu örnekte bu sınıf BackgroundTask olarak adlandırılır. Yardımcı sınıf, C# dilinden yerel COM kayıt yöntemlerine erişmek için LibraryImportAttribute kullanır. Daha fazla bilgi için bkz. Platform çağrıları için kaynak oluşturma. yardımcı sınıfının uygulamasını ComServer.cs içindeki örnek depoda görebilirsiniz.
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;
}
}
C# dilindeki proc içi arka plan görevleri için, UYGULAMA nesnesi oluşturucusunda uygulama başlatma sırasında COM kaydı gerçekleştirilir. App.xaml.cs içindeki örnek depoda yardımcı yöntemine yapılan çağrıyı görebilirsiniz.
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);
}
C# dilinde out-of-proc görevler için, uygulama başlangıcında COM kaydı gerçekleştirmeniz gerekir. Bunu yapmak için, uygulamanızın proje dosyanızı güncelleyerek varsayılan XAML ile oluşturulmuş Main giriş noktasını devre dışı bırakmalısınız.
Varsayılan project şablonunda, Main yöntemi giriş noktası derleyici tarafından otomatik olarak oluşturulur. Bu örnek, gerekli etkinleştirme kodunun başlangıçta çalıştırılabilmesi için Main'ın otomatik olarak yenilenmesini devre dışı bırakır.
- Çözüm Gezgini'da project simgesine sağ tıklayın ve Project Dosyasını Düzenle'yi seçin.
- PropertyGroup öğesinde, otomatik olarak oluşturulan ana işlevi devre dışı bırakmak için aşağıdaki alt öğeyi ekleyin.
<DefineConstants>$(DefineConstants);DISABLE_XAML_GENERATED_MAIN</DefineConstants>
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();
}
}
İlgili içerik
Windows developer