實作類似 QQ 截圖功能:先擷取全螢幕到全螢幕覆蓋表單,使用者在覆蓋層框選區域,再將選取影像傳回主表單。關鍵技術包含 GDI 截圖、表單間資料傳遞(委派/建構子)、資源釋放。
GetAllScreen() 截取全螢幕位圖。CaptureScreen,建構子傳入全螢幕位圖與主表單參考。GetPartScreen() 截取選取區域位圖。OnPaint 確保影像正確重繪。[DllImport("gdi32.dll")]
private static extern bool BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, int dwRop);
private Bitmap GetAllScreen()
{
Graphics gScreen = Graphics.FromHwnd(IntPtr.Zero);
Bitmap bmp = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, gScreen);
Graphics gBmp = Graphics.FromImage(bmp);
IntPtr hdcScreen = gScreen.GetHdc();
IntPtr hdcBmp = gBmp.GetHdc();
BitBlt(hdcBmp, 0, 0, bmp.Width, bmp.Height, hdcScreen, 0, 0, 0x00CC0020); // SRCCOPY
gBmp.ReleaseHdc(hdcBmp);
gScreen.ReleaseHdc(hdcScreen);
gBmp.Dispose();
gScreen.Dispose();
return bmp;
}
private Bitmap GetPartScreen(Point p1, Point p2)
{
int x = Math.Min(p1.X, p2.X);
int y = Math.Min(p1.Y, p2.Y);
int w = Math.Abs(p1.X - p2.X);
int h = Math.Abs(p1.Y - p2.Y);
if (w == 0 || h == 0) return null;
IntPtr hdcScreen = CreateDC("DISPLAY", null, null, IntPtr.Zero);
IntPtr hdcMem = CreateCompatibleDC(hdcScreen);
IntPtr hBitmap = CreateCompatibleBitmap(hdcScreen, w, h);
IntPtr hOld = SelectObject(hdcMem, hBitmap);
BitBlt(hdcMem, 0, 0, w, h, hdcScreen, x, y, 0x00CC0020);
SelectObject(hdcMem, hOld);
DeleteDC(hdcScreen);
DeleteDC(hdcMem);
return Bitmap.FromHbitmap(hBitmap);
}
// 所需 API
[DllImport("gdi32.dll")] private static extern IntPtr CreateDC(string driver, string device, string output, IntPtr init);
[DllImport("gdi32.dll")] private static extern IntPtr CreateCompatibleDC(IntPtr hdc);
[DllImport("gdi32.dll")] private static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int w, int h);
[DllImport("gdi32.dll")] private static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
[DllImport("gdi32.dll")] private static extern int DeleteDC(IntPtr hdc);
// 主表單定義委派
public delegate void ImageReceivedHandler(Bitmap img);
public event ImageReceivedHandler OnImageReceived;
// 截圖表單建構子接收委派
public CaptureScreen(Bitmap fullScreen, ImageReceivedHandler callback)
{
InitializeComponent();
_fullScreen = fullScreen;
_callback = callback;
}
// 雙擊確認時觸發
private void picScreen_DoubleClick(object sender, EventArgs e)
{
Bitmap part = GetPartScreen(_startPoint, _endPoint);
_callback?.Invoke(part);
this.Close();
}
PictureBox 未重繪 → 覆寫 OnPaint 強制更新。GetHdc、CreateDC、SelectObject 必須配對 ReleaseHdc/DeleteDC/SelectObject 還原。Screen.AllScreens 計算虛擬桌面範圍,而非單一 PrimaryScreen。
進階擴充: 加入標註工具、直接存檔、上傳雲端、多螢幕合成截圖。