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

C# 螢幕截圖完整實現:全螢幕、指定視窗、儲存檔案三合一類庫

     編輯:關於C語言

功能概覽

本類庫 ScreenCameraClass 封裝 Windows GDI API,提供三大核心功能:

  • CaptureScreen():截取整個桌面畫面
  • CaptureWindow(IntPtr handle):截取指定視窗句柄畫面
  • CaptureScreenToFile / CaptureWindowToFile:直接儲存為圖片檔(支援 PNG、JPEG、BMP 等格式)

核心代碼

using System;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Drawing.Imaging;

namespace CSharpChat
{
    public class ScreenCameraClass
    {
        /// 截取全螢幕
        public Image CaptureScreen()
        {
            return CaptureWindow(User32.GetDesktopWindow());
        }

        /// 截取指定視窗
        public Image CaptureWindow(IntPtr handle)
        {
            // 1. 取得視窗 DC
            IntPtr hdcSrc = User32.GetWindowDC(handle);

            // 2. 取得視窗矩形區域
            User32.RECT windowRect = new User32.RECT();
            User32.GetWindowRect(handle, ref windowRect);
            int width = windowRect.right - windowRect.left;
            int height = windowRect.bottom - windowRect.top;

            // 3. 建立相容 DC 與位圖
            IntPtr hdcDest = GDI32.CreateCompatibleDC(hdcSrc);
            IntPtr hBitmap = GDI32.CreateCompatibleBitmap(hdcSrc, width, height);

            // 4. 選入位圖並 BitBlt 複製像素
            IntPtr hOld = GDI32.SelectObject(hdcDest, hBitmap);
            GDI32.BitBlt(hdcDest, 0, 0, width, height, hdcSrc, 0, 0, GDI32.SRCCOPY);

            // 5. 還原選擇、釋放資源
            GDI32.SelectObject(hdcDest, hOld);
            GDI32.DeleteDC(hdcDest);
            User32.ReleaseDC(handle, hdcSrc);

            // 6. 轉為 .NET Image 物件並釋放原生位圖
            Image img = Image.FromHbitmap(hBitmap);
            GDI32.DeleteObject(hBitmap);

            return img;
        }

        /// 截取視窗並存檔
        public void CaptureWindowToFile(IntPtr handle, string filename, ImageFormat format)
        {
            Image img = CaptureWindow(handle);
            img.Save(filename, format);
        }

        /// 截取全螢幕並存檔
        public void CaptureScreenToFile(string filename, ImageFormat format)
        {
            Image img = CaptureScreen();
            img.Save(filename, format);
        }

        // --- P/Invoke 內部類別 ---
        private class GDI32
        {
            public const int SRCCOPY = 0x00CC0020;

            [DllImport("gdi32.dll")] public static extern bool BitBlt(IntPtr hObject, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hObjectSource, int nXSrc, int nYSrc, int dwRop);
            [DllImport("gdi32.dll")] public static extern IntPtr CreateCompatibleBitmap(IntPtr hDC, int nWidth, int nHeight);
            [DllImport("gdi32.dll")] public static extern IntPtr CreateCompatibleDC(IntPtr hDC);
            [DllImport("gdi32.dll")] public static extern bool DeleteDC(IntPtr hDC);
            [DllImport("gdi32.dll")] public static extern bool DeleteObject(IntPtr hObject);
            [DllImport("gdi32.dll")] public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);
        }

        private class User32
        {
            [StructLayout(LayoutKind.Sequential)]
            public struct RECT { public int left, top, right, bottom; }

            [DllImport("user32.dll")] public static extern IntPtr GetDesktopWindow();
            [DllImport("user32.dll")] public static extern IntPtr GetWindowDC(IntPtr hWnd);
            [DllImport("user32.dll")] public static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDC);
            [DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr hWnd, ref RECT rect);
        }
    }
}

使用範例

var camera = new ScreenCameraClass();

// 1. 全螢幕截圖存 PNG
camera.CaptureScreenToFile(@"C:\Temp\fullscreen.png", ImageFormat.Png);

// 2. 截取指定視窗(以 Notepad 為例)
Process[] notepads = Process.GetProcessesByName("notepad");
if (notepads.Length > 0)
{
    camera.CaptureWindowToFile(notepads[0].MainWindowHandle, @"C:\Temp\notepad.jpg", ImageFormat.Jpeg);
}

// 3. 取得 Image 物件進一步處理(如顯示在 PictureBox)
Image img = camera.CaptureScreen();
pictureBox1.Image = img;

技術細節深度解析

GDI 複製流程

  1. GetWindowDC:取得視窗裝置內容(含非客戶區:標題列、邊框)
  2. CreateCompatibleDC:在記憶體建立相容 DC
  3. CreateCompatibleBitmap:建立與螢幕相容的 DDB(裝置相依位圖)
  4. SelectObject:將位圖選入記憶體 DC(舊物件需保存以便還原)
  5. BitBlt (SRCCOPY):將來源 DC 像素逐點複製到目標 DC
  6. Image.FromHbitmap:將 HBITMAP 包裝為 managed System.Drawing.Bitmap
  7. DeleteObject / DeleteDC / ReleaseDC:嚴格釋放非託管資源,防止 GDI 物件洩漏

常見問題與解決方案

問題原因解決
截圖為黑畫面視窗被遮擋、最小化、或採用 DirectX/DWM 繪製改用 PrintWindow API 或 DwmThumbnail;確保視窗可見
高 DPI 模糊應用程式未宣告 DPI Awareness在 app.manifest 設定 <dpiAware>True</dpiAware> 或呼叫 SetProcessDpiAwareness
多螢幕座標偏移GetWindowRect 回傳虛擬螢幕座標直接使用該座標建立位圖即可,BitBlt 會正確處理
UWP/Store App 無法截圖應用容器隔離,無法跨程序存取 DC使用 GraphicsCapture API (Win10 1903+)

現代替代方案 (.NET 6+ / WinUI 3)

// 使用 Windows.Graphics.Capture (需 Win10 1903+)
using Windows.Graphics.Capture;
using Windows.Graphics.DirectX.Direct3D11;

var picker = new GraphicsCapturePicker();
GraphicsCaptureItem item = await picker.PickSingleItemAsync();
if (item != null)
{
    var session = item.CreateCaptureSession();
    // 需搭配 Direct3D11 處理框架,較複雜但支援 UWP、HDR、高 DPI
}

總結

ScreenCameraClass 是經典 GDI 截圖的標準實現,適合 WinForms、WPF、Console 等傳統桌面應用。對於高 DPI、UWP、硬體加速視窗等現代場景,建議遷移至 Windows.Graphics.Capture API。記得在長時間運行的服務中妥善 Dispose() 回傳的 Image 物件,避免記憶體壓力。

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