承上篇,前兩種方案 (GDI BitBlt、PrintWindow) 在 WPF Popup 視窗上均失效:前者截到背景,後者 WPF 區域呈現黑塊。根因在於 WPF 使用 DirectX 渲染,繞過 GDI 裝置內容 (DC)。本文探討第三種方案:模擬 PrintScreen 鍵並從剪貼簿取圖。
const uint KEYEVENTF_EXTENDEDKEY = 0x1;
const uint KEYEVENTF_KEYUP = 0x2;
const byte VK_SNAPSHOT = 0x2C;
Native.keybd_event(VK_SNAPSHOT, 0x45, KEYEVENTF_EXTENDEDKEY, UIntPtr.Zero);
Native.keybd_event(VK_SNAPSHOT, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, UIntPtr.Zero);
// 給系統時間將圖片放入剪貼簿
Thread.Sleep(100);
IDataObject data = Clipboard.GetDataObject();
if (data.GetDataPresent(DataFormats.Bitmap))
{
using (var screenBmp = (Bitmap)data.GetData(DataFormats.Bitmap))
using (var outputBmp = new Bitmap(rect.Width, rect.Height, PixelFormat.Format24bppRgb))
using (var g = Graphics.FromImage(outputBmp))
{
g.DrawImage(screenBmp,
new Rectangle(0, 0, rect.Width, rect.Height),
rect.X, rect.Y, rect.Width, rect.Height,
GraphicsUnit.Pixel);
outputBmp.Save(path, ImageFormat.Bmp);
}
}
Thread.Sleep 不可靠。需輪詢剪貼簿或使用 Clipboard.GetDataObject() 非同步模式。RenderTargetBitmap 可直接渲染 WPF 視覺樹,但無法捕捉非 WPF 視窗 (如 Win32 子視窗、硬體加速視訊)。RenderTargetBitmap 是最佳選擇。若專案允許依賴第三方庫,推薦 ScreenToGif 核心截圖邏輯 (採用 Desktop Duplication + Magnification 回退)。若必須自行實作,優先嘗試 RenderTargetBitmap (純 WPF) 或 Magnification API (混合 HWND),將模擬鍵盤方案作為最後回退。