如何在 NET 5 / 6 中使用 Direct3D11CaptureFramePool

How to use Direct3D11CaptureFramePool in NET 5 / 6

替代标题: WinRT 对 IDirect3DDevice 的支持

我有一个应用程序使用“Direct3D11CaptureFramePool" class to capture the content of an application window as shown here (link)

我想将此示例移植到 NET 6.0

此处介绍了如何移植 WinRT 代码 link 这按预期工作。但是 CreateFreeThreaded method

要求的 IDirect3DDevice 是不可能的

如何将此代码移植到 NET 6.0

    uint hr = CreateDirect3D11DeviceFromDXGIDevice(dxgiDevice.NativePointer, out IntPtr pUnknown);
    if (hr == 0)
    {
        device = Marshal.GetObjectForIUnknown(pUnknown) as IDirect3DDevice;
        Marshal.Release(pUnknown);
    }

没有描述的 IDrect3DDEvice 的 FromAbi 方法here

编辑:

我有接口类型,我有一个指向 IUnknown object 的指针,但我无法获取实例,因为获取 IUnknown 指针的 object 的代码已更改。没有 Windows.Graphics.DirectX.Direct3D11.IDirect3DDevice.FromAbi(pUnknown)

编辑 2:

我创建了一个示例存储库来重现该问题: https://github.com/Amberg/GraphicsCaptureItemNet6Problem

此代码适用于 NET 4.8 但不适用于 NET 6。我相信是因为 call Marshal.GetObjectForIUnknown(pUnknown) 应替换为 IDirect3DDevice.FromAbi(pUnknown)但是没有这样的方法

internal class Program
{

[DllImport(
        "d3d11.dll",
        EntryPoint = "CreateDirect3D11DeviceFromDXGIDevice",
        SetLastError = true,
        CharSet = CharSet.Unicode,
        ExactSpelling = true,
        CallingConvention = CallingConvention.StdCall
        )]
static extern UInt32 CreateDirect3D11DeviceFromDXGIDevice(IntPtr dxgiDevice, out IntPtr graphicsDevice);

static void Main(string[] args)
{

    using var sharpDxDevice = new SharpDX.Direct3D11.Device(SharpDX.Direct3D.DriverType.Hardware, SharpDX.Direct3D11.DeviceCreationFlags.BgraSupport);
    IDirect3DDevice direct3dDevice = CreateDirect3DDeviceFromSharpDXDevice(sharpDxDevice);

    // this will throw internal cast exception 
    using var framePool = Direct3D11CaptureFramePool.CreateFreeThreaded(
                        direct3dDevice,
                        DirectXPixelFormat.B8G8R8A8UIntNormalized,
                        2,
                        new SizeInt32(64, 64));

}

private static IDirect3DDevice CreateDirect3DDeviceFromSharpDXDevice(SharpDX.Direct3D11.Device sharpDxDevice)
{
    IDirect3DDevice device = null;
    using (var dxgiDevice = sharpDxDevice.QueryInterface<SharpDX.DXGI.Device3>())
    {
        uint hr = CreateDirect3D11DeviceFromDXGIDevice(dxgiDevice.NativePointer, out IntPtr pUnknown);
        if (hr == 0)
        {
            // with NET 6 there should be something like 
            // IDirect3DDevice.FromAbi(pUnknown)
            // see here https://github.com/microsoft/CsWinRT/blob/master/docs/interop.md#create-rcw
            device = Marshal.GetObjectForIUnknown(pUnknown) as IDirect3DDevice;
            Marshal.Release(pUnknown);
        }
    }
    return device;
}
}

使用 .NET 6 和 CsWinRT,您可以像这样编写 CreateDirect3DDeviceFromSharpDXDevice 函数:

private static IDirect3DDevice CreateDirect3DDeviceFromSharpDXDevice(SharpDX.Direct3D11.Device sharpDxDevice)
{
    if (CreateDirect3D11DeviceFromDXGIDevice(sharpDxDevice.NativePointer, out var punk) != 0)
        return null;

    return WinRT.MarshalInterface<IDirect3DDevice>.FromAbi(punk);
}