如何暂停应用(DirectX 和 C++)

本主题演示如何在系统暂停通用 Windows 平台 (UWP) DirectX 应用时保存重要的系统状态和应用数据。

注册挂起事件处理程序

首先,注册处理 CoreApplication::Suspending 事件,这是在您的应用程序因用户或系统操作而进入挂起状态时触发的。

将此代码添加到视图提供程序的 IFrameworkView::Initialize 方法的实现中:

void App::Initialize(CoreApplicationView^ applicationView)
{
  //...
  
    CoreApplication::Suspending +=
        ref new EventHandler<SuspendingEventArgs^>(this, &App::OnSuspending);

  //...
}

在暂停之前保存任何应用数据

当应用处理 CoreApplication::Suspending 事件时,它有机会在处理程序函数中保存其重要的应用程序数据。 应用应使用 LocalSettings 存储 API 同步保存简单的应用程序数据。 如果要开发游戏,请保存任何关键的游戏状态信息。 不要忘记暂停音频处理!

现在,实现回调。 将应用数据保存在此方法中。

void App::OnSuspending(Platform::Object^ sender, SuspendingEventArgs^ args)
{
    // Save app state asynchronously after requesting a deferral. Holding a deferral
    // indicates that the application is busy performing suspending operations. Be
    // aware that a deferral may not be held indefinitely. After about five seconds,
    // the app will be forced to exit.
    SuspendingDeferral^ deferral = args->SuspendingOperation->GetDeferral();

    create_task([this, deferral]()
    {
        m_deviceResources->Trim();

        // Insert your code here.

        deferral->Complete();
    });
}

此回调必须用 5 秒完成。 在此回调期间,必须通过调用 SuspendingOperation::GetDeferral来请求延迟,这会启动倒计时。 当应用完成保存操作时,请调用 SuspendingDeferral::Complete,告知系统应用现在已准备好暂停。 如果不请求延迟,或者应用保存数据所需的时间超过 5 秒,则应用会自动暂停。

此回调作为由应用的 CoreWindowCoreDispatcher 处理的事件消息发生。 如果在应用的主循环中没有调用 CoreDispatcher::ProcessEvents(在视图提供程序的 IFrameworkView::Run 方法中实现),则不会调用此回调。

// This method is called after the window becomes active.
void App::Run()
{
    while (!m_windowClosed)
    {
        if (m_windowVisible)
        {
            CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);

            m_main->Update();

            if (m_main->Render())
            {
                m_deviceResources->Present();
            }
        }
        else
        {
            CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
        }
    }
}

呼叫Trim()

从 Windows 8.1 开始,所有 DirectX UWP 应用必须在暂停时调用 IDXGIDevice3::Trim。 此调用告知图形驱动程序释放为应用分配的所有临时缓冲区,从而减少应用在处于暂停状态时因释放内存资源而被终止的机会。 这是 Windows 8.1 的认证要求。

void App::OnSuspending(Platform::Object^ sender, SuspendingEventArgs^ args)
{
    // Save app state asynchronously after requesting a deferral. Holding a deferral
    // indicates that the application is busy performing suspending operations. Be
    // aware that a deferral may not be held indefinitely. After about five seconds,
    // the app will be forced to exit.
    SuspendingDeferral^ deferral = args->SuspendingOperation->GetDeferral();

    create_task([this, deferral]()
    {
        m_deviceResources->Trim();

        // Insert your code here.

        deferral->Complete();
    });
}

// Call this method when the app suspends. It provides a hint to the driver that the app 
// is entering an idle state and that temporary buffers can be reclaimed for use by other apps.
void DX::DeviceResources::Trim()
{
    ComPtr<IDXGIDevice3> dxgiDevice;
    m_d3dDevice.As(&dxgiDevice);

    dxgiDevice->Trim();
}

释放任何独占资源和文件句柄

当您的应用处理 CoreApplication::Suspending 事件时,它也有机会释放独占资源和文件句柄。 显式释放独占资源和文件句柄有助于确保在您的应用程序不使用时其他应用可以访问它们。 当应用在终止后激活时,它应打开其独占资源和文件句柄。

注解

每当用户切换到另一个应用或桌面时,系统就会暂停你的应用。 每当用户切换回应用时,系统就会恢复你的应用。 当系统恢复应用时,变量和数据结构的内容与系统暂停应用之前的内容相同。 系统会将应用恢复到其退出时的状态,让用户感觉应用一直在后台运行。

系统尝试在应用暂停时将应用及其数据保留在内存中。 但是,如果系统没有将应用保留在内存中的资源,系统将终止你的应用。 当用户切换回已终止的挂起应用时,系统将发送 激活 事件,并在其处理程序中还原其应用程序数据,为 CoreApplicationView::Activated 事件做好准备。

系统不会在应用终止时通知应用,因此你的应用必须在暂停时保存其应用程序数据并释放独占资源和文件句柄,并在终止后激活应用时还原它们。