Public Access
Archive meeting workflow and screenshot changes
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace MeetingAssistant.Screenshots;
|
||||
|
||||
public sealed class ActiveWindowScreenshotCapture : IActiveWindowScreenshotCapture
|
||||
{
|
||||
private static readonly IntPtr DpiAwarenessContextPerMonitorAwareV2 = new(-4);
|
||||
private const int DwmWindowAttributeExtendedFrameBounds = 9;
|
||||
|
||||
public Task<ActiveWindowScreenshot> CaptureAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var previousDpiContext = TrySetThreadDpiAwarenessContext(DpiAwarenessContextPerMonitorAwareV2);
|
||||
try
|
||||
{
|
||||
var foregroundWindow = GetForegroundWindow();
|
||||
if (foregroundWindow == IntPtr.Zero ||
|
||||
!TryGetWindowBounds(foregroundWindow, out var rect))
|
||||
{
|
||||
throw new InvalidOperationException("Could not determine the active window bounds.");
|
||||
}
|
||||
|
||||
using var bitmap = new Bitmap(rect.Width, rect.Height);
|
||||
using (var graphics = Graphics.FromImage(bitmap))
|
||||
{
|
||||
graphics.CopyFromScreen(rect.Left, rect.Top, 0, 0, new Size(rect.Width, rect.Height));
|
||||
}
|
||||
|
||||
using var stream = new MemoryStream();
|
||||
bitmap.Save(stream, ImageFormat.Png);
|
||||
return Task.FromResult(new ActiveWindowScreenshot(stream.ToArray(), GetWindowTitle(foregroundWindow)));
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (previousDpiContext != IntPtr.Zero)
|
||||
{
|
||||
TrySetThreadDpiAwarenessContext(previousDpiContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TryGetWindowBounds(IntPtr window, out NativeRect rect)
|
||||
{
|
||||
if (DwmGetWindowAttribute(
|
||||
window,
|
||||
DwmWindowAttributeExtendedFrameBounds,
|
||||
out rect,
|
||||
Marshal.SizeOf<NativeRect>()) == 0 &&
|
||||
rect.Width > 0 &&
|
||||
rect.Height > 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return GetWindowRect(window, out rect) &&
|
||||
rect.Width > 0 &&
|
||||
rect.Height > 0;
|
||||
}
|
||||
|
||||
private static IntPtr TrySetThreadDpiAwarenessContext(IntPtr dpiContext)
|
||||
{
|
||||
try
|
||||
{
|
||||
return SetThreadDpiAwarenessContext(dpiContext);
|
||||
}
|
||||
catch (EntryPointNotFoundException)
|
||||
{
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
private static string? GetWindowTitle(IntPtr window)
|
||||
{
|
||||
var length = GetWindowTextLength(window);
|
||||
if (length <= 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var buffer = new System.Text.StringBuilder(length + 1);
|
||||
return GetWindowText(window, buffer, buffer.Capacity) > 0
|
||||
? buffer.ToString()
|
||||
: null;
|
||||
}
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern IntPtr GetForegroundWindow();
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
private static extern bool GetWindowRect(IntPtr hWnd, out NativeRect lpRect);
|
||||
|
||||
[DllImport("dwmapi.dll", PreserveSig = true)]
|
||||
private static extern int DwmGetWindowAttribute(
|
||||
IntPtr hwnd,
|
||||
int dwAttribute,
|
||||
out NativeRect pvAttribute,
|
||||
int cbAttribute);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern IntPtr SetThreadDpiAwarenessContext(IntPtr dpiContext);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
private static extern int GetWindowText(IntPtr hWnd, System.Text.StringBuilder lpString, int nMaxCount);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
private static extern int GetWindowTextLength(IntPtr hWnd);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private readonly struct NativeRect
|
||||
{
|
||||
public readonly int Left;
|
||||
public readonly int Top;
|
||||
public readonly int Right;
|
||||
public readonly int Bottom;
|
||||
|
||||
public int Width => Right - Left;
|
||||
|
||||
public int Height => Bottom - Top;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user