透過 gdi32.dll / user32.dll 建立相容裝置內容(DC)、位圖,複製桌面像素到記憶體位圖,再用 Bitmap.GetPixel 讀取指定座標顏色。
public static class Win32Api
{
[DllImport("gdi32.dll")] public static extern IntPtr DeleteDC(IntPtr hdc);
[DllImport("gdi32.dll")] public static extern IntPtr DeleteObject(IntPtr hObject);
[DllImport("gdi32.dll")] public static extern bool BitBlt(IntPtr hdcDest, int nXDest, int nYDest,
int nWidth, int nHeight, IntPtr hdcSrc, 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 IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobjBmp);
[DllImport("user32.dll")] public static extern IntPtr GetDesktopWindow();
[DllImport("user32.dll")] public static extern IntPtr GetDC(IntPtr hWnd);
[DllImport("user32.dll")] public static extern int GetSystemMetrics(int nIndex);
[DllImport("user32.dll")] public static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDC);
public static Bitmap CaptureDesktop()
{
int screenX = GetSystemMetrics(0); // SM_CXSCREEN
int screenY = GetSystemMetrics(1); // SM_CYSCREEN
IntPtr hdcScreen = GetDC(GetDesktopWindow());
IntPtr hdcCompat = CreateCompatibleDC(hdcScreen);
IntPtr hBmp = CreateCompatibleBitmap(hdcScreen, screenX, screenY);
if (hBmp == IntPtr.Zero) return null;
IntPtr hOldBmp = SelectObject(hdcCompat, hBmp);
const int SRCCOPY = 0x00CC0020; // 13369376
BitBlt(hdcCompat, 0, 0, screenX, screenY, hdcScreen, 0, 0, SRCCOPY);
SelectObject(hdcCompat, hOldBmp);
DeleteDC(hdcCompat);
ReleaseDC(GetDesktopWindow(), hdcScreen);
Bitmap bmp = Image.FromHbitmap(hBmp);
DeleteObject(hBmp);
GC.Collect(); // 釋放非受控資源
return bmp;
}
}
public partial class MainForm : Form
{
private Bitmap _desktopBmp;
private Label _lblColor;
public MainForm()
{
InitializeComponent();
_lblColor = new Label
{
BorderStyle = BorderStyle.FixedSingle,
Text = "",
Dock = DockStyle.Top,
Height = 50,
BackColor = Color.White
};
Controls.Add(_lblColor);
_lblColor.MouseDown += (s, e) => _desktopBmp = Win32Api.CaptureDesktop();
_lblColor.MouseUp += (s, e) =>
{
if (_desktopBmp != null)
{
Color c = _desktopBmp.GetPixel(Cursor.Position.X, Cursor.Position.Y);
_lblColor.BackColor = c;
_lblColor.Text = $"R={c.R}, G={c.G}, B={c.B}";
}
};
}
}
BitBlt + SRCCOPY:高速像素複製CreateCompatibleBitmap/DC:建立螢幕相容的記憶體位圖Image.FromHbitmap:將 HBITMAP 轉為 .NET BitmapCursor.Position:取得螢幕座標(非客戶區座標)GC.Collect():確保非受控 GDI 物件及時釋放
// .NET 6+ 可用 Graphics.CopyFromScreen(無需 P/Invoke)
public static Bitmap CaptureDesktopModern()
{
var bmp = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
using (var g = Graphics.FromImage(bmp))
g.CopyFromScreen(Point.Empty, Point.Empty, bmp.Size);
return bmp;
}
但 GetPixel 仍較慢,高頻取色建議鎖定位圖記憶體 (Bitmap.LockBits) 直接讀取陣列。