螢幕擷取

從 Windows 10 版本 1803 開始,Windows.Graphics.Capture 命名空間提供 API 來從顯示器或應用程式視窗取得畫面、建立視訊串流或快照以建立協作和互動體驗。

使用螢幕擷取時,開發人員會叫用安全的系統 UI,讓使用者挑選要擷取的顯示或應用程式視窗,而系統會在主動擷取的專案周圍繪製黃色通知框線。 在多個同時擷取工作階段的情況下,會在每個正在擷取的專案周圍繪製黃色框線。

注意

只有 Windows 裝置和 Windows Mixed Reality 沉浸式頭戴裝置才支援螢幕擷取 API。

本文說明擷取顯示或應用程式視窗的單一影像。 如需從畫面擷取到視訊檔案之編碼畫面的資訊,請參閱螢幕擷取至影片

新增螢幕擷取功能

Windows.Graphics.Capture 命名空間中找到的 API 需要在應用程式的資訊清單中宣告一般功能:

  1. 方案總管中,開啟 Package.appxmanifest
  2. 選取 [功能] 索引標籤。
  3. 檢查圖形擷取

Graphics Capture

啟動系統 UI 以啟動螢幕擷取

啟動系統 UI 之前,您可以檢查您的應用程式目前是否能夠擷取螢幕快照。 您的應用程式可能無法使用螢幕擷取有幾個原因,包括裝置是否符合硬體需求,或針對擷取封鎖螢幕擷取的目標應用程式。 使用 GraphicsCaptureSession 類別中的 IsSupported 方法來判斷是否支援 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 類別來叫用系統選擇器 UI。 使用者使用此 UI 來選取要擷取螢幕快照的顯示或應用程式視窗。 選擇器會傳回用來建立 GraphicsCaptureSessionGraphicsCaptureItem

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

因為這是 UI 程式碼,所以必須在 UI 執行緒上呼叫它。 如果您要從應用程式頁面的程式碼後置呼叫它 (例如 MainPage.xaml.cs),這會自動為您完成,但如果不是,您可以強制它以下列程式碼在 UI 執行緒上執行:

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,您將使用您的 D3D 裝置建立 Direct3D11CaptureFramePool、支援的像素格式(DXGI_FORMAT_B8G8R8A8_UNORM)、所需的畫面數目 (可以是任何整數),以及畫面大小。 GraphicsCaptureItem 類別的 ContentSize屬性可用來做為畫面的大小:

注意

在啟用 Windows HD 色彩的系統上,內容像素格式不一定是 DXGI_FORMAT_B8G8R8A8_UNORM。 若要避免擷取 HDR 內容時像素過度剪裁 (亦即擷取的內容看起來已清除),請考慮針對擷取管線中的每個元件使用 DXGI_FORMAT_R16G16B16A16_FLOAT,包括 Direct3D11CaptureFramePool,例如 CanvasBitmap 的目標目的地。 視需要而定,可能需要其他處理,例如儲存至 HDR 內容格式或 HDR 到 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

接下來,將 GraphicsCaptureItem 傳遞至 CreateCaptureSession 方法,以取得 Direct3D11CaptureFramePoolGraphicsCaptureSession 類別執行個體:

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

一旦使用者明確同意擷取應用程式視窗或顯示在系統 UI 中,GraphicsCaptureItem 就可以與多個 CaptureSession 物件相關聯。 如此一來,您的應用程式可以選擇針對各種體驗擷取相同的專案。

若要同時擷取多個專案,您的應用程式必須為每個要擷取的專案建立擷取工作階段,這需要針對要擷取的每個專案叫用選擇器 UI。

取得擷取畫面

建立畫面集區和擷取工作階段之後,請在 GraphicsCaptureSession 執行個體上呼叫 StartCapture 方法,以通知系統開始將擷取畫面傳送至您的應用程式:

_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 可能的話,建議您避免使用 UI 執行緒,因為每次有新的畫面可用時都會引發此事件,這將會很頻繁。 如果您選擇在 UI 執行緒上接聽 FrameArrived,請留意每次引發事件時要執行的工作。

或者,您可以使用 Direct3D11CaptureFramePool.TryGetNextFrame 方法手動提取畫面,直到取得您需要的所有畫面。

Direct3D11CaptureFrame 物件包含 ContentSizeSurfaceSystemRelativeTime 屬性。 SystemRelativeTime 是 QPC (QQueryPerformanceCounter) 時間,可用來同步處理其他媒體元素。

處理擷取畫面

呼叫 TryGetNextFrame 時,會取出 Direct3D11CaptureFramePool 中的每個畫面,並根據 Direct3D11CaptureFrame 物件的存留期重新簽入。 針對原生應用程式,釋放 Direct3D11CaptureFrame 物件就足以檢查畫面集區中的畫面。 針對受控應用程式,建議使用 Direct3D11CaptureFrame.Dispose (C++中的 Close) 方法。 Direct3D11CaptureFrame 會實作 IClosable 介面,其投影為 C# 呼叫端的 IDisposable

應用程式不應該儲存 Direct3D11CaptureFrame 使用者的參考,也不應該在簽回畫面之後儲存基礎 Direct3D 介面的參考。

處理畫面時,建議應用程式在與 Direct3D11CaptureFramePool 物件相關聯的相同裝置上取得 ID3D11Multithread 鎖定。

基礎 Direct3D 表面一律是建立 Direct3D11CaptureFramePool 時所指定的大小。 如果內容大於畫面,則會將內容裁剪為畫面的大小。 如果內容小於畫面,則畫面的其餘部分會包含未定義的資料。 建議應用程式使用 Direct3D11CaptureFrameContentSize 屬性來複製子內容,以避免顯示未定義的內容。

拍攝螢幕擷取畫面

在我們的範例中,我們會將每個 Direct3D11CaptureFrame 轉換成 CanvasBitmap,這是 Win2D APIs 的一部分。

// 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 物件上的 Recreate 方法是建議的工具。

呼叫 Recreate 時,會捨棄所有現有的畫面。 這是為了避免將基礎 Direct3D 表面所屬的畫面傳送到應用程式可能無法再存取的裝置。 基於這個理由,在呼叫 Recreate 之前,處理所有擱置的畫面可能是明智的。

融會貫通

下列程式碼片段是如何在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 進行程式設計。

另請參閱