首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 三種螢幕截圖技術深度解析:從 BitBlt 到 PrintScreen 模擬

     編輯:關於C#

問題背景

在自動化測試中需要截取 WPF 的 Popup 視窗,卻發現傳統 GDI 方式(BitBlt)與 PrintWindow API 皆無法正確捕捉 WPF 繪製的內容(呈現黑畫面或只抓到背景)。本文記錄三種截圖方案的嘗試與比較。

方案一:BitBlt (GDI 裝置內容複製)

BitBlt(dcImage, 0, 0, (int)rect.Width, (int)rect.Height,
       dcScreen, (int)rect.Left, (int)rect.Top, TernaryRasterOperations.SRCCOPY);
  • 原理:直接從螢幕 DC 複製像素到記憶體 DC。
  • 缺點:對 WPF 硬體加速渲染的視窗(特別是 Popup、ToolTip 等無框視窗)支援不佳,常抓不到內容或只抓到背景。

方案二:PrintWindow API

IntPtr hdc = Native.GetWindowDC(hwnd);
IntPtr hdcMem = Native.CreateCompatibleDC(hdc);
IntPtr hbitmap = Native.CreateCompatibleBitmap(hdc, width, height);
Native.SelectObject(hdcMem, hbitmap);
Native.PrintWindow(hwnd, hdcMem, 0); // 關鍵呼叫
Bitmap bmp = Bitmap.FromHbitmap(hbitmap);
// 釋放資源...
  • 原理:要求視窗自行繪製到指定 DC,理論上支援被遮蓋視窗。
  • 實測結果:MFC/Win32 視窗正常,但 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);

IDataObject iObj = Clipboard.GetDataObject();
if (iObj.GetDataPresent(DataFormats.Bitmap))
{
    Bitmap bmpScreen = (Bitmap)iObj.GetData(DataFormats.Bitmap);
    Bitmap bmpOutput = new Bitmap(rect.Width, rect.Height, PixelFormat.Format24bppRgb);
    using (Graphics g = Graphics.FromImage(bmpOutput))
    {
        g.DrawImage(bmpScreen, new Rectangle(0,0,rect.Width,rect.Height),
                    rect.X, rect.Y, rect.Width, rect.Height, GraphicsUnit.Pixel);
    }
    bmpOutput.Save(path, ImageFormat.Bmp);
}
  • 原理:模擬全域熱鍵截圖至剪貼板,再裁剪所需區域。
  • 優點:能正確截取 WPF/DirectX 內容,包含 Popup 視窗。
  • 缺點:會汙染剪貼板(需備份/還原)、依賴 UI 執行緒、非純 API 呼叫、多螢幕座標計算較繁瑣。

技術根本原因分析

WPF 採用 DirectX (硬體加速) 繪製繞過 GDI,故傳統 BitBlt/PrintWindow(基於 GDI DC)無法取得像素。PrintScreen 由視窗管理器 (DWM) 合成最終畫面,故能捕捉所有視覺內容。

待解決問題與替代方向

  1. 尋找 PrintScreen 背後的核心 API(如 DwmGetWindowAttribute、DirectX Surface Copy),避免模擬按鍵。
  2. 研究 RenderTargetBitmap (WPF 內建) 對視覺樹渲染,但需在 UI 執行緒且無法跨進程。
  3. 考慮 Windows.Graphics.Capture API (Win10 1903+) 實現高效、無剪貼板依賴的跨進程截圖。

結語

若需截取 WPF 應用程式的完整視覺內容(含 Popup、ToolTip、硬體加速區域),目前最穩健的無外部相依方案仍是模擬 PrintScreen;長遠來看,應遷移至 Windows.Graphics.Capture 或同層級的現代截圖 API。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved