本類庫 ScreenCameraClass 封裝 Windows GDI API,提供三大核心功能:
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;
System.Drawing.Bitmap| 問題 | 原因 | 解決 |
|---|---|---|
| 截圖為黑畫面 | 視窗被遮擋、最小化、或採用 DirectX/DWM 繪製 | 改用 PrintWindow API 或 DwmThumbnail;確保視窗可見 |
| 高 DPI 模糊 | 應用程式未宣告 DPI Awareness | 在 app.manifest 設定 <dpiAware>True</dpiAware> 或呼叫 SetProcessDpiAwareness |
| 多螢幕座標偏移 | GetWindowRect 回傳虛擬螢幕座標 | 直接使用該座標建立位圖即可,BitBlt 會正確處理 |
| UWP/Store App 無法截圖 | 應用容器隔離,無法跨程序存取 DC | 使用 GraphicsCapture API (Win10 1903+) |
// 使用 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 物件,避免記憶體壓力。