截取屏幕快照,并使用SharpDX将其绘制在Windows窗体上

问题描述 投票:1回答:1

我正在尝试捕获屏幕快照,并使用SharpDX在Windows窗体(或面板)上显示它,但遇到了一些麻烦。我使用OutputDuplication.AcquireNextFrame捕获了屏幕截图,但是当我尝试使用WindowRenderTarget.DrawBitmap绘制带字幕的帧时,它失败,并出现WrongResourceDomain异常。我添加了一个表格并修改了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个回答
0
投票
我尝试再次使用SwapChain,而不是WindowRenderTarget,这次我成功了。

    创建SwapChainDescription,指定目标控件(例如,窗体或面板)的宽度,高度和句柄。
  • 使用SwapChaindxgiFactoryd3dDevice创建新的SwapChainDescription
  • 获取back bufferSwapChain
  • DXGI Surface获取back buffer
  • (有关SwapChainback bufferDXGI SurfaceMiniRect sample的创建的更多信息

      使用d2dContextDirect2D1.Bitmap1创建DXGI Surface
  • 使用d2dContextDirect2D1.Bitmap1创建另一个screenResource(如上面的代码所示。
  • 将第一个Direct2D1.Bitmap1设置为d2dContext的目标。
  • 使用d2dContext绘制第二个Direct2D1.Bitmap1
  • 呈现SwapChain
  • 完成。
  • © www.soinside.com 2019 - 2024. All rights reserved.