Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Regression: Out arguments in many COM interfaces (eg. DXGI/D3D11) are suddenly unmanaged #1185

Open
VentuzTammoHinrichs opened this issue May 15, 2024 · 6 comments
Labels
bug Something isn't working

Comments

@VentuzTammoHinrichs
Copy link

VentuzTammoHinrichs commented May 15, 2024

Actual behavior

COM Out arguments in methods in the Graphics.DXGI and .D3D11 namespaces are now I..._unmanaged** (instead of out I... in 0.3.49beta). Look at e.g. all the Create* functions in ID3D11Device.

Note that this doesn't apply to top level functions such as D3D11CreateDevice. Those still work as expected.

Expected behavior

I'd really like to have the managed out arguments back if possible.

Repro steps

  1. NativeMethods.txt content:
Windows.Win32.Graphics.Direct3D11
Windows.Win32.Graphics.DXGI
D3DCompile
  1. NativeMethods.json content (if present):
{
  "$schema": "https://aka.ms/CsWin32.schema.json",
  "useSafeHandles": false,
  "allowMarshaling": true
}

Context

CsWin32 version: 0.3.106
Target Framework: net8.0

@VentuzTammoHinrichs VentuzTammoHinrichs added the bug Something isn't working label May 15, 2024
@AArnott
Copy link
Member

AArnott commented May 17, 2024

I suspect this change is a fallout of improving support in other areas where we discovered certain interop rules had to be honored, and this was an area where we weren't fully following the rules, causing failures in at least some cases.

I'll leave this active till we have a chance to confirm.

@iraqigeek
Copy link

having the same issue with D3D11 after updating from 0.3.49-beta to 0.3.106

@smourier
Copy link

Same for me. It's actually a showstopper for upgrading nuget packages.

@AffluentOwl
Copy link

AffluentOwl commented Jun 3, 2024

It wasn't that hard to work around this issue. Just had to spend the month learning x64 ASM and how to reverse engineer Windows binaries. Then produced the following elegant and idiomatic C# code which is required to both retain managed and unmanaged copies of the same COM objects, and properly handle both of their lifetimes. My new favorite part of coding in C# with projections is all the time one gets to spend reading and writing assembly.

  [Guid("94D99BDB-F1F8-4AB0-B236-7DA0170EDAB1"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), ComImport()]
  internal interface IDXGISwapChain3Extra : IDXGISwapChain3
  {
    void _VtblGap_6();
  
    unsafe void GetBufferRaw(uint Buffer, Guid* riid, void** ppSurface);
  }

  List<ID3D12Resource> gSurfaces = new List<ID3D12Resource>();
  List<nint> gSurfacesRaw = new List<nint>();

  // ...

  guid = typeof(ID3D12Resource).GUID;
  void* ppSurface;
  gSwapChain.GetBufferRaw(i, &guid, &ppSurface);
  gSurfacesRaw.Add((nint)ppSurface);
  gSurfaces.Add((ID3D12Resource)Marshal.GetObjectForIUnknown((nint)ppSurface));
  
  gDevice.CreateRenderTargetView(gSurfaces.Last(), null, rtvHandle);
  
  // ...
  
  ID3D12Resource_unmanaged* p = (ID3D12Resource_unmanaged*)gSurfacesRaw[(int)gFrameIndex];
  D3D12_RESOURCE_BARRIER[] b = [
    new() {
      Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE,
      Anonymous = new()
      {
        Transition = new()
        {
          pResource = p,
          Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
          StateBefore = D3D12_RESOURCE_STATE_PRESENT,
          StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET,
        }
      }
    }
  ];
  gCommandList.ResourceBarrier(1, b);
  
  // ...

  void ResizeBuffers(nint lParam)
  {
    if (gSwapChain != null && gFence != null && gSurfaces.Count > 0)
    {
      WaitForPreviousFrame();

      for (int i = 0; i < 2; i++)
      {
        Marshal.ReleaseComObject(gSurfaces[i]);
        ((ID3D12Resource_unmanaged*)gSurfacesRaw[(int)i])->Release();
      }
      gSurfaces.Clear();
      gSurfacesRaw.Clear();

      // ...
      
      Guid guid = typeof(ID3D12Resource).GUID;
      void* ppSurface;
      gSwapChain!.GetBufferRaw(i, &guid, &ppSurface);
      gSurfacesRaw.Add((nint)ppSurface);
      gSurfaces.Add((ID3D12Resource)Marshal.GetObjectForIUnknown((nint)ppSurface));

      gDevice.CreateRenderTargetView(gSurfaces.Last(), null, rtvHandle);

@mitchcapper
Copy link

@AffluentOwl if you can update the title to just says something like "regression/breaking change: Multiple prior COM out objects are now _unmanaged double pointers" as it goes beyond the DX items. This only happened in the latest release 106 the 0.3.49 beta did not.

As this is expected it seems mostly just a few more lines of code, although one does need to track and cleanup the pointer as well now I believe. Here is a define around the old and new code.

            var FilePath=@"c:\users\image.jpg";
            PInvoke.CoCreateInstance<IThumbnailCache>(CLSID_LocalThumbnailCache, null, Windows.Win32.System.Com.CLSCTX.CLSCTX_INPROC_HANDLER | Windows.Win32.System.Com.CLSCTX.CLSCTX_INPROC_SERVER, out var thumCache);
            IShellItem shellItem = GetShellItem(FilePath);
            var size = 256u;
#if NEW_CSWIN32
            ISharedBitmap_unmanaged* img;
            thumCache.GetThumbnail(shellItem, size, WTS_FLAGS.WTS_INCACHEONLY,&img);
            img->GetSharedBitmap(out var hBitmap);           
#else
            thumCache.GetThumbnail(shellItem, size, WTS_FLAGS.WTS_INCACHEONLY,out var img);
            img.GetSharedBitmap(out var hBitmap);
#endif

@VentuzTammoHinrichs VentuzTammoHinrichs changed the title COM Out arguments in DXGI/D3D11 are suddenly unmanaged Out arguments in many COM interfaces (eg. DXGI/D3D11) are suddenly unmanaged Jan 7, 2025
@VentuzTammoHinrichs
Copy link
Author

It was me. Changed the title.

And I also would like to bump this issue. Yes, you can work with the unmanaged pointers somehow but it's so cumbersome I'd rather write a C++ wrapper DLL now instead of using CsWin32, which kind of runs counter to its point.

@VentuzTammoHinrichs VentuzTammoHinrichs changed the title Out arguments in many COM interfaces (eg. DXGI/D3D11) are suddenly unmanaged Regression: Out arguments in many COM interfaces (eg. DXGI/D3D11) are suddenly unmanaged Jan 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

6 participants