4

Alternative title: WinRT support for IDirect3DDevice

I've an application that uses the "Direct3D11CaptureFramePool" class to capture the content of an application window as shown here (link)

I would like to port this example to NET 6.0

How to port WinRT code is described here link This worked as expected. But it was not possible for the IDirect3DDevice required by the CreateFreeThreaded method

How can i port this code to NET 6.0

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

There is no FromAbi method for IDrect3DDEvice as described here

Edit:

I have the Interface Type, I have a pointer to a IUnknown object, but i cannot get an instance because the Code to get an object for a IUnknown pointer has changed. There is no Windows.Graphics.DirectX.Direct3D11.IDirect3DDevice.FromAbi(pUnknown)

Edit 2:

I've created a sample repo to reproduce the problem: https://github.com/Amberg/GraphicsCaptureItemNet6Problem

This code works with NET 4.8 but not with NET 6. I belive because the call Marshal.GetObjectForIUnknown(pUnknown) should be replaced with IDirect3DDevice.FromAbi(pUnknown) but there is no such method

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;
}
}
Manuel Amstutz
  • 1,311
  • 13
  • 33
  • 1
    Windows.Graphics.DirectX.Direct3D11.IDirect3DDevice is available directly in .NET/C# if you make sure your .NET 6 project has a TargetFramework that includes "windows", like `net6.0-windows10.0.19041.0` see C#/WinRT common issues: https://learn.microsoft.com/en-us/windows/apps/develop/platform/csharp-winrt/ – Simon Mourier Apr 05 '22 at 18:00
  • Yes - I did that. I have the Interface as Type available, I Have a pointer to a IUnknown object, but i cannot get a valid instance – Manuel Amstutz Apr 06 '22 at 05:36
  • Note sure what your problem is. Can you provide a full reproducing sample? – Simon Mourier Apr 06 '22 at 05:53
  • @SimonMourier Thx - I've created a repo to show the problem https://github.com/Amberg/GraphicsCaptureItemNet6Problem – Manuel Amstutz Apr 06 '22 at 08:25
  • I am also currently struggling to get to capture windows in Windows 11 that are in the background / without focus. For Windows 10 BitBlt was working that is broken now on W11 for some reason. Is there a way to get WindowsRuntimeMarshal in NET 6.0? Seems it's the only that I am missing and isn't available to create the GraphicsCaptureItem from my hWnd. – Artur K. Apr 06 '22 at 19:16

1 Answers1

2

With .NET 6 and CsWinRT, you can write your CreateDirect3DDeviceFromSharpDXDevice function like this:

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

    return WinRT.MarshalInterface<IDirect3DDevice>.FromAbi(punk);
}
Simon Mourier
  • 132,049
  • 21
  • 248
  • 298