I am fiddling with recording the screen of Windows Sandbox based on https://github.com/mika-f/dotnet-window-capture :
var hr = _duplication.TryAcquireNextFrame(100, out _, out var desktopResourceOut);
if (hr.Failure)
return null;
using var desktopTexture = desktopResourceOut.QueryInterface<Texture2D>();
var texture2dDescription = new Texture2DDescription {
ArraySize = 1,
BindFlags = BindFlags.ShaderResource | BindFlags.RenderTarget,
CpuAccessFlags = CpuAccessFlags.None,
Format = Format.B8G8R8A8_UNorm,
Height = desktopTexture.Description.Height,
MipLevels = 1,
SampleDescription = new SampleDescription(1, 0),
Usage = ResourceUsage.Default,
Width = desktopTexture.Description.Width
};
var texture2d = new Texture2D(device, texture2dDescription);
device.ImmediateContext.CopyResource(desktopTexture, texture2d);
// release resources
desktopResourceOut.Dispose();
_duplication.ReleaseFrame();
return texture2d;
Problem is from the start the code works on my own machine and also via RDP. But inside the Windows Sandbox all I get is a blank window.
Now I searched around, and found a few "deficiencies" in the above sample, namely:
- All failures of
TryAcquireNextFrame
are ignored silently. OutputDuplicateFrameInformation
is ignored. Specifically, it never checksLastPresentTime
which must be checked according to this SO thread (although that contradictsWhen AcquireNextFrame returns successfully, the calling application can access the desktop image that AcquireNextFrame returns in the variable at ppDesktopResource
from MSDN).
So after fiddling with error handling and OutputDuplicateFrameInformation
all I am getting from Windows Sandbox is:
- As long as I move mouse around,
TryAcquireNextFrame
mostly succeeds, howeverOutputDuplicateFrameInformation.LastPresentTime
is always 0. - The only error code I get in simple tests is
0x887A0027
aka timeout, which just indicates the need to wait more as there was no picture update. - If I ignore
LastPresentTime == 0
, thetexture2d
comes out black. - I also tried to copy some
Texture2DDescription
parameters directly fromdesktopTexture
in attempt to avoid potential silent failure ofCopyResource
as suggested in this SO thread, but that had no visible effect. - I enumerated Adapters and their associated Outputs, and there's only one Output in the system.
The final modification that still exhibits the blank texture2d
behavior is
var hr = _duplication.TryAcquireNextFrame(100, out var frameInfo, out var desktopResourceOut);
if (hr.Failure) {
if (hr.Code == unchecked((int)0x887A0027)) return null; // no changes
hr.CheckError();
return null;
}
try {
//if (frameInfo.LastPresentTime == 0) {
// return null; // in Sandbox all frames go here
//}
using var desktopTexture = desktopResourceOut.QueryInterface<Texture2D>();
var texture2dDescription = new Texture2DDescription {
ArraySize = desktopTexture.Description.ArraySize,
BindFlags = BindFlags.ShaderResource | BindFlags.RenderTarget,
CpuAccessFlags = CpuAccessFlags.None,
Format = desktopTexture.Description.Format,
Height = desktopTexture.Description.Height,
MipLevels = 1,
SampleDescription = new SampleDescription(1, 0),
Usage = ResourceUsage.Default,
Width = desktopTexture.Description.Width
};
var texture2d = new Texture2D(device, texture2dDescription);
device.ImmediateContext.CopyResource(desktopTexture, texture2d);
return texture2d;
} finally {
// release resources
desktopResourceOut.Dispose();
_duplication.ReleaseFrame();
}
P.S. As alternative I also tried WinRT's IGraphicsCaptureItemInterop::CreateForMonitor(hmon, new Guid("79C3F95B-31F7-4EC2-A464-632EF5D30760"))
but this one fails with 0x80040154 REGDB_E_CLASSNOTREG
.