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


Снимок экрана

Начиная с Windows 10 версии 1803 пространство имен Windows.Graphics.Capture предоставляет API-интерфейсы для получения кадров из окна отображения или приложения, чтобы создать видеопотоки или моментальные снимки для создания совместных и интерактивных интерфейсов.

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

Примечание.

API захвата экрана поддерживаются только на устройствах Windows и Windows Смешанная реальность иммерсивные гарнитуры.

В этой статье описывается запись одного изображения окна отображения или приложения. Сведения о кодировке кадров, захваченных с экрана на видеофайл, см. в разделе "Снимок экрана" в видео

Добавление возможности захвата экрана

Api, найденные в пространстве имен Windows.Graphics.Capture , требуют объявления общей возможности в манифесте приложения:

  1. Откройте Package.appxmanifest в Обозреватель решений.
  2. Перейдите на вкладку Возможности.
  3. Проверьте запись графики.

Захват графики

Запуск системного пользовательского интерфейса для запуска записи экрана

Перед запуском системного пользовательского интерфейса можно проверить, сможет ли ваше приложение в настоящее время принимать снимки экрана. Существует несколько причин, по которым ваше приложение может не использовать запись экрана, в том числе, если устройство не соответствует требованиям к оборудованию или если приложение предназначено для захвата блоков с экрана. Используйте метод IsSupported в классе GraphicsCaptureSession, чтобы определить, поддерживается ли запись экрана UWP:

// This runs when the application starts.
public void OnInitialization()
{
    if (!GraphicsCaptureSession.IsSupported())
    {
        // Hide the capture UI if screen capture is not supported.
        CaptureButton.Visibility = Visibility.Collapsed;
    }
}
Public Sub OnInitialization()
    If Not GraphicsCaptureSession.IsSupported Then
        CaptureButton.Visibility = Visibility.Collapsed
    End If
End Sub

Убедившись, что запись экрана поддерживается, используйте класс GraphicsCapturePicker для вызова пользовательского интерфейса средства выбора системы. Конечный пользователь использует этот пользовательский интерфейс для выбора окна отображения или приложения, из которого выполняется захват экрана. Средство выбора вернет графический объект GraphicsCaptureItem , который будет использоваться для создания объекта GraphicsCaptureSession:

public async Task StartCaptureAsync()
{
    // The GraphicsCapturePicker follows the same pattern the
    // file pickers do.
    var picker = new GraphicsCapturePicker();
    GraphicsCaptureItem item = await picker.PickSingleItemAsync();

    // The item may be null if the user dismissed the
    // control without making a selection or hit Cancel.
    if (item != null)
    {
        // We'll define this method later in the document.
        StartCaptureInternal(item);
    }
}
Public Async Function StartCaptureAsync() As Task
    ' The GraphicsCapturePicker follows the same pattern the
    ' file pickers do.
    Dim picker As New GraphicsCapturePicker
    Dim item As GraphicsCaptureItem = Await picker.PickSingleItemAsync()

    ' The item may be null if the user dismissed the
    ' control without making a selection or hit Cancel.
    If item IsNot Nothing Then
        StartCaptureInternal(item)
    End If
End Function

Так как это код пользовательского интерфейса, его необходимо вызвать в потоке пользовательского интерфейса. Если вы вызываете его из кода программной части для страницы приложения (например , MainPage.xaml.cs), это делается автоматически, но если нет, вы можете принудительно запустить его в потоке пользовательского интерфейса со следующим кодом:

CoreWindow window = CoreApplication.MainView.CoreWindow;

await window.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
    await StartCaptureAsync();
});
Dim window As CoreWindow = CoreApplication.MainView.CoreWindow
Await window.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
                                 Async Sub() Await StartCaptureAsync())

Создание пула кадров записи и сеанс записи

Используя GraphicsCaptureItem, вы создадите Direct3D11CaptureFramePool с устройством D3D, поддерживаемым форматом пикселей (DXGI_FORMAT_B8G8R8A8_UNORM), количеством нужных кадров (которые могут быть любым целым числом) и размером кадра. Свойство ContentSize класса GraphicsCaptureItem можно использовать в качестве размера кадра:

Примечание.

В системах с включенным цветом Windows HD формат пикселей содержимого может быть не обязательно DXGI_FORMAT_B8G8R8A8_UNORM. Чтобы избежать переполнения пикселей (т. е. захваченное содержимое выглядит вымытым) при захвате содержимого HDR, рекомендуется использовать DXGI_FORMAT_R16G16B16A16_FLOAT для каждого компонента в конвейере записи, включая Direct3D11CaptureFramePool, целевое назначение, например CanvasBitmap. Зависит от необходимости, может потребоваться дополнительная обработка, например сохранение в формате содержимого HDR или сопоставление тонов HDR-to-SDR. В этой статье рассматривается запись содержимого SDR. Дополнительные сведения см. в разделе "Использование DirectX" с отображением и расширенным цветом с высоким динамическим диапазоном.

private GraphicsCaptureItem _item;
private Direct3D11CaptureFramePool _framePool;
private CanvasDevice _canvasDevice;
private GraphicsCaptureSession _session;

public void StartCaptureInternal(GraphicsCaptureItem item)
{
    _item = item;

    _framePool = Direct3D11CaptureFramePool.Create(
        _canvasDevice, // D3D device
        DirectXPixelFormat.B8G8R8A8UIntNormalized, // Pixel format
        2, // Number of frames
        _item.Size); // Size of the buffers
}
WithEvents CaptureItem As GraphicsCaptureItem
WithEvents FramePool As Direct3D11CaptureFramePool
Private _canvasDevice As CanvasDevice
Private _session As GraphicsCaptureSession

Private Sub StartCaptureInternal(item As GraphicsCaptureItem)
    CaptureItem = item

    FramePool = Direct3D11CaptureFramePool.Create(
        _canvasDevice, ' D3D device
        DirectXPixelFormat.B8G8R8A8UIntNormalized, ' Pixel format
        2, '  Number of frames
        CaptureItem.Size) ' Size of the buffers
End Sub

Затем получите экземпляр класса GraphicsCaptureSession для direct3D11CaptureFramePool путем передачи GraphicsCaptureItem методу CreateCaptureSession :

_session = _framePool.CreateCaptureSession(_item);
_session = FramePool.CreateCaptureSession(CaptureItem)

После того как пользователь явно дал согласие на запись окна приложения или отображения в системном пользовательском интерфейсе, ГрафическийCaptureItem может быть связан с несколькими объектами CaptureSession . Таким образом приложение может записать один и тот же элемент для различных возможностей.

Чтобы записать несколько элементов одновременно, приложение должно создать сеанс записи для каждого элемента, который требует вызова пользовательского интерфейса средства выбора для каждого элемента, который требуется записать.

Получение кадров записи

Создав пул кадров и сеанс захвата, вызовите метод StartCapture в экземпляре GraphicsCaptureSession, чтобы уведомить систему о начале отправки кадров записи в приложение:

_session.StartCapture();
_session.StartCapture()

Чтобы получить эти кадры захвата, которые являются объектами Direct3D11CaptureFrame , можно использовать событие Direct3D11CaptureFramePool.FrameArrived :

_framePool.FrameArrived += (s, a) =>
{
    // The FrameArrived event fires for every frame on the thread that
    // created the Direct3D11CaptureFramePool. This means we don't have to
    // do a null-check here, as we know we're the only one  
    // dequeueing frames in our application.  

    // NOTE: Disposing the frame retires it and returns  
    // the buffer to the pool.
    using (var frame = _framePool.TryGetNextFrame())
    {
        // We'll define this method later in the document.
        ProcessFrame(frame);
    }  
};
Private Sub FramePool_FrameArrived(sender As Direct3D11CaptureFramePool, args As Object) Handles FramePool.FrameArrived
    ' The FrameArrived event is raised for every frame on the thread
    ' that created the Direct3D11CaptureFramePool. This means we
    ' don't have to do a null-check here, as we know we're the only
    ' one dequeueing frames in our application.  

    ' NOTE Disposing the frame retires it And returns  
    ' the buffer to the pool.

    Using frame = FramePool.TryGetNextFrame()
        ProcessFrame(frame)
    End Using
End Sub

Рекомендуется избегать использования потока пользовательского интерфейса, если это возможно для FrameArrived, так как это событие будет возникать каждый раз, когда будет доступен новый кадр, который будет частым. Если вы решите прослушивать FrameArrived в потоке пользовательского интерфейса, помните, сколько работы вы выполняете каждый раз при срабатывании события.

Кроме того, можно вручную извлекать кадры с помощью метода Direct3D11CaptureFramePool.TryGetNextFrame , пока не получите все необходимые кадры.

Объект Direct3D11CaptureFrame содержит свойства ContentSize, Surface и SystemRelativeTime. SystemRelativeTime — это время QPC (QueryPerformanceCounter), которое можно использовать для синхронизации других элементов мультимедиа.

Кадры отслеживания процесса

Каждый кадр из Direct3D11CaptureFramePool извлекается при вызове TryGetNextFrame и проверяется обратно в соответствии со временем существования объекта Direct3D11CaptureFrame. Для собственных приложений, освобождение объекта Direct3D11CaptureFrame достаточно, чтобы проверить кадр обратно в пул кадров. Для управляемых приложений рекомендуется использовать метод Direct3D11CaptureFrame.Dispose (Close in C++). Direct3D11CaptureFrame реализует интерфейс IClosable, который проецируется как IDisposable для вызывающих объектов C#.

Приложения не должны сохранять ссылки на объекты Direct3D11CaptureFrame , а также не должны сохранять ссылки на базовую поверхность Direct3D после возврата кадра.

При обработке кадра рекомендуется использовать блокировку ID3D11Multithread на том же устройстве, которое связано с объектом Direct3D11CaptureFramePool .

Базовая поверхность Direct3D всегда будет иметь размер, указанный при создании (или повторном создании) Direct3D11CaptureFramePool. Если содержимое больше кадра, содержимое обрезается до размера кадра. Если содержимое меньше кадра, остальная часть кадра содержит неопределенные данные. Рекомендуется, чтобы приложения копировали вложенный прямоугольник с помощью свойства ContentSize для этого Direct3D11CaptureFrame , чтобы избежать отображения неопределенного содержимого.

Снимок экрана

В нашем примере мы преобразуем каждый Direct3D11CaptureFrame в CanvasBitmap, который является частью API Win2D.

// Convert our D3D11 surface into a Win2D object.
CanvasBitmap canvasBitmap = CanvasBitmap.CreateFromDirect3D11Surface(
    _canvasDevice,
    frame.Surface);

После создания CanvasBitmap его можно сохранить в виде файла изображения. В следующем примере мы сохраняем его в виде PNG-файла в папке сохраненных изображений пользователя.

StorageFolder pictureFolder = KnownFolders.SavedPictures;
StorageFile file = await pictureFolder.CreateFileAsync("test.png", CreationCollisionOption.ReplaceExisting);

using (var fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
    await canvasBitmap.SaveAsync(fileStream, CanvasBitmapFileFormat.Png, 1f);
}

Реагирование на изменение размера элемента или потерянное устройство

Во время процесса отслеживания приложения могут изменить аспекты их Direct3D11CaptureFramePool. Это включает в себя предоставление нового устройства Direct3D, изменение размера буферов кадров или даже изменение количества буферов в пуле. В каждом из этих сценариев рекомендуется использовать метод Повторного создания объекта Direct3D11CaptureFramePool.

При вызове повторного создания все существующие кадры удаляются. Это позволяет предотвратить передачу кадров, базовые поверхности Direct3D которых принадлежат устройству, к которому приложение больше не имеет доступа. По этой причине может быть разумно обработать все ожидающие кадры перед вызовом повторного вызова.

Сборка

Следующий фрагмент кода является комплексным примером реализации захвата экрана в приложении UWP. В этом примере в интерфейсе есть две кнопки: один вызов Button_ClickAsync, а другие вызовы ScreenshotButton_ClickAsync.

Примечание.

Этот фрагмент использует Win2D, библиотеку для отрисовки графики 2D. Сведения о настройке проекта см. в их документации.

using Microsoft.Graphics.Canvas;
using Microsoft.Graphics.Canvas.UI.Composition;
using System;
using System.Numerics;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.Graphics;
using Windows.Graphics.Capture;
using Windows.Graphics.DirectX;
using Windows.Storage;
using Windows.UI;
using Windows.UI.Composition;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Hosting;

namespace ScreenCaptureTest
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page
    {
        // Capture API objects.
        private SizeInt32 _lastSize;
        private GraphicsCaptureItem _item;
        private Direct3D11CaptureFramePool _framePool;
        private GraphicsCaptureSession _session;

        // Non-API related members.
        private CanvasDevice _canvasDevice;
        private CompositionGraphicsDevice _compositionGraphicsDevice;
        private Compositor _compositor;
        private CompositionDrawingSurface _surface;
        private CanvasBitmap _currentFrame;
        private string _screenshotFilename = "test.png";

        public MainPage()
        {
            this.InitializeComponent();
            Setup();
        }

        private void Setup()
        {
            _canvasDevice = new CanvasDevice();

            _compositionGraphicsDevice = CanvasComposition.CreateCompositionGraphicsDevice(
                Window.Current.Compositor,
                _canvasDevice);

            _compositor = Window.Current.Compositor;

            _surface = _compositionGraphicsDevice.CreateDrawingSurface(
                new Size(400, 400),
                DirectXPixelFormat.B8G8R8A8UIntNormalized,
                DirectXAlphaMode.Premultiplied);    // This is the only value that currently works with
                                                    // the composition APIs.

            var visual = _compositor.CreateSpriteVisual();
            visual.RelativeSizeAdjustment = Vector2.One;
            var brush = _compositor.CreateSurfaceBrush(_surface);
            brush.HorizontalAlignmentRatio = 0.5f;
            brush.VerticalAlignmentRatio = 0.5f;
            brush.Stretch = CompositionStretch.Uniform;
            visual.Brush = brush;
            ElementCompositionPreview.SetElementChildVisual(this, visual);
        }

        public async Task StartCaptureAsync()
        {
            // The GraphicsCapturePicker follows the same pattern the
            // file pickers do.
            var picker = new GraphicsCapturePicker();
            GraphicsCaptureItem item = await picker.PickSingleItemAsync();

            // The item may be null if the user dismissed the
            // control without making a selection or hit Cancel.
            if (item != null)
            {
                StartCaptureInternal(item);
            }
        }

        private void StartCaptureInternal(GraphicsCaptureItem item)
        {
            // Stop the previous capture if we had one.
            StopCapture();

            _item = item;
            _lastSize = _item.Size;

            _framePool = Direct3D11CaptureFramePool.Create(
               _canvasDevice, // D3D device
               DirectXPixelFormat.B8G8R8A8UIntNormalized, // Pixel format
               2, // Number of frames
               _item.Size); // Size of the buffers

            _framePool.FrameArrived += (s, a) =>
            {
                // The FrameArrived event is raised for every frame on the thread
                // that created the Direct3D11CaptureFramePool. This means we
                // don't have to do a null-check here, as we know we're the only
                // one dequeueing frames in our application.  

                // NOTE: Disposing the frame retires it and returns  
                // the buffer to the pool.

                using (var frame = _framePool.TryGetNextFrame())
                {
                    ProcessFrame(frame);
                }
            };

            _item.Closed += (s, a) =>
            {
                StopCapture();
            };

            _session = _framePool.CreateCaptureSession(_item);
            _session.StartCapture();
        }

        public void StopCapture()
        {
            _session?.Dispose();
            _framePool?.Dispose();
            _item = null;
            _session = null;
            _framePool = null;
        }

        private void ProcessFrame(Direct3D11CaptureFrame frame)
        {
            // Resize and device-lost leverage the same function on the
            // Direct3D11CaptureFramePool. Refactoring it this way avoids
            // throwing in the catch block below (device creation could always
            // fail) along with ensuring that resize completes successfully and
            // isn’t vulnerable to device-lost.
            bool needsReset = false;
            bool recreateDevice = false;

            if ((frame.ContentSize.Width != _lastSize.Width) ||
                (frame.ContentSize.Height != _lastSize.Height))
            {
                needsReset = true;
                _lastSize = frame.ContentSize;
            }

            try
            {
                // Take the D3D11 surface and draw it into a  
                // Composition surface.

                // Convert our D3D11 surface into a Win2D object.
                CanvasBitmap canvasBitmap = CanvasBitmap.CreateFromDirect3D11Surface(
                    _canvasDevice,
                    frame.Surface);

                _currentFrame = canvasBitmap;

                // Helper that handles the drawing for us.
                FillSurfaceWithBitmap(canvasBitmap);
            }

            // This is the device-lost convention for Win2D.
            catch (Exception e) when (_canvasDevice.IsDeviceLost(e.HResult))
            {
                // We lost our graphics device. Recreate it and reset
                // our Direct3D11CaptureFramePool.  
                needsReset = true;
                recreateDevice = true;
            }

            if (needsReset)
            {
                ResetFramePool(frame.ContentSize, recreateDevice);
            }
        }

        private void FillSurfaceWithBitmap(CanvasBitmap canvasBitmap)
        {
            CanvasComposition.Resize(_surface, canvasBitmap.Size);

            using (var session = CanvasComposition.CreateDrawingSession(_surface))
            {
                session.Clear(Colors.Transparent);
                session.DrawImage(canvasBitmap);
            }
        }

        private void ResetFramePool(SizeInt32 size, bool recreateDevice)
        {
            do
            {
                try
                {
                    if (recreateDevice)
                    {
                        _canvasDevice = new CanvasDevice();
                    }

                    _framePool.Recreate(
                        _canvasDevice,
                        DirectXPixelFormat.B8G8R8A8UIntNormalized,
                        2,
                        size);
                }
                // This is the device-lost convention for Win2D.
                catch (Exception e) when (_canvasDevice.IsDeviceLost(e.HResult))
                {
                    _canvasDevice = null;
                    recreateDevice = true;
                }
            } while (_canvasDevice == null);
        }

        private async void Button_ClickAsync(object sender, RoutedEventArgs e)
        {
            await StartCaptureAsync();
        }

        private async void ScreenshotButton_ClickAsync(object sender, RoutedEventArgs e)
        {
            await SaveImageAsync(_screenshotFilename, _currentFrame);
        }

        private async Task SaveImageAsync(string filename, CanvasBitmap frame)
        {
            StorageFolder pictureFolder = KnownFolders.SavedPictures;

            StorageFile file = await pictureFolder.CreateFileAsync(
                filename,
                CreationCollisionOption.ReplaceExisting);

            using (var fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))
            {
                await frame.SaveAsync(fileStream, CanvasBitmapFileFormat.Png, 1f);
            }
        }
    }
}
Imports System.Numerics
Imports Microsoft.Graphics.Canvas
Imports Microsoft.Graphics.Canvas.UI.Composition
Imports Windows.Graphics
Imports Windows.Graphics.Capture
Imports Windows.Graphics.DirectX
Imports Windows.UI
Imports Windows.UI.Composition
Imports Windows.UI.Xaml.Hosting

Partial Public NotInheritable Class MainPage
    Inherits Page

    ' Capture API objects.
    WithEvents CaptureItem As GraphicsCaptureItem
    WithEvents FramePool As Direct3D11CaptureFramePool

    Private _lastSize As SizeInt32
    Private _session As GraphicsCaptureSession

    ' Non-API related members.
    Private _canvasDevice As CanvasDevice
    Private _compositionGraphicsDevice As CompositionGraphicsDevice
    Private _compositor As Compositor
    Private _surface As CompositionDrawingSurface

    Sub New()
        InitializeComponent()
        Setup()
    End Sub

    Private Sub Setup()
        _canvasDevice = New CanvasDevice()
        _compositionGraphicsDevice = CanvasComposition.CreateCompositionGraphicsDevice(Window.Current.Compositor, _canvasDevice)
        _compositor = Window.Current.Compositor
        _surface = _compositionGraphicsDevice.CreateDrawingSurface(
            New Size(400, 400), DirectXPixelFormat.B8G8R8A8UIntNormalized, DirectXAlphaMode.Premultiplied)
        Dim visual = _compositor.CreateSpriteVisual()
        visual.RelativeSizeAdjustment = Vector2.One
        Dim brush = _compositor.CreateSurfaceBrush(_surface)
        brush.HorizontalAlignmentRatio = 0.5F
        brush.VerticalAlignmentRatio = 0.5F
        brush.Stretch = CompositionStretch.Uniform
        visual.Brush = brush
        ElementCompositionPreview.SetElementChildVisual(Me, visual)
    End Sub

    Public Async Function StartCaptureAsync() As Task
        ' The GraphicsCapturePicker follows the same pattern the
        ' file pickers do.
        Dim picker As New GraphicsCapturePicker
        Dim item As GraphicsCaptureItem = Await picker.PickSingleItemAsync()

        ' The item may be null if the user dismissed the
        ' control without making a selection or hit Cancel.
        If item IsNot Nothing Then
            StartCaptureInternal(item)
        End If
    End Function

    Private Sub StartCaptureInternal(item As GraphicsCaptureItem)
        ' Stop the previous capture if we had one.
        StopCapture()

        CaptureItem = item
        _lastSize = CaptureItem.Size

        FramePool = Direct3D11CaptureFramePool.Create(
            _canvasDevice, ' D3D device
            DirectXPixelFormat.B8G8R8A8UIntNormalized, ' Pixel format
            2, '  Number of frames
            CaptureItem.Size) ' Size of the buffers

        _session = FramePool.CreateCaptureSession(CaptureItem)
        _session.StartCapture()
    End Sub

    Private Sub FramePool_FrameArrived(sender As Direct3D11CaptureFramePool, args As Object) Handles FramePool.FrameArrived
        ' The FrameArrived event is raised for every frame on the thread
        ' that created the Direct3D11CaptureFramePool. This means we
        ' don't have to do a null-check here, as we know we're the only
        ' one dequeueing frames in our application.  

        ' NOTE Disposing the frame retires it And returns  
        ' the buffer to the pool.

        Using frame = FramePool.TryGetNextFrame()
            ProcessFrame(frame)
        End Using
    End Sub

    Private Sub CaptureItem_Closed(sender As GraphicsCaptureItem, args As Object) Handles CaptureItem.Closed
        StopCapture()
    End Sub

    Public Sub StopCapture()
        _session?.Dispose()
        FramePool?.Dispose()
        CaptureItem = Nothing
        _session = Nothing
        FramePool = Nothing
    End Sub

    Private Sub ProcessFrame(frame As Direct3D11CaptureFrame)
        ' Resize and device-lost leverage the same function on the
        ' Direct3D11CaptureFramePool. Refactoring it this way avoids
        ' throwing in the catch block below (device creation could always
        ' fail) along with ensuring that resize completes successfully And
        ' isn't vulnerable to device-lost.

        Dim needsReset As Boolean = False
        Dim recreateDevice As Boolean = False

        If (frame.ContentSize.Width <> _lastSize.Width) OrElse
            (frame.ContentSize.Height <> _lastSize.Height) Then
            needsReset = True
            _lastSize = frame.ContentSize
        End If

        Try
            ' Take the D3D11 surface and draw it into a  
            ' Composition surface.

            ' Convert our D3D11 surface into a Win2D object.
            Dim bitmap = CanvasBitmap.CreateFromDirect3D11Surface(
                _canvasDevice,
                frame.Surface)

            ' Helper that handles the drawing for us.
            FillSurfaceWithBitmap(bitmap)
            ' This is the device-lost convention for Win2D.
        Catch e As Exception When _canvasDevice.IsDeviceLost(e.HResult)
            ' We lost our graphics device. Recreate it and reset
            ' our Direct3D11CaptureFramePool.  
            needsReset = True
            recreateDevice = True
        End Try

        If needsReset Then
            ResetFramePool(frame.ContentSize, recreateDevice)
        End If
    End Sub

    Private Sub FillSurfaceWithBitmap(canvasBitmap As CanvasBitmap)
        CanvasComposition.Resize(_surface, canvasBitmap.Size)

        Using session = CanvasComposition.CreateDrawingSession(_surface)
            session.Clear(Colors.Transparent)
            session.DrawImage(canvasBitmap)
        End Using
    End Sub

    Private Sub ResetFramePool(size As SizeInt32, recreateDevice As Boolean)
        Do
            Try
                If recreateDevice Then
                    _canvasDevice = New CanvasDevice()
                End If
                FramePool.Recreate(_canvasDevice, DirectXPixelFormat.B8G8R8A8UIntNormalized, 2, size)
                ' This is the device-lost convention for Win2D.
            Catch e As Exception When _canvasDevice.IsDeviceLost(e.HResult)
                _canvasDevice = Nothing
                recreateDevice = True
            End Try
        Loop While _canvasDevice Is Nothing
    End Sub

    Private Async Sub Button_ClickAsync(sender As Object, e As RoutedEventArgs) Handles CaptureButton.Click
        Await StartCaptureAsync()
    End Sub

End Class

Запись видео

Если вы хотите записать видео приложения, вы можете выполнить пошаговое руководство, представленное в статье "Снимок экрана" в видео. Вы также можете использовать пространство имен Windows.Media.AppRecording. Это часть пакета SDK расширения для настольных компьютеров, поэтому он работает только на настольных компьютерах Windows и требует добавить ссылку на него из проекта. Дополнительные сведения см. в статье "Программирование с помощью пакетов SDK для расширений ".

См. также