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


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

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

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

Замечание

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

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

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

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. Дополнительные сведения см. в разделе Using DirectX with high dynamic range Displays and Advanced Color.

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)

После явного предоставления пользователю согласия на запись окна приложения или отображения в системном пользовательском интерфейсе GraphicsCaptureItem можно связать с несколькими объектами 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 в 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, изменение размера буферов кадров или даже изменение количества буферов в пуле. В каждом из этих сценариев метод Recreate на объекте 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.

См. также