【问题标题】:Take screenshot and draw it on a Windows Form using SharpDX截屏并使用 SharpDX 在 Windows 窗体上绘制
【发布时间】:2020-04-23 00:44:37
【问题描述】:

我正在尝试使用 SharpDX 捕获屏幕截图并在 Windows 窗体(或面板)上显示它,但我遇到了一些麻烦。我使用OutputDuplication.AcquireNextFrame 捕获屏幕截图,但是当我尝试使用WindowRenderTarget.DrawBitmap 绘制捕获的帧时,它会因WrongResourceDomain 异常而失败。我添加了一个Form并修改了ScreenCapture sample的代码来说明我的问题:

using System;
using SharpDX;
using SharpDX.Direct2D1;
using SharpDX.Direct3D11;
using SharpDX.DXGI;

namespace MiniTri
{
    /// <summary>
    ///   Screen capture of the desktop using DXGI OutputDuplication.
    /// </summary>
    internal static class Program
    {

        [STAThread]
        private static void Main()
        {
            var Form1 = new ScreenCapture.Form1();

            // # of graphics card adapter
            const int numAdapter = 0;

            // # of output device (i.e. monitor)
            const int numOutput = 0;

            // Create DXGI Factory1
            var dxgiFactory = new SharpDX.DXGI.Factory1();
            var dxgiAdapter = dxgiFactory.GetAdapter1(numAdapter);

            // Create device from Adapter
            var d3dDevice = new SharpDX.Direct3D11.Device(dxgiAdapter, DeviceCreationFlags.BgraSupport);

            // Create Direct2D1 Factory1
            var d2dFactory = new SharpDX.Direct2D1.Factory1();

            // Create Direct2D device
            SharpDX.Direct2D1.Device d2dDevice;
            using (var dxgiDevice = d3dDevice.QueryInterface<SharpDX.DXGI.Device>())
                d2dDevice = new SharpDX.Direct2D1.Device(d2dFactory, dxgiDevice);

            // Get the Direct2D1 DeviceContext
            var d2dContext = new SharpDX.Direct2D1.DeviceContext(d2dDevice, DeviceContextOptions.None);

            // Create Direct2D1 WindowRenderTarget
            var WindowRenderTarget = new WindowRenderTarget(d2dFactory,
                                                            new RenderTargetProperties
                                                            {
                                                                Type = RenderTargetType.Default
                                                            },
                                                            new HwndRenderTargetProperties
                                                            {
                                                                Hwnd = Form1.Handle,
                                                                PixelSize = new Size2(Form1.Width, Form1.Height),
                                                                PresentOptions = PresentOptions.Immediately
                                                            });

            // Get DXGI.Output
            var output = dxgiAdapter.GetOutput(numOutput);
            var output1 = output.QueryInterface<Output1>();

            // Create RawRectangleF with the Form size
            var FormRectangle = new SharpDX.Mathematics.Interop.RawRectangleF(0, 0, Form1.Width, Form1.Height);

            // Duplicate the output
            var duplicatedOutput = output1.DuplicateOutput(d3dDevice);

            bool captureDone = false;
            for (int i = 0; !captureDone; i++)
            {
                try
                {
                    SharpDX.DXGI.Resource screenResource;
                    OutputDuplicateFrameInformation duplicateFrameInformation;

                    // Try to get duplicated frame within given time
                    duplicatedOutput.AcquireNextFrame(10000, out duplicateFrameInformation, out screenResource);

                    if (i > 0)
                    {
                        // Create a Direct2D1 Bitmap1 from screenResource
                        var dxgiSurface = screenResource.QueryInterface<Surface>();
                        var d2dBitmap1 = new Bitmap1(d2dContext, dxgiSurface);

                        // Should draw the bitmap on the form, but fails with "WrongResourceDomain" exception
                        WindowRenderTarget.BeginDraw();
                        WindowRenderTarget.DrawBitmap(d2dBitmap1, FormRectangle, 1.0f, BitmapInterpolationMode.Linear);
                        WindowRenderTarget.EndDraw();

                        // Capture done
                        captureDone = true;
                    }

                    screenResource.Dispose();
                    duplicatedOutput.ReleaseFrame();

                }
                catch (SharpDXException e)
                {
                    if (e.ResultCode.Code != SharpDX.DXGI.ResultCode.WaitTimeout.Result.Code)
                    {
                        throw e;
                    }
                }
            }

            // TODO: We should cleanp up all allocated COM objects here
        }
    }
}

我知道我可以将框架转换为System.Drawing.Bitmap(就像在原始示例中一样),然后使用System.Drawing.Graphics.DrawImage 将位图绘制到表单,但我想避免这种情况并使用 SharpDX 绘制框架。 我也尝试创建一个SwapChain 并使用Direct2D1.RenderTarget.DrawBitmap 绘制框架(类似于MiniRect sample),但它失败了同样的异常。同样使用Direct2D1.DeviceContext.DrawBitmap。 我读到here,这个异常意味着我正在混合来自不同资源域的资源,但我不明白它在我的代码中的确切含义。我没有使用 DirectX 的经验。

【问题讨论】:

    标签: c# drawing directx screen-capture sharpdx


    【解决方案1】:

    我再次尝试使用SwapChain,而不是WindowRenderTarget,这次我成功了。

    • 创建一个SwapChainDescription,指定目标控件(例如窗体或面板)的宽度、高度和句柄。
    • 使用dxgiFactoryd3dDeviceSwapChainDescription 创建一个新的SwapChain
    • 获取SwapChainback buffer
    • back buffer 获取DXGI Surface

    (更多关于在MiniRect sample 中创建SwapChainback bufferDXGI Surface

    • 使用d2dContextDXGI Surface 创建一个Direct2D1.Bitmap1
    • 使用d2dContextscreenResource 创建另一个Direct2D1.Bitmap1(如上面的代码所示)。
    • 将第一个Direct2D1.Bitmap1设置为d2dContext的目标。
    • 使用d2dContext 绘制第二个Direct2D1.Bitmap1
    • 提交SwapChain
    • 完成。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多