I have the following code in my WinUI3 app:
public class Screenshot(byte[] pixels, int width, int height)
{
public byte[] Pixels { get; } = pixels;
public int Width { get; } = width;
public int Height { get; } = height;
}
public static async Task<string> ByteArrayToBase64PNGStringAsync(Screenshot screenshot)
{
using (InMemoryRandomAccessStream memoryStream = new())
{
await RenderPixelsToRasterStreamAsync(memoryStream, screenshot);
using (DataReader reader = new(memoryStream.GetInputStreamAt(0)))
{
await reader.LoadAsync((uint)memoryStream.Size);
byte[] byteArray = new byte[memoryStream.Size];
reader.ReadBytes(byteArray);
return Convert.ToBase64String(byteArray);
}
}
}
public static async Task<bool> CopyScreenshotToClipboardAsync(Screenshot screenshot)
{
InMemoryRandomAccessStream stream = new();
await RenderPixelsToRasterStreamAsync(stream, screenshot);
DataPackage dataPackage = new();
dataPackage.RequestedOperation = DataPackageOperation.Copy;
dataPackage.SetBitmap(RandomAccessStreamReference.CreateFromStream(stream));
try
{
Clipboard.SetContent(dataPackage);
return true;
}
catch (Exception)
{
return false;
}
finally
{
Debug.WriteLine("Clipboard flushed");
Clipboard.Flush();
stream.Dispose();
}
}
private static async Task RenderPixelsToRasterStreamAsync(IRandomAccessStream stream, Screenshot screenshot)
{
double dpi = App.Window.DPI;
Debug.WriteLine($"RenderPixelsToRasterStreamAsync method called with {(uint)screenshot.Width} {(uint)screenshot.Height} {dpi}");
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream);
Debug.WriteLine("Encoder initialised");
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied, (uint)screenshot.Width, (uint)screenshot.Height, dpi, dpi, screenshot.Pixels);
Debug.WriteLine("Bitmap set");
await encoder.FlushAsync();
Debug.WriteLine("Encoder flushed");
}
I can call any combination/repetitions of ByteArrayToBase64PNGStringAsync
and CopyScreenshotToClipboardAsync
without issue, apart from if I call CopyScreenshotToClipboardAsync
then ByteArrayToBase64PNGStringAsync
, in which case the code hangs indefinitely on await encoder.FlushAsync()
. (using the UI thread throughout).
Can anyone suggest what might be causing this?
Whilst trying to make a reproduceable example I discovered a .GetAwaiter().GetResult()
back in the calling code that seemed to be creating a deadlock only in the scenario I described in my question. Replacing this with an async function solved the issue.