public static DXGI_MODE_DESC1?FindClosestMatchingMode1(this IDXGIOutput1 output, DXGI_MODE_DESC1 modeToMatch, object concernedDevice) { if (output == null) { throw new ArgumentNullException(nameof(output)); } var closest = new DXGI_MODE_DESC1(); if (output.FindClosestMatchingMode1(ref modeToMatch, out closest, ComObject.Unwrap(concernedDevice)).IsError) { return(null); } return(closest); }
public static ComObject <IDXGIOutputDuplication> DuplicateOutput(this IDXGIOutput1 output, object device, bool throwOnError = true) { if (output == null) { throw new ArgumentNullException(nameof(output)); } if (device == null) { throw new ArgumentNullException(nameof(device)); } device = ComObject.Unwrap(device); // this wonderful magic (mess) is because of a horrible bug in DXGI // https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/0c28328a-100a-4d6f-9a08-44a452d3ca6a/idxgioutputduplication-implementation-bug?forum=windowssdk#0c28328a-100a-4d6f-9a08-44a452d3ca6a output.DuplicateOutput(device, out var unk).ThrowOnError(throwOnError); if (unk == IntPtr.Zero) { return(null); } // we copy the original COM's vtable to our process var vtablePtr = Marshal.ReadIntPtr(unk); var vtable = new IDXGIOutputDuplicationVTable(); Marshal.PtrToStructure(vtablePtr, vtable); // patch QueryInterface so it works (route to our code) var wrapper = new Wrapper(unk); vtable.QueryInterfacePtr = Marshal.GetFunctionPointerForDelegate <QueryInterfaceFn>(wrapper.QueryInterface); using (var newVtablePtr = new ComMemory(Marshal.SizeOf <IDXGIOutputDuplicationVTable>())) { Marshal.StructureToPtr(vtable, newVtablePtr.Pointer, false); // create a new vtable for the CLR using (var newUnk = new ComMemory(IntPtr.Size)) { Marshal.WriteIntPtr(newUnk.Pointer, newVtablePtr.Pointer); var dup = (IDXGIOutputDuplication)Marshal.GetObjectForIUnknown(newUnk.Pointer); return(new ComObject <IDXGIOutputDuplication>(dup)); } } }